diff --git a/0001-refactor-patch-code-of-utils-commands-and-so-on.patch b/0001-refactor-patch-code-of-utils-commands-and-so-on.patch new file mode 100644 index 0000000000000000000000000000000000000000..e39be2e3586bb864a4a27eed1bf3649037446e54 --- /dev/null +++ b/0001-refactor-patch-code-of-utils-commands-and-so-on.patch @@ -0,0 +1,2368 @@ +From d6745a42729f4704a0d9913676bf6d8b03c21903 Mon Sep 17 00:00:00 2001 +From: zhangxiaoyu +Date: Fri, 15 Jul 2022 17:06:09 +0800 +Subject: [PATCH] refactor patch code of utils commands and so on + +Signed-off-by: zhangxiaoyu +--- + 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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#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 ++#include ++ ++#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 + #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 ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#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 "" */ ++ 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 ++#include ++ ++/* 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 ++#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 + #include + #include ++#ifdef HAVE_ISULAD ++#include ++#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/. */ + 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 + diff --git a/0002-iSulad-adapt-security-conf-attach-cgroup-and-start.patch b/0002-refactor-patch-code-of-isulad-for-conf-exec-attach.patch similarity index 41% rename from 0002-iSulad-adapt-security-conf-attach-cgroup-and-start.patch rename to 0002-refactor-patch-code-of-isulad-for-conf-exec-attach.patch index ba43f16a45f5e62fd97aa5cf9f480f549227b894..00c07a530d90ec93ba22964a0855777097ab1675 100644 --- a/0002-iSulad-adapt-security-conf-attach-cgroup-and-start.patch +++ b/0002-refactor-patch-code-of-isulad-for-conf-exec-attach.patch @@ -1,1542 +1,1274 @@ -From ef27d69db952dc64fc3c476a89c3e822c891e663 Mon Sep 17 00:00:00 2001 +From 7166cf40250f00544e204a33da668b56ed4b13ca Mon Sep 17 00:00:00 2001 From: haozi007 -Date: Mon, 17 Jul 2023 20:40:48 +0800 -Subject: [PATCH 2/3] [iSulad] adapt security conf attach cgroup and start +Date: Mon, 18 Jul 2022 11:30:33 +0800 +Subject: [PATCH] refactor patch code of isulad for conf/exec/attach Signed-off-by: haozi007 --- - src/lxc/attach.c | 503 ++++++++++- - src/lxc/attach.h | 6 + - src/lxc/attach_options.h | 25 + - src/lxc/cgroups/cgroup.c | 5 +- - src/lxc/cgroups/cgroup.h | 7 + - src/lxc/conf.c | 1703 +++++++++++++++++++++++++++++++++++- - src/lxc/conf.h | 82 ++ - src/lxc/isulad_utils.c | 25 + - src/lxc/isulad_utils.h | 26 +- - src/lxc/lsm/apparmor.c | 14 + - src/lxc/lsm/lsm.h | 4 + - src/lxc/lsm/nop.c | 14 + - src/lxc/lsm/selinux.c | 256 ++++++ - src/lxc/lxc.h | 7 + - src/lxc/lxclock.c | 27 + - src/lxc/lxclock.h | 4 + - src/lxc/mainloop.c | 16 + - src/lxc/mainloop.h | 4 + - src/lxc/mount_utils.c | 5 + - src/lxc/seccomp.c | 32 + - src/lxc/start.h | 11 + - src/lxc/tools/arguments.h | 28 + - src/lxc/tools/lxc_attach.c | 490 ++++++++++- - src/lxc/tools/lxc_start.c | 107 ++- - 24 files changed, 3376 insertions(+), 25 deletions(-) + src/lxc/attach_options.h | 41 +- + src/lxc/conf.c | 1993 ++++++++++++++++++++++++++++++++++++- + src/lxc/criu.c | 8 +- + src/lxc/execute.c | 19 + + src/lxc/file_utils.c | 27 + + src/lxc/lsm/apparmor.c | 14 + + src/lxc/tools/arguments.h | 24 + + 7 files changed, 2122 insertions(+), 4 deletions(-) -diff --git a/src/lxc/attach.c b/src/lxc/attach.c -index f086e96..1a89001 100644 ---- a/src/lxc/attach.c -+++ b/src/lxc/attach.c -@@ -47,6 +47,24 @@ - #include "terminal.h" - #include "utils.h" +diff --git a/src/lxc/attach_options.h b/src/lxc/attach_options.h +index 63e62d4..16b4e21 100644 +--- a/src/lxc/attach_options.h ++++ b/src/lxc/attach_options.h +@@ -49,7 +49,11 @@ enum { + * + * \return Function should return \c 0 on success, and any other value to denote failure. + */ ++#ifdef HAVE_ISULAD ++typedef int (*lxc_attach_exec_t)(void* payload, int msg_fd); ++#else + typedef int (*lxc_attach_exec_t)(void* payload); ++#endif + + /*! + * LXC attach options for \ref lxc_container \c attach(). +@@ -113,9 +117,18 @@ typedef struct lxc_attach_options_t { + + /*! File descriptor to log output. */ + int log_fd; ++ ++#ifdef HAVE_ISULAD ++ char *init_fifo[3]; /* isulad: default fifos for the start */ ++ int64_t timeout;/* isulad: Seconds for waiting on a container to attach/exec before it is killed*/ ++ const char *suffix; ++ bool disable_pty; ++ bool open_stdin; ++#endif + } lxc_attach_options_t; + + /*! Default attach options to use */ ++#ifndef HAVE_ISULAD + #define LXC_ATTACH_OPTIONS_DEFAULT \ + { \ + /* .attach_flags = */ LXC_ATTACH_DEFAULT, \ +@@ -132,7 +145,25 @@ typedef struct lxc_attach_options_t { + /* .stderr_fd = */ 2, \ + /* .log_fd = */ -EBADF, \ + } +- ++#else ++#define LXC_ATTACH_OPTIONS_DEFAULT \ ++ { \ ++ /* .attach_flags = */ LXC_ATTACH_DEFAULT, \ ++ /* .namespaces = */ -1, \ ++ /* .personality = */ -1, \ ++ /* .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, \ ++ /* .init_fifo = */ {NULL, NULL, NULL}, \ ++ } ++#endif + /*! + * Representation of a command to run in a container. + */ +@@ -148,7 +179,11 @@ typedef struct lxc_attach_command_t { + * + * \return \c -1 on error, exit code of lxc_attach_command_t program on success. + */ ++#ifdef HAVE_ISULAD ++extern int lxc_attach_run_command(void* payload, int msg_fd); ++#else + extern int lxc_attach_run_command(void* payload); ++#endif + + /*! + * \brief Run a shell command in the container. +@@ -157,7 +192,11 @@ extern int lxc_attach_run_command(void* payload); + * + * \return Exit code of shell. + */ ++#ifdef HAVE_ISULAD ++extern int lxc_attach_run_shell(void* payload, int msg_fd); ++#else + extern int lxc_attach_run_shell(void* payload); ++#endif + + #ifdef __cplusplus + } +diff --git a/src/lxc/conf.c b/src/lxc/conf.c +index 0078996..378cf9f 100644 +--- a/src/lxc/conf.c ++++ b/src/lxc/conf.c +@@ -33,6 +33,14 @@ + #include + #include +#ifdef HAVE_ISULAD -+#include "exec_commands.h" ++#include ++#include "sync.h" ++#include "path.h" ++#include "utils.h" ++#include "loop.h" ++#endif + -+typedef enum { -+ ATTACH_INIT, -+ ATTACH_TIMEOUT, -+ ATTACH_MAX, -+} attach_timeout_t; + #include "af_unix.h" + #include "caps.h" + #include "cgroup.h" +@@ -118,7 +126,14 @@ char *lxchook_names[NUM_LXC_HOOKS] = { + "post-stop", + "clone", + "destroy", ++#ifdef HAVE_ISULAD ++ "start-host", ++ "oci-prestart", ++ "oci-poststart", ++ "oci-poststop" ++#else + "start-host" ++#endif + }; + + struct mount_opt { +@@ -285,6 +300,22 @@ static struct limit_opt limit_opt[] = { + #endif + }; + ++#ifdef HAVE_ISULAD ++static int rootfs_parent_mount_private(char *rootfs); ++static int setup_rootfs_ropaths(struct lxc_list *ropaths); ++static int setup_rootfs_maskedpaths(struct lxc_list *maskedpaths); ++static int remount_proc_sys_mount_entries(struct lxc_list *mount_list, bool lsm_aa_allow_nesting); ++static int check_mount_destination(const char *rootfs, const char *dest, const char *src); ++static int mount_entry_with_loop_dev(const char *src, const char *dest, const char *fstype, ++ char *mnt_opts, const char *rootfs); ++static bool need_setup_proc(const struct lxc_conf *conf, struct lxc_list *mount); ++static bool need_setup_dev(const struct lxc_conf *conf, struct lxc_list *mount); ++static int setup_populate_devs(const struct lxc_rootfs *rootfs, struct lxc_list *devs, const char *mount_label); ++static int setup_rootfs_mountopts(const struct lxc_rootfs *rootfs); ++static int create_mtab_link(); + -+static volatile attach_timeout_t g_attach_timeout_state = ATTACH_INIT; ++#endif + -+struct attach_timeout_conf { -+ int64_t timeout; -+ unsigned long long start_time; -+ pid_t pid; -+}; + static int run_buffer(char *buffer) + { + __do_free char *output = NULL; +@@ -637,8 +668,13 @@ static int lxc_mount_auto_mounts(struct lxc_conf *conf, int flags, struct lxc_ha + { LXC_AUTO_PROC_MASK, LXC_AUTO_PROC_MIXED, "%r/proc/sysrq-trigger", "%r/proc/sysrq-trigger", NULL, MS_BIND, NULL }, + { LXC_AUTO_PROC_MASK, LXC_AUTO_PROC_MIXED, NULL, "%r/proc/sysrq-trigger", NULL, MS_REMOUNT|MS_BIND|MS_RDONLY, NULL }, + { LXC_AUTO_PROC_MASK, LXC_AUTO_PROC_RW, "proc", "%r/proc", "proc", MS_NODEV|MS_NOEXEC|MS_NOSUID, NULL }, ++#ifdef HAVE_ISULAD ++ { LXC_AUTO_SYS_MASK, LXC_AUTO_SYS_RW, "sysfs", "%r/sys", "sysfs", MS_NODEV|MS_NOEXEC|MS_NOSUID, NULL }, ++ { LXC_AUTO_SYS_MASK, LXC_AUTO_SYS_RO, "sysfs", "%r/sys", "sysfs", MS_RDONLY|MS_NODEV|MS_NOEXEC|MS_NOSUID, NULL }, ++#else + { LXC_AUTO_SYS_MASK, LXC_AUTO_SYS_RW, "sysfs", "%r/sys", "sysfs", 0, NULL }, + { LXC_AUTO_SYS_MASK, LXC_AUTO_SYS_RO, "sysfs", "%r/sys", "sysfs", MS_RDONLY, NULL }, ++#endif + { LXC_AUTO_SYS_MASK, LXC_AUTO_SYS_MIXED, "sysfs", "%r/sys", "sysfs", MS_NODEV|MS_NOEXEC|MS_NOSUID, NULL }, + { LXC_AUTO_SYS_MASK, LXC_AUTO_SYS_MIXED, "%r/sys", "%r/sys", NULL, MS_BIND, NULL }, + { LXC_AUTO_SYS_MASK, LXC_AUTO_SYS_MIXED, NULL, "%r/sys", NULL, MS_REMOUNT|MS_BIND|MS_RDONLY, NULL }, +@@ -670,11 +706,24 @@ static int lxc_mount_auto_mounts(struct lxc_conf *conf, int flags, struct lxc_ha + if (!destination) + return -1; + ++#ifdef HAVE_ISULAD ++ if (mkdir_p(destination, 0755) < 0) { ++ SYSERROR("Failed to create mount target '%s'", destination); ++ return log_error(-1, "Failed to mkdir destination %s", destination); ++ } +#endif + - lxc_log_define(attach, lxc); + mflags = add_required_remount_flags(source, destination, + default_mounts[i].flags); ++#ifdef HAVE_ISULAD ++ r = safe_mount(source, destination, default_mounts[i].fstype, ++ mflags, default_mounts[i].options, ++ conf->rootfs.path ? conf->rootfs.mount : NULL, NULL); ++#else + r = safe_mount(source, destination, default_mounts[i].fstype, + mflags, default_mounts[i].options, + conf->rootfs.path ? conf->rootfs.mount : NULL); ++#endif + saved_errno = errno; + if (r < 0 && errno == ENOENT) { + INFO("Mount source or target for \"%s\" on \"%s\" does not exist. Skipping", source, destination); +@@ -1047,8 +1096,13 @@ on_error: + /* Just create a path for /dev under $lxcpath/$name and in rootfs If we hit an + * error, log it but don't fail yet. + */ ++#ifdef HAVE_ISULAD ++static int mount_autodev(const char *name, const struct lxc_rootfs *rootfs, ++ int autodevtmpfssize, const char *lxcpath, char *systemd, const char *mount_label) ++#else + static int mount_autodev(const char *name, const struct lxc_rootfs *rootfs, + int autodevtmpfssize, const char *lxcpath) ++#endif + { + __do_free char *path = NULL; + int ret; +@@ -1076,6 +1130,23 @@ static int mount_autodev(const char *name, const struct lxc_rootfs *rootfs, + goto reset_umask; + } - /* Define default options if no options are supplied by the user. */ -@@ -1115,6 +1133,9 @@ struct attach_payload { - struct attach_context *ctx; - lxc_attach_exec_t exec_function; - void *exec_payload; +#ifdef HAVE_ISULAD -+ struct lxc_terminal *terminal; ++ if (systemd != NULL && !strcmp(systemd, "true")) { ++ ret = mount(path, path, "", MS_BIND, NULL); ++ if (ret < 0) { ++ SYSERROR("Failed to bind mount path \"%s\"", path); ++ goto reset_umask; ++ } ++ } else { ++ ret = safe_mount("none", path, "tmpfs", 0, mount_options, ++ rootfs->path ? rootfs->mount : NULL, mount_label); ++ if (ret < 0) { ++ SYSERROR("Failed to mount tmpfs on \"%s\"", path); ++ goto reset_umask; ++ } ++ TRACE("Mounted tmpfs on \"%s\"", path); ++ } ++#else + ret = safe_mount("none", path, "tmpfs", 0, mount_options, + rootfs->path ? rootfs->mount : NULL ); + if (ret < 0) { +@@ -1083,6 +1154,7 @@ static int mount_autodev(const char *name, const struct lxc_rootfs *rootfs, + goto reset_umask; + } + TRACE("Mounted tmpfs on \"%s\"", path); +#endif + + ret = snprintf(path, clen, "%s/dev/pts", rootfs->path ? rootfs->mount : ""); + if (ret < 0 || (size_t)ret >= clen) { +@@ -1132,8 +1204,11 @@ enum { + LXC_DEVNODE_PARTIAL, + LXC_DEVNODE_OPEN, }; +- ++#ifdef HAVE_ISULAD ++static int lxc_fill_autodev(const struct lxc_rootfs *rootfs, const char *mount_label) ++#else + static int lxc_fill_autodev(const struct lxc_rootfs *rootfs) ++#endif + { + int i, ret; + char path[PATH_MAX]; +@@ -1209,9 +1284,13 @@ static int lxc_fill_autodev(const struct lxc_rootfs *rootfs) + ret = snprintf(hostpath, PATH_MAX, "/dev/%s", device->name); + if (ret < 0 || ret >= PATH_MAX) + return -1; +- ++#ifdef HAVE_ISULAD ++ ret = safe_mount(hostpath, path, 0, MS_BIND, NULL, ++ rootfs->path ? rootfs->mount : NULL, mount_label); ++#else + ret = safe_mount(hostpath, path, 0, MS_BIND, NULL, + rootfs->path ? rootfs->mount : NULL); ++#endif + if (ret < 0) + return log_error_errno(-1, errno, "Failed to bind mount host device node \"%s\" onto \"%s\"", + hostpath, path); +@@ -1227,12 +1306,29 @@ static int lxc_mount_rootfs(struct lxc_conf *conf) + { + int ret; + struct lxc_storage *bdev; ++#ifdef HAVE_ISULAD ++ struct lxc_rootfs *rootfs = &conf->rootfs; ++#else + const struct lxc_rootfs *rootfs = &conf->rootfs; ++#endif ++ ++#ifdef HAVE_ISULAD ++ unsigned long flags, mntflags, pflags; ++ char *mntdata = NULL; ++#endif + + if (!rootfs->path) { + ret = mount("", "/", NULL, MS_SLAVE | MS_REC, 0); + if (ret < 0) + return log_error_errno(-1, errno, "Failed to recursively turn root mount tree into dependent mount"); ++#ifdef HAVE_ISULAD ++ if (!access(rootfs->mount, F_OK)) { ++ rootfs->path = safe_strdup("/"); ++ if (mount("/", rootfs->mount, NULL, MS_BIND, 0)) { ++ return log_error_errno(-1, errno, "Failed to mount \"/\" to %s", rootfs->mount); ++ } ++ } ++#endif - static void put_attach_payload(struct attach_payload *p) -@@ -1127,6 +1148,48 @@ static void put_attach_payload(struct attach_payload *p) + return 0; } - } +@@ -1242,6 +1338,48 @@ static int lxc_mount_rootfs(struct lxc_conf *conf) + return log_error_errno(-1, errno, "Failed to access to \"%s\". Check it is present", + rootfs->mount); +#ifdef HAVE_ISULAD -+static int isulad_set_attach_pipes(struct lxc_terminal *terminal) -+{ -+ int ret = 0; -+ if (terminal->pipes[0][1] >= 0) { -+ close(terminal->pipes[0][1]); -+ terminal->pipes[0][1] = -1; ++ // Support mount propagations of rootfs ++ // Get rootfs mnt propagation options, such as slave or shared ++ if (parse_mntopts(conf->rootfs.options, &mntflags, &pflags, &mntdata) < 0) { ++ free(mntdata); ++ return -1; + } ++ free(mntdata); + -+ if (terminal->pipes[0][0] >= 0) { -+ ret = dup2(terminal->pipes[0][0], STDIN_FILENO); -+ if (ret < 0) -+ goto out; -+ } ++ flags = MS_SLAVE | MS_REC; ++ if (pflags) ++ flags = pflags; + -+ if (terminal->pipes[1][0] >= 0) { -+ close(terminal->pipes[1][0]); -+ terminal->pipes[1][0] = -1; ++ /* Mount propagation inside container can not greater than host. ++ * So we must change propagation of root according to flags, default is rslave. ++ * That means shared propagation inside container is disabled by default. ++ */ ++ ret = mount("", "/", NULL, flags, NULL); ++ if (ret < 0) { ++ return log_error_errno(-1, errno, "Failed to make / to propagation flags %lu.", flags); + } + -+ if (terminal->pipes[1][1] >= 0) { -+ ret = dup2(terminal->pipes[1][1], STDOUT_FILENO); -+ if (ret < 0) -+ goto out; ++ /* Make parent mount private to make sure following bind mount does ++ * not propagate in other namespaces. Also it will help with kernel ++ * check pass in pivot_root. (IS_SHARED(new_mnt->mnt_parent)) ++ */ ++ ret = rootfs_parent_mount_private(conf->rootfs.path); ++ if (ret != 0) { ++ return log_error(-1, "Failed to make parent of rootfs %s to private.", conf->rootfs.path); + } -+ if (terminal->pipes[2][0] >= 0) { -+ close(terminal->pipes[2][0]); -+ terminal->pipes[2][0] = -1; ++ ret = rootfs_parent_mount_private(conf->rootfs.mount); ++ if (ret != 0) { ++ return log_error(-1, "Failed to make parent of rootfs %s to private.", conf->rootfs.mount); + } + -+ if (terminal->pipes[2][1] >= 0) { -+ ret = dup2(terminal->pipes[2][1], STDERR_FILENO); -+ if (ret < 0) -+ goto out; ++ ret = mount(conf->rootfs.mount, conf->rootfs.mount, "bind", MS_BIND | MS_REC, NULL); ++ if (ret < 0) { ++ SYSERROR("Failed to mount rootfs %s", conf->rootfs.mount); ++ return -1; + } -+ -+ setsid(); -+out: -+ return ret; -+} +#endif + - __noreturn static void do_attach(struct attach_payload *ap) + bdev = storage_init(conf); + if (!bdev) + return log_error(-1, "Failed to mount rootfs \"%s\" onto \"%s\" with options \"%s\"", +@@ -1475,17 +1613,34 @@ static int lxc_setup_devpts(struct lxc_conf *conf) { - lxc_attach_exec_t attach_function = move_ptr(ap->exec_function); -@@ -1135,6 +1198,31 @@ __noreturn static void do_attach(struct attach_payload *ap) - lxc_attach_options_t* options = ap->options; - struct attach_context *ctx = ap->ctx; - struct lxc_conf *conf = ctx->container->lxc_conf; + int ret; + char **opts; +#ifdef HAVE_ISULAD -+ int msg_fd = -1; -+ sigset_t mask; -+ -+ /*isulad: record errpipe fd*/ -+ msg_fd = init_ctx->container->lxc_conf->errpipe[1]; -+ init_ctx->container->lxc_conf->errpipe[1] = -1; -+ /*isulad: set system umask */ -+ umask(init_ctx->container->lxc_conf->umask); -+ -+ /*isulad: restore default signal handlers and unblock all signals*/ -+ for (int i = 1; i < NSIG; i++) -+ signal(i, SIG_DFL); -+ -+ ret = sigfillset(&mask); -+ if (ret < 0) { -+ SYSERROR("Failed to fill signal mask"); -+ goto on_error;; -+ } -+ ret = sigprocmask(SIG_UNBLOCK, &mask, NULL); -+ if (ret < 0) { -+ SYSERROR("Failed to set signal mask"); -+ goto on_error; -+ } ++ __do_free char *devpts_mntopts = NULL; ++#else + char devpts_mntopts[256]; +#endif + char *mntopt_sets[5]; + char default_devpts_mntopts[256] = "gid=5,newinstance,ptmxmode=0666,mode=0620"; - /* - * We currently artificially restrict core scheduling to be a pid -@@ -1209,6 +1297,27 @@ __noreturn static void do_attach(struct attach_payload *ap) - TRACE("Dropped capabilities"); - } + if (conf->pty_max <= 0) + return log_debug(0, "No new devpts instance will be mounted since no pts devices are requested"); +#ifdef HAVE_ISULAD -+ /* isulad: set workdir */ -+ if (options->initial_cwd || conf->init_cwd) { -+ char *init_cwd; -+ init_cwd = options->initial_cwd ? options->initial_cwd : conf->init_cwd; -+ /* try to create workdir if not exist */ -+ struct stat st; -+ if (stat(init_cwd, &st) < 0 && mkdir_p(init_cwd, 0750) < 0) { -+ SYSERROR("Try to create directory \"%s\" as workdir failed when attach", init_cwd); -+ lxc_write_error_message(msg_fd, "Try to create directory \"%s\" as workdir failed when attach: %s", -+ init_cwd, strerror(errno)); -+ goto on_error; ++ if (conf->lsm_se_mount_context != NULL) { ++ if (asprintf(&devpts_mntopts, "%s,max=%zu,context=\"%s\"", ++ default_devpts_mntopts, conf->pty_max, conf->lsm_se_mount_context) < 0) { ++ return -1; + } -+ if (chdir(init_cwd)) { -+ SYSERROR("Could not change directory to \"%s\" when attach", init_cwd); -+ lxc_write_error_message(msg_fd, "Could not change directory to \"%s\" when attach: %s", -+ init_cwd, strerror(errno)); -+ goto on_error; ++ } else { ++ if (asprintf(&devpts_mntopts, "%s,max=%zu", default_devpts_mntopts, conf->pty_max) < 0) { ++ return -1; + } + } -+#endif - /* Always set the environment (specify (LXC_ATTACH_KEEP_ENV, NULL, NULL) - * if you want this to be a no-op). - */ -@@ -1248,6 +1357,7 @@ __noreturn static void do_attach(struct attach_payload *ap) - goto on_error; - } - -+#ifndef HAVE_ISULAD - if ((options->attach_flags & LXC_ATTACH_SETGROUPS) && - options->groups.size > 0) { - if (!lxc_setgroups(options->groups.list, options->groups.size)) -@@ -1256,6 +1366,7 @@ __noreturn static void do_attach(struct attach_payload *ap) - if (!lxc_drop_groups() && errno != EPERM) - goto on_error; - } ++#else + ret = snprintf(devpts_mntopts, sizeof(devpts_mntopts), "%s,max=%zu", + default_devpts_mntopts, conf->pty_max); + if (ret < 0 || (size_t)ret >= sizeof(devpts_mntopts)) + return -1; +#endif - if (options->namespaces & CLONE_NEWUSER) - if (!lxc_switch_uid_gid(ctx->setup_ns_uid, ctx->setup_ns_gid)) -@@ -1274,6 +1385,13 @@ __noreturn static void do_attach(struct attach_payload *ap) - TRACE("Set %s LSM label to \"%s\"", ctx->lsm_ops->name, ctx->lsm_label); - } + (void)umount2("/dev/pts", MNT_DETACH); -+#ifdef HAVE_ISULAD -+ // isulad: set env home in container -+ if (lxc_setup_env_home(ctx->setup_ns_uid != LXC_INVALID_UID ? ctx->setup_ns_uid : 0) < 0) { -+ goto on_error; -+ } -+#endif -+ - if (conf->no_new_privs || (options->attach_flags & LXC_ATTACH_NO_NEW_PRIVS)) { - ret = prctl(PR_SET_NO_NEW_PRIVS, prctl_arg(1), prctl_arg(0), - prctl_arg(0), prctl_arg(0)); -@@ -1327,7 +1445,21 @@ __noreturn static void do_attach(struct attach_payload *ap) - } +@@ -1580,9 +1735,14 @@ static inline bool wants_console(const struct lxc_terminal *terminal) + return !terminal->path || strcmp(terminal->path, "none"); + } - if (options->attach_flags & LXC_ATTACH_TERMINAL) { +#ifdef HAVE_ISULAD -+ /* isulad: dup2 pipe[0][0] to container stdin, pipe[1][1] to container stdout, pipe[2][1] to container stderr */ -+ if (ap->terminal->disable_pty) { -+ ret = isulad_set_attach_pipes(ap->terminal); -+ if (ret < 0) { -+ SYSERROR("Failed to prepare terminal file pipes"); -+ goto on_error; -+ } -+ } else { ++static int lxc_setup_dev_console(const struct lxc_rootfs *rootfs, ++ const struct lxc_terminal *console, const char *mount_label) +#else - ret = lxc_terminal_prepare_login(ap->terminal_pts_fd); -+#endif -+#ifdef HAVE_ISULAD -+ } + static int lxc_setup_dev_console(const struct lxc_rootfs *rootfs, + const struct lxc_terminal *console, + int pts_mnt_fd) +#endif - if (ret < 0) { - SYSERROR("Failed to prepare terminal file descriptor %d", ap->terminal_pts_fd); - goto on_error; -@@ -1343,6 +1475,20 @@ __noreturn static void do_attach(struct attach_payload *ap) - if (ctx->setup_ns_gid == ctx->target_ns_gid) - ctx->target_ns_gid = LXC_INVALID_GID; + { + int ret; + char path[PATH_MAX]; +@@ -1615,10 +1775,14 @@ static int lxc_setup_dev_console(const struct lxc_rootfs *rootfs, + if (ret < 0 && errno != EEXIST) + return log_error_errno(-errno, errno, "Failed to create console"); +#ifdef HAVE_ISULAD -+ if (prctl(PR_SET_KEEPCAPS, 1) < 0) { -+ SYSERROR("Failed to keep permitted capabilities"); -+ goto on_error; -+ } -+ if ((options->attach_flags & LXC_ATTACH_SETGROUPS) && -+ options->groups.size > 0) { -+ if (!lxc_setgroups(options->groups.list, options->groups.size)) -+ goto on_error; -+ } else { -+ if (!lxc_drop_groups() && errno != EPERM) -+ goto on_error; -+ } ++ if (console->pts > 0) { +#endif - /* - * Make sure that the processes STDIO is correctly owned by the user - * that we are switching to. -@@ -1367,6 +1513,18 @@ __noreturn static void do_attach(struct attach_payload *ap) - if (!lxc_switch_uid_gid(ctx->target_ns_uid, ctx->target_ns_gid)) - goto on_error; + ret = fchmod(console->pts, S_IXUSR | S_IXGRP); + if (ret < 0) + return log_error_errno(-errno, errno, "Failed to set mode \"0%o\" to \"%s\"", S_IXUSR | S_IXGRP, console->name); -+#ifdef HAVE_ISULAD -+ if (prctl(PR_SET_KEEPCAPS, 0) < 0) { -+ SYSERROR("Failed to clear permitted capabilities"); -+ goto on_error; -+ } ++#ifndef HAVE_ISULAD + if (pts_mnt_fd >= 0) { + ret = move_mount(pts_mnt_fd, "", -EBADF, path, MOVE_MOUNT_F_EMPTY_PATH); + if (!ret) { +@@ -1633,17 +1797,35 @@ static int lxc_setup_dev_console(const struct lxc_rootfs *rootfs, + } + + ret = safe_mount(console->name, path, "none", MS_BIND, 0, rootfs_path); ++ + if (ret < 0) + return log_error_errno(-1, errno, "Failed to mount %d(%s) on \"%s\"", pts_mnt_fd, console->name, path); + + finish: + DEBUG("Mounted pts device %d(%s) onto \"%s\"", pts_mnt_fd, console->name, path); ++#else ++ // add mount lable for console ++ ret = safe_mount(console->name, path, "bind", MS_BIND, 0, rootfs_path, mount_label); ++ ++ if (ret < 0) ++ return log_error_errno(-1, errno, "Failed to mount \"%s\" on \"%s\"", console->name, path); + -+ if (lxc_drop_caps(conf) != 0) { -+ ERROR("Failed to drop caps."); -+ goto on_error; + } ++ DEBUG("Mounted pts device \"%s\" onto \"%s\"", console->name, path); +#endif + - put_attach_payload(ap); - - /* We're done, so we can now do whatever the user intended us to do. */ -@@ -1378,13 +1536,37 @@ on_error: - _exit(EXIT_FAILURE); + return 0; } +#ifdef HAVE_ISULAD -+static int lxc_attach_terminal(const char *name, const char *lxcpath, struct lxc_conf *conf, -+ struct lxc_terminal *terminal, lxc_attach_options_t *options) ++static int lxc_setup_ttydir_console(const struct lxc_rootfs *rootfs, ++ const struct lxc_terminal *console, ++ char *ttydir, const char *mount_label) +#else - static int lxc_attach_terminal(const char *name, const char *lxcpath, struct lxc_conf *conf, - struct lxc_terminal *terminal) + static int lxc_setup_ttydir_console(const struct lxc_rootfs *rootfs, + const struct lxc_terminal *console, + char *ttydir, int pts_mnt_fd) +#endif { int ret; - - lxc_terminal_init(terminal); + char path[PATH_MAX], lxcpath[PATH_MAX]; +@@ -1686,11 +1868,15 @@ static int lxc_setup_ttydir_console(const struct lxc_rootfs *rootfs, + if (ret < 0 && errno != EEXIST) + return log_error_errno(-errno, errno, "Failed to create console"); +#ifdef HAVE_ISULAD -+ /* isulad: if we pass fifo in option, use them as init fifos */ -+ if (options->init_fifo[0]) { -+ free(terminal->init_fifo[0]); -+ terminal->init_fifo[0] = safe_strdup(options->init_fifo[0]); -+ } -+ if (options->init_fifo[1]) { -+ free(terminal->init_fifo[1]); -+ terminal->init_fifo[1] = safe_strdup(options->init_fifo[1]); -+ } -+ if (options->init_fifo[2]) { -+ free(terminal->init_fifo[2]); -+ terminal->init_fifo[2] = safe_strdup(options->init_fifo[2]); ++ if (console->pts > 0) { ++#endif + ret = fchmod(console->pts, S_IXUSR | S_IXGRP); + if (ret < 0) + return log_error_errno(-errno, errno, "Failed to set mode \"0%o\" to \"%s\"", S_IXUSR | S_IXGRP, console->name); + + /* bind mount console->name to '/dev//console' */ ++#ifndef HAVE_ISULAD + if (pts_mnt_fd >= 0) { + ret = move_mount(pts_mnt_fd, "", -EBADF, lxcpath, MOVE_MOUNT_F_EMPTY_PATH); + if (!ret) { +@@ -1707,11 +1893,23 @@ static int lxc_setup_ttydir_console(const struct lxc_rootfs *rootfs, + ret = safe_mount(console->name, lxcpath, "none", MS_BIND, 0, rootfs_path); + if (ret < 0) + return log_error_errno(-1, errno, "Failed to mount %d(%s) on \"%s\"", pts_mnt_fd, console->name, lxcpath); ++#else ++ ret = safe_mount(console->name, lxcpath, "none", MS_BIND, 0, rootfs_path, mount_label); ++ if (ret < 0) ++ return log_error_errno(-1, errno, "Failed to mount \"%s\" on \"%s\"", console->name, lxcpath); ++#endif + DEBUG("Mounted \"%s\" onto \"%s\"", console->name, lxcpath); ++#ifdef HAVE_ISULAD + } -+ -+ terminal->disable_pty = options->disable_pty; -+ terminal->open_stdin = options->open_stdin; +#endif -+ - ret = lxc_terminal_create(name, lxcpath, conf, terminal); + ++#ifndef HAVE_ISULAD + finish: + /* bind mount '/dev//console' to '/dev/console' */ + ret = safe_mount(lxcpath, path, "none", MS_BIND, 0, rootfs_path); ++#else ++ ret = safe_mount(lxcpath, path, "none", MS_BIND, 0, rootfs_path, mount_label); ++#endif if (ret < 0) - return syserror("Failed to create terminal"); -@@ -1430,9 +1612,128 @@ static inline void lxc_attach_terminal_close_log(struct lxc_terminal *terminal) - close_prot_errno_disarm(terminal->log_fd); + return log_error_errno(-1, errno, "Failed to mount \"%s\" on \"%s\"", console->name, lxcpath); + DEBUG("Mounted \"%s\" onto \"%s\"", console->name, lxcpath); +@@ -1720,6 +1918,7 @@ finish: + return 0; } -+#ifdef HAVE_ISULAD -+/* isulad: attach timeout thread function */ -+static void* wait_attach_timeout(void *arg) ++#ifndef HAVE_ISULAD + static int lxc_setup_console(const struct lxc_rootfs *rootfs, + const struct lxc_terminal *console, char *ttydir, + int pts_mnt_fd) +@@ -1730,7 +1929,18 @@ static int lxc_setup_console(const struct lxc_rootfs *rootfs, + + return lxc_setup_ttydir_console(rootfs, console, ttydir, pts_mnt_fd); + } ++#else ++static int lxc_setup_console(const struct lxc_rootfs *rootfs, ++ const struct lxc_terminal *console, char *ttydir, const char *mount_label) +{ -+ struct attach_timeout_conf *conf = (struct attach_timeout_conf *)arg; -+ -+ if (!conf || conf->timeout < 1) -+ goto out; -+ sleep(conf->timeout); -+ if (lxc_process_alive(conf->pid, conf->start_time)) { -+ g_attach_timeout_state = ATTACH_TIMEOUT; -+ if (kill(conf->pid, SIGKILL) < 0) { -+ ERROR("Failed to send signal %d to pid %d", SIGKILL, conf->pid); -+ } -+ } -+ -+out: -+ free(conf); -+ return ((void *)0); ++ if (!ttydir) ++ return lxc_setup_dev_console(rootfs, console, mount_label); + ++ return lxc_setup_ttydir_console(rootfs, console, ttydir, mount_label); +} ++#endif + -+/* isulad: create attach timeout thread */ -+static int create_attach_timeout_thread(int64_t attach_timeout, pid_t pid) ++#ifndef HAVE_ISULAD + static int parse_mntopt(char *opt, unsigned long *flags, char **data, size_t size) + { + ssize_t ret; +@@ -1798,6 +2008,77 @@ int parse_mntopts(const char *mntopts, unsigned long *mntflags, char **mntdata) + + return 0; + } ++#else ++static void parse_mntopt(char *opt, unsigned long *mflags, unsigned long *pflags, char **data, size_t size) +{ -+ int ret = 0; -+ pthread_t ptid; -+ pthread_attr_t attr; -+ struct attach_timeout_conf *timeout_conf = NULL; -+ -+ timeout_conf = malloc(sizeof(struct attach_timeout_conf)); -+ if (timeout_conf == NULL) { -+ ERROR("Failed to malloc attach timeout conf"); -+ ret = -1; -+ goto out; -+ } ++ struct mount_opt *mo; + -+ memset(timeout_conf, 0, sizeof(struct attach_timeout_conf)); -+ timeout_conf->timeout = attach_timeout; -+ timeout_conf->pid = pid; -+ timeout_conf->start_time = lxc_get_process_startat(pid); ++ /* If opt is found in mount_opt, set or clear flags. ++ * Otherwise append it to data. */ + -+ pthread_attr_init(&attr); -+ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); -+ ret = pthread_create(&ptid, &attr, wait_attach_timeout, timeout_conf); -+ pthread_attr_destroy(&attr); -+ if (ret != 0) { -+ ERROR("Create attach wait timeout thread failed"); -+ free(timeout_conf); -+ goto out; ++ for (mo = &mount_opt[0]; mo->name != NULL; mo++) { ++ if (strncmp(opt, mo->name, strlen(mo->name)) == 0) { ++ if (mo->clear) ++ *mflags &= ~mo->flag; ++ else ++ *mflags |= mo->flag; ++ return; ++ } + } + -+out: -+ return ret; -+} -+ -+static int attach_signal_handler(int fd, uint32_t events, void *data, -+ struct lxc_epoll_descr *descr) -+{ -+ int ret; -+ siginfo_t info; -+ struct signalfd_siginfo siginfo; -+ pid_t *pid = data; -+ -+ ret = lxc_read_nointr(fd, &siginfo, sizeof(siginfo)); -+ if (ret < 0) -+ return log_error(LXC_MAINLOOP_ERROR, "Failed to read signal info from signal file descriptor %d", fd); ++ /* If opt is found in propagation_opt, set or clear flags. */ ++ for (mo = &propagation_opt[0]; mo->name != NULL; mo++) { ++ if (strncmp(opt, mo->name, strlen(mo->name)) != 0) ++ continue; + -+ if (ret != sizeof(siginfo)) -+ return log_error(LXC_MAINLOOP_ERROR, "Unexpected size for struct signalfd_siginfo"); ++ if (mo->clear) ++ *pflags &= ~mo->flag; ++ else ++ *pflags |= mo->flag; + -+ /* Check whether init is running. */ -+ info.si_pid = 0; -+ ret = waitid(P_PID, *pid, &info, WEXITED | WNOWAIT | WNOHANG); -+ if (ret == 0 && info.si_pid == *pid) { -+ return log_warn(LXC_MAINLOOP_CLOSE, "Container attach init process %d exited", *pid); ++ return; + } + -+ return LXC_MAINLOOP_CONTINUE; ++ if (strlen(*data)) ++ (void)strlcat(*data, ",", size); ++ ++ (void)strlcat(*data, opt, size); +} + -+static int isulad_setup_signal_fd(sigset_t *oldmask) ++int parse_mntopts(const char *mntopts, unsigned long *mntflags, unsigned long *pflags, char **mntdata) +{ -+ int ret; -+ sigset_t mask; -+ const int signals[] = {SIGBUS, SIGILL, SIGSEGV, SIGWINCH, SIGTERM}; -+ -+ /* Block everything except serious error signals. */ -+ ret = sigfillset(&mask); -+ if (ret < 0) -+ return -EBADF; -+ -+ for (int sig = 0; sig < (sizeof(signals) / sizeof(signals[0])); sig++) { -+ ret = sigdelset(&mask, signals[sig]); -+ if (ret < 0) -+ return -EBADF; -+ } ++ char *data, *p, *s; ++ size_t size; + -+ ret = pthread_sigmask(SIG_BLOCK, &mask, oldmask); -+ if (ret < 0) -+ return log_error_errno(-EBADF, errno, -+ "Failed to set signal mask"); ++ *mntdata = NULL; ++ *mntflags = 0L; ++ *pflags = 0L; + -+ ret = signalfd(-1, &mask, SFD_CLOEXEC); -+ if (ret < 0) -+ return log_error_errno(-EBADF, -+ errno, "Failed to create signal file descriptor"); ++ if (!mntopts) ++ return 0; + -+ TRACE("Created signal file descriptor %d", ret); ++ s = safe_strdup(mntopts); + -+ return ret; -+} -+#endif ++ size = strlen(s) + 1; ++ data = malloc(size); ++ if (!data) { ++ free(s); ++ return -1; ++ } ++ *data = 0; + -+#ifdef HAVE_ISULAD -+int lxc_attach(struct lxc_container *container, lxc_attach_exec_t exec_function, -+ void *exec_payload, lxc_attach_options_t *options, -+ pid_t *attached_process, char **err_msg) -+#else - int lxc_attach(struct lxc_container *container, lxc_attach_exec_t exec_function, - void *exec_payload, lxc_attach_options_t *options, - pid_t *attached_process) -+#endif - { - int ret_parent = -1; - struct lxc_async_descr descr = {}; -@@ -1443,6 +1744,17 @@ int lxc_attach(struct lxc_container *container, lxc_attach_exec_t exec_function, - struct attach_context *ctx; - struct lxc_terminal terminal; - struct lxc_conf *conf; -+#ifdef HAVE_ISULAD -+ struct lxc_exec_command_handler exec_command; -+ const char *suffix = options->suffix; ++ lxc_iterate_parts(p, s, ",") ++ parse_mntopt(p, mntflags, pflags, &data, size); + -+ exec_command.maincmd_fd = -1; -+ exec_command.terminal = &terminal; ++ if (*data) ++ *mntdata = data; ++ else ++ free(data); ++ free(s); + -+ int isulad_sigfd; -+ sigset_t isulad_oldmask; -+ struct lxc_epoll_descr isulad_descr = {0}; ++ return 0; ++} +#endif - if (!container) - return ret_errno(EINVAL); -@@ -1472,6 +1784,14 @@ int lxc_attach(struct lxc_container *container, lxc_attach_exec_t exec_function, - - conf = ctx->container->lxc_conf; + static void parse_propagationopt(char *opt, unsigned long *flags) + { +@@ -1862,10 +2143,17 @@ static char *get_field(char *src, int nfields) + return p; + } +#ifdef HAVE_ISULAD -+ // always switch uid and gid for attach -+ if (options->uid == -1) -+ options->uid = conf->init_uid; -+ if (options->gid == -1) -+ options->gid = conf->init_gid; ++static int mount_entry(const char *fsname, const char *target, ++ const char *fstype, unsigned long mountflags, ++ unsigned long pflags, const char *data, bool optional, ++ bool dev, bool relative, const char *rootfs, const char *mount_label) ++#else + static int mount_entry(const char *fsname, const char *target, + const char *fstype, unsigned long mountflags, + unsigned long pflags, const char *data, bool optional, + bool dev, bool relative, const char *rootfs) +#endif -+ - if (!fetch_seccomp(ctx->container, options)) - WARN("Failed to get seccomp policy"); - -@@ -1485,13 +1805,23 @@ int lxc_attach(struct lxc_container *container, lxc_attach_exec_t exec_function, + { + int ret; + char srcbuf[PATH_MAX]; +@@ -1881,8 +2169,13 @@ static int mount_entry(const char *fsname, const char *target, + srcpath = srcbuf; } - if (options->attach_flags & LXC_ATTACH_TERMINAL) { +#ifdef HAVE_ISULAD -+ ret = lxc_attach_terminal(name, lxcpath, conf, &terminal, options); ++ ret = safe_mount(srcpath, target, fstype, mountflags & ~MS_REMOUNT, data, ++ rootfs, mount_label); +#else - ret = lxc_attach_terminal(name, lxcpath, conf, &terminal); -+#endif - if (ret < 0) { - put_attach_context(ctx); - return syserror("Failed to setup new terminal"); - } - - terminal.log_fd = options->log_fd; -+#ifdef HAVE_ISULAD -+ if (suffix != NULL) { -+ exec_command.maincmd_fd = lxc_exec_cmd_init(name, lxcpath, suffix); -+ exec_command.terminal = &terminal; -+ } + ret = safe_mount(srcpath, target, fstype, mountflags & ~MS_REMOUNT, data, + rootfs); +#endif - } else { - lxc_terminal_init(&terminal); - } -@@ -1531,10 +1861,38 @@ int lxc_attach(struct lxc_container *container, lxc_attach_exec_t exec_function, - */ - ret = socketpair(PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0, ipc_sockets); if (ret < 0) { -+#ifdef HAVE_ISULAD -+ if (options->attach_flags & LXC_ATTACH_TERMINAL) { -+ lxc_terminal_delete(&terminal); -+ lxc_terminal_conf_free(&terminal); -+ if (exec_command.maincmd_fd != -1) { -+ close(exec_command.maincmd_fd); -+ } -+ lxc_exec_unix_sock_delete(name, suffix); -+ } -+#endif - put_attach_context(ctx); - return syserror("Could not set up required IPC mechanism for attaching"); - } + if (optional) + return log_info_errno(0, errno, "Failed to mount \"%s\" on \"%s\" (optional)", +@@ -2010,8 +2303,15 @@ static int mount_entry_create_dir_file(const struct mntent *mntent, + if (hasmntopt(mntent, "create=dir")) { + ret = mkdir_p(path, 0755); +#ifdef HAVE_ISULAD -+ /* isulad: pipdfd for get error message of child or grandchild process. */ -+ if (pipe2(conf->errpipe, O_CLOEXEC) != 0) { -+ SYSERROR("Failed to init errpipe"); -+ if (options->attach_flags & LXC_ATTACH_TERMINAL) { -+ lxc_terminal_delete(&terminal); -+ lxc_terminal_conf_free(&terminal); -+ if (exec_command.maincmd_fd != -1) { -+ close(exec_command.maincmd_fd); -+ } -+ lxc_exec_unix_sock_delete(name, suffix); -+ } -+ close(ipc_sockets[0]); -+ close(ipc_sockets[1]); -+ put_attach_context(ctx); -+ return -1; -+ } -+#endif - /* Create transient process, two reasons: - * 1. We can't setns() in the child itself, since we want to make - * sure we are properly attached to the pidns. -@@ -1544,6 +1902,18 @@ int lxc_attach(struct lxc_container *container, lxc_attach_exec_t exec_function, - */ - pid = fork(); - if (pid < 0) { -+#ifdef HAVE_ISULAD -+ if (options->attach_flags & LXC_ATTACH_TERMINAL) { -+ lxc_terminal_delete(&terminal); -+ lxc_terminal_conf_free(&terminal); -+ if (exec_command.maincmd_fd != -1) { -+ close(exec_command.maincmd_fd); -+ } -+ lxc_exec_unix_sock_delete(name, suffix); ++ if (ret < 0 && errno != EEXIST) { ++ lxc_write_error_message(rootfs->errfd, "%s:%d: mkdir %s: %s.", __FILE__, __LINE__, path, strerror(errno)); ++ return log_error_errno(-1, errno, "Failed to create directory \"%s\"", path); + } -+ close(ipc_sockets[0]); -+ close(ipc_sockets[1]); ++#else + if (ret < 0 && errno != EEXIST) + return log_error_errno(-1, errno, "Failed to create directory \"%s\"", path); +#endif - put_attach_context(ctx); - return syserror("Failed to create first subprocess"); } -@@ -1551,6 +1921,11 @@ int lxc_attach(struct lxc_container *container, lxc_attach_exec_t exec_function, - if (pid == 0) { - char *cwd, *new_cwd; -+#ifdef HAVE_ISULAD -+ /* isulad: close errpipe */ -+ close_prot_errno_disarm(conf->errpipe[0]); -+ conf->errpipe[0] = -1; -+#endif - /* close unneeded file descriptors */ - close_prot_errno_disarm(ipc_sockets[0]); + if (!hasmntopt(mntent, "create=file")) +@@ -2028,29 +2328,56 @@ static int mount_entry_create_dir_file(const struct mntent *mntent, + p2 = dirname(p1); -@@ -1558,6 +1933,11 @@ int lxc_attach(struct lxc_container *container, lxc_attach_exec_t exec_function, - lxc_attach_terminal_close_ptx(&terminal); - lxc_attach_terminal_close_peer(&terminal); - lxc_attach_terminal_close_log(&terminal); + ret = mkdir_p(p2, 0755); +#ifdef HAVE_ISULAD -+ if (exec_command.maincmd_fd != -1) { -+ close_prot_errno_disarm(exec_command.maincmd_fd); -+ } ++ if (ret < 0 && errno != EEXIST) { ++ lxc_write_error_message(rootfs->errfd, "%s:%d: mkdir %s: %s.", __FILE__, __LINE__, path, strerror(errno)); ++ return log_error_errno(-1, errno, "Failed to create directory \"%s\"", path); ++ } ++#else + if (ret < 0 && errno != EEXIST) + return log_error_errno(-1, errno, "Failed to create directory \"%s\"", path); +#endif - } - /* Wait for the parent to have setup cgroups. */ -@@ -1622,9 +2002,15 @@ int lxc_attach(struct lxc_container *container, lxc_attach_exec_t exec_function, - .terminal_pts_fd = terminal.pty, - .exec_function = exec_function, - .exec_payload = exec_payload, -+#ifdef HAVE_ISULAD -+ .terminal = &terminal, -+#endif - }; -- + ret = mknod(path, S_IFREG | 0000, 0); +#ifdef HAVE_ISULAD -+ if (options->attach_flags & LXC_ATTACH_TERMINAL && terminal.tty_state) { ++ if (ret < 0 && errno != EEXIST) { ++ lxc_write_error_message(rootfs->errfd, "%s:%d: open %s: %s.", __FILE__, __LINE__, path, strerror(errno)); ++ return -errno; ++ } +#else - if (options->attach_flags & LXC_ATTACH_TERMINAL) { + if (ret < 0 && errno != EEXIST) + return -errno; +#endif - ret = lxc_terminal_signal_sigmask_safe_blocked(&terminal); - if (ret < 0) { - SYSERROR("Failed to reset signal mask"); -@@ -1663,6 +2049,26 @@ int lxc_attach(struct lxc_container *container, lxc_attach_exec_t exec_function, - /* close unneeded file descriptors */ - close_prot_errno_disarm(ipc_sockets[1]); -+#ifdef HAVE_ISULAD -+ /* isulad: close errpipe */ -+ close_prot_errno_disarm(conf->errpipe[1]); -+ conf->errpipe[1] = -1; -+ /* isulad: close pipe after clone */ -+ if (terminal.pipes[0][0] >= 0) { -+ close_prot_errno_disarm(terminal.pipes[0][0]); -+ terminal.pipes[0][0] = -1; -+ } -+ -+ if (terminal.pipes[1][1] >= 0) { -+ close_prot_errno_disarm(terminal.pipes[1][1]); -+ terminal.pipes[1][1] = -1; -+ } -+ -+ if (terminal.pipes[2][1] >= 0) { -+ close_prot_errno_disarm(terminal.pipes[2][1]); -+ terminal.pipes[2][1] = -1; -+ } -+#endif - put_namespaces(ctx); - if (options->attach_flags & LXC_ATTACH_TERMINAL) - lxc_attach_terminal_close_pts(&terminal); -@@ -1714,9 +2120,28 @@ int lxc_attach(struct lxc_container *container, lxc_attach_exec_t exec_function, - if (ret < 0) - goto on_error; + return 0; + } + /* rootfs, lxc_name, and lxc_path can be NULL when the container is created + * without a rootfs. */ +#ifdef HAVE_ISULAD -+ ret = lxc_attach_terminal_mainloop_init(&terminal, &isulad_descr); -+ if (ret < 0) -+ goto on_error; -+ -+ if (suffix != NULL) { -+ (void)lxc_exec_cmd_mainloop_add(&descr, &exec_command); -+ } ++static inline int mount_entry_on_generic(struct mntent *mntent, ++ const char *path, ++ const struct lxc_rootfs *rootfs, ++ const char *lxc_name, ++ const char *lxc_path, ++ const char *mount_label) ++#else + static inline int mount_entry_on_generic(struct mntent *mntent, + const char *path, + const struct lxc_rootfs *rootfs, + const char *lxc_name, + const char *lxc_path) +#endif - TRACE("Initialized terminal mainloop"); - } - + { + __do_free char *mntdata = NULL; + unsigned long mntflags = 0, pflags = 0; + char *rootfs_path = NULL; + int ret; + bool dev, optional, relative; +#ifdef HAVE_ISULAD -+ /* The signal fd has to be created before forking otherwise if the child -+ * process exits before we setup the signal fd, the event will be lost -+ * and the command will be stuck. -+ */ -+ isulad_sigfd = isulad_setup_signal_fd(&isulad_oldmask); -+ if (isulad_sigfd < 0) -+ goto close_mainloop; ++ const char *dest = path; ++ char *rpath = NULL; +#endif -+ - /* Let the child process know to go ahead. */ - if (!sync_wake(ipc_sockets[0], ATTACH_SYNC_CGROUP)) - goto close_mainloop; -@@ -1783,6 +2208,34 @@ int lxc_attach(struct lxc_container *container, lxc_attach_exec_t exec_function, - *attached_process = attached_pid; + optional = hasmntopt(mntent, "optional") != NULL; + dev = hasmntopt(mntent, "dev") != NULL; +@@ -2059,9 +2386,41 @@ static inline int mount_entry_on_generic(struct mntent *mntent, + if (rootfs && rootfs->path) + rootfs_path = rootfs->mount; -+#ifdef HAVE_ISULAD -+ if (options->timeout > 0) { -+ ret = create_attach_timeout_thread(options->timeout, *attached_process); -+ if (ret) { -+ ERROR("Failed to create attach timeout thread for container."); -+ goto close_mainloop; -+ } -+ } -+ /* isulad: read error msg from pipe */ -+ ssize_t size_read; -+ char errbuf[BUFSIZ + 1] = {0}; -+ pid_t tmp_pid = *attached_process; -+ -+ size_read = read(conf->errpipe[0], errbuf, BUFSIZ); -+ if (size_read > 0) { -+ if (err_msg) -+ *err_msg = safe_strdup(errbuf); -+ goto close_mainloop; -+ } -+ if (options->attach_flags & LXC_ATTACH_TERMINAL) { -+ ret = lxc_mainloop_add_handler(&descr, isulad_sigfd, attach_signal_handler, &tmp_pid); -+ if (ret < 0) { -+ ERROR("Failed to add signal handler for %d to mainloop", tmp_pid); -+ goto close_mainloop; ++#ifndef HAVE_ISULAD + ret = mount_entry_create_dir_file(mntent, path, rootfs, lxc_name, + lxc_path); ++#else ++ // isulad: ensure that the destination of the bind mount is resolved of symlinks at mount time because ++ // any previous mounts can invalidate the next mount's destination. ++ // this can happen when a user specifies mounts within other mounts to cause breakouts or other ++ // evil stuff to try to escape the container's rootfs. ++ if (rootfs_path) { ++ rpath = follow_symlink_in_scope(path, rootfs_path); ++ if (!rpath) { ++ ERROR("Failed to get real path of '%s' in scope '%s'.", path, rootfs_path); ++ lxc_write_error_message(rootfs->errfd, "%s:%d: failed to get real path of '%s' in scope '%s'.", ++ __FILE__, __LINE__, path, rootfs_path); ++ return -1; + } -+ } -+#endif ++ dest = rpath; + - /* Now shut down communication with child, we're done. */ - shutdown(ipc_sockets[0], SHUT_RDWR); - close_prot_errno_disarm(ipc_sockets[0]); -@@ -1790,17 +2243,46 @@ int lxc_attach(struct lxc_container *container, lxc_attach_exec_t exec_function, - ret_parent = 0; - to_cleanup_pid = -1; - -+#ifdef HAVE_ISULAD -+ // iSulad: close stdin pipe if we do not want open_stdin with container stdin -+ if (!terminal.open_stdin) { -+ if (terminal.pipes[0][1] > 0) { -+ close_prot_errno_disarm(terminal.pipes[0][1]); -+ terminal.pipes[0][1] = -1; ++ ret = check_mount_destination(rootfs_path, dest, mntent->mnt_fsname); ++ if (ret) { ++ ERROR("Mount destination is invalid: '%s'", dest); ++ lxc_write_error_message(rootfs->errfd, "%s:%d: mount destination is invalid: '%s'.", ++ __FILE__, __LINE__, dest); ++ free(rpath); ++ return -1; + } + } ++ ret = mount_entry_create_dir_file(mntent, dest, rootfs, lxc_name, ++ lxc_path); +#endif + - if (options->attach_flags & LXC_ATTACH_TERMINAL) { + if (ret < 0) { +#ifdef HAVE_ISULAD -+ ret = isulad_safe_mainloop(&descr, -1); -+#else - ret = lxc_mainloop(&descr, -1); ++ free(rpath); +#endif - if (ret < 0) { - ret_parent = -1; - to_cleanup_pid = attached_pid; - } + if (optional) + return 0; + +@@ -2069,6 +2428,29 @@ static inline int mount_entry_on_generic(struct mntent *mntent, } + cull_mntent_opt(mntent); +#ifdef HAVE_ISULAD -+ // do lxc_mainloop to make sure we do not lose any output -+ (void)isulad_safe_mainloop(&isulad_descr, 100); -+ if (g_attach_timeout_state == ATTACH_TIMEOUT && err_msg != NULL && *err_msg == NULL) { -+ *err_msg = safe_strdup("Attach exceeded timeout"); ++ ret = parse_mntopts(mntent->mnt_opts, &mntflags, &pflags, &mntdata); ++ if (ret < 0) { ++ free(rpath); ++ return -1; + } -+#endif + - close_mainloop: -+#ifdef HAVE_ISULAD -+ if (options->attach_flags & LXC_ATTACH_TERMINAL) { -+ lxc_mainloop_close(&isulad_descr); -+ lxc_mainloop_close(&descr); ++ // support squashfs ++ if (strcmp(mntent->mnt_type, "squashfs") == 0) { ++ ret = mount_entry_with_loop_dev(mntent->mnt_fsname, dest, mntent->mnt_type, ++ mntent->mnt_opts, rootfs_path); ++ } else { ++ ret = mount_entry(mntent->mnt_fsname, dest, mntent->mnt_type, mntflags, ++ pflags, mntdata, optional, dev, relative, rootfs_path, mount_label); ++ } ++ ++ if (ret < 0) { ++ lxc_write_error_message(rootfs->errfd, "%s:%d: failed to mount %s as type %s.", ++ __FILE__, __LINE__, mntent->mnt_fsname, mntent->mnt_type); + } ++ ++ free(rpath); +#else - if (options->attach_flags & LXC_ATTACH_TERMINAL) - lxc_mainloop_close(&descr); + ret = parse_propagationopts(mntent->mnt_opts, &pflags); + if (ret < 0) + return -1; +@@ -2079,6 +2461,7 @@ static inline int mount_entry_on_generic(struct mntent *mntent, + + ret = mount_entry(mntent->mnt_fsname, path, mntent->mnt_type, mntflags, + pflags, mntdata, optional, dev, relative, rootfs_path); +#endif - on_error: - if (ipc_sockets[0] >= 0) { -@@ -1814,13 +2296,23 @@ on_error: - if (options->attach_flags & LXC_ATTACH_TERMINAL) { - lxc_terminal_delete(&terminal); - lxc_terminal_conf_free(&terminal); + return ret; + } +@@ -2098,13 +2481,25 @@ static inline int mount_entry_on_systemfs(struct mntent *mntent) + if (ret < 0 || ret >= sizeof(path)) + return -1; + +#ifdef HAVE_ISULAD -+ if (exec_command.maincmd_fd != -1) { -+ close_prot_errno_disarm(exec_command.maincmd_fd); -+ } -+ lxc_exec_unix_sock_delete(name, suffix); ++ return mount_entry_on_generic(mntent, path, NULL, NULL, NULL, NULL); ++#else + return mount_entry_on_generic(mntent, path, NULL, NULL, NULL); +#endif - } - - put_attach_context(ctx); - return ret_parent; } +#ifdef HAVE_ISULAD -+int lxc_attach_run_command(void *payload, int msg_fd) ++static int mount_entry_on_absolute_rootfs(struct mntent *mntent, ++ const struct lxc_rootfs *rootfs, ++ const char *lxc_name, ++ const char *lxc_path, ++ const char *mount_label) +#else - int lxc_attach_run_command(void *payload) + static int mount_entry_on_absolute_rootfs(struct mntent *mntent, + const struct lxc_rootfs *rootfs, + const char *lxc_name, + const char *lxc_path) +#endif { - int ret = -1; - lxc_attach_command_t *cmd = payload; -@@ -1838,10 +2330,19 @@ int lxc_attach_run_command(void *payload) - } - } + int offset; + char *aux; +@@ -2140,13 +2535,25 @@ skipabs: + if (ret < 0 || ret >= PATH_MAX) + return -1; +#ifdef HAVE_ISULAD -+ /* isulad: write error messages */ -+ lxc_write_error_message(msg_fd, "exec: \"%s\": %s.", cmd->program, strerror(errno)); ++ return mount_entry_on_generic(mntent, path, rootfs, lxc_name, lxc_path, mount_label); ++#else + return mount_entry_on_generic(mntent, path, rootfs, lxc_name, lxc_path); +#endif -+ - return syserror_ret(ret, "Failed to exec \"%s\"", cmd->program); } +#ifdef HAVE_ISULAD -+int lxc_attach_run_shell(void* payload, int msg_fd) ++static int mount_entry_on_relative_rootfs(struct mntent *mntent, ++ const struct lxc_rootfs *rootfs, ++ const char *lxc_name, ++ const char *lxc_path, ++ const char *mount_label) +#else - int lxc_attach_run_shell(void* payload) + static int mount_entry_on_relative_rootfs(struct mntent *mntent, + const struct lxc_rootfs *rootfs, + const char *lxc_name, + const char *lxc_path) +#endif { - __do_free char *buf = NULL; - uid_t uid; -diff --git a/src/lxc/attach.h b/src/lxc/attach.h -index c85b84f..7ba0ff8 100644 ---- a/src/lxc/attach.h -+++ b/src/lxc/attach.h -@@ -16,9 +16,15 @@ - struct lxc_conf; - struct lxc_container; + int ret; + char path[PATH_MAX]; +@@ -2156,12 +2563,22 @@ static int mount_entry_on_relative_rootfs(struct mntent *mntent, + if (ret < 0 || (size_t)ret >= sizeof(path)) + return -1; +#ifdef HAVE_ISULAD -+__hidden extern int lxc_attach(struct lxc_container *container, lxc_attach_exec_t exec_function, -+ void *exec_payload, lxc_attach_options_t *options, -+ pid_t *attached_process, char **err_msg); ++ return mount_entry_on_generic(mntent, path, rootfs, lxc_name, lxc_path, mount_label); +#else - __hidden extern int lxc_attach(struct lxc_container *container, lxc_attach_exec_t exec_function, - void *exec_payload, lxc_attach_options_t *options, - pid_t *attached_process); + return mount_entry_on_generic(mntent, path, rootfs, lxc_name, lxc_path); +#endif + } - __hidden extern int lxc_attach_remount_sys_proc(void); - -diff --git a/src/lxc/attach_options.h b/src/lxc/attach_options.h -index 8187eca..d09dfce 100644 ---- a/src/lxc/attach_options.h -+++ b/src/lxc/attach_options.h -@@ -75,7 +75,11 @@ enum { - * - * \return Function should return \c 0 on success, and any other value to denote failure. - */ +#ifdef HAVE_ISULAD -+typedef int (*lxc_attach_exec_t)(void* payload, int msg_fd); ++static int mount_file_entries(const struct lxc_conf *conf, ++ const struct lxc_rootfs *rootfs, FILE *file, ++ const char *lxc_name, const char *lxc_path, const char *mount_label) +#else - typedef int (*lxc_attach_exec_t)(void* payload); + static int mount_file_entries(const struct lxc_conf *conf, + const struct lxc_rootfs *rootfs, FILE *file, + const char *lxc_name, const char *lxc_path) +#endif + { + char buf[PATH_MAX]; + struct mntent mntent; +@@ -2169,6 +2586,42 @@ static int mount_file_entries(const struct lxc_conf *conf, + while (getmntent_r(file, &mntent, buf, sizeof(buf))) { + int ret; - typedef struct lxc_groups_t { - size_t size; -@@ -155,6 +159,16 @@ typedef struct lxc_attach_options_t { - * If unset all additional groups are dropped. - */ - lxc_groups_t groups; -+ +#ifdef HAVE_ISULAD -+ char *init_fifo[3]; /* isulad: default fifos for the start */ -+ int64_t timeout;/* isulad: Seconds for waiting on a container to attach/exec before it is killed*/ -+ const char *suffix; -+ bool disable_pty; -+ bool open_stdin; -+ gid_t *add_gids; /* attach user additional gids */ -+ size_t add_gids_len; // iSulad TODO: shoud replace by lxc_groups_t groups; -+#endif - } lxc_attach_options_t; - - /*! Default attach options to use */ -@@ -175,6 +189,9 @@ typedef struct lxc_attach_options_t { - .log_fd = -EBADF, \ - .lsm_label = NULL, \ - .groups = {}, \ -+#ifdef HAVE_ISULAD -+ /* .init_fifo = */ {NULL, NULL, NULL}, \ ++ //isulad, system contaienr, skip "proc/sys/xxx" path ++ if (conf->systemd != NULL && strcmp(conf->systemd, "true") == 0) { ++ if (strstr(mntent.mnt_dir, "proc/sys") != NULL) { ++ continue; ++ } ++ } ++ ++ /* Note: Workaround for volume file path with space*/ ++ mntent.mnt_fsname = lxc_string_replace(SPACE_MAGIC_STR, " ", mntent.mnt_fsname); ++ if(!mntent.mnt_fsname) { ++ SYSERROR("memory allocation error"); ++ return -1; ++ } ++ mntent.mnt_dir = lxc_string_replace(SPACE_MAGIC_STR, " ", mntent.mnt_dir); ++ if(!mntent.mnt_dir) { ++ SYSERROR("memory allocation error"); ++ free(mntent.mnt_fsname); ++ return -1; ++ } ++ ++ if (!rootfs->path) ++ ret = mount_entry_on_systemfs(&mntent); ++ else if (mntent.mnt_dir[0] != '/') ++ ret = mount_entry_on_relative_rootfs(&mntent, rootfs, ++ lxc_name, lxc_path, mount_label); ++ else ++ ret = mount_entry_on_absolute_rootfs(&mntent, rootfs, ++ lxc_name, lxc_path, mount_label); ++ ++ free(mntent.mnt_fsname); ++ mntent.mnt_fsname = NULL; ++ free(mntent.mnt_dir); ++ mntent.mnt_dir = NULL; ++#else ++ + if (!rootfs->path) + ret = mount_entry_on_systemfs(&mntent); + else if (mntent.mnt_dir[0] != '/') +@@ -2177,6 +2630,8 @@ static int mount_file_entries(const struct lxc_conf *conf, + else + ret = mount_entry_on_absolute_rootfs(&mntent, rootfs, + lxc_name, lxc_path); +#endif ++ + if (ret < 0) + return -1; } +@@ -2195,9 +2650,15 @@ static inline void __auto_endmntent__(FILE **f) + + #define __do_endmntent __attribute__((__cleanup__(__auto_endmntent__))) - /*! -@@ -192,7 +209,11 @@ typedef struct lxc_attach_command_t { - * - * \return \c -1 on error, exit code of lxc_attach_command_t program on success. - */ +#ifdef HAVE_ISULAD -+extern int lxc_attach_run_command(void* payload, int msg_fd); ++static int setup_mount(const struct lxc_conf *conf, ++ const struct lxc_rootfs *rootfs, const char *fstab, ++ const char *lxc_name, const char *lxc_path, const char *mount_label) +#else - extern int lxc_attach_run_command(void* payload); + static int setup_mount(const struct lxc_conf *conf, + const struct lxc_rootfs *rootfs, const char *fstab, + const char *lxc_name, const char *lxc_path) +#endif + { + __do_endmntent FILE *f = NULL; + int ret; +@@ -2209,7 +2670,11 @@ static int setup_mount(const struct lxc_conf *conf, + if (!f) + return log_error_errno(-1, errno, "Failed to open \"%s\"", fstab); - /*! - * \brief Run a shell command in the container. -@@ -201,7 +222,11 @@ extern int lxc_attach_run_command(void* payload); - * - * \return Exit code of shell. - */ +#ifdef HAVE_ISULAD -+extern int lxc_attach_run_shell(void* payload, int msg_fd); ++ ret = mount_file_entries(conf, rootfs, f, lxc_name, lxc_path, mount_label); +#else - extern int lxc_attach_run_shell(void* payload); + ret = mount_file_entries(conf, rootfs, f, lxc_name, lxc_path); +#endif + if (ret < 0) + ERROR("Failed to set up mount entries"); - #ifdef __cplusplus +@@ -2285,10 +2750,17 @@ FILE *make_anonymous_mount_file(struct lxc_list *mount, + return f; } -diff --git a/src/lxc/cgroups/cgroup.c b/src/lxc/cgroups/cgroup.c -index 5e2a7d0..5de88e3 100644 ---- a/src/lxc/cgroups/cgroup.c -+++ b/src/lxc/cgroups/cgroup.c -@@ -32,8 +32,11 @@ struct cgroup_ops *cgroup_init(struct lxc_conf *conf) - cgroup_ops = cgroup_ops_init(conf); - if (!cgroup_ops) - return log_error_errno(NULL, errno, "Failed to initialize cgroup driver"); -- -+#ifdef HAVE_ISULAD -+ if (cgroup_ops->data_init(cgroup_ops, conf)) { -+#else - if (cgroup_ops->data_init(cgroup_ops)) { -+#endif - cgroup_exit(cgroup_ops); - return log_error_errno(NULL, errno, "Failed to initialize cgroup data"); - } -diff --git a/src/lxc/cgroups/cgroup.h b/src/lxc/cgroups/cgroup.h -index 108e5d8..ebfd3a1 100644 ---- a/src/lxc/cgroups/cgroup.h -+++ b/src/lxc/cgroups/cgroup.h -@@ -245,8 +245,15 @@ struct cgroup_ops { - */ - cgroup_layout_t cgroup_layout; +#ifdef HAVE_ISULAD -+ int (*data_init)(struct cgroup_ops *ops, struct lxc_conf *conf); -+ bool (*payload_destroy)(struct cgroup_ops *ops, struct lxc_handler *handler); -+ // different with get_cgroup(), which return relative path -+ const char *(*get_cgroup_full_path)(struct cgroup_ops *ops, const char *controller); ++static int setup_mount_entries(const struct lxc_conf *conf, ++ const struct lxc_rootfs *rootfs, ++ struct lxc_list *mount, const char *lxc_name, ++ const char *lxc_path, const char *mount_label) +#else - int (*data_init)(struct cgroup_ops *ops); - void (*payload_destroy)(struct cgroup_ops *ops, struct lxc_handler *handler); + static int setup_mount_entries(const struct lxc_conf *conf, + const struct lxc_rootfs *rootfs, + struct lxc_list *mount, const char *lxc_name, + const char *lxc_path) +#endif - void (*monitor_destroy)(struct cgroup_ops *ops, struct lxc_handler *handler); - bool (*monitor_create)(struct cgroup_ops *ops, struct lxc_handler *handler); - bool (*monitor_enter)(struct cgroup_ops *ops, struct lxc_handler *handler); -diff --git a/src/lxc/conf.c b/src/lxc/conf.c -index 9158713..23783db 100644 ---- a/src/lxc/conf.c -+++ b/src/lxc/conf.c -@@ -103,6 +103,12 @@ - #include "strchrnul.h" - #endif + { + __do_fclose FILE *f = NULL; -+#ifdef HAVE_ISULAD -+#include -+#include "path.h" -+#include "loop.h" -+#endif -+ - lxc_log_define(conf, lxc); +@@ -2296,7 +2768,11 @@ static int setup_mount_entries(const struct lxc_conf *conf, + if (!f) + return -1; - /* -@@ -122,6 +128,11 @@ char *lxchook_names[NUM_LXC_HOOKS] = { - "clone", - "destroy", - "start-host" +#ifdef HAVE_ISULAD -+ , "oci-prestart", -+ "oci-poststart", -+ "oci-poststop" ++ return mount_file_entries(conf, rootfs, f, lxc_name, lxc_path, mount_label); ++#else + return mount_file_entries(conf, rootfs, f, lxc_name, lxc_path); +#endif - }; + } - struct mount_opt { -@@ -284,6 +295,21 @@ static struct limit_opt limit_opt[] = { - #endif - }; + static int parse_cap(const char *cap) +@@ -2395,6 +2871,16 @@ static int dropcaps_except(struct lxc_list *caps) + lxc_list_for_each (iterator, caps) { + keep_entry = iterator->elem; +#ifdef HAVE_ISULAD -+static int rootfs_parent_mount_private(char *rootfs); -+static int setup_rootfs_ropaths(struct lxc_list *ropaths); -+static int setup_rootfs_maskedpaths(struct lxc_list *maskedpaths); -+static int remount_proc_sys_mount_entries(struct lxc_list *mount_list, bool lsm_aa_allow_nesting); -+static int check_mount_destination(const char *rootfs, const char *dest, const char *src); -+static int mount_entry_with_loop_dev(const char *src, const char *dest, const char *fstype, -+ char *mnt_opts, const char *rootfs); -+static bool need_setup_proc(const struct lxc_conf *conf, struct lxc_list *mount); -+static bool need_setup_dev(const struct lxc_conf *conf, struct lxc_list *mount); -+static int setup_populate_devs(const struct lxc_rootfs *rootfs, struct lxc_list *devs, const char *mount_label); -+static int setup_rootfs_mountopts(const struct lxc_rootfs *rootfs); -+static int create_mtab_link(); -+#endif -+ - static int run_buffer(char *buffer) - { - __do_free char *output = NULL; -@@ -707,8 +733,13 @@ static int lxc_mount_auto_mounts(struct lxc_handler *handler, int flags) - { LXC_AUTO_PROC_MASK, LXC_AUTO_PROC_MIXED, "%r/proc/sysrq-trigger", "%r/proc/sysrq-trigger", NULL, MS_BIND, NULL, false }, - { LXC_AUTO_PROC_MASK, LXC_AUTO_PROC_MIXED, NULL, "%r/proc/sysrq-trigger", NULL, MS_REMOUNT|MS_BIND|MS_RDONLY, NULL, false }, - { LXC_AUTO_PROC_MASK, LXC_AUTO_PROC_RW, "proc", "%r/proc", "proc", MS_NODEV|MS_NOEXEC|MS_NOSUID, NULL, false }, -+#ifdef HAVE_ISULAD -+ { LXC_AUTO_SYS_MASK, LXC_AUTO_SYS_RW, "sysfs", "%r/sys", "sysfs", MS_NODEV|MS_NOEXEC|MS_NOSUID, NULL, false }, -+ { LXC_AUTO_SYS_MASK, LXC_AUTO_SYS_RO, "sysfs", "%r/sys", "sysfs", MS_RDONLY|MS_NODEV|MS_NOEXEC|MS_NOSUID, NULL, false }, -+#else - { LXC_AUTO_SYS_MASK, LXC_AUTO_SYS_RW, "sysfs", "%r/sys", "sysfs", 0, NULL, false }, - { LXC_AUTO_SYS_MASK, LXC_AUTO_SYS_RO, "sysfs", "%r/sys", "sysfs", MS_RDONLY, NULL, false }, ++ /* Do not keep any cap*/ ++ if (strcmp(keep_entry, "ISULAD_KEEP_NONE") == 0) { ++ DEBUG("Do not keep any capability"); ++ for(i = 0; i < numcaps; i++) { ++ caplist[i] = 0; ++ } ++ break; ++ } +#endif - /* /proc/sys is used as a temporary staging directory for the read-write sysfs mount and unmounted after binding net */ - { LXC_AUTO_SYS_MASK, LXC_AUTO_SYS_MIXED, "sysfs", "%r/proc/sys", "sysfs", MS_NOSUID|MS_NODEV|MS_NOEXEC, NULL, false }, - { LXC_AUTO_SYS_MASK, LXC_AUTO_SYS_MIXED, "sysfs", "%r/sys", "sysfs", MS_RDONLY|MS_NOSUID|MS_NODEV|MS_NOEXEC, NULL, false }, -@@ -801,11 +832,25 @@ static int lxc_mount_auto_mounts(struct lxc_handler *handler, int flags) - if (!destination) - return syserror_set(-ENOMEM, "Failed to create target path"); + capid = parse_cap(keep_entry); + if (capid == -2) + continue; +@@ -2443,7 +2929,11 @@ static int parse_resource(const char *res) + return resid; + } +#ifdef HAVE_ISULAD -+ if (mkdir_p(destination, 0755) < 0) { -+ SYSERROR("Failed to create mount target '%s'", destination); -+ return log_error(-1, "Failed to mkdir destination %s", destination); -+ } -+ -+ // add selinux label for safe mount -+ ret = safe_mount(source, destination, -+ default_mounts[i].fstype, -+ mflags, -+ default_mounts[i].options, -+ rootfs->path ? rootfs->mount : NULL, NULL); ++int setup_resource_limits(struct lxc_list *limits, pid_t pid, int errfd) +#else - ret = safe_mount(source, destination, - default_mounts[i].fstype, - mflags, - default_mounts[i].options, - rootfs->path ? rootfs->mount : NULL); + int setup_resource_limits(struct lxc_list *limits, pid_t pid) +#endif - if (ret < 0) { - if (errno != ENOENT) - return syserror("Failed to mount \"%s\" on \"%s\" with flags %lu", source, destination, mflags); -@@ -1210,7 +1255,9 @@ static int lxc_send_ttys_to_parent(struct lxc_handler *handler) - static int mount_autodev(const char *name, const struct lxc_rootfs *rootfs, - int autodevtmpfssize, const char *lxcpath) { -+#ifndef HAVE_ISULAD - __do_close int fd_fs = -EBADF; -+#endif - const char *path = rootfs->path ? rootfs->mount : NULL; - size_t tmpfs_size = (autodevtmpfssize != 0) ? autodevtmpfssize : 500000; - int ret; -@@ -1227,6 +1274,10 @@ static int mount_autodev(const char *name, const struct lxc_rootfs *rootfs, - goto reset_umask; - } + int resid; + struct lxc_list *it; +@@ -2457,8 +2947,17 @@ int setup_resource_limits(struct lxc_list *limits, pid_t pid) + return log_error(-1, "Unknown resource %s", lim->resource); + #if HAVE_PRLIMIT || HAVE_PRLIMIT64 +#ifdef HAVE_ISULAD -+ if (systemd != NULL && !strcmp(systemd, "true")) { -+ ret = mount(path, path, "", MS_BIND, NULL); ++ if (prlimit(pid, resid, &lim->limit, NULL) != 0) { ++ lxc_write_error_message(errfd, "%s:%d: Failed to set limit %s %lu %lu: %s.", ++ __FILE__, __LINE__, lim->resource, ++ lim->limit.rlim_cur, lim->limit.rlim_max, strerror(errno)); ++ return log_error_errno(-1, errno, "Failed to set limit %s", lim->resource); ++ } +#else - if (can_use_mount_api()) { - fd_fs = fs_prepare("tmpfs", -EBADF, "", 0, 0); - if (fd_fs < 0) -@@ -1245,6 +1296,7 @@ static int mount_autodev(const char *name, const struct lxc_rootfs *rootfs, - ret = fs_attach(fd_fs, rootfs->dfd_mnt, "dev", - PROTECT_OPATH_DIRECTORY, - PROTECT_LOOKUP_BENEATH_XDEV, 0); + if (prlimit(pid, resid, &lim->limit, NULL) != 0) + return log_error_errno(-1, errno, "Failed to set limit %s", lim->resource); +#endif - } else { - __do_free char *fallback_path = NULL; -@@ -1253,9 +1305,17 @@ static int mount_autodev(const char *name, const struct lxc_rootfs *rootfs, + TRACE("Setup \"%s\" limit", lim->resource); + #else +@@ -2601,6 +3100,27 @@ struct lxc_conf *lxc_conf_init(void) + memset(&new->ns_share, 0, sizeof(char *) * LXC_NS_MAX); + seccomp_conf_init(new); - if (path) { - fallback_path = must_make_path(path, "/dev", NULL); +#ifdef HAVE_ISULAD -+ ret = safe_mount("none", fallback_path, "tmpfs", 0, mount_options, path, rootfs->lsm_se_mount_context); -+#else - ret = safe_mount("none", fallback_path, "tmpfs", 0, mount_options, path); ++ lxc_list_init(&new->populate_devs); ++ lxc_list_init(&new->rootfs.maskedpaths); ++ lxc_list_init(&new->rootfs.ropaths); ++ new->exit_fd = -1; ++ new->umask = 0027; /*default umask 0027*/ ++ new->console.init_fifo[0] = NULL; ++ new->console.init_fifo[1] = NULL; ++ new->console.init_fifo[2] = NULL; ++ new->console.pipes[0][0] = -1; ++ new->console.pipes[0][1] = -1; ++ new->console.pipes[1][0] = -1; ++ new->console.pipes[1][1] = -1; ++ new->console.pipes[2][0] = -1; ++ new->console.pipes[2][1] = -1; ++ lxc_list_init(&new->console.fifos); ++ new->errmsg = NULL; ++ new->errpipe[0] = -1; ++ new->errpipe[1] = -1; +#endif - } else { ++ + return new; + } + +@@ -3001,7 +3521,11 @@ again: + null_endofword(target); + ret = mount(NULL, target, NULL, MS_SLAVE, NULL); + if (ret < 0) { +#ifdef HAVE_ISULAD -+ ret = safe_mount("none", "dev", "tmpfs", 0, mount_options, NULL, rootfs->lsm_se_mount_context); ++ SYSERROR("Failed to recursively turn old root mount tree: %s into dependent mount. Continuing...", target); +#else - ret = safe_mount("none", "dev", "tmpfs", 0, mount_options, NULL); + SYSERROR("Failed to recursively turn old root mount tree into dependent mount. Continuing..."); +#endif + continue; } + TRACE("Recursively turned old root mount tree into dependent mount"); +@@ -3046,7 +3570,11 @@ static int lxc_execute_bind_init(struct lxc_handler *handler) + return log_error_errno(-1, errno, "Failed to create dummy \"%s\" file as bind mount target", destpath); } - if (ret < 0) { -@@ -1392,7 +1452,11 @@ static int lxc_fill_autodev(struct lxc_rootfs *rootfs) - if (ret < 0) - return log_error(-1, "Failed to create device path for %s", device->name); +#ifdef HAVE_ISULAD -+ ret = safe_mount(rootfs->buf, path, 0, MS_BIND, NULL, get_rootfs_mnt(rootfs), rootfs->lsm_se_mount_context); ++ ret = safe_mount(path, destpath, "none", MS_BIND, NULL, conf->rootfs.mount, conf->lsm_se_mount_context); ++#else + ret = safe_mount(path, destpath, "none", MS_BIND, NULL, conf->rootfs.mount); ++#endif + if (ret < 0) + return log_error_errno(-1, errno, "Failed to bind mount lxc.init.static into container"); + +@@ -3082,7 +3610,13 @@ int lxc_setup_rootfs_prepare_root(struct lxc_conf *conf, const char *name, + return log_trace(0, "Bind mounted container / onto itself"); + } + ++#ifndef HAVE_ISULAD + turn_into_dependent_mounts(); +#else - ret = safe_mount(rootfs->buf, path, 0, MS_BIND, NULL, get_rootfs_mnt(rootfs)); ++ if (!conf->rootfs.options) { ++ turn_into_dependent_mounts(); ++ } +#endif - if (ret < 0) - return log_error_errno(-1, errno, "Failed to bind mount host device node \"%s\" to \"%s\"", rootfs->buf, path); -@@ -1410,12 +1474,23 @@ static int lxc_fill_autodev(struct lxc_rootfs *rootfs) - static int lxc_mount_rootfs(struct lxc_rootfs *rootfs) + ret = run_lxc_hooks(name, "pre-mount", conf, NULL); + if (ret < 0) +@@ -3182,15 +3716,29 @@ static int lxc_setup_boot_id(void) + + int lxc_setup(struct lxc_handler *handler) { ++#ifndef HAVE_ISULAD + __do_close int pts_mnt_fd = -EBADF; ++#endif int ret; + const char *lxcpath = handler->lxcpath, *name = handler->name; + struct lxc_conf *lxc_conf = handler->conf; + char *keyring_context = NULL; +#ifdef HAVE_ISULAD -+ unsigned long flags; ++ bool setup_dev = true; ++ bool setup_proc = true; +#endif - if (!rootfs->path) { - ret = mount("", "/", NULL, MS_SLAVE | MS_REC, 0); - if (ret < 0) - return log_error_errno(-1, errno, "Failed to recursively turn root mount tree into dependent mount"); + ret = lxc_setup_rootfs_prepare_root(lxc_conf, name, lxcpath); + if (ret < 0) ++#ifdef HAVE_ISULAD ++ { ++ lxc_write_error_message(lxc_conf->errpipe[1], "%s:%d: failed to setup rootfs %s.", ++ __FILE__, __LINE__, lxc_conf->rootfs.path); ++ return log_error(-1, "Failed to setup rootfs"); ++ } ++#else + return log_error(-1, "Failed to setup rootfs"); ++#endif + if (handler->nsfd[LXC_NS_UTS] == -EBADF) { + ret = setup_utsname(lxc_conf->utsname); +@@ -3221,6 +3769,7 @@ int lxc_setup(struct lxc_handler *handler) + return log_error(-1, "Failed to send network device names and ifindices to parent"); + } + ++#ifndef HAVE_ISULAD + if (wants_console(&lxc_conf->console)) { + pts_mnt_fd = open_tree(-EBADF, lxc_conf->console.name, + OPEN_TREE_CLONE | OPEN_TREE_CLOEXEC | AT_EMPTY_PATH); +@@ -3231,9 +3780,15 @@ int lxc_setup(struct lxc_handler *handler) + TRACE("Created detached mount for container's console \"%s\"", + lxc_conf->console.name); + } ++#endif + + if (lxc_conf->autodev > 0) { +#ifdef HAVE_ISULAD -+ if (!access(rootfs->mount, F_OK)) { -+ rootfs->path = safe_strdup("/"); -+ if (mount("/", rootfs->mount, NULL, MS_BIND, 0)) { -+ return log_error_errno(-1, errno, "Failed to mount \"/\" to %s", rootfs->mount); -+ } -+ } ++ ret = mount_autodev(name, &lxc_conf->rootfs, lxc_conf->autodevtmpfssize, lxcpath, ++ lxc_conf->systemd, lxc_conf->lsm_se_mount_context); ++#else + ret = mount_autodev(name, &lxc_conf->rootfs, lxc_conf->autodevtmpfssize, lxcpath); +#endif - rootfs->dfd_mnt = open_at(-EBADF, "/", PROTECT_OPATH_DIRECTORY, PROTECT_LOOKUP_ABSOLUTE, 0); - if (rootfs->dfd_mnt < 0) - return -errno; -@@ -1428,6 +1503,42 @@ static int lxc_mount_rootfs(struct lxc_rootfs *rootfs) - return log_error_errno(-1, errno, "Failed to access to \"%s\". Check it is present", - rootfs->mount); + if (ret < 0) + return log_error(-1, "Failed to mount \"/dev\""); + } +@@ -3245,15 +3800,38 @@ int lxc_setup(struct lxc_handler *handler) + if (ret < 0) + return log_error(-1, "Failed to setup first automatic mounts"); +#ifdef HAVE_ISULAD -+ // Support mount propagations of rootfs -+ // Get rootfs mnt propagation options, such as slave or shared -+ flags = MS_SLAVE | MS_REC; -+ if (rootfs->mnt_opts.prop_flags) -+ flags = rootfs->mnt_opts.prop_flags; -+ -+ /* Mount propagation inside container can not greater than host. -+ * So we must change propagation of root according to flags, default is rslave. -+ * That means shared propagation inside container is disabled by default. -+ */ -+ ret = mount("", "/", NULL, flags, NULL); -+ if (ret < 0) { -+ return log_error_errno(-1, errno, "Failed to make / to propagation flags %lu.", flags); -+ } -+ -+ /* Make parent mount private to make sure following bind mount does -+ * not propagate in other namespaces. Also it will help with kernel -+ * check pass in pivot_root. (IS_SHARED(new_mnt->mnt_parent)) -+ */ -+ ret = rootfs_parent_mount_private(rootfs->path); -+ if (ret != 0) { -+ return log_error(-1, "Failed to make parent of rootfs %s to private.", rootfs->path); -+ } -+ ret = rootfs_parent_mount_private(rootfs->mount); -+ if (ret != 0) { -+ return log_error(-1, "Failed to make parent of rootfs %s to private.", rootfs->mount); -+ } -+ -+ ret = mount(rootfs->mount, rootfs->mount, "bind", MS_BIND | MS_REC, NULL); -+ if (ret < 0) { -+ SYSERROR("Failed to mount rootfs %s", rootfs->mount); -+ return -1; -+ } ++ /* Now mount only cgroups, if wanted. Before, /sys could not have been ++ * mounted. It is guaranteed to be mounted now either through ++ * automatically or via fstab entries. ++ */ ++ ret = lxc_mount_auto_mounts(lxc_conf, lxc_conf->auto_mounts & LXC_AUTO_CGROUP_MASK, handler); ++ if (ret < 0) ++ return log_error(-1, "Failed to setup remaining automatic mounts"); +#endif + - ret = rootfs->storage->ops->mount(rootfs->storage); - if (ret < 0) - return log_error(-1, "Failed to mount rootfs \"%s\" onto \"%s\" with options \"%s\"", -@@ -1780,7 +1891,11 @@ static int lxc_setup_devpts_child(struct lxc_handler *handler) - DEBUG("Attached detached devpts mount %d to %d/pts", devpts_fd, rootfs->dfd_dev); - } else { - char **opts; +#ifdef HAVE_ISULAD -+ __do_free char *devpts_mntopts = NULL; ++ ret = setup_mount(lxc_conf, &lxc_conf->rootfs, lxc_conf->fstab, name, lxcpath, lxc_conf->lsm_se_mount_context); +#else - char devpts_mntopts[256]; + ret = setup_mount(lxc_conf, &lxc_conf->rootfs, lxc_conf->fstab, name, lxcpath); +#endif - char *mntopt_sets[5]; - char default_devpts_mntopts[256] = "gid=5,newinstance,ptmxmode=0666,mode=0620"; + if (ret < 0) + return log_error(-1, "Failed to setup mounts"); -@@ -1788,9 +1903,18 @@ static int lxc_setup_devpts_child(struct lxc_handler *handler) - * Fallback codepath in case the new mount API can't be used to - * create detached mounts. - */ -- + if (!lxc_list_empty(&lxc_conf->mount_list)) { +#ifdef HAVE_ISULAD -+ if (rootfs->lsm_se_mount_context != NULL) { -+ ret = strnprintf(devpts_mntopts, sizeof(devpts_mntopts), "%s,max=%zu,context=\"%s\"", -+ default_devpts_mntopts, pty_max, rootfs->lsm_se_mount_context); -+ } else { ++ ret = setup_mount_entries(lxc_conf, &lxc_conf->rootfs, ++ &lxc_conf->mount_list, name, lxcpath, lxc_conf->lsm_se_mount_context); +#else - ret = strnprintf(devpts_mntopts, sizeof(devpts_mntopts), "%s,max=%zu", - default_devpts_mntopts, pty_max); + ret = setup_mount_entries(lxc_conf, &lxc_conf->rootfs, + &lxc_conf->mount_list, name, lxcpath); +#endif + if (ret < 0) + return log_error(-1, "Failed to setup mount entries"); +#ifdef HAVE_ISULAD -+ } ++ setup_dev = need_setup_dev(lxc_conf, &lxc_conf->mount_list); ++ setup_proc = need_setup_proc(lxc_conf, &lxc_conf->mount_list); +#endif - if (ret < 0) - return -1; + } -@@ -1951,6 +2075,15 @@ static int bind_mount_console(int fd_devpts, struct lxc_rootfs *rootfs, - struct lxc_terminal *console, int fd_to) - { - __do_close int fd_pty = -EBADF; -+#ifdef HAVE_ISULAD -+ __do_free char *mnt_opts = NULL; -+ -+ if (rootfs->lsm_se_mount_context != NULL) { -+ if (asprintf(mnt_opts, "context=\"%s\"", rootfs->lsm_se_mount_context) < 0) { -+ return syserror("Out of memory"); -+ } -+ } -+#endif - - if (is_empty_string(console->name)) - return ret_errno(EINVAL); -@@ -1981,7 +2114,11 @@ static int bind_mount_console(int fd_devpts, struct lxc_rootfs *rootfs, - if (can_use_mount_api()) - return fd_bind_mount(fd_pty, "", 0, 0, fd_to, "", 0, 0, 0, 0, 0, false); - -+#ifdef HAVE_ISULAD -+ return mount_fd(fd_pty, fd_to, "none", MS_BIND, mnt_opts); -+#else - return mount_fd(fd_pty, fd_to, "none", MS_BIND, 0); -+#endif - } + if (lxc_conf->is_execute) { +@@ -3278,6 +3856,7 @@ int lxc_setup(struct lxc_handler *handler) + } + } - static int lxc_setup_dev_console(int fd_devpts, struct lxc_rootfs *rootfs, -@@ -2040,6 +2177,15 @@ static int lxc_setup_ttydir_console(int fd_devpts, struct lxc_rootfs *rootfs, - __do_close int fd_ttydir = -EBADF, fd_dev_console = -EBADF, - fd_reg_console = -EBADF, fd_reg_ttydir_console = -EBADF; - int ret; -+#ifdef HAVE_ISULAD -+ __do_free char *mnt_opts = NULL; -+ -+ if (rootfs->lsm_se_mount_context != NULL) { -+ if (asprintf(mnt_opts, "context=\"%s\"", rootfs->lsm_se_mount_context) < 0) { -+ return syserror("Out of memory"); -+ } -+ } ++#ifndef HAVE_ISULAD + /* Now mount only cgroups, if wanted. Before, /sys could not have been + * mounted. It is guaranteed to be mounted now either through + * automatically or via fstab entries. +@@ -3285,6 +3864,7 @@ int lxc_setup(struct lxc_handler *handler) + ret = lxc_mount_auto_mounts(lxc_conf, lxc_conf->auto_mounts & LXC_AUTO_CGROUP_MASK, handler); + if (ret < 0) + return log_error(-1, "Failed to setup remaining automatic mounts"); +#endif - /* create dev/ */ - ret = mkdirat(rootfs->dfd_dev, ttydir, 0755); -@@ -2124,7 +2270,11 @@ static int lxc_setup_ttydir_console(int fd_devpts, struct lxc_rootfs *rootfs, - 0, - false); - else -+#ifdef HAVE_ISULAD -+ ret = mount_fd(fd_dev_console, fd_reg_console, "none", MS_BIND, mnt_opts); -+#else - ret = mount_fd(fd_dev_console, fd_reg_console, "none", MS_BIND, 0); -+#endif + ret = run_lxc_hooks(name, "mount", lxc_conf, NULL); if (ret < 0) - return syserror("Failed to mount \"%d\" on \"%d\"", - fd_dev_console, fd_reg_console); -@@ -2410,10 +2560,17 @@ static char *get_field(char *src, int nfields) - return p; - } +@@ -3295,21 +3875,45 @@ int lxc_setup(struct lxc_handler *handler) + if (ret < 0) + return log_error(-1, "Failed to run autodev hooks"); +#ifdef HAVE_ISULAD -+static int mount_entry(const char *fsname, const char *target, -+ const char *fstype, unsigned long mountflags, -+ unsigned long pflags, const char *data, bool optional, -+ bool dev, bool relative, const char *rootfs, const char *mount_label) ++ ret = lxc_fill_autodev(&lxc_conf->rootfs, lxc_conf->lsm_se_mount_context); +#else - static int mount_entry(const char *fsname, const char *target, - const char *fstype, unsigned long mountflags, - unsigned long pflags, const char *data, bool optional, - bool dev, bool relative, const char *rootfs) + ret = lxc_fill_autodev(&lxc_conf->rootfs); +#endif - { - int ret; - char srcbuf[PATH_MAX]; -@@ -2428,9 +2585,13 @@ static int mount_entry(const char *fsname, const char *target, - return log_error_errno(-1, errno, "source path is too long"); - srcpath = srcbuf; + if (ret < 0) + return log_error(-1, "Failed to populate \"/dev\""); } -- -+#ifdef HAVE_ISULAD -+ ret = safe_mount(srcpath, target, fstype, mountflags & ~MS_REMOUNT, data, -+ rootfs, mount_label); -+#else - ret = safe_mount(srcpath, target, fstype, mountflags & ~MS_REMOUNT, data, - rootfs); -+#endif - if (ret < 0) { - if (optional) - return log_info_errno(0, errno, "Failed to mount \"%s\" on \"%s\" (optional)", -@@ -2639,6 +2800,10 @@ static inline int mount_entry_on_generic(struct mntent *mntent, - int ret; - bool dev, optional, relative; - struct lxc_mount_options opts = {}; -+#ifdef HAVE_ISULAD -+ const char *dest = path; -+ __do_free char *rpath = NULL; -+#endif - - optional = hasmntopt(mntent, "optional") != NULL; - dev = hasmntopt(mntent, "dev") != NULL; -@@ -2647,8 +2812,31 @@ static inline int mount_entry_on_generic(struct mntent *mntent, - if (rootfs && rootfs->path) - rootfs_path = rootfs->mount; +#ifdef HAVE_ISULAD -+ // isulad: ensure that the destination of the bind mount is resolved of symlinks at mount time because -+ // any previous mounts can invalidate the next mount's destination. -+ // this can happen when a user specifies mounts within other mounts to cause breakouts or other -+ // evil stuff to try to escape the container's rootfs. -+ if (rootfs_path) { -+ rpath = follow_symlink_in_scope(path, rootfs_path); -+ if (!rpath) { -+ ERROR("Failed to get real path of '%s' in scope '%s'.", path, rootfs_path); -+ return -1; -+ } -+ dest = rpath; -+ -+ ret = check_mount_destination(rootfs_path, dest, mntent->mnt_fsname); -+ if (ret) { -+ ERROR("Mount destination is invalid: '%s'", dest); -+ return -1; ++ /* isulad: setup devices which will be populated in the container. */ ++ if (!lxc_list_empty(&lxc_conf->populate_devs) && setup_dev) { ++ if (setup_populate_devs(&lxc_conf->rootfs, &lxc_conf->populate_devs, lxc_conf->lsm_se_mount_context) != 0) { ++ return log_error(-1, "Failed to setup devices in the container"); + } + } -+ ret = mount_entry_create_dir_file(mntent, dest, rootfs, lxc_name, -+ lxc_path); -+#else - ret = mount_entry_create_dir_file(mntent, path, rootfs, lxc_name, - lxc_path); -+#endif - if (ret < 0) { - if (optional) - return 0; -@@ -2673,7 +2861,24 @@ static inline int mount_entry_on_generic(struct mntent *mntent, - ret = parse_mount_attrs(&opts, mntent->mnt_opts); - if (ret < 0) - return -1; -- -+#ifdef HAVE_ISULAD -+ // support squashfs -+ if (strcmp(mntent->mnt_type, "squashfs") == 0) { -+ ret = mount_entry_with_loop_dev(mntent->mnt_fsname, dest, mntent->mnt_type, -+ mntent->mnt_opts, rootfs_path); -+ } else { -+ ret = mount_entry(mntent->mnt_fsname, -+ dest, -+ mntent->mnt_type, -+ opts.mnt_flags, -+ opts.prop_flags, -+ opts.data, -+ optional, -+ dev, -+ relative, -+ rootfs_path, rootfs != NULL ? rootfs->lsm_se_mount_context : NULL); -+ } -+#else - ret = mount_entry(mntent->mnt_fsname, - path, - mntent->mnt_type, -@@ -2684,6 +2889,7 @@ static inline int mount_entry_on_generic(struct mntent *mntent, - dev, - relative, - rootfs_path); +#endif - - return ret; - } -@@ -2771,6 +2977,27 @@ static int mount_file_entries(struct lxc_rootfs *rootfs, FILE *file, - while (getmntent_r(file, &mntent, buf, sizeof(buf))) { - int ret; - -+#ifdef HAVE_ISULAD -+ //isulad, system contaienr, skip "proc/sys/xxx" path -+ if (conf->systemd != NULL && strcmp(conf->systemd, "true") == 0) { -+ if (strstr(mntent.mnt_dir, "proc/sys") != NULL) { -+ continue; -+ } -+ } + -+ /* Note: Workaround for volume file path with space*/ -+ mntent.mnt_fsname = lxc_string_replace(SPACE_MAGIC_STR, " ", mntent.mnt_fsname); -+ if(!mntent.mnt_fsname) { -+ SYSERROR("memory allocation error"); -+ return -1; -+ } -+ mntent.mnt_dir = lxc_string_replace(SPACE_MAGIC_STR, " ", mntent.mnt_dir); -+ if(!mntent.mnt_dir) { -+ SYSERROR("memory allocation error"); -+ free(mntent.mnt_fsname); -+ return -1; -+ } -+#endif - if (!rootfs->path) - ret = mount_entry_on_systemfs(rootfs, &mntent); - else if (mntent.mnt_dir[0] != '/') -@@ -2779,6 +3006,12 @@ static int mount_file_entries(struct lxc_rootfs *rootfs, FILE *file, - else - ret = mount_entry_on_absolute_rootfs(&mntent, rootfs, - lxc_name, lxc_path); -+#ifdef HAVE_ISULAD -+ free(mntent.mnt_fsname); -+ mntent.mnt_fsname = NULL; -+ free(mntent.mnt_dir); -+ mntent.mnt_dir = NULL; -+#endif - if (ret < 0) - return -1; - } -@@ -3255,6 +3488,17 @@ static int capabilities_allow(struct lxc_conf *conf) - if (cap->cap > last_cap) - continue; - -+#ifdef HAVE_ISULAD -+ /* Do not keep any cap*/ -+ if (strcmp(cap->cap_name, "ISULAD_KEEP_NONE") == 0) { -+ DEBUG("Do not keep any capability"); -+ __u32 i; -+ for(i = 0; i < nr_u32; i++) { -+ keep_bits[i] = 0; -+ } -+ break; -+ } -+#endif - set_bit(cap->cap, keep_bits); - DEBUG("Keeping %s (%d) capability", cap->cap_name, cap->cap); - } -@@ -3473,6 +3717,27 @@ struct lxc_conf *lxc_conf_init(void) - - INIT_LIST_HEAD(&new->netdevs); + /* Make sure any start hooks are in the container */ + if (!verify_start_hooks(lxc_conf)) + return log_error(-1, "Failed to verify start hooks"); -+#ifdef HAVE_ISULAD -+ lxc_list_init(&new->populate_devs); -+ lxc_list_init(&new->rootfs.maskedpaths); -+ lxc_list_init(&new->rootfs.ropaths); -+ new->exit_fd = -1; -+ new->umask = 0027; /*default umask 0027*/ -+ new->console.init_fifo[0] = NULL; -+ new->console.init_fifo[1] = NULL; -+ new->console.init_fifo[2] = NULL; -+ new->console.pipes[0][0] = -1; -+ new->console.pipes[0][1] = -1; -+ new->console.pipes[1][0] = -1; -+ new->console.pipes[1][1] = -1; -+ new->console.pipes[2][0] = -1; -+ new->console.pipes[2][1] = -1; -+ lxc_list_init(&new->console.fifos); -+ new->errmsg = NULL; -+ new->errpipe[0] = -1; -+ new->errpipe[1] = -1; -+#endif -+ - return new; - } ++#ifndef HAVE_ISULAD + ret = lxc_create_tmp_proc_mount(lxc_conf); + if (ret < 0) + return log_error(-1, "Failed to \"/proc\" LSMs"); -@@ -3945,7 +4210,11 @@ static void turn_into_dependent_mounts(const struct lxc_rootfs *rootfs) - null_endofword(target); - ret = mount(NULL, target, NULL, MS_SLAVE, NULL); - if (ret < 0) { -+#ifdef HAVE_ISULAD -+ SYSERROR("Failed to recursively turn old root mount tree: %s into dependent mount. Continuing...", target); + ret = lxc_setup_console(&lxc_conf->rootfs, &lxc_conf->console, + lxc_conf->ttys.dir, pts_mnt_fd); +#else - SYSERROR("Failed to recursively turn old root mount tree into dependent mount. Continuing..."); -+#endif - continue; - } - } -@@ -3964,6 +4233,10 @@ int lxc_setup_rootfs_prepare_root(struct lxc_conf *conf, const char *name, - if (conf->rootfs.dfd_host < 0) - return log_error_errno(-errno, errno, "Failed to open \"/\""); - -+#ifdef HAVE_ISULAD -+ // iSulad: will remount all mounts when we setted propagation flags -+ if (conf->rootfs.mnt_opts.prop_flags == 0) -+#endif - turn_into_dependent_mounts(&conf->rootfs); - - if (conf->rootfs_setup) { -@@ -4358,10 +4631,22 @@ int lxc_setup(struct lxc_handler *handler) - int ret; - const char *lxcpath = handler->lxcpath, *name = handler->name; - struct lxc_conf *lxc_conf = handler->conf; -+#ifdef HAVE_ISULAD -+ bool setup_dev = true; -+ bool setup_proc = true; -+#endif - - ret = lxc_rootfs_prepare_child(handler); - if (ret < 0) -+#ifdef HAVE_ISULAD -+ { -+ lxc_write_error_message(lxc_conf->errpipe[1], "%s:%d: failed to setup rootfs %s.", -+ __FILE__, __LINE__, lxc_conf->rootfs.path); -+ return syserror("Failed to prepare rootfs"); ++ if (setup_proc) { ++ ret = lxc_create_tmp_proc_mount(lxc_conf); ++ if (ret < 0) ++ return log_error(-1, "Failed to \"/proc\" LSMs"); + } -+#else - return syserror("Failed to prepare rootfs"); -+#endif - - ret = lxc_setup_rootfs_prepare_root(lxc_conf, name, lxcpath); - if (ret < 0) -@@ -4402,6 +4687,16 @@ int lxc_setup(struct lxc_handler *handler) - if (ret < 0) - return log_error(-1, "Failed to setup first automatic mounts"); - -+#ifdef HAVE_ISULAD -+ /* Now mount only cgroups, if wanted. Before, /sys could not have been -+ * mounted. It is guaranteed to be mounted now either through -+ * automatically or via fstab entries. -+ */ -+ ret = lxc_mount_auto_mounts(handler, lxc_conf->auto_mounts & LXC_AUTO_CGROUP_MASK); -+ if (ret < 0) -+ return log_error(-1, "Failed to setup remaining automatic mounts"); -+#endif + - ret = setup_mount_fstab(&lxc_conf->rootfs, lxc_conf->fstab, name, lxcpath); - if (ret < 0) - return log_error(-1, "Failed to setup mounts"); -@@ -4410,6 +4705,10 @@ int lxc_setup(struct lxc_handler *handler) - ret = setup_mount_entries(lxc_conf, &lxc_conf->rootfs, name, lxcpath); - if (ret < 0) - return log_error(-1, "Failed to setup mount entries"); -+#ifdef HAVE_ISULAD -+ setup_dev = need_setup_dev(lxc_conf, &lxc_conf->mount_entries); -+ setup_proc = need_setup_proc(lxc_conf, &lxc_conf->mount_entries); ++ ret = lxc_setup_console(&lxc_conf->rootfs, &lxc_conf->console, ++ lxc_conf->ttys.dir, lxc_conf->lsm_se_mount_context); +#endif - } - - if (!lxc_sync_wake_parent(handler, START_SYNC_IDMAPPED_MOUNTS)) -@@ -4424,6 +4723,7 @@ int lxc_setup(struct lxc_handler *handler) - if (lxc_conf->rootfs.dfd_dev < 0 && errno != ENOENT) - return log_error_errno(-errno, errno, "Failed to open \"/dev\""); - -+#ifndef HAVE_ISULAD - /* Now mount only cgroups, if wanted. Before, /sys could not have been - * mounted. It is guaranteed to be mounted now either through - * automatically or via fstab entries. -@@ -4431,6 +4731,7 @@ int lxc_setup(struct lxc_handler *handler) - ret = lxc_mount_auto_mounts(handler, lxc_conf->auto_mounts & LXC_AUTO_CGROUP_MASK); if (ret < 0) - return log_error(-1, "Failed to setup remaining automatic mounts"); -+#endif + return log_error(-1, "Failed to setup console"); - ret = run_lxc_hooks(name, "mount", lxc_conf, NULL); +@@ -3317,6 +3921,12 @@ int lxc_setup(struct lxc_handler *handler) if (ret < 0) -@@ -4453,13 +4754,28 @@ int lxc_setup(struct lxc_handler *handler) - if (!verify_start_hooks(lxc_conf)) - return log_error(-1, "Failed to verify start hooks"); + return log_error(-1, "Failed to setup \"/dev\" symlinks"); +#ifdef HAVE_ISULAD -+ if (setup_proc) ++ /* Ask father to run oci prestart hooks and wait for him to finish. */ ++ if (lxc_sync_barrier_parent(handler, LXC_SYNC_OCI_PRESTART_HOOK)) { ++ return log_error(-1, "Failed to sync parent to start host hook"); ++ } +#endif - ret = lxc_create_tmp_proc_mount(lxc_conf); + ret = lxc_setup_rootfs_switch_root(&lxc_conf->rootfs); if (ret < 0) - return log_error(-1, "Failed to mount transient procfs instance for LSMs"); + return log_error(-1, "Failed to pivot root into rootfs"); +@@ -3325,14 +3935,31 @@ int lxc_setup(struct lxc_handler *handler) + if (lxc_conf->autodev > 0) + (void)lxc_setup_boot_id(); +#ifdef HAVE_ISULAD + if (setup_rootfs_mountopts(&lxc_conf->rootfs)) { + return log_error(-1, "failed to set rootfs for '%s'", name); + } + if (lxc_conf->rootfs.path != NULL && setup_dev) { -+ ret = lxc_setup_devpts_child(handler); ++ ret = lxc_setup_devpts(lxc_conf); + if (ret < 0) { + return log_error(-1, "Failed to setup new devpts instance for '%s'", name); + } + } +#else - ret = lxc_setup_devpts_child(handler); + ret = lxc_setup_devpts(lxc_conf); if (ret < 0) - return log_error(-1, "Failed to prepare new devpts instance"); + return log_error(-1, "Failed to setup new devpts instance"); +#endif - ret = lxc_finish_devpts_child(handler); + ret = lxc_create_ttys(handler); if (ret < 0) -@@ -4478,6 +4794,12 @@ int lxc_setup(struct lxc_handler *handler) - if (ret < 0) - return log_error(-1, "Failed to setup \"/dev\" symlinks"); - -+#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)) { -+ return log_error(-1, "Failed to sync parent to start host hook"); -+ } -+#endif - ret = lxc_setup_rootfs_switch_root(&lxc_conf->rootfs); - if (ret < 0) - return log_error(-1, "Failed to pivot root into rootfs"); -@@ -4491,6 +4813,11 @@ int lxc_setup(struct lxc_handler *handler) - if (lxc_conf->autodev > 0) - (void)lxc_setup_boot_id(); + return -1; +#ifdef HAVE_ISULAD + /*isulad: set system umask */ @@ -1545,19 +1277,12 @@ index 9158713..23783db 100644 + ret = setup_personality(lxc_conf->personality); if (ret < 0) - return syserror("Failed to set personality"); -@@ -4503,6 +4830,37 @@ int lxc_setup(struct lxc_handler *handler) - if (ret < 0) - return log_error(-1, "Failed to setup sysctl parameters"); + return log_error(-1, "Failed to set personality"); +@@ -3347,6 +3974,37 @@ int lxc_setup(struct lxc_handler *handler) + return log_error(-1, "Failed to setup sysctl parameters"); + } +#ifdef HAVE_ISULAD -+ // isulad: setup rootfs ro paths -+ if (!lxc_list_empty(&lxc_conf->rootfs.ropaths)) { -+ if (setup_rootfs_ropaths(&lxc_conf->rootfs.ropaths)) { -+ return log_error(-1, "failed to setup readonlypaths"); -+ } -+ } -+ + // isulad: setup rootfs masked paths + if (!lxc_list_empty(&lxc_conf->rootfs.maskedpaths)) { + if (setup_rootfs_maskedpaths(&lxc_conf->rootfs.maskedpaths)) { @@ -1565,6 +1290,13 @@ index 9158713..23783db 100644 + } + } + ++ // isulad: setup rootfs ro paths ++ if (!lxc_list_empty(&lxc_conf->rootfs.ropaths)) { ++ if (setup_rootfs_ropaths(&lxc_conf->rootfs.ropaths)) { ++ return log_error(-1, "failed to setup readonlypaths"); ++ } ++ } ++ + //isulad: system container, remount /proc/sys/xxx by mount_list + if (lxc_conf->systemd != NULL && strcmp(lxc_conf->systemd, "true") == 0) { + if (!lxc_list_empty(&lxc_conf->mount_list)) { @@ -1581,14 +1313,13 @@ index 9158713..23783db 100644 + } +#endif + - ret = setup_capabilities(lxc_conf); - if (ret < 0) - return log_error(-1, "Failed to setup capabilities"); -@@ -4876,6 +5234,27 @@ void lxc_conf_free(struct lxc_conf *conf) - free(conf->cgroup_meta.systemd_scope); + if (!lxc_list_empty(&lxc_conf->keepcaps)) { + if (!lxc_list_empty(&lxc_conf->caps)) + return log_error(-1, "Container requests lxc.cap.drop and lxc.cap.keep: either use lxc.cap.drop or lxc.cap.keep, not both"); +@@ -3753,6 +4411,25 @@ void lxc_conf_free(struct lxc_conf *conf) + free(conf->cgroup_meta.controllers); free(conf->shmount.path_host); free(conf->shmount.path_cont); -+ +#ifdef HAVE_ISULAD + free(conf->container_info_file); + if (conf->exit_fd != -1) { @@ -1608,13 +1339,12 @@ index 9158713..23783db 100644 + free(conf->lsm_se_mount_context); + free(conf->lsm_se_keyring_context); +#endif -+ free(conf); } -@@ -5798,3 +6177,1321 @@ int lxc_set_environment(const struct lxc_conf *conf) +@@ -4775,3 +5452,1315 @@ struct lxc_list *sort_cgroup_settings(struct lxc_list *cgroup_settings) - return 0; + return result; } + +#ifdef HAVE_ISULAD @@ -1692,8 +1422,7 @@ index 9158713..23783db 100644 + if (caplist[i]) { + cap_data[CAP_TO_INDEX(i)].effective = cap_data[CAP_TO_INDEX(i)].effective | (i > 31 ? __DEF_CAP_TO_MASK(i % 32) : __DEF_CAP_TO_MASK(i)); + cap_data[CAP_TO_INDEX(i)].permitted = cap_data[CAP_TO_INDEX(i)].permitted | (i > 31 ? __DEF_CAP_TO_MASK(i % 32) : __DEF_CAP_TO_MASK(i)); -+ // fix CVE-2022-24769 -+ // inheritable capability should be empty ++ cap_data[CAP_TO_INDEX(i)].inheritable = cap_data[CAP_TO_INDEX(i)].inheritable | (i > 31 ? __DEF_CAP_TO_MASK(i % 32) : __DEF_CAP_TO_MASK(i)); + } + } + @@ -2228,8 +1957,7 @@ index 9158713..23783db 100644 + + // Unprivileged containers cannot create devices, so + // try to bind mount the device from the host -+ // dev_elem name is the device path -+ ret = snprintf(hostpath, MAXPATHLEN, "%s", dev_elem->name); ++ ret = snprintf(hostpath, MAXPATHLEN, "/dev/%s", dev_elem->name); + if (ret < 0 || ret >= MAXPATHLEN) { + ret = -1; + goto reset_umask; @@ -2268,19 +1996,16 @@ index 9158713..23783db 100644 +static int setup_rootfs_mountopts(const struct lxc_rootfs *rootfs) +{ + unsigned long mflags, mntflags, pflags; -+ __do_free char *mntdata = NULL; ++ char *mntdata = NULL; + + if(!rootfs || !rootfs->options) + return 0; + -+ if (parse_mntopts_legacy(rootfs->options, &mntflags, &mntdata) < 0) { ++ if (parse_mntopts(rootfs->options, &mntflags, &pflags, &mntdata) < 0) { ++ free(mntdata); + return -1; + } -+ -+ ret = parse_propagationopts(rootfs->options, &pflags); -+ if (ret < 0) { -+ return -EINVAL; -+ } ++ free(mntdata); + + if (mntflags & MS_RDONLY) { + mflags = add_required_remount_flags("/", NULL, MS_BIND | MS_REC | mntflags | pflags | MS_REMOUNT); @@ -2392,8 +2117,7 @@ index 9158713..23783db 100644 +{ + char **result = NULL; + size_t result_len = env_len; -+ size_t i = 0; -+ size_t j, k; ++ size_t i, j; + char *tmpenv = NULL; + char *lxc_envs[] = {"LD_LIBRARY_PATH", "PATH", "LXC_CGNS_AWARE", "LXC_PID", "LXC_ROOTFS_MOUNT", + "LXC_CONFIG_FILE", "LXC_CGROUP_PATH", "LXC_ROOTFS_PATH", "LXC_NAME" @@ -2408,6 +2132,11 @@ index 9158713..23783db 100644 + return NULL; + memset(result, 0, sizeof(char *) * result_len); + ++ for(i = 0; i < env_len; i++) { ++ if (oldenvs[i]) ++ result[i] = safe_strdup(oldenvs[i]); ++ } ++ + for(j = 0; j < (sizeof(lxc_envs) / sizeof(char *)); j++) { + size_t env_buf_len = 0; + tmpenv = getenv(lxc_envs[j]); @@ -2431,11 +2160,6 @@ index 9158713..23783db 100644 + } + } + -+ for(k = 0; k < env_len; k++) { -+ if (oldenvs[k] && i < (result_len - 1)) -+ result[i++] = safe_strdup(oldenvs[k]); -+ } -+ + *merge_env_len = i; + return result; +} @@ -2563,1923 +2287,570 @@ index 9158713..23783db 100644 + if (pipe_msg[1] >= 0) + close(pipe_msg[1]); + -+ if (fp) -+ free(fp); -+ -+ return NULL; -+} -+ -+void* wait_ocihook_timeout(void *arg) -+{ -+ bool alive = false; -+ struct wait_conf *conf = (struct wait_conf *)arg; -+ -+ if (!conf || conf->timeout < 1) -+ goto out; -+ -+ sleep(conf->timeout); -+ -+ alive = lxc_process_alive(conf->pid, conf->startat); -+ -+ if (alive) { -+ ERROR("%s:%d: running %s hook caused \"hook ran past specified timeout of %.1fs\"", -+ __FILE__, __LINE__, lxchook_names[conf->which], -+ (double)conf->timeout); -+ -+ lxc_write_error_message(conf->errfd, "%s:%d: running %s hook caused \"hook ran past specified timeout of %.1fs\".", -+ __FILE__, __LINE__, lxchook_names[conf->which], -+ (double)conf->timeout); -+ -+ if (kill(conf->pid, SIGKILL) && errno != ESRCH) { -+ ERROR("Send kill signal failed"); -+ goto out; -+ } -+ } -+ -+out: -+ free(conf); -+ return ((void *)0); -+} -+ -+static int run_ocihook_buffer(struct oci_hook_conf *oconf, const char *inmsg) -+{ -+ struct lxc_popen_FILE *f; -+ char output[LXC_LOG_BUFFER_SIZE] = {0}; -+ int ret; -+ pthread_t ptid; -+ int err; -+ struct wait_conf *conf = NULL; -+ pthread_attr_t attr; -+ char *buffer = oconf->ocihook->path; -+ char *err_args_msg = NULL; -+ char *err_envs_msg = NULL; -+ char **hookenvs = NULL; -+ size_t hookenvs_len = 0; -+ -+ hookenvs = merge_ocihook_env(oconf->ocihook->env, oconf->ocihook->env_len, &hookenvs_len); -+ if (!hookenvs) { -+ ERROR("Out of memory."); -+ return -1; -+ } -+ -+ f = lxc_popen_ocihook(buffer, oconf->ocihook->args, oconf->ocihook->args_len, hookenvs, hookenvs_len, inmsg); -+ lxc_free_array((void **)hookenvs, free); -+ if (!f) { -+ SYSERROR("Failed to popen() %s.", buffer); -+ return -1; -+ } -+ -+ conf = malloc(sizeof(struct wait_conf)); -+ if (conf == NULL) { -+ SYSERROR("Failed to malloc."); -+ goto on_error; -+ } -+ -+ memset(conf, 0x00, sizeof(struct wait_conf)); -+ -+ conf->pid = f->child_pid; -+ conf->startat = lxc_get_process_startat(conf->pid); -+ -+ INFO("hook_conf timeout %d", oconf->ocihook->timeout); -+ if(oconf->ocihook->timeout > 0) -+ conf->timeout = oconf->ocihook->timeout; -+ else { -+ conf->timeout = 30; -+ INFO("Set hook timeout 30s"); -+ } -+ conf->errfd = oconf->errfd; -+ conf->which = oconf->which; -+ -+ pthread_attr_init(&attr); -+ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); -+ err = pthread_create(&ptid, &attr, wait_ocihook_timeout, conf); -+ pthread_attr_destroy(&attr); -+ if (err != 0) { -+ ERROR("Create wait timeout thread failed"); -+ free(conf); -+ goto on_error; -+ } -+ -+ ret = lxc_wait_for_pid_status(f->child_pid); -+ -+ lxc_read_nointr(f->pipe, output, sizeof(output) - 1); -+ close(f->pipe); -+ free(f); -+ -+ if (ret == -1) { -+ SYSERROR("Script exited with error."); -+ goto print_hook; -+ } else if (WIFEXITED(ret) && WEXITSTATUS(ret) != 0) { -+ ERROR("Script exited with status %d. output: %s", WEXITSTATUS(ret), output); -+ lxc_write_error_message(oconf->errfd, "%s:%d: running %s hook caused \"error running hook: exit status %d, output: %s\".", -+ __FILE__, __LINE__, -+ (oconf->which >= NUM_LXC_HOOKS) ? "invalid type" : lxchook_names[oconf->which], -+ WEXITSTATUS(ret), output); -+ -+ goto print_hook; -+ } else if (WIFSIGNALED(ret)) { -+ ERROR("Script terminated by signal %d.", WTERMSIG(ret)); -+ lxc_write_error_message(oconf->errfd, "%s:%d: running %s hook caused \"error running hook: Script terminated by signal %d\".", -+ __FILE__, __LINE__, -+ (oconf->which >= NUM_LXC_HOOKS) ? "invalid type" : lxchook_names[oconf->which], -+ WTERMSIG(ret)); -+ -+ goto print_hook; -+ } -+ -+ return 0; -+ -+on_error: -+ if (f) { -+ if (f->pipe >= 0) -+ close(f->pipe); -+ free(f); -+ } -+ -+print_hook: -+ if (oconf->ocihook->args) -+ err_args_msg = lxc_string_join(" ", (const char **)oconf->ocihook->args, false); -+ if (oconf->ocihook->env) -+ err_envs_msg = lxc_string_join(" ", (const char **)oconf->ocihook->env, false); -+ ERROR("Hook script command: \"%s\", args: \"%s\", envs: \"%s\", timeout: %d.", -+ buffer, err_args_msg ? err_args_msg : "", -+ err_envs_msg ? err_envs_msg : "", oconf->ocihook->timeout); -+ -+ free(err_args_msg); -+ free(err_envs_msg); -+ return -1; -+} -+ -+static int run_ocihook_script_argv(const char *name, const char *section, -+ struct oci_hook_conf *oconf, -+ const char *lxcpath, const char *rootfs) -+{ -+ int ret; -+ const char *script = oconf->ocihook->path; -+ char *inmsg = NULL; -+ -+ INFO("Executing script \"%s\" for container \"%s\", config section \"%s\".", -+ script, name, section); -+ -+ inmsg = generate_json_str(name, lxcpath, rootfs); -+ if (!inmsg) { -+ return -1; -+ } -+ -+ ret = run_ocihook_buffer(oconf, inmsg); -+ free(inmsg); -+ inmsg = NULL; -+ return ret; -+} -+ -+static char *get_root_path(const char *path, const char *backend) -+{ -+ char *ret = NULL; -+ char *tmp = NULL; -+ -+ if (!path) { -+ ret = safe_strdup("/"); -+ return ret; -+ } -+ if (!backend) { -+ goto default_out; -+ } -+ -+ if (strcmp(backend, "aufs") == 0 || -+ strcmp(backend, "overlayfs") == 0 || -+ strcmp(backend, "loop") == 0) { -+ tmp = strrchr(path, ':'); -+ if (tmp == NULL) { -+ ERROR("Invalid root path format"); -+ return NULL; -+ } -+ tmp++; -+ ret = safe_strdup(tmp); -+ return ret; -+ } -+ -+default_out: -+ ret = safe_strdup(path); -+ return ret; -+} -+ -+static int do_run_oci_hooks(const char *name, const char *lxcpath, struct lxc_conf *lc, int which, int errfd) -+{ -+ struct oci_hook_conf work_conf = {0}; -+ size_t i; -+ int ret = 0; -+ int nret = 0; -+ char *rootpath = NULL; -+ -+ if (!lc) { -+ return -1; -+ } -+ if (!lc->ocihooks) { -+ return 0; -+ } -+ -+ rootpath = get_root_path(lc->rootfs.path ? lc->rootfs.mount : NULL, lc->rootfs.bdev_type); -+ if (!rootpath) { -+ ERROR("Get container %s rootpath failed.", name); -+ return -1; -+ } -+ -+ work_conf.errfd = errfd; -+ work_conf.which = which; -+ switch (which) { -+ case OCI_HOOK_PRESTART: -+ for (i = 0; i < lc->ocihooks->prestart_len; i++) { -+ work_conf.ocihook = lc->ocihooks->prestart[i]; -+ ret = run_ocihook_script_argv(name, "lxc", &work_conf, lxcpath, rootpath); -+ if (ret != 0) -+ break; -+ } -+ break; -+ case OCI_HOOK_POSTSTART: -+ for (i = 0; i < lc->ocihooks->poststart_len; i++) { -+ work_conf.ocihook = lc->ocihooks->poststart[i]; -+ nret = run_ocihook_script_argv(name, "lxc", &work_conf, lxcpath, rootpath); -+ if (nret != 0) -+ WARN("running poststart hook %zu failed, ContainerId: %s", i, name); -+ } -+ break; -+ case OCI_HOOK_POSTSTOP: -+ for (i = 0; i < lc->ocihooks->poststop_len; i++) { -+ work_conf.ocihook = lc->ocihooks->poststop[i]; -+ nret = run_ocihook_script_argv(name, "lxc", &work_conf, lxcpath, rootpath); -+ if (nret != 0) -+ WARN("running poststart hook %zu failed, ContainerId: %s", i, name); -+ } -+ break; -+ default: -+ ret = -1; -+ } -+ if (rootpath) -+ free(rootpath); -+ return ret; -+} -+ -+int run_oci_hooks(const char *name, const char *hookname, struct lxc_conf *conf, const char *lxcpath) -+{ -+ int which = -1; -+ -+ if (strcmp(hookname, "oci-prestart") == 0) { -+ which = OCI_HOOK_PRESTART; -+ if (!lxcpath) { -+ ERROR("oci hook require lxcpath"); -+ return -1; -+ } -+ return do_run_oci_hooks(name, lxcpath, conf, which, conf->errpipe[1]); -+ } else if (strcmp(hookname, "oci-poststart") == 0) { -+ which = OCI_HOOK_POSTSTART; -+ if (!lxcpath) { -+ ERROR("oci hook require lxcpath"); -+ return -1; -+ } -+ return do_run_oci_hooks(name, lxcpath, conf, which, conf->errpipe[1]); -+ } else if (strcmp(hookname, "oci-poststop") == 0) { -+ which = OCI_HOOK_POSTSTOP; -+ if (!lxcpath) { -+ ERROR("oci hook require lxcpath"); -+ return -1; -+ } -+ return do_run_oci_hooks(name, lxcpath, conf, which, conf->errpipe[1]); -+ } else -+ return -1; -+ -+ return 0; -+} -+ -+/*isulad clear init args*/ -+int lxc_clear_init_args(struct lxc_conf *lxc_conf) -+{ -+ int i; -+ -+ for (i = 0; i < lxc_conf->init_argc; i++) { -+ free(lxc_conf->init_argv[i]); -+ lxc_conf->init_argv[i] = NULL; -+ } -+ free(lxc_conf->init_argv); -+ lxc_conf->init_argv = NULL; -+ lxc_conf->init_argc = 0; -+ -+ return 0; -+} -+ -+/*isulad clear init groups*/ -+int lxc_clear_init_groups(struct lxc_conf *lxc_conf) -+{ -+ free(lxc_conf->init_groups); -+ lxc_conf->init_groups = NULL; -+ lxc_conf->init_groups_len = 0; -+ -+ return 0; -+} -+ -+/*isulad: clear populate devices*/ -+int lxc_clear_populate_devices(struct lxc_conf *c) -+{ -+ struct lxc_list *it = NULL; -+ struct lxc_list *next = NULL; -+ -+ lxc_list_for_each_safe(it, &c->populate_devs, next) { -+ struct lxc_populate_devs *dev_elem = it->elem; -+ lxc_list_del(it); -+ free(dev_elem->name); -+ free(dev_elem->type); -+ free(dev_elem); -+ free(it); -+ } -+ return 0; -+} -+ -+/*isulad: clear rootfs masked paths*/ -+int lxc_clear_rootfs_masked_paths(struct lxc_conf *c) -+{ -+ struct lxc_list *it = NULL; -+ struct lxc_list *next = NULL; -+ -+ lxc_list_for_each_safe(it, &c->rootfs.maskedpaths, next) { -+ lxc_list_del(it); -+ free(it->elem); -+ free(it); -+ } -+ return 0; -+} -+ -+/*isulad: clear rootfs ro paths*/ -+int lxc_clear_rootfs_ro_paths(struct lxc_conf *c) -+{ -+ struct lxc_list *it = NULL; -+ struct lxc_list *next = NULL; -+ -+ lxc_list_for_each_safe(it, &c->rootfs.ropaths, next) { -+ lxc_list_del(it); -+ free(it->elem); -+ free(it); -+ } -+ return 0; -+} -+ -+/*isulad: close error pipe */ -+void lxc_close_error_pipe(int *errpipe) -+{ -+ if (errpipe[0] >= 0) { -+ close(errpipe[0]); -+ errpipe[0] = -1; -+ } -+ if (errpipe[1] >= 0) { -+ close(errpipe[1]); -+ errpipe[1] = -1; -+ } -+} -+#endif -diff --git a/src/lxc/conf.h b/src/lxc/conf.h -index 82cb66a..683b8ba 100644 ---- a/src/lxc/conf.h -+++ b/src/lxc/conf.h -@@ -31,6 +31,10 @@ - #include "syscall_wrappers.h" - #include "terminal.h" - -+#ifdef HAVE_ISULAD -+#include "oci_runtime_hooks.h" -+#endif -+ - #if HAVE_SYS_RESOURCE_H - #include - #endif -@@ -255,6 +259,15 @@ struct lxc_rootfs { - bool managed; - struct lxc_mount_options mnt_opts; - struct lxc_storage *storage; -+#ifdef HAVE_ISULAD -+ /* isulad: maskedpaths */ -+ struct lxc_list maskedpaths; -+ /* isulad: ropaths */ -+ struct lxc_list ropaths; -+ -+ /* Linux Security Modules SELinux context for device mount */ -+ char *lsm_se_mount_context; -+#endif - }; - - /* -@@ -345,6 +358,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 - }; - -@@ -407,6 +425,27 @@ struct string_entry { - struct list_head head; - }; - -+#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; -@@ -574,6 +613,37 @@ struct lxc_conf { - - struct timens_offsets timens; - -+ -+#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; -+#endif -+ - bool sched_core; - __u64 sched_core_cookie; - }; -@@ -721,4 +791,16 @@ static inline int lxc_personality(personality_t persona) - __hidden extern int lxc_set_environment(const struct lxc_conf *conf); - __hidden extern int parse_cap(const char *cap_name, __u32 *cap); - -+#ifdef HAVE_ISULAD -+// isulad add -+__hidden int lxc_clear_init_args(struct lxc_conf *lxc_conf); -+__hidden int lxc_clear_init_groups(struct lxc_conf *lxc_conf); -+__hidden int lxc_clear_populate_devices(struct lxc_conf *c); -+__hidden int lxc_clear_rootfs_masked_paths(struct lxc_conf *c); -+__hidden int lxc_clear_rootfs_ro_paths(struct lxc_conf *c); -+__hidden int lxc_drop_caps(struct lxc_conf *conf); -+__hidden int run_oci_hooks(const char *name, const char *hookname, struct lxc_conf *conf, const char *lxcpath); -+__hidden 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 -index ee39302..889d912 100644 ---- a/src/lxc/isulad_utils.c -+++ b/src/lxc/isulad_utils.c -@@ -533,3 +533,28 @@ out: - funlockfile(stream); - return ret; - } -+ -+ssize_t lxc_write_nointr_for_fifo(int fd, const char *buf, size_t count) -+{ -+ ssize_t nret = 0; -+ ssize_t nwritten; -+ -+ if (buf == NULL) { -+ return -1; -+ } -+ -+ for (nwritten = 0; nwritten < count;) { -+ nret = write(fd, buf + nwritten, count - nwritten); -+ if (nret < 0) { -+ if (errno == EINTR || errno == EAGAIN) { -+ continue; -+ } else { -+ return nret; -+ } -+ } else { -+ nwritten += nret; -+ } -+ } -+ -+ return nwritten; -+} -diff --git a/src/lxc/isulad_utils.h b/src/lxc/isulad_utils.h -index 7a5eb89..93174ae 100644 ---- a/src/lxc/isulad_utils.h -+++ b/src/lxc/isulad_utils.h -@@ -80,23 +80,25 @@ typedef struct proc_t { - 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); -+__hidden extern int lxc_mem_realloc(void **newptr, size_t newsize, void *oldptr, size_t oldsize); -+__hidden extern void *lxc_common_calloc_s(size_t size); -+__hidden 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); -+__hidden extern int lxc_open(const char *filename, int flags, mode_t mode); -+__hidden 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); -+__hidden extern void lxc_write_error_message(int errfd, const char *format, ...); -+__hidden extern int lxc_file2str(const char *filename, char ret[], int cap); -+__hidden 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); -+__hidden extern int lxc_setup_env_home(uid_t uid); - --extern bool lxc_process_alive(pid_t pid, unsigned long long start_time); -+__hidden extern bool lxc_process_alive(pid_t pid, unsigned long long start_time); - --extern bool is_non_negative_num(const char *s); -+__hidden extern bool is_non_negative_num(const char *s); - --int util_getpwent_r(FILE *stream, struct passwd *resbuf, char *buffer, size_t buflen, struct passwd **result); -+__hidden int util_getpwent_r(FILE *stream, struct passwd *resbuf, char *buffer, size_t buflen, struct passwd **result); -+ -+__hidden extern ssize_t lxc_write_nointr_for_fifo(int fd, const char *buf, size_t count); - - #endif -diff --git a/src/lxc/lsm/apparmor.c b/src/lxc/lsm/apparmor.c -index 23af021..7ff5ba1 100644 ---- a/src/lxc/lsm/apparmor.c -+++ b/src/lxc/lsm/apparmor.c -@@ -1232,6 +1232,16 @@ static int apparmor_process_label_set(struct lsm_ops *ops, const char *inlabel, - return log_info(0, "Changed AppArmor profile to %s", label); - } - -+#ifdef HAVE_ISULAD -+static int apparmor_file_label_set(const char *path, const char *label) { -+ return 0; -+} -+ -+static int apparmor_relabel(const char *path, const char *label, bool shared) { -+ return 0; -+} -+#endif -+ - static struct lsm_ops apparmor_ops = { - .name = "AppArmor", - .aa_admin = -1, -@@ -1250,6 +1260,10 @@ static struct lsm_ops apparmor_ops = { - .process_label_set = apparmor_process_label_set, - .process_label_get_at = apparmor_process_label_get_at, - .process_label_set_at = apparmor_process_label_set_at, -+#ifdef HAVE_ISULAD -+ .file_label_set = apparmor_file_label_set, -+ .relabel = apparmor_relabel, -+#endif - }; - - struct lsm_ops *lsm_apparmor_ops_init(void) -diff --git a/src/lxc/lsm/lsm.h b/src/lxc/lsm/lsm.h -index a26abb8..93e1a99 100644 ---- a/src/lxc/lsm/lsm.h -+++ b/src/lxc/lsm/lsm.h -@@ -34,6 +34,10 @@ struct lsm_ops { - int (*process_label_fd_get)(struct lsm_ops *ops, pid_t pid, bool on_exec); - char *(*process_label_get_at)(struct lsm_ops *ops, int fd_pid); - int (*process_label_set_at)(struct lsm_ops *ops, int label_fd, const char *label, bool on_exec); -+#ifdef HAVE_ISULAD -+ int (*file_label_set)(const char *path, const char *label); -+ int (*relabel)(const char *path, const char *label, bool share); -+#endif - }; - - __hidden extern struct lsm_ops *lsm_init_static(void); -diff --git a/src/lxc/lsm/nop.c b/src/lxc/lsm/nop.c -index 56b97aa..d3f4081 100644 ---- a/src/lxc/lsm/nop.c -+++ b/src/lxc/lsm/nop.c -@@ -51,6 +51,16 @@ static int nop_process_label_set_at(struct lsm_ops *ops, int label_fd, const cha - return 0; - } - -+#ifdef HAVE_ISULAD -+static int nop_file_label_set(const char *path, const char *label) { -+ return 0; -+} -+ -+static int nop_relabel(const char *path, const char *label, bool shared) { -+ return 0; -+} -+#endif -+ - static struct lsm_ops nop_ops = { - .name = "nop", - .aa_admin = -1, -@@ -69,6 +79,10 @@ static struct lsm_ops nop_ops = { - .process_label_set = nop_process_label_set, - .process_label_get_at = nop_process_label_get_at, - .process_label_set_at = nop_process_label_set_at, -+#ifdef HAVE_ISULAD -+ .file_label_set = nop_file_label_set, -+ .relabel = nop_relabel, -+#endif - }; - - struct lsm_ops *lsm_nop_ops_init(void) -diff --git a/src/lxc/lsm/selinux.c b/src/lxc/lsm/selinux.c -index 9c131ee..5190110 100644 ---- a/src/lxc/lsm/selinux.c -+++ b/src/lxc/lsm/selinux.c -@@ -9,6 +9,9 @@ - #include - #include - #include -+#ifdef HAVE_ISULAD -+#include -+#endif - - #include "conf.h" - #include "file_utils.h" -@@ -165,6 +168,255 @@ static int selinux_enabled(struct lsm_ops *ops) - return is_selinux_enabled(); - } - -+#ifdef HAVE_ISULAD -+/* -+ * selinux_file_label_set: Set SELinux context of a file -+ * -+ * @path : a file -+ * @label : label string -+ * -+ * Returns 0 on success, < 0 on failure -+ */ -+static int selinux_file_label_set(const char *path, const char *label) -+{ -+ if (path == NULL || label == NULL || strcmp(label, "unconfined_t") == 0) { -+ return 0; -+ } -+ -+ if (!is_selinux_enabled()) { -+ return 0; -+ } -+ -+ if (lsetfilecon(path, label) != 0) { -+ SYSERROR("Failed to setSELinux context to \"%s\": %s", label, path); -+ return -1; -+ } -+ -+ INFO("Changed SELinux context to \"%s\": %s", label, path); -+ return 0; -+} -+ -+/* -+ * is_exclude_relabel_path: Determine whether it is a excluded path to label -+ * -+ * @path : a file or directory -+ * -+ * Returns 0 on success, < 0 on failure -+ */ -+static bool is_exclude_relabel_path(const char *path) -+{ -+ const char *exclude_path[] = { "/", "/usr", "/etc", "/tmp", "/home", "/run", "/var", "/root" }; -+ size_t i; -+ -+ for (i = 0; i < sizeof(exclude_path) / sizeof(char *); i++) { -+ if (strcmp(path, exclude_path[i]) == 0) { -+ return true; -+ } -+ } -+ -+ return false; -+} -+ -+/* -+ * bad_prefix: Prevent users from relabing system files -+ * -+ * @path : a file or directory -+ * -+ * Returns 0 on success, < 0 on failure -+ */ -+static int bad_prefix(const char *fpath) -+{ -+ const char *bad_prefixes = "/usr"; -+ -+ if (fpath == NULL) { -+ ERROR("Empty file path"); -+ return -1; -+ } -+ -+ if (strncmp(fpath, bad_prefixes, strlen(bad_prefixes)) == 0) { -+ ERROR("relabeling content in %s is not allowed", bad_prefixes); -+ return -1; -+ } -+ -+ return 0; -+} -+ -+/* -+ * recurse_set_file_label: Recursively label files or folders -+ * -+ * @path : a file or directory -+ * @label : label string -+ * -+ * Returns 0 on success, < 0 on failure -+ */ -+static int recurse_set_file_label(const char *basePath, const char *label) -+{ -+ int ret = 0; -+ __do_closedir DIR *dir = NULL; -+ struct dirent *ptr = NULL; -+ char base[PATH_MAX] = { 0 }; -+ -+ if ((dir = opendir(basePath)) == NULL) { -+ ERROR("Failed to Open dir: %s", basePath); -+ return -1; -+ } -+ -+ ret = lsetfilecon(basePath, label); -+ if (ret != 0) { -+ ERROR("Failed to set file label"); -+ return ret; -+ } -+ -+ while ((ptr = readdir(dir)) != NULL) { -+ if (strcmp(ptr->d_name, ".") == 0 || strcmp(ptr->d_name, "..") == 0) { -+ continue; -+ } else { -+ int nret = snprintf(base, sizeof(base), "%s/%s", basePath, ptr->d_name); -+ if (nret < 0 || nret >= sizeof(base)) { -+ ERROR("Failed to get path"); -+ return -1; -+ } -+ if (ptr->d_type == DT_DIR) { -+ ret = recurse_set_file_label(base, label); -+ if (ret != 0) { -+ ERROR("Failed to set dir label"); -+ return ret; -+ } -+ } else { -+ ret = lsetfilecon(base, label); -+ if (ret != 0) { -+ ERROR("Failed to set file label"); -+ return ret; -+ } -+ } -+ } -+ } -+ -+ return 0; -+} -+ -+/* -+ * selinux_chcon: Chcon changes the `fpath` file object to the SELinux label `label`. -+ * If `fpath` is a directory and `recurse`` is true, Chcon will walk the -+ * directory tree setting the label. -+ * -+ * @fpath : a file or directory -+ * @label : label string -+ * @recurse : whether to recurse -+ * -+ * Returns 0 on success, < 0 on failure -+ */ -+static int selinux_chcon(const char *fpath, const char *label, bool recurse) -+{ -+ struct stat s_buf; -+ -+ if (fpath == NULL || label == NULL) { -+ ERROR("Invalid parameters!"); -+ return -1; -+ } -+ -+ if (bad_prefix(fpath) != 0) { -+ return -1; -+ } -+ if (stat(fpath, &s_buf) != 0) { -+ return -1; -+ } -+ if (recurse && S_ISDIR(s_buf.st_mode)) { -+ return recurse_set_file_label(fpath, label); -+ } -+ -+ if (lsetfilecon(fpath, label) != 0) { -+ ERROR("Failed to set file label"); -+ return -1; -+ } -+ -+ return 0; -+} -+ -+/* -+ * convert_context_to_share_mode: set sensitivity to s0 and remove categories -+ * user:role:type:sensitivity[:categories] => user:role:type:s0 -+ * -+ * @label : label string -+ * -+ * Returns label with share mode on success, NULL on failure -+ */ -+static char *convert_context_to_share_mode(const char *label) { -+ __do_free char *converted_label = strdup(label); -+ char *s = converted_label; -+ const char *shared_level = "s0"; -+ int cnt = 0; -+ -+ // selinux label format: user:role:type:sensitivity[:categories] -+ // locates the ":" position in front of the sensitivity -+ while (cnt++ < 3 && (s = strchr(s, ':')) != NULL) { -+ s++; -+ } -+ -+ // make sure sensitivity can set s0 value -+ if (s == NULL || strlen(s) < strlen(shared_level)) { -+ ERROR("Invalid selinux file context: %s", label); -+ return NULL; -+ } -+ -+ if (strcmp(s, shared_level) == 0) { -+ return move_ptr(converted_label); -+ } -+ -+ *s = '\0'; -+ strcat(converted_label, shared_level); -+ -+ return move_ptr(converted_label); -+} -+ -+/* -+ * selinux_relabel: Relabel changes the label of path to the filelabel string. -+ * It changes the MCS label to s0 if shared is true. -+ * This will allow all containers to share the content. -+ * -+ * @path : a file or directory -+ * @label : label string -+ * @shared : whether to use share mode -+ * -+ * Returns 0 on success, < 0 on failure -+ */ -+static int selinux_relabel(const char *path, const char *label, bool shared) -+{ -+ __do_free char *tmp_file_label = NULL; -+ -+ if (path == NULL || label == NULL) { -+ return 0; -+ } -+ -+ if (!is_selinux_enabled()) { -+ return 0; -+ } -+ -+ if (is_exclude_relabel_path(path)) { -+ ERROR("SELinux relabeling of %s is not allowed", path); -+ return -1; -+ } -+ -+ if (shared) { -+ tmp_file_label = convert_context_to_share_mode(label); -+ if (tmp_file_label == NULL) { -+ ERROR("Failed to convert context to share mode: %s", label); -+ return -1; -+ } -+ } else { -+ tmp_file_label = strdup(label); -+ } -+ -+ -+ if (selinux_chcon(path, tmp_file_label, true) != 0) { -+ ERROR("Failed to modify %s's selinux context: %s", path, tmp_file_label); -+ return -1; -+ } -+ -+ return 0; -+} -+#endif -+ - static struct lsm_ops selinux_ops = { - .name = "SELinux", - .aa_admin = -1, -@@ -183,6 +435,10 @@ static struct lsm_ops selinux_ops = { - .process_label_set = selinux_process_label_set, - .process_label_get_at = selinux_process_label_get_at, - .process_label_set_at = selinux_process_label_set_at, -+#ifdef HAVE_ISULAD -+ .file_label_set = selinux_file_label_set, -+ .relabel = selinux_relabel, -+#endif - }; - - struct lsm_ops *lsm_selinux_ops_init(void) -diff --git a/src/lxc/lxc.h b/src/lxc/lxc.h -index e58fb21..879e899 100644 ---- a/src/lxc/lxc.h -+++ b/src/lxc/lxc.h -@@ -88,6 +88,13 @@ __hidden 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/lxclock.c b/src/lxc/lxclock.c -index acddc13..2c15daf 100644 ---- a/src/lxc/lxclock.c -+++ b/src/lxc/lxclock.c -@@ -310,3 +310,30 @@ void container_disk_unlock(struct lxc_container *c) - lxcunlock(c->slock); - lxcunlock(c->privlock); - } -+ -+#ifdef HAVE_ISULAD -+static int lxc_removelock(struct lxc_lock *l) -+{ -+ int ret = 0; -+ -+ if (l->type == LXC_LOCK_FLOCK) { -+ ret = unlink(l->u.f.fname); -+ if (ret && errno != ENOENT) { -+ SYSERROR("Error unlink %s", l->u.f.fname); -+ return ret; -+ } -+ } -+ -+ return ret; -+} -+ -+int container_disk_removelock(struct lxc_container *c) -+{ -+ int ret; -+ -+ ret = lxc_removelock(c->slock); -+ if (ret) -+ return ret; -+ return lxc_removelock(c->privlock); -+} -+#endif -\ No newline at end of file -diff --git a/src/lxc/lxclock.h b/src/lxc/lxclock.h -index a20d356..987c3e5 100644 ---- a/src/lxc/lxclock.h -+++ b/src/lxc/lxclock.h -@@ -158,4 +158,8 @@ __hidden extern int container_disk_lock(struct lxc_container *c); - */ - __hidden extern void container_disk_unlock(struct lxc_container *c); - -+#ifdef HAVE_ISULAD -+__hidden int container_disk_removelock(struct lxc_container *c); -+#endif -+ - #endif -diff --git a/src/lxc/mainloop.c b/src/lxc/mainloop.c -index a98e21a..765240e 100644 ---- a/src/lxc/mainloop.c -+++ b/src/lxc/mainloop.c -@@ -532,3 +532,19 @@ void lxc_mainloop_close(struct lxc_async_descr *descr) - - INIT_LIST_HEAD(&descr->handlers); - } -+ -+#ifdef HAVE_ISULAD -+int isulad_safe_mainloop(struct lxc_epoll_descr *descr, int timeout_ms) -+{ -+ int ret; -+ -+ ret = lxc_mainloop(descr, timeout_ms); -+ -+ // There are stdout and stderr channels, and two epolls should be performed to prevent -+ // one of the channels from exiting first, causing the other channel to not receive data, -+ // resulting in data loss -+ (void)lxc_mainloop(descr, 100); -+ -+ return ret; -+} -+#endif -diff --git a/src/lxc/mainloop.h b/src/lxc/mainloop.h -index 7d644b7..e8ce082 100644 ---- a/src/lxc/mainloop.h -+++ b/src/lxc/mainloop.h -@@ -65,4 +65,8 @@ __hidden extern void lxc_mainloop_close(struct lxc_async_descr *descr); - - define_cleanup_function(struct lxc_async_descr *, lxc_mainloop_close); - -+#ifdef HAVE_ISULAD -+__hidden extern int isulad_safe_mainloop(struct lxc_epoll_descr *descr, int timeout_ms); -+#endif -+ - #endif -diff --git a/src/lxc/mount_utils.c b/src/lxc/mount_utils.c -index fe8da82..be154af 100644 ---- a/src/lxc/mount_utils.c -+++ b/src/lxc/mount_utils.c -@@ -539,6 +539,11 @@ bool can_use_mount_api(void) - { - static int supported = -1; - -+#ifdef HAVE_ISULAD -+ // isulad just use save_mount() -+ return supported == 1; -+#endif -+ - if (supported == -1) { - __do_close int fd = -EBADF; - -diff --git a/src/lxc/seccomp.c b/src/lxc/seccomp.c -index 5a725f6..f0fa297 100644 ---- a/src/lxc/seccomp.c -+++ b/src/lxc/seccomp.c -@@ -352,8 +352,13 @@ static int get_hostarch(void) - return lxc_seccomp_arch_unknown; - } - -+#ifdef HAVE_ISULAD -+static scmp_filter_ctx get_new_ctx(enum lxc_hostarch_t n_arch, uint32_t default_policy_action, -+ uint32_t *architectures) -+#else - static scmp_filter_ctx get_new_ctx(enum lxc_hostarch_t n_arch, uint32_t default_policy_action, - bool *needs_merge) -+#endif - { - int ret; - uint32_t arch; -@@ -477,9 +482,17 @@ static scmp_filter_ctx get_new_ctx(enum lxc_hostarch_t n_arch, uint32_t default_ - } - TRACE("Removed native arch from main seccomp context"); - -+#ifdef HAVE_ISULAD -+ *architectures = arch; -+#else - *needs_merge = true; -+#endif - } else { -+#ifdef HAVE_ISULAD -+ *architectures = SCMP_ARCH_NATIVE; -+#else - *needs_merge = false; -+#endif - TRACE("Arch %d already present in main seccomp context", (int)n_arch); - } - -@@ -517,8 +530,13 @@ static enum lxc_seccomp_rule_status_t do_resolve_add_rule(uint32_t arch, char *l - SCMP_A1(SCMP_CMP_MASKED_EQ, MNT_FORCE, MNT_FORCE)); - if (ret < 0) { - errno = -ret; -+#ifdef HAVE_ISULAD -+ SYSWARN("Failed loading rule to reject force umount"); -+ return lxc_seccomp_rule_added; -+#else - SYSERROR("Failed loading rule to reject force umount"); - return lxc_seccomp_rule_err; -+#endif - } - - INFO("Set seccomp rule to reject force umounts"); -@@ -544,11 +562,19 @@ static enum lxc_seccomp_rule_status_t do_resolve_add_rule(uint32_t arch, char *l - - memset(&arg_cmp, 0, sizeof(arg_cmp)); - for (size_t i = 0; i < rule->args_num; i++) { -+#ifdef HAVE_ISULAD -+ DEBUG("arg_cmp[%zu]: SCMP_CMP(%u, %llu, %llu, %llu)", i, -+ rule->args_value[i].index, -+ (long long unsigned int)rule->args_value[i].op, -+ (long long unsigned int)rule->args_value[i].mask, -+ (long long unsigned int)rule->args_value[i].value); -+#else - INFO("arg_cmp[%zu]: SCMP_CMP(%u, %llu, %llu, %llu)", i, - rule->args_value[i].index, - (long long unsigned int)rule->args_value[i].op, - (long long unsigned int)rule->args_value[i].mask, - (long long unsigned int)rule->args_value[i].value); -+#endif - - if (SCMP_CMP_MASKED_EQ == rule->args_value[i].op) - arg_cmp[i] = SCMP_CMP(rule->args_value[i].index, -@@ -569,9 +595,15 @@ static enum lxc_seccomp_rule_status_t do_resolve_add_rule(uint32_t arch, char *l - rule->args_num, arg_cmp); - if (ret < 0) { - errno = -ret; -+#ifdef HAVE_ISULAD -+ SYSDEBUG("Failed to add rule for syscall[%d:%s] action[%d:%s] arch[%u]", -+ nr, line, rule->action, get_action_name(rule->action), arch); -+ return lxc_seccomp_rule_added; -+#else - SYSERROR("Failed to add rule for syscall[%d:%s] action[%d:%s] arch[%u]", - nr, line, rule->action, get_action_name(rule->action), arch); - return lxc_seccomp_rule_err; -+#endif - } - - return lxc_seccomp_rule_added; -diff --git a/src/lxc/start.h b/src/lxc/start.h -index cd36bc5..bbd1a83 100644 ---- a/src/lxc/start.h -+++ b/src/lxc/start.h -@@ -123,6 +123,17 @@ struct lxc_handler { - - struct cgroup_ops *cgroup_ops; - -+#ifdef HAVE_ISULAD -+ int exit_code;/* isulad: record the exit code of container */ -+ /* Indicates whether should we using pipes or pty dup to std{in,out,err} for console log. */ -+ bool disable_pty; -+ /* Indicates whether should we keep stdin active. */ -+ bool open_stdin; -+ bool image_type_oci; -+ // isulad need timeout in __lxc_start -+ unsigned int start_timeout; -+#endif -+ - /* Internal fds that always need to stay open. */ - int keep_fds[3]; - -diff --git a/src/lxc/tools/arguments.h b/src/lxc/tools/arguments.h -index 92510ec..d5c9169 100644 ---- a/src/lxc/tools/arguments.h -+++ b/src/lxc/tools/arguments.h -@@ -126,6 +126,20 @@ struct lxc_arguments { - const char *want_hostname; - bool setuid; - -+#ifdef HAVE_ISULAD -+ char *workdir; -+ const char *container_info; /* isulad: file used to store pid and ppid info of container */ -+ char *terminal_fifos[3]; /* isulad add, fifos used to redirct stdin/out/err */ -+ const char *exit_monitor_fifo; /* isulad: fifo used to monitor state of monitor process */ -+ const char *suffix; /* isulad add, suffix used for connect with parent of execed process*/ -+ int disable_pty; -+ int open_stdin; -+ unsigned int start_timeout; /* isulad: Seconds for waiting on a container to start before it is killed*/ -+ int64_t attach_timeout; /* for lxc-attach */ -+ gid_t *add_gids; -+ size_t add_gids_len; -+#endif -+ - /* remaining arguments */ - char *const *argv; - int argc; -@@ -156,6 +170,20 @@ struct lxc_arguments { - #define OPT_SHARE_UTS OPT_USAGE - 5 - #define OPT_SHARE_PID OPT_USAGE - 6 - -+#ifdef HAVE_ISULAD -+#define OPT_INPUT_FIFO OPT_USAGE - 7 -+#define OPT_OUTPUT_FIFO OPT_USAGE - 8 -+#define OPT_STDERR_FIFO OPT_USAGE - 9 -+#define OPT_CONTAINER_INFO OPT_USAGE - 10 -+#define OPT_EXIT_FIFO OPT_USAGE - 11 -+#define OPT_START_TIMEOUT OPT_USAGE - 12 -+#define OPT_DISABLE_PTY OPT_USAGE - 13 -+#define OPT_OPEN_STDIN OPT_USAGE - 14 -+#define OPT_ATTACH_TIMEOUT OPT_USAGE - 15 -+#define OPT_ATTACH_SUFFIX OPT_USAGE - 16 -+#define OPT_ADDITIONAL_GIDS OPT_USAGE - 17 -+#endif -+ - __hidden extern int lxc_arguments_parse(struct lxc_arguments *args, int argc, char *const argv[]); - - __hidden extern int lxc_arguments_str_to_int(struct lxc_arguments *args, const char *str); -diff --git a/src/lxc/tools/lxc_attach.c b/src/lxc/tools/lxc_attach.c -index 8c519f1..1283bcf 100644 ---- a/src/lxc/tools/lxc_attach.c -+++ b/src/lxc/tools/lxc_attach.c -@@ -73,9 +73,22 @@ static const struct option my_longopts[] = { - {"set-var", required_argument, 0, 'v'}, - {"pty-log", required_argument, 0, 'L'}, - {"rcfile", required_argument, 0, 'f'}, -+ {"context", required_argument, 0, 'c'}, -+#ifndef HAVE_ISULAD - {"uid", required_argument, 0, 'u'}, - {"gid", required_argument, 0, 'g'}, -- {"context", required_argument, 0, 'c'}, -+#else -+ {"workdir", required_argument, 0, 'w'}, -+ {"user", required_argument, 0, 'u'}, -+ {"add-gids", required_argument, 0, OPT_ADDITIONAL_GIDS}, -+ {"in-fifo", required_argument, 0, OPT_INPUT_FIFO}, /* isulad add terminal fifos*/ -+ {"out-fifo", required_argument, 0, OPT_OUTPUT_FIFO}, -+ {"err-fifo", required_argument, 0, OPT_STDERR_FIFO}, -+ {"suffix", required_argument, 0, OPT_ATTACH_SUFFIX}, -+ {"timeout", required_argument, 0, OPT_ATTACH_TIMEOUT}, -+ {"disable-pty", no_argument, 0, OPT_DISABLE_PTY}, -+ {"open-stdin", no_argument, 0, OPT_OPEN_STDIN}, -+#endif - LXC_COMMON_OPTIONS - }; - -@@ -126,11 +139,29 @@ Options :\n\ - multiple times.\n\ - -f, --rcfile=FILE\n\ - Load configuration file FILE\n\ -- -u, --uid=UID Execute COMMAND with UID inside the container\n\ -- -g, --gid=GID Execute COMMAND with GID inside the container\n\ - -c, --context=context\n\ - SELinux Context to transition into\n\ --", -+" -+#ifndef HAVE_ISULAD -+"\ -+ -u, --uid=UID Execute COMMAND with UID inside the container\n\ -+ -g, --gid=GID Execute COMMAND with GID inside the container\n\ -+" -+#else -+"\ -+ -w, --workdir Working directory inside the container.\n\ -+ -u, --user User ID (format: UID[:GID])\n\ -+ --add-gids Additional gids (format: GID[,GID])\n\ -+ --in-fifo Stdin fifo path\n\ -+ --out-fifo Stdout fifo path\n\ -+ --err-fifo Stderr fifo path\n\ -+ --suffix ID for mutli-attach on one container\n\ -+ --timeout Timeout in seconds (default: 0)\n\ -+ --disable-pty Disable pty for attach\n\ -+ --open-stdin Open stdin for attach\n\ -+" -+#endif -+, - .options = my_longopts, - .parser = my_parser, - .checker = NULL, -@@ -140,6 +171,123 @@ Options :\n\ - .gid = LXC_INVALID_GID, - }; - -+#ifdef HAVE_ISULAD -+static int parse_user_id(const char *username, char **uid, char **gid, char **tmp_dup) -+{ -+ char *tmp = NULL; -+ char *pdot = NULL; -+ -+ if (uid == NULL || gid == NULL || tmp_dup == NULL) { -+ return -1; -+ } -+ -+ if (username != NULL) { -+ tmp = strdup(username); -+ if (tmp == NULL) { -+ ERROR("Failed to duplicate user name"); -+ return -1; -+ } -+ -+ // for free tmp in caller -+ *tmp_dup = tmp; -+ pdot = strstr(tmp, ":"); -+ if (pdot != NULL) { -+ *pdot = '\0'; -+ if (pdot != tmp) { -+ // uid found -+ *uid = tmp; -+ } -+ -+ if (*(pdot + 1) != '\0') { -+ // gid found -+ *gid = pdot + 1; -+ } -+ } else { -+ // No : found -+ if (*tmp != '\0') { -+ *uid = tmp; -+ } -+ } -+ } ++ if (fp) ++ free(fp); + -+ return 0; ++ return NULL; +} + -+static int get_attach_uid_gid(const char *username, uid_t *user_id, gid_t *group_id) ++void* wait_ocihook_timeout(void *arg) +{ -+ char *tmp = NULL; -+ char *uid = NULL; -+ char *gid = NULL; ++ bool alive = false; ++ struct wait_conf *conf = (struct wait_conf *)arg; + -+ // parse uid and gid by username -+ if (parse_user_id(username, &uid, &gid, &tmp) != 0) { -+ return -1; -+ } ++ if (!conf || conf->timeout < 1) ++ goto out; + -+ if (uid != NULL) { -+ *user_id = (unsigned int)atoll(uid); -+ } -+ if (gid != NULL) { -+ *group_id = (unsigned int)atoll(gid); ++ sleep(conf->timeout); ++ ++ alive = lxc_process_alive(conf->pid, conf->startat); ++ ++ if (alive) { ++ ERROR("%s:%d: running %s hook caused \"hook ran past specified timeout of %.1fs\"", ++ __FILE__, __LINE__, lxchook_names[conf->which], ++ (double)conf->timeout); ++ ++ lxc_write_error_message(conf->errfd, "%s:%d: running %s hook caused \"hook ran past specified timeout of %.1fs\".", ++ __FILE__, __LINE__, lxchook_names[conf->which], ++ (double)conf->timeout); ++ ++ if (kill(conf->pid, SIGKILL) && errno != ESRCH) { ++ ERROR("Send kill signal failed"); ++ goto out; ++ } + } + -+ free(tmp); -+ return 0; ++out: ++ free(conf); ++ return ((void *)0); +} + -+static int get_attach_add_gids(const char *add_gids, gid_t **gids, size_t *gids_len) ++static int run_ocihook_buffer(struct oci_hook_conf *oconf, const char *inmsg) +{ -+ long long int readvalue; -+ size_t i, len; -+ const size_t max_gids = 100; -+ gid_t *g = NULL; -+ __do_free_string_list char **gids_str = NULL; -+ -+ if (add_gids == NULL || strlen(add_gids) == 0) { -+ ERROR("None additional gids"); ++ struct lxc_popen_FILE *f; ++ char output[LXC_LOG_BUFFER_SIZE] = {0}; ++ int ret; ++ pthread_t ptid; ++ int err; ++ struct wait_conf *conf = NULL; ++ pthread_attr_t attr; ++ char *buffer = oconf->ocihook->path; ++ char *err_args_msg = NULL; ++ char *err_envs_msg = NULL; ++ char **hookenvs = NULL; ++ size_t hookenvs_len = 0; ++ ++ hookenvs = merge_ocihook_env(oconf->ocihook->env, oconf->ocihook->env_len, &hookenvs_len); ++ if (!hookenvs) { ++ ERROR("Out of memory."); + return -1; + } + -+ gids_str = lxc_string_split(add_gids, ','); -+ if (gids_str == NULL) { -+ ERROR("Failed to split additional gids"); ++ f = lxc_popen_ocihook(buffer, oconf->ocihook->args, oconf->ocihook->args_len, hookenvs, hookenvs_len, inmsg); ++ lxc_free_array((void **)hookenvs, free); ++ if (!f) { ++ SYSERROR("Failed to popen() %s.", buffer); + return -1; + } + -+ len = lxc_array_len((void **)gids_str); -+ if (len > max_gids) { -+ ERROR("Too many gids"); -+ return -1; ++ conf = malloc(sizeof(struct wait_conf)); ++ if (conf == NULL) { ++ SYSERROR("Failed to malloc."); ++ goto on_error; + } + -+ g = calloc(len, sizeof(gid_t)); -+ if (g == NULL) { -+ ERROR("Out of memory"); -+ return -1; ++ memset(conf, 0x00, sizeof(struct wait_conf)); ++ ++ conf->pid = f->child_pid; ++ conf->startat = lxc_get_process_startat(conf->pid); ++ ++ INFO("hook_conf timeout %d", oconf->ocihook->timeout); ++ if(oconf->ocihook->timeout > 0) ++ conf->timeout = oconf->ocihook->timeout; ++ else { ++ conf->timeout = 30; ++ INFO("Set hook timeout 30s"); + } ++ conf->errfd = oconf->errfd; ++ conf->which = oconf->which; + -+ for (i = 0; i < len; i++) { -+ if (lxc_safe_long_long(gids_str[i], &readvalue) != 0) { -+ SYSERROR("Invalid gid value %s", gids_str[i]); -+ goto err_out; -+ } -+ if (readvalue < 0) { -+ ERROR("Invalid gid value: %lld", readvalue); -+ goto err_out; -+ } -+ g[i] = (unsigned int)readvalue; ++ pthread_attr_init(&attr); ++ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); ++ err = pthread_create(&ptid, &attr, wait_ocihook_timeout, conf); ++ pthread_attr_destroy(&attr); ++ if (err != 0) { ++ ERROR("Create wait timeout thread failed"); ++ free(conf); ++ goto on_error; + } + -+ *gids = g; -+ *gids_len = len; -+ return 0; ++ ret = lxc_wait_for_pid_status(f->child_pid); + -+err_out: -+ free(g); -+ return -1; -+} -+#endif ++ lxc_read_nointr(f->pipe, output, sizeof(output) - 1); ++ close(f->pipe); ++ free(f); + - static int my_parser(struct lxc_arguments *args, int c, char *arg) - { - int ret; -@@ -197,6 +345,10 @@ static int my_parser(struct lxc_arguments *args, int c, char *arg) - case 'f': - args->rcfile = arg; - break; -+ case 'c': -+ selinux_context = arg; -+ break; -+#ifndef HAVE_ISULAD - case 'u': - if (lxc_safe_uint(arg, &args->uid) < 0) - return -1; -@@ -205,9 +357,48 @@ static int my_parser(struct lxc_arguments *args, int c, char *arg) - if (lxc_safe_uint(arg, &args->gid) < 0) - return -1; - break; -- case 'c': -- selinux_context = arg; -- break; -+#else -+ case 'u': -+ if (get_attach_uid_gid(arg, &args->uid, &args->gid) != 0) { -+ ERROR("Failed to get attach user U/GID"); -+ return -1; -+ } -+ break; -+ case 'w': -+ args->workdir=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_ATTACH_SUFFIX: -+ args->suffix = arg; -+ break; -+ case OPT_ATTACH_TIMEOUT: -+ if(!is_non_negative_num(arg)) { -+ ERROR("Error attach timeout parameter:%s.\n", arg); -+ return -1; -+ } -+ args->attach_timeout = (unsigned int)atoll(arg); -+ break; -+ case OPT_DISABLE_PTY: -+ args->disable_pty = 1; -+ break; -+ case OPT_OPEN_STDIN: -+ args->open_stdin = 1; -+ break; -+ case OPT_ADDITIONAL_GIDS: -+ if (get_attach_add_gids(arg, &args->add_gids, &args->add_gids_len) != 0) { -+ ERROR("Failed to get attach additional gids"); -+ return -1; -+ } -+ break; -+#endif - } - - return 0; -@@ -271,6 +462,290 @@ static int lxc_attach_create_log_file(const char *log_file) - return fd; - } - -+#ifdef HAVE_ISULAD -+// isulad: send '128 + signal' if container is killed by signal. -+#define EXIT_SIGNAL_OFFSET 128 ++ if (ret == -1) { ++ SYSERROR("Script exited with error."); ++ goto print_hook; ++ } else if (WIFEXITED(ret) && WEXITSTATUS(ret) != 0) { ++ ERROR("Script exited with status %d. output: %s", WEXITSTATUS(ret), output); ++ lxc_write_error_message(oconf->errfd, "%s:%d: running %s hook caused \"error running hook: exit status %d, output: %s\".", ++ __FILE__, __LINE__, ++ (oconf->which >= NUM_LXC_HOOKS) ? "invalid type" : lxchook_names[oconf->which], ++ WEXITSTATUS(ret), output); + -+/*isulad: attach with terminal*/ -+static int do_attach_foreground(struct lxc_container *c, lxc_attach_command_t *command, -+ lxc_attach_options_t *attach_options, -+ char **errmsg) -+{ -+ int ret = 0; -+ pid_t pid; -+ int wexit = -1; -+ int signal; ++ goto print_hook; ++ } else if (WIFSIGNALED(ret)) { ++ ERROR("Script terminated by signal %d.", WTERMSIG(ret)); ++ lxc_write_error_message(oconf->errfd, "%s:%d: running %s hook caused \"error running hook: Script terminated by signal %d\".", ++ __FILE__, __LINE__, ++ (oconf->which >= NUM_LXC_HOOKS) ? "invalid type" : lxchook_names[oconf->which], ++ WTERMSIG(ret)); + -+ if (command->program) -+ ret = c->attach(c, lxc_attach_run_command, command, attach_options, &pid); -+ else -+ ret = c->attach(c, lxc_attach_run_shell, NULL, attach_options, &pid); -+ if (ret < 0) { -+ *errmsg = safe_strdup("Internal error, failed to call attach"); -+ goto out; ++ goto print_hook; + } + -+ ret = lxc_wait_for_pid_status(pid); -+ if (ret < 0) { -+ free(*errmsg); -+ *errmsg = safe_strdup("Internal error, failed to wait attached process"); -+ goto out; ++ return 0; ++ ++on_error: ++ if (f) { ++ if (f->pipe >= 0) ++ close(f->pipe); ++ free(f); + } + -+ if (WIFEXITED(ret)) -+ wexit = WEXITSTATUS(ret); -+ else -+ wexit = -1; ++print_hook: ++ if (oconf->ocihook->args) ++ err_args_msg = lxc_string_join(" ", (const char **)oconf->ocihook->args, false); ++ if (oconf->ocihook->env) ++ err_envs_msg = lxc_string_join(" ", (const char **)oconf->ocihook->env, false); ++ ERROR("Hook script command: \"%s\", args: \"%s\", envs: \"%s\", timeout: %d.", ++ buffer, err_args_msg ? err_args_msg : "", ++ err_envs_msg ? err_envs_msg : "", oconf->ocihook->timeout); + -+ if (WIFSIGNALED(ret)) { -+ signal = WTERMSIG(ret); -+ wexit = EXIT_SIGNAL_OFFSET + signal; -+ } ++ free(err_args_msg); ++ free(err_envs_msg); ++ return -1; ++} ++ ++static int run_ocihook_script_argv(const char *name, const char *section, ++ struct oci_hook_conf *oconf, ++ const char *lxcpath, const char *rootfs) ++{ ++ int ret; ++ const char *script = oconf->ocihook->path; ++ char *inmsg = NULL; + -+ WARN("Execd pid %d exit with %d", pid, wexit); ++ INFO("Executing script \"%s\" for container \"%s\", config section \"%s\".", ++ script, name, section); + -+out: -+ if (c->lxc_conf->errmsg) { -+ free(*errmsg); -+ *errmsg = safe_strdup(c->lxc_conf->errmsg); ++ inmsg = generate_json_str(name, lxcpath, rootfs); ++ if (!inmsg) { ++ return -1; + } -+ return wexit; ++ ++ ret = run_ocihook_buffer(oconf, inmsg); ++ free(inmsg); ++ inmsg = NULL; ++ return ret; +} + -+static void close_msg_pipe(int *errpipe) ++static char *get_root_path(const char *path, const char *backend) +{ -+ if (errpipe[0] >= 0) { -+ close(errpipe[0]); -+ errpipe[0] = -1; ++ char *ret = NULL; ++ char *tmp = NULL; ++ ++ if (!path) { ++ ret = safe_strdup("/"); ++ return ret; + } -+ if (errpipe[1] >= 0) { -+ close(errpipe[1]); -+ errpipe[1] = -1; ++ if (!backend) { ++ goto default_out; ++ } ++ ++ if (strcmp(backend, "aufs") == 0 || ++ strcmp(backend, "overlayfs") == 0 || ++ strcmp(backend, "loop") == 0) { ++ tmp = strrchr(path, ':'); ++ if (tmp == NULL) { ++ ERROR("Invalid root path format"); ++ return NULL; ++ } ++ tmp++; ++ ret = safe_strdup(tmp); ++ return ret; + } ++ ++default_out: ++ ret = safe_strdup(path); ++ return ret; +} + -+/*isulad: attach without terminal in background */ -+static int do_attach_background(struct lxc_container *c, lxc_attach_command_t *command, -+ lxc_attach_options_t *attach_options, -+ char **errmsg) ++static int do_run_oci_hooks(const char *name, const char *lxcpath, struct lxc_conf *lc, int which, int errfd) +{ ++ struct oci_hook_conf work_conf = {0}; ++ size_t i; + int ret = 0; -+ int msgpipe[2]; -+ pid_t pid = 0; -+ ssize_t size_read; -+ char msgbuf[BUFSIZ + 1] = {0}; -+ -+ //pipdfd for get error message of child or grandchild process. -+ if (pipe2(msgpipe, O_CLOEXEC) != 0) { -+ SYSERROR("Failed to init msgpipe"); ++ int nret = 0; ++ char *rootpath = NULL; ++ ++ if (!lc) { + return -1; + } ++ if (!lc->ocihooks) { ++ return 0; ++ } + -+ pid = fork(); -+ if (pid < 0) { -+ close_msg_pipe(msgpipe); ++ rootpath = get_root_path(lc->rootfs.path ? lc->rootfs.mount : NULL, lc->rootfs.bdev_type); ++ if (!rootpath) { ++ ERROR("Get container %s rootpath failed.", name); + return -1; + } + -+ if (pid != 0) { -+ close(msgpipe[1]); -+ msgpipe[1] = -1; -+ size_read = read(msgpipe[0], msgbuf, BUFSIZ); -+ if (size_read > 0) { -+ *errmsg = safe_strdup(msgbuf); -+ ret = -1; ++ work_conf.errfd = errfd; ++ work_conf.which = which; ++ switch (which) { ++ case OCI_HOOK_PRESTART: ++ for (i = 0; i < lc->ocihooks->prestart_len; i++) { ++ work_conf.ocihook = lc->ocihooks->prestart[i]; ++ ret = run_ocihook_script_argv(name, "lxc", &work_conf, lxcpath, rootpath); ++ if (ret != 0) ++ break; ++ } ++ break; ++ case OCI_HOOK_POSTSTART: ++ for (i = 0; i < lc->ocihooks->poststart_len; i++) { ++ work_conf.ocihook = lc->ocihooks->poststart[i]; ++ nret = run_ocihook_script_argv(name, "lxc", &work_conf, lxcpath, rootpath); ++ if (nret != 0) ++ WARN("running poststart hook %zu failed, ContainerId: %s", i, name); ++ } ++ break; ++ case OCI_HOOK_POSTSTOP: ++ for (i = 0; i < lc->ocihooks->poststop_len; i++) { ++ work_conf.ocihook = lc->ocihooks->poststop[i]; ++ nret = run_ocihook_script_argv(name, "lxc", &work_conf, lxcpath, rootpath); ++ if (nret != 0) ++ WARN("running poststart hook %zu failed, ContainerId: %s", i, name); + } -+ -+ close(msgpipe[0]); -+ msgpipe[0] = -1; -+ -+ return ret; -+ } -+ -+ /* second fork to be reparented by init */ -+ pid = fork(); -+ if (pid < 0) { -+ SYSERROR("Error doing dual-fork"); -+ close_msg_pipe(msgpipe); -+ exit(1); -+ } -+ if (pid != 0) { -+ close_msg_pipe(msgpipe); -+ exit(0); -+ } -+ -+ close(msgpipe[0]); -+ msgpipe[0] = -1; -+ -+ if (null_stdfds() < 0) { -+ ERROR("failed to close fds"); -+ exit(1); -+ } -+ setsid(); -+ -+ if (command->program) -+ ret = c->attach(c, lxc_attach_run_command, command, attach_options, &pid); -+ else -+ ret = c->attach(c, lxc_attach_run_shell, NULL, attach_options, &pid); -+ if (ret < 0) { -+ if (c->lxc_conf->errmsg) -+ lxc_write_error_message(msgpipe[1], "%s", c->lxc_conf->errmsg); -+ else -+ lxc_write_error_message(msgpipe[1], "Failed to attach container"); -+ close(msgpipe[1]); -+ msgpipe[1] = -1; ++ break; ++ default: + ret = -1; -+ goto out; + } -+ -+ close(msgpipe[1]); -+ msgpipe[1] = -1; -+ -+ ret = wait_for_pid(pid); -+out: -+ lxc_container_put(c); -+ if (ret) -+ exit(EXIT_FAILURE); -+ else -+ exit(0); ++ if (rootpath) ++ free(rootpath); ++ return ret; +} + -+int main(int argc, char *argv[]) ++int run_oci_hooks(const char *name, const char *hookname, struct lxc_conf *conf, const char *lxcpath) +{ -+ int wexit = 0; -+ struct lxc_log log; -+ char *errmsg = NULL; -+ lxc_attach_options_t attach_options = LXC_ATTACH_OPTIONS_DEFAULT; -+ lxc_attach_command_t command = (lxc_attach_command_t){.program = NULL}; -+ -+ if (lxc_caps_init()) -+ exit(EXIT_FAILURE); -+ -+ if (lxc_arguments_parse(&my_args, argc, argv)) -+ exit(EXIT_FAILURE); -+ -+ log.name = my_args.name; -+ log.file = my_args.log_file; -+ log.level = my_args.log_priority; -+ log.prefix = my_args.progname; -+ log.quiet = my_args.quiet; -+ log.lxcpath = my_args.lxcpath[0]; -+ -+ if (lxc_log_init(&log)) -+ exit(EXIT_FAILURE); -+ -+ if (geteuid()) -+ if (access(my_args.lxcpath[0], O_RDONLY) < 0) { -+ ERROR("You lack access to %s", my_args.lxcpath[0]); -+ exit(EXIT_FAILURE); -+ } -+ -+ struct lxc_container *c = lxc_container_new(my_args.name, my_args.lxcpath[0]); -+ if (!c) -+ exit(EXIT_FAILURE); ++ int which = -1; + -+ if (my_args.rcfile) { -+ c->clear_config(c); -+ if (!c->load_config(c, my_args.rcfile)) { -+ ERROR("Failed to load rcfile"); -+ lxc_container_put(c); -+ exit(EXIT_FAILURE); ++ if (strcmp(hookname, "oci-prestart") == 0) { ++ which = OCI_HOOK_PRESTART; ++ if (!lxcpath) { ++ ERROR("oci hook require lxcpath"); ++ return -1; + } -+ -+ c->configfile = strdup(my_args.rcfile); -+ if (!c->configfile) { -+ ERROR("Out of memory setting new config filename"); -+ lxc_container_put(c); -+ exit(EXIT_FAILURE); ++ return do_run_oci_hooks(name, lxcpath, conf, which, conf->errpipe[1]); ++ } else if (strcmp(hookname, "oci-poststart") == 0) { ++ which = OCI_HOOK_POSTSTART; ++ if (!lxcpath) { ++ ERROR("oci hook require lxcpath"); ++ return -1; + } -+ } -+ -+ if (!c->may_control(c)) { -+ ERROR("Insufficent privileges to control %s", c->name); -+ lxc_container_put(c); -+ exit(EXIT_FAILURE); -+ } ++ return do_run_oci_hooks(name, lxcpath, conf, which, conf->errpipe[1]); ++ } else if (strcmp(hookname, "oci-poststop") == 0) { ++ which = OCI_HOOK_POSTSTOP; ++ if (!lxcpath) { ++ ERROR("oci hook require lxcpath"); ++ return -1; ++ } ++ return do_run_oci_hooks(name, lxcpath, conf, which, conf->errpipe[1]); ++ } else ++ return -1; + -+ if (remount_sys_proc) -+ attach_options.attach_flags |= LXC_ATTACH_REMOUNT_PROC_SYS; ++ return 0; ++} + -+ if (elevated_privileges) -+ attach_options.attach_flags &= ~(elevated_privileges); ++/*isulad clear init args*/ ++int lxc_clear_init_args(struct lxc_conf *lxc_conf) ++{ ++ int i; + -+ if (my_args.terminal_fifos[0] || my_args.terminal_fifos[1] || my_args.terminal_fifos[2]) { -+ attach_options.init_fifo[0] = my_args.terminal_fifos[0]; -+ attach_options.init_fifo[1] = my_args.terminal_fifos[1]; -+ attach_options.init_fifo[2] = my_args.terminal_fifos[2]; -+ attach_options.attach_flags |= LXC_ATTACH_TERMINAL; -+ } else if (stdfd_is_pty()) { -+ attach_options.attach_flags |= LXC_ATTACH_TERMINAL; ++ for (i = 0; i < lxc_conf->init_argc; i++) { ++ free(lxc_conf->init_argv[i]); ++ lxc_conf->init_argv[i] = NULL; + } ++ free(lxc_conf->init_argv); ++ lxc_conf->init_argv = NULL; ++ lxc_conf->init_argc = 0; + -+ attach_options.namespaces = namespace_flags; -+ attach_options.personality = new_personality; -+ attach_options.env_policy = env_policy; -+ attach_options.extra_env_vars = extra_env; -+ attach_options.extra_keep_env = extra_keep; -+ attach_options.timeout = my_args.attach_timeout; ++ return 0; ++} + -+ if (my_args.argc > 0) { -+ command.program = my_args.argv[0]; -+ command.argv = (char**)my_args.argv; -+ } ++/*isulad clear init groups*/ ++int lxc_clear_init_groups(struct lxc_conf *lxc_conf) ++{ ++ free(lxc_conf->init_groups); ++ lxc_conf->init_groups = NULL; ++ lxc_conf->init_groups_len = 0; + -+ if (my_args.console_log) { -+ attach_options.log_fd = lxc_attach_create_log_file(my_args.console_log); -+ if (attach_options.log_fd < 0) { -+ ERROR("Failed to create log file for %s", c->name); -+ lxc_container_put(c); -+ exit(EXIT_FAILURE); -+ } -+ } ++ return 0; ++} + -+ if (my_args.uid != LXC_INVALID_UID) -+ attach_options.uid = my_args.uid; ++/*isulad: clear populate devices*/ ++int lxc_clear_populate_devices(struct lxc_conf *c) ++{ ++ struct lxc_list *it = NULL; ++ struct lxc_list *next = NULL; + -+ if (my_args.gid != LXC_INVALID_GID) -+ attach_options.gid = my_args.gid; ++ lxc_list_for_each_safe(it, &c->populate_devs, next) { ++ struct lxc_populate_devs *dev_elem = it->elem; ++ lxc_list_del(it); ++ free(dev_elem->name); ++ free(dev_elem->type); ++ free(dev_elem); ++ free(it); ++ } ++ return 0; ++} + -+ attach_options.suffix = my_args.suffix; ++/*isulad: clear rootfs masked paths*/ ++int lxc_clear_rootfs_masked_paths(struct lxc_conf *c) ++{ ++ struct lxc_list *it = NULL; ++ struct lxc_list *next = NULL; + -+ if (my_args.disable_pty) { -+ attach_options.disable_pty = true; ++ lxc_list_for_each_safe(it, &c->rootfs.maskedpaths, next) { ++ lxc_list_del(it); ++ free(it->elem); ++ free(it); + } ++ return 0; ++} + -+ if (my_args.open_stdin) { -+ attach_options.open_stdin = true; -+ } ++/*isulad: clear rootfs ro paths*/ ++int lxc_clear_rootfs_ro_paths(struct lxc_conf *c) ++{ ++ struct lxc_list *it = NULL; ++ struct lxc_list *next = NULL; + -+ if (my_args.workdir) { -+ attach_options.initial_cwd = my_args.workdir; ++ lxc_list_for_each_safe(it, &c->rootfs.ropaths, next) { ++ lxc_list_del(it); ++ free(it->elem); ++ free(it); + } ++ return 0; ++} + -+ if (my_args.add_gids) { -+ attach_options.add_gids = my_args.add_gids; -+ attach_options.add_gids_len = my_args.add_gids_len; ++/*isulad: close error pipe */ ++void lxc_close_error_pipe(int *errpipe) ++{ ++ if (errpipe[0] >= 0) { ++ close(errpipe[0]); ++ errpipe[0] = -1; + } -+ -+ /* isulad: add do attach background */ -+ if (attach_options.attach_flags & LXC_ATTACH_TERMINAL) -+ wexit = do_attach_foreground(c, &command, &attach_options, &errmsg); -+ else -+ wexit = do_attach_background(c, &command, &attach_options, &errmsg); -+ -+ if (errmsg) { -+ fprintf(stderr, "%s:%s:%s:%d starting container process caused \"%s\"", c->name, -+ __FILE__, __func__, __LINE__, errmsg); -+ free(errmsg); ++ if (errpipe[1] >= 0) { ++ close(errpipe[1]); ++ errpipe[1] = -1; + } -+ -+ lxc_container_put(c); -+ if (wexit >= 0) -+ exit(wexit); -+ -+ exit(EXIT_FAILURE); +} -+#else - int main(int argc, char *argv[]) - { - int ret = -1; -@@ -408,3 +883,4 @@ out: ++#endif +diff --git a/src/lxc/criu.c b/src/lxc/criu.c +index 19f2a17..58d2351 100644 +--- a/src/lxc/criu.c ++++ b/src/lxc/criu.c +@@ -310,7 +310,6 @@ static void exec_criu(struct cgroup_ops *cgroup_ops, struct lxc_conf *conf, + } + } else { + const char *p; +- + p = cgroup_ops->get_limiting_cgroup(cgroup_ops, controllers[0]); + if (!p) { + ERROR("failed to get cgroup path for %s", controllers[0]); +@@ -371,8 +370,15 @@ static void exec_criu(struct cgroup_ops *cgroup_ops, struct lxc_conf *conf, + char *mntdata = NULL; + char arg[2 * PATH_MAX + 2]; - exit(EXIT_FAILURE); - } ++#ifdef HAVE_ISULAD ++ unsigned long pflags; ++ ++ if (parse_mntopts(mntent.mnt_opts, &flags, &pflags, &mntdata) < 0) ++ goto err; ++#else + if (parse_mntopts(mntent.mnt_opts, &flags, &mntdata) < 0) + goto err; +#endif -\ No newline at end of file -diff --git a/src/lxc/tools/lxc_start.c b/src/lxc/tools/lxc_start.c -index 6d2c0ae..d30d8b8 100644 ---- a/src/lxc/tools/lxc_start.c -+++ b/src/lxc/tools/lxc_start.c -@@ -26,6 +26,11 @@ - #include "confile.h" - #include "log.h" + + free(mntdata); + +diff --git a/src/lxc/execute.c b/src/lxc/execute.c +index 7175ef2..1431b81 100644 +--- a/src/lxc/execute.c ++++ b/src/lxc/execute.c +@@ -19,7 +19,11 @@ + + lxc_log_define(execute, start); +#ifdef HAVE_ISULAD -+#include -+#include "isulad_utils.h" ++static int execute_start(struct lxc_handler *handler, void* data, int fd) ++#else + static int execute_start(struct lxc_handler *handler, void* data) +#endif -+ - lxc_log_define(lxc_start, lxc); + { + int argc_add, j; + char **argv; +@@ -71,6 +75,9 @@ static int execute_start(struct lxc_handler *handler, void* data) + execvp(argv[0], argv); + SYSERROR("Failed to exec %s", argv[0]); - static int my_parser(struct lxc_arguments *args, int c, char *arg); -@@ -46,6 +51,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}, ++ lxc_write_error_message(fd, "Failed to exec: \"%s\": %s.", argv[0], strerror(errno)); +#endif - LXC_COMMON_OPTIONS + free(argv); + out1: + return 1; +@@ -88,14 +95,26 @@ static struct lxc_operations execute_start_ops = { + .post_start = execute_post_start }; -@@ -68,7 +83,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\ -+" ++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 + int lxc_execute(const char *name, char *const argv[], int quiet, + struct lxc_handler *handler, const char *lxcpath, + bool daemonize, int *error_num) +#endif -+, - .options = my_longopts, - .parser = my_parser, - .checker = NULL, -@@ -116,6 +144,36 @@ static int my_parser(struct lxc_arguments *args, int c, char *arg) - case OPT_SHARE_PID: - args->share_ns[LXC_NS_PID] = arg; - break; + { ++ + struct execute_args args = {.argv = argv, .quiet = quiet}; + + TRACE("Doing lxc_execute"); + handler->conf->is_execute = true; +#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; ++ return __lxc_start(handler, &execute_start_ops, &args, lxcpath, ++ daemonize, error_num, start_timeout); ++#else + return __lxc_start(handler, &execute_start_ops, &args, lxcpath, + daemonize, error_num); +#endif - } - return 0; } -@@ -161,6 +219,9 @@ int main(int argc, char *argv[]) - "/sbin/init", - NULL, - }; -+#ifdef HAVE_ISULAD -+ char *container_info_file = NULL; -+#endif - - lxc_list_init(&defines); - -@@ -281,6 +342,42 @@ int main(int argc, char *argv[]) - goto out; - } +diff --git a/src/lxc/file_utils.c b/src/lxc/file_utils.c +index 1689cba..681207b 100644 +--- a/src/lxc/file_utils.c ++++ b/src/lxc/file_utils.c +@@ -122,6 +122,33 @@ int lxc_read_from_file(const char *filename, void *buf, size_t count) + return ret; + } +#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; -+ } -+ } ++ssize_t lxc_write_nointr_for_fifo(int fd, const char *buf, size_t count) ++{ ++ ssize_t nret = 0; ++ ssize_t nwritten; + -+ 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]); -+ } ++ if (buf == NULL) { ++ return -1; ++ } + -+ /* 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); -+ } ++ for (nwritten = 0; nwritten < count;) { ++ nret = write(fd, buf + nwritten, count - nwritten); ++ if (nret < 0) { ++ if (errno == EINTR || errno == EAGAIN) { ++ continue; ++ } else { ++ return nret; ++ } ++ } else { ++ nwritten += nret; ++ } ++ } + -+ if (my_args.disable_pty) { -+ c->want_disable_pty(c, true); -+ } ++ return nwritten; ++} ++#endif + -+ if (my_args.open_stdin) { -+ c->want_open_stdin(c, true); -+ } + ssize_t lxc_write_nointr(int fd, const void *buf, size_t count) + { + ssize_t ret; +diff --git a/src/lxc/lsm/apparmor.c b/src/lxc/lsm/apparmor.c +index 02f824f..96c6728 100644 +--- a/src/lxc/lsm/apparmor.c ++++ b/src/lxc/lsm/apparmor.c +@@ -1186,6 +1186,16 @@ static int apparmor_process_label_set(const char *inlabel, struct lxc_conf *conf + return 0; + } + ++#ifdef HAVE_ISULAD ++static int apparmor_file_label_set(const char *path, const char *label) { ++ return 0; ++} + -+ /* isulad: add start timeout */ -+ if(my_args.start_timeout) { -+ c->set_start_timeout(c, my_args.start_timeout); -+ } ++static int apparmor_relabel(const char *path, const char *label, bool shared) { ++ return 0; ++} +#endif + - if (my_args.console) - if (!c->set_config_item(c, "lxc.console.path", my_args.console)) - goto out; -@@ -303,6 +400,11 @@ int main(int argc, char *argv[]) - else - err = c->start(c, 0, args) ? EXIT_SUCCESS : EXIT_FAILURE; - if (err) { + static struct lsm_drv apparmor_drv = { + .name = "AppArmor", + .enabled = apparmor_enabled, +@@ -1193,6 +1203,10 @@ static struct lsm_drv apparmor_drv = { + .process_label_set = apparmor_process_label_set, + .prepare = apparmor_prepare, + .cleanup = apparmor_cleanup, ++#ifdef HAVE_ISULAD ++ .file_label_set = apparmor_file_label_set, ++ .relabel = apparmor_relabel, ++#endif + }; + + struct lsm_drv *lsm_apparmor_drv_init(void) +diff --git a/src/lxc/tools/arguments.h b/src/lxc/tools/arguments.h +index cb0ba74..c16d99f 100644 +--- a/src/lxc/tools/arguments.h ++++ b/src/lxc/tools/arguments.h +@@ -40,6 +40,17 @@ struct lxc_arguments { + + /* for lxc-start */ + const char *share_ns[32]; /* size must be greater than LXC_NS_MAX */ +#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); ++ char *workdir; ++ const char *container_info; /* isulad: file used to store pid and ppid info of container */ ++ char *terminal_fifos[3]; /* isulad add, fifos used to redirct stdin/out/err */ ++ const char *exit_monitor_fifo; /* isulad: fifo used to monitor state of monitor process */ ++ const char *suffix; /* isulad add, suffix used for connect with parent of execed process*/ ++ int disable_pty; ++ int open_stdin; ++ unsigned int start_timeout; /* isulad: Seconds for waiting on a container to start before it is killed*/ ++ int64_t attach_timeout; /* for lxc-attach */ +#endif - ERROR("The container failed to start"); - if (my_args.daemonize) -@@ -318,5 +420,8 @@ int main(int argc, char *argv[]) + /* for lxc-console */ + unsigned int ttynum; +@@ -152,6 +163,19 @@ struct lxc_arguments { + #define OPT_SHARE_UTS OPT_USAGE - 5 + #define OPT_SHARE_PID OPT_USAGE - 6 - out: - lxc_container_put(c); +#ifdef HAVE_ISULAD -+ free(container_info_file); ++#define OPT_INPUT_FIFO OPT_USAGE - 7 ++#define OPT_OUTPUT_FIFO OPT_USAGE - 8 ++#define OPT_STDERR_FIFO OPT_USAGE - 9 ++#define OPT_CONTAINER_INFO OPT_USAGE - 10 ++#define OPT_EXIT_FIFO OPT_USAGE - 11 ++#define OPT_START_TIMEOUT OPT_USAGE - 12 ++#define OPT_DISABLE_PTY OPT_USAGE - 13 ++#define OPT_OPEN_STDIN OPT_USAGE - 14 ++#define OPT_ATTACH_TIMEOUT OPT_USAGE - 15 ++#define OPT_ATTACH_SUFFIX OPT_USAGE - 16 +#endif - exit(err); - } ++ + extern int lxc_arguments_parse(struct lxc_arguments *args, int argc, + char *const argv[]); + -- 2.25.1 diff --git a/0003-iSulad-adapt-conf-network-storage-and-termianl.patch b/0003-iSulad-adapt-conf-network-storage-and-termianl.patch deleted file mode 100644 index 0c7322d0fd9d1718fb779e29e6e130b7c8443419..0000000000000000000000000000000000000000 --- a/0003-iSulad-adapt-conf-network-storage-and-termianl.patch +++ /dev/null @@ -1,1901 +0,0 @@ -From 0015fbf989f5f1837f9588f8385b16dd38dbd29f Mon Sep 17 00:00:00 2001 -From: haozi007 -Date: Fri, 21 Jul 2023 17:35:52 +0800 -Subject: [PATCH 3/3] [iSulad] adapt conf network storage and termianl - -Signed-off-by: haozi007 ---- - 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 -@@ -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/. */ - 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 - -@@ -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 - diff --git a/0003-refactor-patch-code-of-isulad-for-selinux-attach.patch b/0003-refactor-patch-code-of-isulad-for-selinux-attach.patch new file mode 100644 index 0000000000000000000000000000000000000000..c7e81d3b3785ced80900ba2700ececb6ec2c4e46 --- /dev/null +++ b/0003-refactor-patch-code-of-isulad-for-selinux-attach.patch @@ -0,0 +1,1243 @@ +From 44dd71a4d76eb464b81890ea3cfa2ac9c6c3d990 Mon Sep 17 00:00:00 2001 +From: haozi007 +Date: Tue, 19 Jul 2022 14:40:59 +0800 +Subject: [PATCH] refactor patch code of isulad for selinux/attach + +Signed-off-by: haozi007 +--- + src/lxc/exec_commands.c | 471 +++++++++++++++++++++++++++++++++++++ + src/lxc/lsm/selinux.c | 258 ++++++++++++++++++++ + src/lxc/tools/lxc_attach.c | 413 +++++++++++++++++++++++++++++++- + 3 files changed, 1141 insertions(+), 1 deletion(-) + create mode 100644 src/lxc/exec_commands.c + +diff --git a/src/lxc/exec_commands.c b/src/lxc/exec_commands.c +new file mode 100644 +index 0000000..50246fa +--- /dev/null ++++ b/src/lxc/exec_commands.c +@@ -0,0 +1,471 @@ ++/****************************************************************************** ++ * Copyright (c) Huawei Technologies Co., Ltd. 2019. All rights reserved. ++ * Author: lifeng ++ * Create: 2019-12-08 ++ * Description: provide container definition ++ * lxc: linux Container library ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2.1 of the License, or (at your option) any later version. ++ * ++ * This library is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with this library; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ++ ******************************************************************************/ ++ ++#ifndef _GNU_SOURCE ++#define _GNU_SOURCE 1 ++#endif ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "af_unix.h" ++#include "cgroup.h" ++#include "exec_commands.h" ++#include "commands_utils.h" ++#include "conf.h" ++#include "config.h" ++#include "confile.h" ++#include "log.h" ++#include "lxc.h" ++#include "lxclock.h" ++#include "mainloop.h" ++#include "monitor.h" ++#include "terminal.h" ++#include "utils.h" ++ ++lxc_log_define(commands_exec, lxc); ++ ++static const char *lxc_exec_cmd_str(lxc_exec_cmd_t cmd) ++{ ++ static const char *const cmdname[LXC_EXEC_CMD_MAX] = { ++ [LXC_EXEC_CMD_SET_TERMINAL_WINCH] = "set_exec_terminal_winch", ++ }; ++ ++ if (cmd >= LXC_EXEC_CMD_MAX) ++ return "Invalid request"; ++ ++ return cmdname[cmd]; ++} ++ ++static int lxc_exec_cmd_rsp_recv(int sock, struct lxc_exec_cmd_rr *cmd) ++{ ++ int ret, rspfd; ++ struct lxc_exec_cmd_rsp *rsp = &cmd->rsp; ++ ++ ret = lxc_abstract_unix_recv_fds_timeout(sock, &rspfd, 1, rsp, sizeof(*rsp), 1000 * 1000); ++ if (ret < 0) { ++ SYSERROR("Failed to receive response for command \"%s\"", ++ lxc_exec_cmd_str(cmd->req.cmd)); ++ ++ if (errno == ECONNRESET || errno == EAGAIN || errno == EWOULDBLOCK) { ++ errno = ECONNRESET; /*isulad set errno ECONNRESET when timeout */ ++ return -1; ++ } ++ ++ return -1; ++ } ++ TRACE("Command \"%s\" received response", lxc_exec_cmd_str(cmd->req.cmd)); ++ ++ if (rsp->datalen == 0) { ++ DEBUG("Response data length for command \"%s\" is 0", ++ lxc_exec_cmd_str(cmd->req.cmd)); ++ return ret; ++ } ++ ++ if (rsp->datalen > LXC_CMD_DATA_MAX) { ++ ERROR("Response data for command \"%s\" is too long: %d bytes > %d", ++ lxc_exec_cmd_str(cmd->req.cmd), rsp->datalen, LXC_CMD_DATA_MAX); ++ return -1; ++ } ++ ++ rsp->data = malloc(rsp->datalen); ++ if (!rsp->data) { ++ errno = ENOMEM; ++ ERROR("Failed to allocate response buffer for command \"%s\"", ++ lxc_exec_cmd_str(cmd->req.cmd)); ++ return -1; ++ } ++ ++ ret = lxc_recv_nointr(sock, rsp->data, rsp->datalen, 0); ++ if (ret != rsp->datalen) { ++ SYSERROR("Failed to receive response data for command \"%s\"", ++ lxc_exec_cmd_str(cmd->req.cmd)); ++ return -1; ++ } ++ ++ return ret; ++} ++ ++static int lxc_exec_cmd_rsp_send(int fd, struct lxc_exec_cmd_rsp *rsp) ++{ ++ ssize_t ret; ++ ++ errno = EMSGSIZE; ++ ret = lxc_send_nointr(fd, rsp, sizeof(*rsp), MSG_NOSIGNAL); ++ if (ret < 0 || (size_t)ret != sizeof(*rsp)) { ++ SYSERROR("Failed to send command response %zd", ret); ++ return -1; ++ } ++ ++ if (!rsp->data || rsp->datalen <= 0) ++ return 0; ++ ++ errno = EMSGSIZE; ++ ret = lxc_send_nointr(fd, rsp->data, rsp->datalen, MSG_NOSIGNAL); ++ if (ret < 0 || ret != (ssize_t)rsp->datalen) { ++ SYSWARN("Failed to send command response data %zd", ret); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++static int lxc_exec_cmd_send(const char *name, struct lxc_exec_cmd_rr *cmd, ++ const char *lxcpath, const char *hashed_sock_name, const char *suffix) ++{ ++ int client_fd, saved_errno; ++ ssize_t ret = -1; ++ ++ client_fd = lxc_cmd_connect(name, lxcpath, hashed_sock_name, suffix); ++ if (client_fd < 0) ++ return -1; ++ ++ ret = lxc_abstract_unix_send_credential(client_fd, &cmd->req, ++ sizeof(cmd->req)); ++ if (ret < 0 || (size_t)ret != sizeof(cmd->req)) ++ goto on_error; ++ ++ if (cmd->req.datalen <= 0) ++ return client_fd; ++ ++ errno = EMSGSIZE; ++ ret = lxc_send_nointr(client_fd, (void *)cmd->req.data, ++ cmd->req.datalen, MSG_NOSIGNAL); ++ if (ret < 0 || ret != (ssize_t)cmd->req.datalen) ++ goto on_error; ++ ++ return client_fd; ++ ++on_error: ++ saved_errno = errno; ++ close(client_fd); ++ errno = saved_errno; ++ ++ return -1; ++} ++ ++static int lxc_exec_cmd(const char *name, struct lxc_exec_cmd_rr *cmd, const char *lxcpath, const char *hashed_sock_name, const char *suffix) ++{ ++ int client_fd = -1; ++ int saved_errno; ++ int ret = -1; ++ ++ client_fd = lxc_exec_cmd_send(name, cmd, lxcpath, hashed_sock_name, suffix); ++ if (client_fd < 0) { ++ SYSTRACE("Command \"%s\" failed to connect command socket", ++ lxc_exec_cmd_str(cmd->req.cmd)); ++ return -1; ++ } ++ ++ ret = lxc_exec_cmd_rsp_recv(client_fd, cmd); ++ ++ saved_errno = errno; ++ close(client_fd); ++ errno = saved_errno; ++ return ret; ++} ++ ++int lxc_exec_cmd_set_terminal_winch(const char *name, const char *lxcpath, const char *suffix, unsigned int height, unsigned int width) ++{ ++ int ret = 0; ++ struct lxc_exec_cmd_set_terminal_winch_request data = { 0 }; ++ ++ data.height = height; ++ data.width = width; ++ ++ struct lxc_exec_cmd_rr cmd = { ++ .req = { ++ .cmd = LXC_EXEC_CMD_SET_TERMINAL_WINCH, ++ .datalen = sizeof(struct lxc_exec_cmd_set_terminal_winch_request), ++ .data = &data, ++ }, ++ }; ++ ++ ret = lxc_exec_cmd(name, &cmd, lxcpath, NULL, suffix); ++ 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_exec_cmd_set_terminal_winch_callback(int fd, struct lxc_exec_cmd_req *req, ++ struct lxc_exec_command_handler *handler) ++{ ++ struct lxc_exec_cmd_rsp rsp; ++ struct lxc_exec_cmd_set_terminal_winch_request *data = (struct lxc_exec_cmd_set_terminal_winch_request *)(req->data); ++ memset(&rsp, 0, sizeof(rsp)); ++ ++ rsp.ret = lxc_set_terminal_winsz(handler->terminal, data->height, data->width);; ++ ++ return lxc_exec_cmd_rsp_send(fd, &rsp); ++ ++} ++ ++static int lxc_exec_cmd_process(int fd, struct lxc_exec_cmd_req *req, ++ struct lxc_exec_command_handler *handler) ++{ ++ typedef int (*callback)(int, struct lxc_exec_cmd_req *, struct lxc_exec_command_handler *); ++ ++ callback cb[LXC_EXEC_CMD_MAX] = { ++ [LXC_EXEC_CMD_SET_TERMINAL_WINCH] = lxc_exec_cmd_set_terminal_winch_callback, ++ }; ++ ++ if (req->cmd >= LXC_EXEC_CMD_MAX) { ++ ERROR("Undefined command id %d", req->cmd); ++ return -1; ++ } ++ return cb[req->cmd](fd, req, handler); ++} ++ ++static void lxc_exec_cmd_fd_cleanup(int fd, struct lxc_epoll_descr *descr) ++{ ++ lxc_mainloop_del_handler(descr, fd); ++ close(fd); ++ return; ++} ++ ++static int lxc_exec_cmd_handler(int fd, uint32_t events, void *data, ++ struct lxc_epoll_descr *descr) ++{ ++ int ret; ++ struct lxc_exec_cmd_req req; ++ void *reqdata = NULL; ++ struct lxc_exec_command_handler *handler = data; ++ ++ ret = lxc_abstract_unix_rcv_credential(fd, &req, sizeof(req)); ++ if (ret < 0) { ++ SYSERROR("Failed to receive data on command socket for command " ++ "\"%s\"", lxc_exec_cmd_str(req.cmd)); ++ ++ if (errno == EACCES) { ++ /* We don't care for the peer, just send and close. */ ++ struct lxc_exec_cmd_rsp rsp = {.ret = ret}; ++ ++ lxc_exec_cmd_rsp_send(fd, &rsp); ++ } ++ ++ goto out_close; ++ } ++ ++ if (ret == 0) ++ goto out_close; ++ ++ if (ret != sizeof(req)) { ++ WARN("Failed to receive full command request. Ignoring request " ++ "for \"%s\"", lxc_exec_cmd_str(req.cmd)); ++ ret = -1; ++ goto out_close; ++ } ++ ++ if (req.datalen > LXC_CMD_DATA_MAX) { ++ ERROR("Received command data length %d is too large for " ++ "command \"%s\"", req.datalen, lxc_exec_cmd_str(req.cmd)); ++ errno = EFBIG; ++ ret = -EFBIG; ++ goto out_close; ++ } ++ ++ if (req.datalen > 0) { ++ reqdata = alloca(req.datalen); ++ if (!reqdata) { ++ ERROR("Failed to allocate memory for \"%s\" command", ++ lxc_exec_cmd_str(req.cmd)); ++ errno = ENOMEM; ++ ret = -ENOMEM; ++ goto out_close; ++ } ++ ++ ret = lxc_recv_nointr(fd, reqdata, req.datalen, 0); ++ if (ret != req.datalen) { ++ WARN("Failed to receive full command request. Ignoring " ++ "request for \"%s\"", lxc_exec_cmd_str(req.cmd)); ++ ret = LXC_MAINLOOP_ERROR; ++ goto out_close; ++ } ++ ++ req.data = reqdata; ++ } ++ ++ ret = lxc_exec_cmd_process(fd, &req, handler); ++ if (ret) { ++ /* This is not an error, but only a request to close fd. */ ++ ret = LXC_MAINLOOP_CONTINUE; ++ goto out_close; ++ } ++ ++out: ++ return ret; ++ ++out_close: ++ lxc_exec_cmd_fd_cleanup(fd, descr); ++ goto out; ++} ++ ++static int lxc_exec_cmd_accept(int fd, uint32_t events, void *data, ++ struct lxc_epoll_descr *descr) ++{ ++ int connection = -1; ++ int opt = 1, ret = -1; ++ ++ connection = accept(fd, NULL, 0); ++ if (connection < 0) { ++ SYSERROR("Failed to accept connection to run command"); ++ return LXC_MAINLOOP_ERROR; ++ } ++ ++ ret = fcntl(connection, F_SETFD, FD_CLOEXEC); ++ if (ret < 0) { ++ SYSERROR("Failed to set close-on-exec on incoming command connection"); ++ goto out_close; ++ } ++ ++ ret = setsockopt(connection, SOL_SOCKET, SO_PASSCRED, &opt, sizeof(opt)); ++ if (ret < 0) { ++ SYSERROR("Failed to enable necessary credentials on command socket"); ++ goto out_close; ++ } ++ ++ ret = lxc_mainloop_add_handler(descr, connection, lxc_exec_cmd_handler, data); ++ if (ret) { ++ ERROR("Failed to add command handler"); ++ goto out_close; ++ } ++ ++out: ++ return ret; ++ ++out_close: ++ close(connection); ++ goto out; ++} ++#ifdef HAVE_ISULAD ++int lxc_exec_unix_sock_delete(const char *name, const char *suffix) ++{ ++ char path[LXC_AUDS_ADDR_LEN] = {0}; ++ ++ if (name == NULL || suffix == NULL) ++ return -1; ++ ++ if (generate_named_unix_sock_path(name, suffix, path, sizeof(path)) != 0) ++ return -1; ++ ++ (void)unlink(path); ++ ++ return 0; ++} ++ ++int lxc_exec_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 *exec_sock_dir = NULL; ++ ++ exec_sock_dir = generate_named_unix_sock_dir(name); ++ if (exec_sock_dir == NULL) ++ return -1; ++ ++ if (mkdir_p(exec_sock_dir, 0600) < 0) ++ return log_error_errno(-1, errno, "Failed to create exec sock directory %s", path); ++ ++ if (generate_named_unix_sock_path(name, suffix, path, sizeof(path)) != 0) ++ return -1; ++ ++ TRACE("Creating unix socket \"%s\"", path); ++ ++ fd = lxc_named_unix_open(path, SOCK_STREAM, 0); ++ if (fd < 0) { ++ if (errno == EADDRINUSE) { ++ WARN("Container \"%s\" exec unix sock is occupied", 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_exec_cmd_init(const char *name, const char *lxcpath, const char *suffix) ++{ ++ int fd, ret; ++ char path[LXC_AUDS_ADDR_LEN] = {0}; ++ ++ ret = lxc_make_abstract_socket_name(path, sizeof(path), name, lxcpath, NULL, suffix); ++ if (ret < 0) ++ return -1; ++ TRACE("Creating abstract unix socket \"%s\"", &path[1]); ++ ++ fd = lxc_abstract_unix_open(path, SOCK_STREAM, 0); ++ if (fd < 0) { ++ SYSERROR("Failed to create command socket %s", &path[1]); ++ if (errno == EADDRINUSE) ++ ERROR("Container \"%s\" appears to be already running", name); ++ ++ return -1; ++ } ++ ++ ret = fcntl(fd, F_SETFD, FD_CLOEXEC); ++ if (ret < 0) { ++ SYSERROR("Failed to set FD_CLOEXEC on command socket file descriptor"); ++ close(fd); ++ return -1; ++ } ++ ++ return fd; ++} ++#endif ++ ++int lxc_exec_cmd_mainloop_add(struct lxc_epoll_descr *descr, struct lxc_exec_command_handler *handler) ++{ ++ int ret; ++ int fd = handler->maincmd_fd; ++ ++ ret = lxc_mainloop_add_handler(descr, fd, lxc_exec_cmd_accept, handler); ++ if (ret < 0) { ++ ERROR("Failed to add handler for command socket"); ++ close(fd); ++ } ++ ++ return ret; ++} +diff --git a/src/lxc/lsm/selinux.c b/src/lxc/lsm/selinux.c +index dba0ab5..bd4f449 100644 +--- a/src/lxc/lsm/selinux.c ++++ b/src/lxc/lsm/selinux.c +@@ -16,6 +16,10 @@ + #include "log.h" + #include "lsm.h" + ++#ifdef HAVE_ISULAD ++#include ++#endif ++ + #define DEFAULT_LABEL "unconfined_t" + + lxc_log_define(selinux, lsm); +@@ -85,6 +89,256 @@ static int selinux_process_label_set(const char *inlabel, struct lxc_conf *conf, + return 0; + } + ++#ifdef HAVE_ISULAD ++/* ++ * selinux_file_label_set: Set SELinux context of a file ++ * ++ * @path : a file ++ * @label : label string ++ * ++ * Returns 0 on success, < 0 on failure ++ */ ++static int selinux_file_label_set(const char *path, const char *label) ++{ ++ if (path == NULL || label == NULL || strcmp(label, "unconfined_t") == 0) { ++ return 0; ++ } ++ ++ if (!is_selinux_enabled()) { ++ return 0; ++ } ++ ++ if (lsetfilecon(path, label) != 0) { ++ SYSERROR("Failed to setSELinux context to \"%s\": %s", label, path); ++ return -1; ++ } ++ ++ INFO("Changed SELinux context to \"%s\": %s", label, path); ++ return 0; ++} ++ ++/* ++ * is_exclude_relabel_path: Determine whether it is a excluded path to label ++ * ++ * @path : a file or directory ++ * ++ * Returns 0 on success, < 0 on failure ++ */ ++static bool is_exclude_relabel_path(const char *path) ++{ ++ const char *exclude_path[] = { "/", "/usr", "/etc", "/tmp", "/home", "/run", "/var", "/root" }; ++ size_t i; ++ ++ for (i = 0; i < sizeof(exclude_path) / sizeof(char *); i++) { ++ if (strcmp(path, exclude_path[i]) == 0) { ++ return true; ++ } ++ } ++ ++ return false; ++} ++ ++/* ++ * bad_prefix: Prevent users from relabing system files ++ * ++ * @path : a file or directory ++ * ++ * Returns 0 on success, < 0 on failure ++ */ ++static int bad_prefix(const char *fpath) ++{ ++ const char *bad_prefixes = "/usr"; ++ ++ if (fpath == NULL) { ++ ERROR("Empty file path"); ++ return -1; ++ } ++ ++ if (strncmp(fpath, bad_prefixes, strlen(bad_prefixes)) == 0) { ++ ERROR("relabeling content in %s is not allowed", bad_prefixes); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++/* ++ * recurse_set_file_label: Recursively label files or folders ++ * ++ * @path : a file or directory ++ * @label : label string ++ * ++ * Returns 0 on success, < 0 on failure ++ */ ++static int recurse_set_file_label(const char *basePath, const char *label) ++{ ++ int ret = 0; ++ __do_closedir DIR *dir = NULL; ++ struct dirent *ptr = NULL; ++ char base[PATH_MAX] = { 0 }; ++ ++ if ((dir = opendir(basePath)) == NULL) { ++ ERROR("Failed to Open dir: %s", basePath); ++ return -1; ++ } ++ ++ ret = lsetfilecon(basePath, label); ++ if (ret != 0) { ++ ERROR("Failed to set file label"); ++ return ret; ++ } ++ ++ while ((ptr = readdir(dir)) != NULL) { ++ if (strcmp(ptr->d_name, ".") == 0 || strcmp(ptr->d_name, "..") == 0) { ++ continue; ++ } else { ++ int nret = snprintf(base, sizeof(base), "%s/%s", basePath, ptr->d_name); ++ if (nret < 0 || nret >= sizeof(base)) { ++ ERROR("Failed to get path"); ++ return -1; ++ } ++ if (ptr->d_type == DT_DIR) { ++ ret = recurse_set_file_label(base, label); ++ if (ret != 0) { ++ ERROR("Failed to set dir label"); ++ return ret; ++ } ++ } else { ++ ret = lsetfilecon(base, label); ++ if (ret != 0) { ++ ERROR("Failed to set file label"); ++ return ret; ++ } ++ } ++ } ++ } ++ ++ return 0; ++} ++ ++/* ++ * selinux_chcon: Chcon changes the `fpath` file object to the SELinux label `label`. ++ * If `fpath` is a directory and `recurse`` is true, Chcon will walk the ++ * directory tree setting the label. ++ * ++ * @fpath : a file or directory ++ * @label : label string ++ * @recurse : whether to recurse ++ * ++ * Returns 0 on success, < 0 on failure ++ */ ++static int selinux_chcon(const char *fpath, const char *label, bool recurse) ++{ ++ struct stat s_buf; ++ ++ if (fpath == NULL || label == NULL) { ++ ERROR("Invalid parameters!"); ++ return -1; ++ } ++ ++ if (bad_prefix(fpath) != 0) { ++ return -1; ++ } ++ if (stat(fpath, &s_buf) != 0) { ++ return -1; ++ } ++ if (recurse && S_ISDIR(s_buf.st_mode)) { ++ return recurse_set_file_label(fpath, label); ++ } ++ ++ if (lsetfilecon(fpath, label) != 0) { ++ ERROR("Failed to set file label"); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++/* ++ * convert_context_to_share_mode: set sensitivity to s0 and remove categories ++ * user:role:type:sensitivity[:categories] => user:role:type:s0 ++ * ++ * @label : label string ++ * ++ * Returns label with share mode on success, NULL on failure ++ */ ++static char *convert_context_to_share_mode(const char *label) { ++ __do_free char *converted_label = strdup(label); ++ char *s = converted_label; ++ const char *shared_level = "s0"; ++ int cnt = 0; ++ ++ // selinux label format: user:role:type:sensitivity[:categories] ++ // locates the ":" position in front of the sensitivity ++ while (cnt++ < 3 && (s = strchr(s, ':')) != NULL) { ++ s++; ++ } ++ ++ // make sure sensitivity can set s0 value ++ if (s == NULL || strlen(s) < strlen(shared_level)) { ++ ERROR("Invalid selinux file context: %s", label); ++ return NULL; ++ } ++ ++ if (strcmp(s, shared_level) == 0) { ++ return move_ptr(converted_label); ++ } ++ ++ *s = '\0'; ++ strcat(converted_label, shared_level); ++ ++ return move_ptr(converted_label); ++} ++ ++/* ++ * selinux_relabel: Relabel changes the label of path to the filelabel string. ++ * It changes the MCS label to s0 if shared is true. ++ * This will allow all containers to share the content. ++ * ++ * @path : a file or directory ++ * @label : label string ++ * @shared : whether to use share mode ++ * ++ * Returns 0 on success, < 0 on failure ++ */ ++static int selinux_relabel(const char *path, const char *label, bool shared) ++{ ++ __do_free char *tmp_file_label = NULL; ++ ++ if (path == NULL || label == NULL) { ++ return 0; ++ } ++ ++ if (!is_selinux_enabled()) { ++ return 0; ++ } ++ ++ if (is_exclude_relabel_path(path)) { ++ ERROR("SELinux relabeling of %s is not allowed", path); ++ return -1; ++ } ++ ++ if (shared) { ++ tmp_file_label = convert_context_to_share_mode(label); ++ if (tmp_file_label == NULL) { ++ ERROR("Failed to convert context to share mode: %s", label); ++ return -1; ++ } ++ } else { ++ tmp_file_label = strdup(label); ++ } ++ ++ ++ if (selinux_chcon(path, tmp_file_label, true) != 0) { ++ ERROR("Failed to modify %s's selinux context: %s", path, tmp_file_label); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++#endif ++ + /* + * selinux_keyring_label_set: Set SELinux context that will be assigned to the keyring + * +@@ -103,6 +357,10 @@ static struct lsm_drv selinux_drv = { + .process_label_get = selinux_process_label_get, + .process_label_set = selinux_process_label_set, + .keyring_label_set = selinux_keyring_label_set, ++#ifdef HAVE_ISULAD ++ .file_label_set = selinux_file_label_set, ++ .relabel = selinux_relabel, ++#endif + }; + + struct lsm_drv *lsm_selinux_drv_init(void) +diff --git a/src/lxc/tools/lxc_attach.c b/src/lxc/tools/lxc_attach.c +index a8f493a..1a5a241 100644 +--- a/src/lxc/tools/lxc_attach.c ++++ b/src/lxc/tools/lxc_attach.c +@@ -72,8 +72,20 @@ static const struct option my_longopts[] = { + {"set-var", required_argument, 0, 'v'}, + {"pty-log", required_argument, 0, 'L'}, + {"rcfile", required_argument, 0, 'f'}, ++#ifndef HAVE_ISULAD + {"uid", required_argument, 0, 'u'}, + {"gid", required_argument, 0, 'g'}, ++#else ++ {"workdir", required_argument, 0, 'w'}, ++ {"user", required_argument, 0, 'u'}, ++ {"in-fifo", required_argument, 0, OPT_INPUT_FIFO}, /* isulad add terminal fifos*/ ++ {"out-fifo", required_argument, 0, OPT_OUTPUT_FIFO}, ++ {"err-fifo", required_argument, 0, OPT_STDERR_FIFO}, ++ {"suffix", required_argument, 0, OPT_ATTACH_SUFFIX}, ++ {"timeout", required_argument, 0, OPT_ATTACH_TIMEOUT}, ++ {"disable-pty", no_argument, 0, OPT_DISABLE_PTY}, ++ {"open-stdin", no_argument, 0, OPT_OPEN_STDIN}, ++#endif + LXC_COMMON_OPTIONS + }; + +@@ -124,9 +136,26 @@ Options :\n\ + multiple times.\n\ + -f, --rcfile=FILE\n\ + Load configuration file FILE\n\ ++" ++#ifndef HAVE_ISULAD ++"\ + -u, --uid=UID Execute COMMAND with UID inside the container\n\ + -g, --gid=GID Execute COMMAND with GID inside the container\n\ +-", ++" ++#else ++"\ ++ -w, --workdir Working directory inside the container.\n\ ++ -u, --user User ID (format: UID[:GID])\n\ ++ --in-fifo Stdin fifo path\n\ ++ --out-fifo Stdout fifo path\n\ ++ --err-fifo Stderr fifo path\n\ ++ --suffi ID for mutli-attach on one container\n\ ++ --timeout Timeout in seconds (default: 0)\n\ ++ --disable-pty Disable pty for attach\n\ ++ --open-stdin Open stdin for attach\n\ ++" ++#endif ++, + .options = my_longopts, + .parser = my_parser, + .checker = NULL, +@@ -136,6 +165,71 @@ Options :\n\ + .gid = LXC_INVALID_GID, + }; + ++#ifdef HAVE_ISULAD ++static int parse_user_id(const char *username, char **uid, char **gid, char **tmp_dup) ++{ ++ char *tmp = NULL; ++ char *pdot = NULL; ++ ++ if (uid == NULL || gid == NULL || tmp_dup == NULL) { ++ return -1; ++ } ++ ++ if (username != NULL) { ++ tmp = strdup(username); ++ if (tmp == NULL) { ++ ERROR("Failed to duplicate user name"); ++ return -1; ++ } ++ ++ // for free tmp in caller ++ *tmp_dup = tmp; ++ pdot = strstr(tmp, ":"); ++ if (pdot != NULL) { ++ *pdot = '\0'; ++ if (pdot != tmp) { ++ // uid found ++ *uid = tmp; ++ } ++ ++ if (*(pdot + 1) != '\0') { ++ // gid found ++ *gid = pdot + 1; ++ } ++ } else { ++ // No : found ++ if (*tmp != '\0') { ++ *uid = tmp; ++ } ++ } ++ } ++ ++ return 0; ++} ++ ++static int get_attach_uid_gid(const char *username, uid_t *user_id, gid_t *group_id) ++{ ++ char *tmp = NULL; ++ char *uid = NULL; ++ char *gid = NULL; ++ ++ // parse uid and gid by username ++ if (parse_user_id(username, &uid, &gid, &tmp) != 0) { ++ return -1; ++ } ++ ++ if (uid != NULL) { ++ *user_id = (unsigned int)atoll(uid); ++ } ++ if (gid != NULL) { ++ *group_id = (unsigned int)atoll(gid); ++ } ++ ++ free(tmp); ++ return 0; ++} ++#endif ++ + static int my_parser(struct lxc_arguments *args, int c, char *arg) + { + int ret; +@@ -193,6 +287,7 @@ static int my_parser(struct lxc_arguments *args, int c, char *arg) + case 'f': + args->rcfile = arg; + break; ++#ifndef HAVE_ISULAD + case 'u': + if (lxc_safe_uint(arg, &args->uid) < 0) + return -1; +@@ -201,6 +296,42 @@ static int my_parser(struct lxc_arguments *args, int c, char *arg) + if (lxc_safe_uint(arg, &args->gid) < 0) + return -1; + break; ++#else ++ case 'u': ++ if (get_attach_uid_gid(arg, &args->uid, &args->gid) != 0) { ++ ERROR("Failed to get attach user U/GID"); ++ return -1; ++ } ++ break; ++ case 'w': ++ args->workdir=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_ATTACH_SUFFIX: ++ args->suffix = arg; ++ break; ++ case OPT_ATTACH_TIMEOUT: ++ if(!is_non_negative_num(arg)) { ++ ERROR("Error attach timeout parameter:%s.\n", arg); ++ return -1; ++ } ++ args->attach_timeout = (unsigned int)atoll(arg); ++ break; ++ case OPT_DISABLE_PTY: ++ args->disable_pty = 1; ++ break; ++ case OPT_OPEN_STDIN: ++ args->open_stdin = 1; ++ break; ++#endif + } + + return 0; +@@ -264,6 +395,285 @@ static int lxc_attach_create_log_file(const char *log_file) + return fd; + } + ++#ifdef HAVE_ISULAD ++// isulad: send '128 + signal' if container is killed by signal. ++#define EXIT_SIGNAL_OFFSET 128 ++ ++/*isulad: attach with terminal*/ ++static int do_attach_foreground(struct lxc_container *c, lxc_attach_command_t *command, ++ lxc_attach_options_t *attach_options, ++ char **errmsg) ++{ ++ int ret = 0; ++ pid_t pid; ++ int wexit = -1; ++ int signal; ++ ++ if (command->program) ++ ret = c->attach(c, lxc_attach_run_command, command, attach_options, &pid); ++ else ++ ret = c->attach(c, lxc_attach_run_shell, NULL, attach_options, &pid); ++ if (ret < 0) { ++ *errmsg = safe_strdup("Internal error, failed to call attach"); ++ goto out; ++ } ++ ++ ret = lxc_wait_for_pid_status(pid); ++ if (ret < 0) { ++ free(*errmsg); ++ *errmsg = safe_strdup("Internal error, failed to wait attached process"); ++ goto out; ++ } ++ ++ if (WIFEXITED(ret)) ++ wexit = WEXITSTATUS(ret); ++ else ++ wexit = -1; ++ ++ if (WIFSIGNALED(ret)) { ++ signal = WTERMSIG(ret); ++ wexit = EXIT_SIGNAL_OFFSET + signal; ++ } ++ ++ WARN("Execd pid %d exit with %d", pid, wexit); ++ ++out: ++ if (c->lxc_conf->errmsg) { ++ free(*errmsg); ++ *errmsg = safe_strdup(c->lxc_conf->errmsg); ++ } ++ return wexit; ++} ++ ++static void close_msg_pipe(int *errpipe) ++{ ++ if (errpipe[0] >= 0) { ++ close(errpipe[0]); ++ errpipe[0] = -1; ++ } ++ if (errpipe[1] >= 0) { ++ close(errpipe[1]); ++ errpipe[1] = -1; ++ } ++} ++ ++/*isulad: attach without terminal in background */ ++static int do_attach_background(struct lxc_container *c, lxc_attach_command_t *command, ++ lxc_attach_options_t *attach_options, ++ char **errmsg) ++{ ++ int ret = 0; ++ int msgpipe[2]; ++ pid_t pid = 0; ++ ssize_t size_read; ++ char msgbuf[BUFSIZ + 1] = {0}; ++ ++ //pipdfd for get error message of child or grandchild process. ++ if (pipe2(msgpipe, O_CLOEXEC) != 0) { ++ SYSERROR("Failed to init msgpipe"); ++ return -1; ++ } ++ ++ pid = fork(); ++ if (pid < 0) { ++ close_msg_pipe(msgpipe); ++ return -1; ++ } ++ ++ if (pid != 0) { ++ close(msgpipe[1]); ++ msgpipe[1] = -1; ++ size_read = read(msgpipe[0], msgbuf, BUFSIZ); ++ if (size_read > 0) { ++ *errmsg = safe_strdup(msgbuf); ++ ret = -1; ++ } ++ ++ close(msgpipe[0]); ++ msgpipe[0] = -1; ++ ++ return ret; ++ } ++ ++ /* second fork to be reparented by init */ ++ pid = fork(); ++ if (pid < 0) { ++ SYSERROR("Error doing dual-fork"); ++ close_msg_pipe(msgpipe); ++ exit(1); ++ } ++ if (pid != 0) { ++ close_msg_pipe(msgpipe); ++ exit(0); ++ } ++ ++ close(msgpipe[0]); ++ msgpipe[0] = -1; ++ ++ if (null_stdfds() < 0) { ++ ERROR("failed to close fds"); ++ exit(1); ++ } ++ setsid(); ++ ++ if (command->program) ++ ret = c->attach(c, lxc_attach_run_command, command, attach_options, &pid); ++ else ++ ret = c->attach(c, lxc_attach_run_shell, NULL, attach_options, &pid); ++ if (ret < 0) { ++ if (c->lxc_conf->errmsg) ++ lxc_write_error_message(msgpipe[1], "%s", c->lxc_conf->errmsg); ++ else ++ lxc_write_error_message(msgpipe[1], "Failed to attach container"); ++ close(msgpipe[1]); ++ msgpipe[1] = -1; ++ ret = -1; ++ goto out; ++ } ++ ++ close(msgpipe[1]); ++ msgpipe[1] = -1; ++ ++ ret = wait_for_pid(pid); ++out: ++ lxc_container_put(c); ++ if (ret) ++ exit(EXIT_FAILURE); ++ else ++ exit(0); ++} ++ ++int main(int argc, char *argv[]) ++{ ++ int wexit = 0; ++ struct lxc_log log; ++ char *errmsg = NULL; ++ lxc_attach_options_t attach_options = LXC_ATTACH_OPTIONS_DEFAULT; ++ lxc_attach_command_t command = (lxc_attach_command_t){.program = NULL}; ++ ++ if (lxc_caps_init()) ++ exit(EXIT_FAILURE); ++ ++ if (lxc_arguments_parse(&my_args, argc, argv)) ++ exit(EXIT_FAILURE); ++ ++ log.name = my_args.name; ++ log.file = my_args.log_file; ++ log.level = my_args.log_priority; ++ log.prefix = my_args.progname; ++ log.quiet = my_args.quiet; ++ log.lxcpath = my_args.lxcpath[0]; ++ ++ if (lxc_log_init(&log)) ++ exit(EXIT_FAILURE); ++ ++ if (geteuid()) ++ if (access(my_args.lxcpath[0], O_RDONLY) < 0) { ++ ERROR("You lack access to %s", my_args.lxcpath[0]); ++ exit(EXIT_FAILURE); ++ } ++ ++ struct lxc_container *c = lxc_container_new(my_args.name, my_args.lxcpath[0]); ++ if (!c) ++ exit(EXIT_FAILURE); ++ ++ if (my_args.rcfile) { ++ c->clear_config(c); ++ if (!c->load_config(c, my_args.rcfile)) { ++ ERROR("Failed to load rcfile"); ++ lxc_container_put(c); ++ exit(EXIT_FAILURE); ++ } ++ ++ c->configfile = strdup(my_args.rcfile); ++ if (!c->configfile) { ++ ERROR("Out of memory setting new config filename"); ++ lxc_container_put(c); ++ exit(EXIT_FAILURE); ++ } ++ } ++ ++ if (!c->may_control(c)) { ++ ERROR("Insufficent privileges to control %s", c->name); ++ lxc_container_put(c); ++ exit(EXIT_FAILURE); ++ } ++ ++ if (remount_sys_proc) ++ attach_options.attach_flags |= LXC_ATTACH_REMOUNT_PROC_SYS; ++ ++ if (elevated_privileges) ++ attach_options.attach_flags &= ~(elevated_privileges); ++ ++ if (my_args.terminal_fifos[0] || my_args.terminal_fifos[1] || my_args.terminal_fifos[2]) { ++ attach_options.init_fifo[0] = my_args.terminal_fifos[0]; ++ attach_options.init_fifo[1] = my_args.terminal_fifos[1]; ++ attach_options.init_fifo[2] = my_args.terminal_fifos[2]; ++ attach_options.attach_flags |= LXC_ATTACH_TERMINAL; ++ } else if (stdfd_is_pty()) { ++ attach_options.attach_flags |= LXC_ATTACH_TERMINAL; ++ } ++ ++ attach_options.namespaces = namespace_flags; ++ attach_options.personality = new_personality; ++ attach_options.env_policy = env_policy; ++ attach_options.extra_env_vars = extra_env; ++ attach_options.extra_keep_env = extra_keep; ++ attach_options.timeout = my_args.attach_timeout; ++ ++ if (my_args.argc > 0) { ++ command.program = my_args.argv[0]; ++ command.argv = (char**)my_args.argv; ++ } ++ ++ if (my_args.console_log) { ++ attach_options.log_fd = lxc_attach_create_log_file(my_args.console_log); ++ if (attach_options.log_fd < 0) { ++ ERROR("Failed to create log file for %s", c->name); ++ lxc_container_put(c); ++ exit(EXIT_FAILURE); ++ } ++ } ++ ++ if (my_args.uid != LXC_INVALID_UID) ++ attach_options.uid = my_args.uid; ++ ++ if (my_args.gid != LXC_INVALID_GID) ++ attach_options.gid = my_args.gid; ++ ++ attach_options.suffix = my_args.suffix; ++ ++ if (my_args.disable_pty) { ++ attach_options.disable_pty = true; ++ } ++ ++ if (my_args.open_stdin) { ++ attach_options.open_stdin = true; ++ } ++ ++ if (my_args.workdir) { ++ attach_options.initial_cwd = my_args.workdir; ++ } ++ ++ /* isulad: add do attach background */ ++ if (attach_options.attach_flags & LXC_ATTACH_TERMINAL) ++ wexit = do_attach_foreground(c, &command, &attach_options, &errmsg); ++ else ++ wexit = do_attach_background(c, &command, &attach_options, &errmsg); ++ ++ if (errmsg) { ++ fprintf(stderr, "%s:%s:%s:%d starting container process caused \"%s\"", c->name, ++ __FILE__, __func__, __LINE__, errmsg); ++ free(errmsg); ++ } ++ ++ lxc_container_put(c); ++ if (wexit >= 0) ++ exit(wexit); ++ ++ exit(EXIT_FAILURE); ++} ++#else + int main(int argc, char *argv[]) + { + int ret = -1; +@@ -377,3 +787,4 @@ out: + + exit(EXIT_FAILURE); + } ++#endif +-- +2.25.1 + diff --git a/0004-iSulad-adapt-confile-lxccontainer-and-start.patch b/0004-refactor-patch-code-of-lxccontianer-and-so-on.patch similarity index 51% rename from 0004-iSulad-adapt-confile-lxccontainer-and-start.patch rename to 0004-refactor-patch-code-of-lxccontianer-and-so-on.patch index 92508980e8200ea326c5d1bf1d3bee7da514e323..3afaced4eaad32ea7ee445c6da8e8f36ff3f62cd 100644 --- a/0004-iSulad-adapt-confile-lxccontainer-and-start.patch +++ b/0004-refactor-patch-code-of-lxccontianer-and-so-on.patch @@ -1,80 +1,88 @@ -From 3e7fb35a35cff34be2bb7ace0b239d540fe0657f Mon Sep 17 00:00:00 2001 -From: zhangxiaoyu -Date: Wed, 26 Jul 2023 14:57:33 +0800 -Subject: [PATCH] [iSulad] adapt confile lxccontainer and start +From 281d09f2dcd4dfd105b41d8da558d4a126ca190b Mon Sep 17 00:00:00 2001 +From: WangFengTu +Date: Mon, 18 Jul 2022 14:14:14 +0800 +Subject: [PATCH] refactor patch code of lxccontianer and so on -Signed-off-by: zhangxiaoyu +Signed-off-by: WangFengTu --- - src/lxc/conf.c | 11 - - src/lxc/conf.h | 4 - - src/lxc/confile.c | 558 +++++++++++++++++++++++++ - src/lxc/lxccontainer.c | 899 +++++++++++++++++++++++++++++++++++++++- - src/lxc/lxccontainer.h | 197 +++++++++ - src/lxc/start.c | 902 +++++++++++++++++++++++++++++++++++++++++ - src/lxc/start.h | 18 + - 7 files changed, 2573 insertions(+), 16 deletions(-) + src/lxc/af_unix.h | 6 + + src/lxc/cgroups/cgroup.h | 13 + + src/lxc/confile.c | 639 +++++++++++++++++++++++++++ + src/lxc/lxccontainer.c | 898 +++++++++++++++++++++++++++++++++++++- + src/lxc/lxclock.c | 31 ++ + src/lxc/mainloop.c | 16 + + src/lxc/path.c | 655 +++++++++++++++++++++++++++ + src/lxc/storage/dir.c | 34 ++ + src/lxc/storage/loop.c | 48 +- + src/lxc/storage/storage.c | 31 +- + 10 files changed, 2367 insertions(+), 4 deletions(-) + create mode 100644 src/lxc/path.c -diff --git a/src/lxc/conf.c b/src/lxc/conf.c -index a0e0375..187e60e 100644 ---- a/src/lxc/conf.c -+++ b/src/lxc/conf.c -@@ -5242,7 +5242,6 @@ void lxc_conf_free(struct lxc_conf *conf) - } - free(conf->systemd); - lxc_clear_init_args(conf); -- lxc_clear_init_groups(conf); - lxc_clear_populate_devices(conf); - lxc_clear_rootfs_masked_paths(conf); - lxc_clear_rootfs_ro_paths(conf); -@@ -7427,16 +7426,6 @@ int lxc_clear_init_args(struct lxc_conf *lxc_conf) - return 0; - } +diff --git a/src/lxc/af_unix.h b/src/lxc/af_unix.h +index 5a1482c..be26ff0 100644 +--- a/src/lxc/af_unix.h ++++ b/src/lxc/af_unix.h +@@ -41,4 +41,10 @@ extern int lxc_unix_connect(struct sockaddr_un *addr); + extern int lxc_unix_connect_type(struct sockaddr_un *addr, int type); + extern int lxc_socket_set_timeout(int fd, int rcv_timeout, int snd_timeout); + ++#ifdef HAVE_ISULAD ++extern int lxc_abstract_unix_recv_fds_timeout(int fd, int *recvfds, int num_recvfds, ++ void *data, size_t size, unsigned int timeout); ++extern int lxc_named_unix_open(const char *path, int type, int flags); ++extern int lxc_named_unix_connect(const char *path); ++#endif + #endif /* __LXC_AF_UNIX_H */ +diff --git a/src/lxc/cgroups/cgroup.h b/src/lxc/cgroups/cgroup.h +index c5bf794..4791112 100644 +--- a/src/lxc/cgroups/cgroup.h ++++ b/src/lxc/cgroups/cgroup.h +@@ -109,6 +109,11 @@ struct cgroup_ops { + char *container_cgroup; + char *monitor_cgroup; --/*isulad clear init groups*/ --int lxc_clear_init_groups(struct lxc_conf *lxc_conf) --{ -- free(lxc_conf->init_groups); -- lxc_conf->init_groups = NULL; -- lxc_conf->init_groups_len = 0; -- -- return 0; --} -- - /*isulad: clear populate devices*/ - int lxc_clear_populate_devices(struct lxc_conf *c) - { -diff --git a/src/lxc/conf.h b/src/lxc/conf.h -index 683b8ba..108e05b 100644 ---- a/src/lxc/conf.h -+++ b/src/lxc/conf.h -@@ -622,9 +622,6 @@ struct lxc_conf { - 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 -@@ -794,7 +791,6 @@ __hidden extern int parse_cap(const char *cap_name, __u32 *cap); - #ifdef HAVE_ISULAD - // isulad add - __hidden int lxc_clear_init_args(struct lxc_conf *lxc_conf); --__hidden int lxc_clear_init_groups(struct lxc_conf *lxc_conf); - __hidden int lxc_clear_populate_devices(struct lxc_conf *c); - __hidden int lxc_clear_rootfs_masked_paths(struct lxc_conf *c); - __hidden int lxc_clear_rootfs_ro_paths(struct lxc_conf *c); ++#ifdef HAVE_ISULAD ++ int errfd; ++ bool no_controller; ++#endif ++ + /* @hierarchies + * - A NULL-terminated array of struct hierarchy, one per legacy + * hierarchy. No duplicates. First sufficient, writeable mounted +@@ -146,14 +151,22 @@ struct cgroup_ops { + */ + cgroup_layout_t cgroup_layout; + ++#ifdef HAVE_ISULAD ++ int (*data_init)(struct cgroup_ops *ops, struct lxc_conf *conf); ++ bool (*payload_destroy)(struct cgroup_ops *ops, struct lxc_handler *handler); ++#else + int (*data_init)(struct cgroup_ops *ops); + void (*payload_destroy)(struct cgroup_ops *ops, struct lxc_handler *handler); ++#endif + void (*monitor_destroy)(struct cgroup_ops *ops, struct lxc_handler *handler); + bool (*monitor_create)(struct cgroup_ops *ops, struct lxc_handler *handler); + bool (*monitor_enter)(struct cgroup_ops *ops, struct lxc_handler *handler); + bool (*payload_create)(struct cgroup_ops *ops, struct lxc_handler *handler); + bool (*payload_enter)(struct cgroup_ops *ops, struct lxc_handler *handler); + const char *(*get_cgroup)(struct cgroup_ops *ops, const char *controller); ++#ifdef HAVE_ISULAD ++ const char *(*get_cgroup_full_path)(struct cgroup_ops *ops, const char *controller); ++#endif + bool (*escape)(const struct cgroup_ops *ops, struct lxc_conf *conf); + int (*num_hierarchies)(struct cgroup_ops *ops); + bool (*get_hierarchies)(struct cgroup_ops *ops, int n, char ***out); diff --git a/src/lxc/confile.c b/src/lxc/confile.c -index 7966d32..1492776 100644 +index 4c27e7d..22d7255 100644 --- a/src/lxc/confile.c +++ b/src/lxc/confile.c -@@ -157,6 +157,18 @@ lxc_config_define(uts_name); +@@ -147,6 +147,19 @@ lxc_config_define(tty_dir); + lxc_config_define(uts_name); lxc_config_define(sysctl); lxc_config_define(proc); - lxc_config_define(sched_core); +#ifdef HAVE_ISULAD +lxc_config_define(init_args); ++lxc_config_define(init_groups); +lxc_config_define(populate_device); +lxc_config_define(umask); +lxc_config_define(rootfs_masked_paths); @@ -86,14 +94,15 @@ index 7966d32..1492776 100644 +lxc_config_define(selinux_mount_context); +#endif - static int set_config_unsupported_key(const char *key, const char *value, - struct lxc_conf *lxc_conf, void *data) -@@ -274,6 +286,18 @@ static struct lxc_config_t config_jump_table[] = { - { "lxc.uts.name", true, set_config_uts_name, get_config_uts_name, clr_config_uts_name, }, - { "lxc.sysctl", false, set_config_sysctl, get_config_sysctl, clr_config_sysctl, }, - { "lxc.proc", false, set_config_proc, get_config_proc, clr_config_proc, }, + /* + * Important Note: +@@ -259,6 +272,19 @@ static struct lxc_config_t config_jump_table[] = { + { "lxc.uts.name", set_config_uts_name, get_config_uts_name, clr_config_uts_name, }, + { "lxc.sysctl", set_config_sysctl, get_config_sysctl, clr_config_sysctl, }, + { "lxc.proc", set_config_proc, get_config_proc, clr_config_proc, }, +#ifdef HAVE_ISULAD + { "lxc.isulad.init.args", set_config_init_args, get_config_init_args, clr_config_init_args, }, ++ { "lxc.isulad.init.groups", set_config_init_groups, get_config_init_groups, clr_config_init_groups, }, + { "lxc.isulad.populate.device", set_config_populate_device, get_config_populate_device, clr_config_populate_device, }, + { "lxc.isulad.umask", set_config_umask, get_config_umask, clr_config_umask, }, + { "lxc.isulad.rootfs.maskedpaths", set_config_rootfs_masked_paths, get_config_rootfs_masked_paths, clr_config_rootfs_masked_paths, }, @@ -106,33 +115,71 @@ index 7966d32..1492776 100644 +#endif }; - static struct lxc_config_t unsupported_config_key = { -@@ -1588,7 +1612,12 @@ static int set_config_environment(const char *key, const char *value, - if (!new_env) - return ret_errno(ENOMEM); + static const size_t config_jump_table_size = sizeof(config_jump_table) / sizeof(struct lxc_config_t); +@@ -1348,6 +1374,10 @@ static int set_config_environment(const char *key, const char *value, + { + struct lxc_list *list_item = NULL; + ++#ifdef HAVE_ISULAD ++ char *replaced = NULL; ++#endif ++ + if (lxc_config_value_empty(value)) + return lxc_clear_environment(lxc_conf); +@@ -1368,7 +1398,16 @@ static int set_config_environment(const char *key, const char *value, + env_var[1] = env_val; + list_item->elem = lxc_string_join("=", env_var, false); + } else { +#ifdef HAVE_ISULAD -+ /* isulad: recover space replaced by SPACE_MAGIC_STR */ -+ dup = lxc_string_replace(SPACE_MAGIC_STR, " ", value); ++ /* isulad: recover space replaced by SPACE_MAGIC_STR */ ++ replaced = lxc_string_replace(SPACE_MAGIC_STR, " ", value); ++ if(!replaced) ++ goto on_error; ++ ++ list_item->elem = replaced; +#else - dup = strdup(value); + list_item->elem = strdup(value); +#endif - if (!dup) - return ret_errno(ENOMEM); + } -@@ -2558,8 +2587,11 @@ static int set_config_console_rotate(const char *key, const char *value, - if (ret) - return ret_errno(EINVAL); + if (!list_item->elem) +@@ -2291,11 +2330,14 @@ static int set_config_console_rotate(const char *key, const char *value, + if (lxc_safe_uint(value, &lxc_conf->console.log_rotate) < 0) + return -1; +#ifndef HAVE_ISULAD + /* isulad: support rotate muti-files */ - if (lxc_conf->console.log_rotate > 1) - return log_error_errno(-EINVAL, EINVAL, "The \"lxc.console.rotate\" config key can only be set to 0 or 1"); + if (lxc_conf->console.log_rotate > 1) { + ERROR("The \"lxc.console.rotate\" config key can only be set " + "to 0 or 1"); + return -1; + } +#endif return 0; } -@@ -3049,6 +3081,54 @@ struct parse_line_conf { +@@ -2581,6 +2623,11 @@ static int set_config_rootfs_options(const char *key, const char *value, + int ret; + struct lxc_rootfs *rootfs = &lxc_conf->rootfs; + ++#ifdef HAVE_ISULAD ++ ret = parse_mntopts(value, &mflags, &pflags, &mdata); ++ if (ret < 0) ++ return -EINVAL; ++#else + ret = parse_mntopts(value, &mflags, &mdata); + if (ret < 0) + return -EINVAL; +@@ -2590,6 +2637,7 @@ static int set_config_rootfs_options(const char *key, const char *value, + free(mdata); + return -EINVAL; + } ++#endif + + ret = set_config_string_item(&opts, value); + if (ret < 0) { +@@ -2722,6 +2770,54 @@ struct parse_line_conf { bool from_include; }; @@ -186,21 +233,21 @@ index 7966d32..1492776 100644 + static int parse_line(char *buffer, void *data) { - __do_free char *linep = NULL; -@@ -3058,6 +3138,9 @@ static int parse_line(char *buffer, void *data) - int ret; + char *dot, *key, *line, *linep, *value; +@@ -2730,6 +2826,9 @@ static int parse_line(char *buffer, void *data) + int ret = 0; char *dup = buffer; struct parse_line_conf *plc = data; +#ifdef HAVE_ISULAD -+ __do_free char *value_decode = NULL; ++ char *value_decode = NULL; +#endif - if (!plc->conf) - return syserror_set(-EINVAL, "Missing config"); -@@ -3118,7 +3201,15 @@ static int parse_line(char *buffer, void *data) + /* If there are newlines in the config file we should keep them. */ + empty_line = lxc_is_line_empty(dup); +@@ -2796,10 +2895,21 @@ static int parse_line(char *buffer, void *data) + goto on_error; } - config = lxc_get_config(key); +#ifdef HAVE_ISULAD + value_decode = escape_string_decode(value); + if (value_decode == NULL) { @@ -208,12 +255,18 @@ index 7966d32..1492776 100644 + } + ret = config->set(key, value_decode ? value_decode: value, plc->conf, NULL); +#else - return config->set(key, value, plc->conf, NULL); + ret = config->set(key, value, plc->conf, NULL); +#endif - } - static struct new_config_item *parse_new_conf_line(char *buffer) -@@ -3222,6 +3313,12 @@ bool lxc_config_define_load(struct lxc_list *defines, struct lxc_container *c) + on_error: + free(linep); ++#ifdef HAVE_ISULAD ++ free(value_decode); ++#endif + + return ret; + } +@@ -2912,6 +3022,12 @@ bool lxc_config_define_load(struct lxc_list *defines, struct lxc_container *c) lxc_list_for_each(it, defines) { struct new_config_item *new_item = it->elem; @@ -226,12 +279,11 @@ index 7966d32..1492776 100644 bret = c->set_config_item(c, new_item->key, new_item->val); if (!bret) break; -@@ -6764,3 +6861,464 @@ static int clr_config_sched_core(const char *key, struct lxc_conf *c, void *data - c->sched_core = false; - return 0; +@@ -6098,3 +6214,526 @@ int lxc_list_net(struct lxc_conf *c, const char *key, char *retv, int inlen) + + return fulllen; } + -+ +#ifdef HAVE_ISULAD +/* isulad: set config for init args */ +static int set_config_init_args(const char *key, const char *value, @@ -285,6 +337,69 @@ index 7966d32..1492776 100644 + return lxc_clear_init_args(c); +} + ++/* isulad: set config for init groups */ ++static int set_config_init_groups(const char *key, const char *value, ++ struct lxc_conf *lxc_conf, void *data) ++{ ++ char *groups = NULL; ++ char *token = NULL; ++ int ret = -1; ++ ++ if (lxc_config_value_empty(value)) ++ return lxc_clear_init_groups(lxc_conf); ++ ++ groups = strdup(value); ++ if (!groups) ++ return -1; ++ ++ /* In case several capability keep is specified in a single line ++ * split these caps in a single element for the list. ++ */ ++ lxc_iterate_parts(token, groups, " \t") { ++ gid_t *tmp = NULL; ++ if (lxc_mem_realloc((void **)&tmp, (lxc_conf->init_groups_len + 1) * sizeof(gid_t), lxc_conf->init_groups, ++ (lxc_conf->init_groups_len) * sizeof(gid_t)) != 0) { ++ ERROR("Out of memory"); ++ goto on_error; ++ } ++ lxc_conf->init_groups = tmp; ++ tmp[lxc_conf->init_groups_len] = atoll(token); ++ lxc_conf->init_groups_len++; ++ } ++ ++ ret = 0; ++ ++on_error: ++ free(groups); ++ ++ return ret; ++} ++ ++/* isulad: get config init groups */ ++static int get_config_init_groups(const char *key, char *retv, int inlen, ++ struct lxc_conf *c, void *data) ++{ ++ int i, len, fulllen = 0; ++ ++ if (!retv) ++ inlen = 0; ++ else ++ memset(retv, 0, inlen); ++ ++ for (i = 0; i < c->init_groups_len; i++) { ++ strprint(retv, inlen, "%u\n", c->init_groups[i]); ++ } ++ ++ return fulllen; ++} ++ ++/* isulad: clr config init args*/ ++static inline int clr_config_init_groups(const char *key, struct lxc_conf *c, ++ void *data) ++{ ++ return lxc_clear_init_groups(c); ++} ++ +/* isulad: set config for populate device */ +static int set_config_populate_device(const char *key, const char *value, + struct lxc_conf *lxc_conf, void *data) @@ -692,7 +807,7 @@ index 7966d32..1492776 100644 +} +#endif diff --git a/src/lxc/lxccontainer.c b/src/lxc/lxccontainer.c -index 8df6059..d4495f7 100644 +index aac6214..3f75184 100644 --- a/src/lxc/lxccontainer.c +++ b/src/lxc/lxccontainer.c @@ -62,6 +62,10 @@ @@ -718,7 +833,7 @@ index 8df6059..d4495f7 100644 static bool do_lxcapi_destroy(struct lxc_container *c); static const char *lxcapi_get_config_path(struct lxc_container *c); #define do_lxcapi_get_config_path(c) lxcapi_get_config_path(c) -@@ -272,6 +281,13 @@ static void lxc_container_free(struct lxc_container *c) +@@ -281,6 +290,13 @@ static void lxc_container_free(struct lxc_container *c) free(c->config_path); c->config_path = NULL; @@ -732,7 +847,15 @@ index 8df6059..d4495f7 100644 free(c); } -@@ -652,6 +668,66 @@ static bool load_config_locked(struct lxc_container *c, const char *fname) +@@ -519,6 +535,7 @@ static bool do_lxcapi_freeze(struct lxc_container *c) + return true; + } + ++ + WRAP_API(bool, lxcapi_freeze) + + static bool do_lxcapi_unfreeze(struct lxc_container *c) +@@ -623,6 +640,66 @@ static bool load_config_locked(struct lxc_container *c, const char *fname) return true; } @@ -799,7 +922,7 @@ index 8df6059..d4495f7 100644 static bool do_lxcapi_load_config(struct lxc_container *c, const char *alt_file) { int lret; -@@ -685,6 +761,11 @@ static bool do_lxcapi_load_config(struct lxc_container *c, const char *alt_file) +@@ -656,6 +733,11 @@ static bool do_lxcapi_load_config(struct lxc_container *c, const char *alt_file) ret = load_config_locked(c, fname); @@ -811,7 +934,7 @@ index 8df6059..d4495f7 100644 if (need_disklock) container_disk_unlock(c); else -@@ -884,6 +965,33 @@ static bool wait_on_daemonized_start(struct lxc_handler *handler, int pid) +@@ -855,6 +937,33 @@ static bool wait_on_daemonized_start(struct lxc_handler *handler, int pid) return true; } @@ -845,7 +968,7 @@ index 8df6059..d4495f7 100644 static bool do_lxcapi_start(struct lxc_container *c, int useinit, char * const argv[]) { int ret; -@@ -894,6 +1002,11 @@ static bool do_lxcapi_start(struct lxc_container *c, int useinit, char * const a +@@ -865,6 +974,11 @@ static bool do_lxcapi_start(struct lxc_container *c, int useinit, char * const a NULL, }; char **init_cmd = NULL; @@ -857,7 +980,7 @@ index 8df6059..d4495f7 100644 /* container does exist */ if (!c) -@@ -940,6 +1053,30 @@ static bool do_lxcapi_start(struct lxc_container *c, int useinit, char * const a +@@ -911,6 +1025,16 @@ static bool do_lxcapi_start(struct lxc_container *c, int useinit, char * const a argv = init_cmd = split_init_cmd(conf->init_cmd); } @@ -866,20 +989,6 @@ index 8df6059..d4495f7 100644 + argv = init_cmd = use_init_args(conf->init_argv, conf->init_argc); + } + -+ // do not allow using default rootfs path when isulad -+ if (conf->rootfs.mount == NULL) { -+ ERROR("Empty rootfs path detected"); -+ lxc_put_handler(handler); -+ return false; -+ } -+ -+ // do not allow using default args when isulad -+ if (!argv) { -+ ERROR("Empty args detected"); -+ lxc_put_handler(handler); -+ return false; -+ } -+ + if (c->image_type_oci) { + handler->image_type_oci = true; + } @@ -888,7 +997,7 @@ index 8df6059..d4495f7 100644 /* ... otherwise use default_args. */ if (!argv) { if (useinit) { -@@ -959,10 +1096,23 @@ static bool do_lxcapi_start(struct lxc_container *c, int useinit, char * const a +@@ -930,10 +1054,23 @@ static bool do_lxcapi_start(struct lxc_container *c, int useinit, char * const a char title[2048]; pid_t pid_first, pid_second; @@ -912,7 +1021,7 @@ index 8df6059..d4495f7 100644 return false; } -@@ -972,11 +1122,25 @@ static bool do_lxcapi_start(struct lxc_container *c, int useinit, char * const a +@@ -943,11 +1080,25 @@ static bool do_lxcapi_start(struct lxc_container *c, int useinit, char * const a * the PID file, child will do the free and unlink. */ c->pidfile = NULL; @@ -938,7 +1047,7 @@ index 8df6059..d4495f7 100644 free_init_cmd(init_cmd); lxc_put_handler(handler); -@@ -1012,6 +1176,9 @@ static bool do_lxcapi_start(struct lxc_container *c, int useinit, char * const a +@@ -983,6 +1134,9 @@ static bool do_lxcapi_start(struct lxc_container *c, int useinit, char * const a if (pid_second != 0) { free_init_cmd(init_cmd); lxc_put_handler(handler); @@ -948,7 +1057,7 @@ index 8df6059..d4495f7 100644 _exit(EXIT_SUCCESS); } -@@ -1024,7 +1191,18 @@ static bool do_lxcapi_start(struct lxc_container *c, int useinit, char * const a +@@ -995,7 +1149,18 @@ static bool do_lxcapi_start(struct lxc_container *c, int useinit, char * const a _exit(EXIT_FAILURE); } @@ -967,8 +1076,8 @@ index 8df6059..d4495f7 100644 if (ret < 0) _exit(EXIT_FAILURE); -@@ -1057,6 +1235,9 @@ static bool do_lxcapi_start(struct lxc_container *c, int useinit, char * const a - if (w < 0) { +@@ -1028,6 +1193,9 @@ static bool do_lxcapi_start(struct lxc_container *c, int useinit, char * const a + if (w < 0 || (size_t)w >= sizeof(pidstr)) { free_init_cmd(init_cmd); lxc_put_handler(handler); +#ifdef HAVE_ISULAD @@ -977,7 +1086,7 @@ index 8df6059..d4495f7 100644 SYSERROR("Failed to write monitor pid to \"%s\"", c->pidfile); -@@ -1070,6 +1251,9 @@ static bool do_lxcapi_start(struct lxc_container *c, int useinit, char * const a +@@ -1041,6 +1209,9 @@ static bool do_lxcapi_start(struct lxc_container *c, int useinit, char * const a if (ret < 0) { free_init_cmd(init_cmd); lxc_put_handler(handler); @@ -987,7 +1096,7 @@ index 8df6059..d4495f7 100644 SYSERROR("Failed to write monitor pid to \"%s\"", c->pidfile); -@@ -1080,6 +1264,19 @@ static bool do_lxcapi_start(struct lxc_container *c, int useinit, char * const a +@@ -1051,6 +1222,19 @@ static bool do_lxcapi_start(struct lxc_container *c, int useinit, char * const a } } @@ -1007,7 +1116,7 @@ index 8df6059..d4495f7 100644 conf->reboot = REBOOT_NONE; /* Unshare the mount namespace if requested */ -@@ -1111,19 +1308,53 @@ reboot: +@@ -1082,19 +1266,53 @@ reboot: } } @@ -1061,7 +1170,34 @@ index 8df6059..d4495f7 100644 if (conf->reboot == REBOOT_REQ) { INFO("Container requested reboot"); -@@ -2065,7 +2296,12 @@ WRAP_API_1(bool, lxcapi_reboot2, int) +@@ -1185,6 +1403,9 @@ WRAP_API(bool, lxcapi_stop) + + static int do_create_container_dir(const char *path, struct lxc_conf *conf) + { ++#ifdef HAVE_ISULAD ++ __do_free char *p = NULL; ++#endif + int lasterr; + int ret = -1; + +@@ -1200,8 +1421,16 @@ static int do_create_container_dir(const char *path, struct lxc_conf *conf) + ret = 0; + } + ++#ifdef HAVE_ISULAD ++ p = must_copy_string(path); ++#endif ++ + if (!lxc_list_empty(&conf->id_map)) { ++#ifdef HAVE_ISULAD ++ ret = chown_mapped_root(p, conf); ++#else + ret = chown_mapped_root(path, conf); ++#endif + if (ret < 0) + ret = -1; + } +@@ -2048,7 +2277,12 @@ WRAP_API_1(bool, lxcapi_reboot2, int) static bool do_lxcapi_shutdown(struct lxc_container *c, int timeout) { __do_close int pidfd = -EBADF, state_client_fd = -EBADF; @@ -1074,7 +1210,7 @@ index 8df6059..d4495f7 100644 pid_t pid = -1; lxc_state_t states[MAX_STATE] = {0}; int killret, ret; -@@ -2084,9 +2320,10 @@ static bool do_lxcapi_shutdown(struct lxc_container *c, int timeout) +@@ -2067,9 +2301,10 @@ static bool do_lxcapi_shutdown(struct lxc_container *c, int timeout) /* Detect whether we should send SIGRTMIN + 3 (e.g. systemd). */ if (c->lxc_conf && c->lxc_conf->haltsignal) haltsignal = c->lxc_conf->haltsignal; @@ -1086,7 +1222,7 @@ index 8df6059..d4495f7 100644 /* * Add a new state client before sending the shutdown signal so -@@ -2939,6 +3176,21 @@ static int lxc_unlink_exec_wrapper(void *data) +@@ -2938,6 +3173,21 @@ static int lxc_unlink_exec_wrapper(void *data) return unlink(arg); } @@ -1108,7 +1244,7 @@ index 8df6059..d4495f7 100644 static bool container_destroy(struct lxc_container *c, struct lxc_storage *storage) { -@@ -2949,8 +3201,19 @@ static bool container_destroy(struct lxc_container *c, +@@ -2948,8 +3198,19 @@ static bool container_destroy(struct lxc_container *c, bool bret = false; int ret = 0; @@ -1128,7 +1264,7 @@ index 8df6059..d4495f7 100644 conf = c->lxc_conf; if (container_disk_lock(c)) -@@ -3070,8 +3333,20 @@ static bool container_destroy(struct lxc_container *c, +@@ -3069,8 +3330,20 @@ static bool container_destroy(struct lxc_container *c, if (ret < 0) { ERROR("Failed to destroy directory \"%s\" for \"%s\"", path, c->name); @@ -1149,7 +1285,7 @@ index 8df6059..d4495f7 100644 INFO("Destroyed directory \"%s\" for \"%s\"", path, c->name); on_success: -@@ -3082,6 +3357,11 @@ out: +@@ -3081,6 +3354,11 @@ out: free(path); container_disk_unlock(c); @@ -1161,7 +1297,7 @@ index 8df6059..d4495f7 100644 return bret; } -@@ -4042,8 +4322,13 @@ static int lxcapi_attach(struct lxc_container *c, +@@ -4030,8 +4308,13 @@ static int lxcapi_attach(struct lxc_container *c, current_config = c->lxc_conf; @@ -1175,7 +1311,7 @@ index 8df6059..d4495f7 100644 current_config = NULL; return ret; } -@@ -4063,7 +4348,11 @@ static int do_lxcapi_attach_run_wait(struct lxc_container *c, +@@ -4051,7 +4334,11 @@ static int do_lxcapi_attach_run_wait(struct lxc_container *c, command.program = (char *)program; command.argv = (char **)argv; @@ -1187,9 +1323,9 @@ index 8df6059..d4495f7 100644 if (ret < 0) return ret; -@@ -5257,6 +5546,560 @@ static int do_lxcapi_seccomp_notify_fd_active(struct lxc_container *c) +@@ -5230,7 +5517,561 @@ static int do_lxcapi_seccomp_notify_fd(struct lxc_container *c) - WRAP_API(int, lxcapi_seccomp_notify_fd_active) + WRAP_API(int, lxcapi_seccomp_notify_fd) +#ifdef HAVE_ISULAD +/* isulad add set console fifos*/ @@ -1713,10 +1849,6 @@ index 8df6059..d4495f7 100644 + metrics->cpu_use_nanos = metrics_get_ull(c, cgroup_ops, "cpuacct.usage"); + metrics->pids_current = metrics_get_ull(c, cgroup_ops, "pids.current"); + -+ metrics->rss_bytes = metrics_match_get_ull(c,cgroup_ops, "memory.stat", "rss", 1); -+ metrics->page_faults = metrics_match_get_ull(c,cgroup_ops, "memory.stat", "pgfault", 1); -+ metrics->major_page_faults = metrics_match_get_ull(c,cgroup_ops, "memory.stat", "pgmajfault", 1); -+ + metrics->cpu_use_user = metrics_match_get_ull(c, cgroup_ops, "cpuacct.stat", "user", 1); + metrics->cpu_use_sys = metrics_match_get_ull(c, cgroup_ops, "cpuacct.stat", "system", 1); + @@ -1745,10 +1877,15 @@ index 8df6059..d4495f7 100644 + +#endif + ++#ifdef HAVE_ISULAD ++static struct lxc_container *do_lxc_container_new(const char *name, const char *configpath, bool load_config) ++#else struct lxc_container *lxc_container_new(const char *name, const char *configpath) ++#endif { struct lxc_container *c; -@@ -5310,10 +6153,24 @@ struct lxc_container *lxc_container_new(const char *name, const char *configpath + size_t len; +@@ -5283,10 +6124,24 @@ struct lxc_container *lxc_container_new(const char *name, const char *configpath goto err; } @@ -1773,20 +1910,21 @@ index 8df6059..d4495f7 100644 rc = ongoing_create(c); switch (rc) { -@@ -5337,6 +6194,9 @@ struct lxc_container *lxc_container_new(const char *name, const char *configpath +@@ -5310,6 +6165,9 @@ struct lxc_container *lxc_container_new(const char *name, const char *configpath - c->daemonize = true; - c->pidfile = NULL; + c->daemonize = true; + c->pidfile = NULL; +#ifdef HAVE_ISULAD + c->image_type_oci = false; +#endif /* Assign the member functions. */ - c->is_defined = lxcapi_is_defined; -@@ -5400,6 +6260,20 @@ struct lxc_container *lxc_container_new(const char *name, const char *configpath - c->umount = lxcapi_umount; - c->seccomp_notify_fd = lxcapi_seccomp_notify_fd; - c->seccomp_notify_fd_active = lxcapi_seccomp_notify_fd_active; + c->is_defined = lxcapi_is_defined; +@@ -5371,7 +6229,20 @@ struct lxc_container *lxc_container_new(const char *name, const char *configpath + c->mount = lxcapi_mount; + c->umount = lxcapi_umount; + c->seccomp_notify_fd = lxcapi_seccomp_notify_fd; +- +#ifdef HAVE_ISULAD + c->set_container_info_file = lxcapi_set_container_info_file; + c->set_terminal_init_fifos = lxcapi_set_terminal_default_fifos; @@ -1801,10 +1939,10 @@ index 8df6059..d4495f7 100644 + c->set_oci_type = lxcapi_set_oci_type; + c->get_container_metrics = lxcapi_get_container_metrics; +#endif - return c; -@@ -5408,6 +6282,19 @@ err: + err: +@@ -5379,6 +6250,19 @@ err: return NULL; } @@ -1824,7 +1962,7 @@ index 8df6059..d4495f7 100644 int lxc_get_wait_states(const char **states) { int i; -@@ -5578,11 +6465,21 @@ int list_active_containers(const char *lxcpath, char ***nret, +@@ -5557,11 +6441,21 @@ int list_active_containers(const char *lxcpath, char ***nret, continue; } @@ -1846,1465 +1984,964 @@ index 8df6059..d4495f7 100644 if (!add_to_array(&ct_name, p, ct_name_cnt)) { if (is_hashed) -diff --git a/src/lxc/lxccontainer.h b/src/lxc/lxccontainer.h -index 3386bff..06e8f0b 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 +diff --git a/src/lxc/lxclock.c b/src/lxc/lxclock.c +index 318e5bf..ce6f889 100644 +--- a/src/lxc/lxclock.c ++++ b/src/lxc/lxclock.c +@@ -179,6 +179,10 @@ struct lxc_lock *lxc_newlock(const char *lxcpath, const char *name) + l->u.f.fd = -1; + on_error: +#ifdef HAVE_ISULAD -+#define LXC_IMAGE_OCI_KEY "lxc.imagetype.oci" ++ if (l == NULL) ++ fprintf(stderr, "Failed to create lock for %s, path %s\n", name, lxcpath); +#endif -+ - struct bdev_specs; - - struct lxc_snapshot; -@@ -40,6 +44,44 @@ struct lxc_mount { - int version; - }; + return l; + } -+#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; -+ uint64_t rss_bytes; -+ uint64_t page_faults; -+ uint64_t major_page_faults; -+ /* 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 +@@ -370,3 +374,30 @@ void container_disk_unlock(struct lxc_container *c) + lxcunlock(c->slock); + lxcunlock(c->privlock); + } + - /*! - * An LXC container. - * -@@ -107,6 +149,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. - * -@@ -884,6 +958,115 @@ struct lxc_container { - * \return Mount fd of the container's devpts instance. - */ - int (*devpts_fd)(struct lxc_container *c); ++static int lxc_removelock(struct lxc_lock *l) ++{ ++ int ret = 0; + -+#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); ++ if (l->type == LXC_LOCK_FLOCK) { ++ ret = unlink(l->u.f.fname); ++ if (ret && errno != ENOENT) { ++ SYSERROR("Error unlink %s", l->u.f.fname); ++ return ret; ++ } ++ } + -+ bool (*set_terminal_winch)(struct lxc_container *c, unsigned int height, unsigned int width); ++ return ret; ++} + -+ bool (*set_exec_terminal_winch)(struct lxc_container *c, const char *suffix, unsigned int height, unsigned int width); ++int container_disk_removelock(struct lxc_container *c) ++{ ++ int ret; + -+ /*! -+ * \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); ++ ret = lxc_removelock(c->slock); ++ if (ret) ++ return ret; ++ return lxc_removelock(c->privlock); ++} +#endif - }; +diff --git a/src/lxc/mainloop.c b/src/lxc/mainloop.c +index d5ae2a6..c47f31b 100644 +--- a/src/lxc/mainloop.c ++++ b/src/lxc/mainloop.c +@@ -150,3 +150,19 @@ void lxc_mainloop_close(struct lxc_epoll_descr *descr) - /*! -@@ -1017,6 +1200,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 + close_prot_errno_disarm(descr->epfd); + } + - /*! - * \brief Add a reference to the specified container. - * -diff --git a/src/lxc/start.c b/src/lxc/start.c -index 9f68304..70af128 100644 ---- a/src/lxc/start.c -+++ b/src/lxc/start.c -@@ -344,7 +344,11 @@ static int setup_signal_fd(sigset_t *oldmask) - { - int ret; - sigset_t mask; -+#ifdef HAVE_ISULAD -+ const int signals[] = {SIGBUS, SIGILL, SIGSEGV, SIGWINCH, SIGTERM}; -+#else - const int signals[] = {SIGBUS, SIGILL, SIGSEGV, SIGWINCH}; -+#endif - - /* Block everything except serious error signals. */ - ret = sigfillset(&mask); -@@ -625,6 +629,16 @@ int lxc_poll(const char *name, struct lxc_handler *handler) - - TRACE("Mainloop is ready"); - +#ifdef HAVE_ISULAD -+ // iSulad: close stdin pipe if we do not want open_stdin with container stdin -+ if (!handler->conf->console.open_stdin) { -+ if (handler->conf->console.pipes[0][1] > 0) { -+ close(handler->conf->console.pipes[0][1]); -+ handler->conf->console.pipes[0][1] = -1; -+ } -+ } -+#endif ++int isulad_safe_mainloop(struct lxc_epoll_descr *descr, int timeout_ms) ++{ ++ int ret; + - ret = lxc_mainloop(&descr, -1); - if (descr.type == LXC_MAINLOOP_EPOLL) - close_prot_errno_disarm(descr.epfd); -@@ -634,7 +648,11 @@ int lxc_poll(const char *name, struct lxc_handler *handler) - if (console) { - ret = lxc_terminal_mainloop_add(&descr_console, console); - if (ret == 0) -+#ifdef HAVE_ISULAD -+ ret = isulad_safe_mainloop(&descr_console, 100); -+#else - ret = lxc_mainloop(&descr_console, 0); -+#endif - } - - out_mainloop_console: -@@ -718,6 +736,12 @@ struct lxc_handler *lxc_init_handler(struct lxc_handler *old, - } - - handler->name = name; ++ ret = lxc_mainloop(descr, timeout_ms); + -+#ifdef HAVE_ISULAD -+ handler->exit_code = -1; /* isulad: record exit code of container */ -+ handler->image_type_oci = false; -+#endif ++ // There are stdout and stderr channels, and two epolls should be performed to prevent ++ // one of the channels from exiting first, causing the other channel to not receive data, ++ // resulting in data loss ++ (void)lxc_mainloop(descr, 100); + - if (daemonize) - handler->transient_pid = lxc_raw_getpid(); - else -@@ -768,6 +792,10 @@ int lxc_init(const char *name, struct lxc_handler *handler) - int ret; - const char *loglevel; - struct lxc_conf *conf = handler->conf; -+#ifdef HAVE_ISULAD -+ conf->console.disable_pty = handler->disable_pty; -+ conf->console.open_stdin = handler->open_stdin; ++ return ret; ++} +#endif - - handler->monitor_pid = lxc_raw_getpid(); - status_fd = open("/proc/self/status", O_RDONLY | O_CLOEXEC); -@@ -908,6 +936,186 @@ void lxc_expose_namespace_environment(const struct lxc_handler *handler) - } - } - +diff --git a/src/lxc/path.c b/src/lxc/path.c +new file mode 100644 +index 0000000..46256cb +--- /dev/null ++++ b/src/lxc/path.c +@@ -0,0 +1,655 @@ ++/* 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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include + -+#ifdef HAVE_ISULAD -+/* isulad: start timeout thread */ -+typedef enum { -+ START_INIT, -+ START_TIMEOUT, -+ START_MAX, -+} start_timeout_t; ++#include "path.h" ++#include "log.h" ++#include "isulad_utils.h" + -+static start_timeout_t global_timeout_state = START_INIT; -+static sem_t global_timeout_sem; ++lxc_log_define(lxc_path_ui, lxc); + -+struct start_timeout_conf { -+ unsigned int timeout; -+ int errfd; -+}; ++#define ISSLASH(C) ((C) == '/') ++#define IS_ABSOLUTE_FILE_NAME(F) (ISSLASH ((F)[0])) ++#define IS_RELATIVE_FILE_NAME(F) (! IS_ABSOLUTE_FILE_NAME (F)) + -+void trim_line(char *s) ++bool specify_current_dir(const char *path) +{ -+ size_t len; ++ char *basec = NULL, *bname = NULL; ++ bool res = false; ++ ++ basec = safe_strdup(path); ++ ++ bname = basename(basec); ++ if (bname == NULL) { ++ free(basec); ++ ERROR("Out of memory"); ++ return false; ++ } ++ res = !strcmp(bname, "."); ++ free(basec); ++ return res; ++} + -+ len = strlen(s); -+ while ((len > 1) && (s[len - 1] == '\n')) -+ s[--len] = '\0'; ++bool has_traling_path_separator(const char *path) ++{ ++ return path && strlen(path) && (path[strlen(path) - 1] == '/'); +} + -+static int _read_procs_file(const char *path, pid_t **pids, size_t *len) ++// PreserveTrailingDotOrSeparator returns the given cleaned path ++// and appends a trailing `/.` or `/` if its corresponding original ++// path ends with a trailing `/.` or `/`. If the cleaned ++// path already ends in a `.` path segment, then another is not added. If the ++// clean path already ends in a path separator, then another is not added. ++char *preserve_trailing_dot_or_separator(const char *cleanedpath, ++ const char *originalpath) +{ -+ FILE *f; -+ char *line = NULL; -+ size_t sz = 0; -+ pid_t *tmp_pids = NULL; ++ char *respath = NULL; ++ size_t len; + -+ f = fopen_cloexec(path, "r"); -+ if (!f) -+ return -1; ++ if (strlen(cleanedpath) > (SIZE_MAX - 3)) { ++ return NULL; ++ } + -+ while (getline(&line, &sz, f) != -1) { -+ pid_t pid; -+ trim_line(line); -+ pid = (pid_t)atoll(line); -+ if (lxc_mem_realloc((void **)&tmp_pids, sizeof(pid_t) * (*len + 1), *pids, sizeof(pid_t) * (*len)) != 0) { -+ free(*pids); -+ *pids = NULL; -+ ERROR("out of memory"); -+ free(line); -+ fclose(f); -+ return -1; -+ } -+ *pids = tmp_pids; ++ len = strlen(cleanedpath) + 3; ++ respath = malloc(len); ++ if (respath == NULL) { ++ ERROR("Out of memory"); ++ return NULL; ++ } ++ memset(respath, 0x00, len); ++ strcat(respath, cleanedpath); + -+ (*pids)[*len] = pid; -+ (*len)++; ++ if (!specify_current_dir(cleanedpath) && specify_current_dir(originalpath)) { ++ if (!has_traling_path_separator(respath)) ++ strcat(respath, "/"); ++ strcat(respath, "."); + } + -+ free(line); -+ fclose(f); -+ return 0; ++ if (!has_traling_path_separator(respath) && ++ has_traling_path_separator(originalpath)) ++ strcat(respath, "/"); ++ ++ return respath; +} + -+static int _recursive_read_cgroup_procs(const char *dirpath, pid_t **pids, size_t *len) ++ ++// Split splits path immediately following the final Separator, ++// separating it into a directory and file name component. ++// If there is no Separator in path, Split returns an empty dir ++// and file set to path. ++// The returned values have the property that path = dir+file. ++bool filepath_split(const char *path, char **dir, char **base) +{ -+ struct dirent *direntp = NULL; -+ DIR *dir = NULL; -+ int ret, failed = 0; -+ char pathname[PATH_MAX]; ++ ssize_t i; ++ size_t len; + -+ dir = opendir(dirpath); -+ if (dir == NULL) { -+ WARN("Failed to open \"%s\"", dirpath); -+ return 0; ++ len = strlen(path); ++ if (len >= PATH_MAX) { ++ ERROR("Invalid path"); ++ return false; + } ++ i = len - 1; ++ while (i >= 0 && path[i] != '/') ++ i--; + -+ while ((direntp = readdir(dir))) { -+ struct stat mystat; -+ int rc; ++ *dir = malloc(i + 2); ++ if (*dir == NULL) { ++ ERROR("Out of memory"); ++ return false; ++ } ++ memcpy(*dir, path, i + 1); ++ *(*dir + i + 1) = '\0'; + -+ if (!strcmp(direntp->d_name, ".") || -+ !strcmp(direntp->d_name, "..")) -+ continue; ++ *base = safe_strdup(path + i + 1); + -+ rc = snprintf(pathname, PATH_MAX, "%s/%s", dirpath, direntp->d_name); -+ if (rc < 0 || rc >= PATH_MAX) { -+ failed = 1; -+ continue; ++ return true; ++} ++ ++ ++static bool do_clean_path_continue(const char *endpos, const char *stpos, const char *respath, char **dst) ++{ ++ if (endpos - stpos == 1 && stpos[0] == '.') { ++ return true; ++ } else if (endpos - stpos == 2 && stpos[0] == '.' && stpos[1] == '.') { ++ char *dest = *dst; ++ if (dest <= respath + 1) { ++ return true; + } ++ for (--dest; dest > respath && !ISSLASH(dest[-1]); --dest) { ++ *dst = dest; ++ return true; ++ } ++ *dst = dest; ++ return true; ++ } ++ return false; ++} + -+ if (strcmp(direntp->d_name, "cgroup.procs") == 0) { -+ if (_read_procs_file(pathname, pids, len)) { -+ failed = 1; ++int do_clean_path(const char *respath, const char *limit_respath, ++ const char *stpos, char **dst) ++{ ++ char *dest = *dst; ++ const char *endpos = NULL; + -+ } -+ continue; ++ for (endpos = stpos; *stpos; stpos = endpos) { ++ while (ISSLASH(*stpos)) { ++ ++stpos; ++ } ++ ++ for (endpos = stpos; *endpos && !ISSLASH(*endpos); ++endpos) { + } + -+ ret = lstat(pathname, &mystat); -+ if (ret) { -+ failed = 1; ++ if (endpos - stpos == 0) { ++ break; ++ } else if (do_clean_path_continue(endpos, stpos, respath, &dest)) { + continue; + } + -+ if (S_ISDIR(mystat.st_mode)) { -+ if (_recursive_read_cgroup_procs(pathname, pids, len) < 0) -+ failed = 1; ++ if (!ISSLASH(dest[-1])) { ++ *dest++ = '/'; + } -+ } + -+ ret = closedir(dir); -+ if (ret) { -+ WARN("Failed to close directory \"%s\"", dirpath); -+ failed = 1; -+ } ++ if (dest + (endpos - stpos) >= limit_respath) { ++ ERROR("Path is too long"); ++ if (dest > respath + 1) { ++ dest--; ++ } ++ *dest = '\0'; ++ return -1; ++ } + -+ return failed ? -1 : 0; ++ memcpy(dest, stpos, (size_t)(endpos - stpos)); ++ dest += endpos - stpos; ++ *dest = '\0'; ++ } ++ *dst = dest; ++ return 0; +} + -+int get_all_pids(struct cgroup_ops *cg_ops, pid_t **pids, size_t *len) ++char *cleanpath(const char *path, char *realpath, size_t realpath_len) +{ -+ const char *devices_path = NULL; ++ char *respath = NULL; ++ char *dest = NULL; ++ const char *stpos = NULL; ++ const char *limit_respath = NULL; + -+ devices_path = cg_ops->get_cgroup_full_path(cg_ops, "devices"); -+ if (!file_exists(devices_path)) { -+ return 0; ++ if (path == NULL || path[0] == '\0' || \ ++ realpath == NULL || (realpath_len < PATH_MAX)) { ++ return NULL; + } + -+ return _recursive_read_cgroup_procs(devices_path, pids, len); -+} -+ -+static int set_cgroup_freezer(struct cgroup_ops *cg_ops, const char *value) -+{ -+ char *fullpath; -+ int ret; -+ -+ fullpath = must_make_path(cg_ops->get_cgroup_full_path(cg_ops, "freezer"), "freezer.state", NULL); -+ ret = lxc_write_to_file(fullpath, value, strlen(value), false, 0666); -+ free(fullpath); -+ return ret; -+} ++ respath = realpath; + -+/* isulad: kill all process in container cgroup path */ -+static void signal_all_processes(struct lxc_handler *handler) -+{ -+ int ret; -+ struct cgroup_ops *cg_ops = handler->cgroup_ops; -+ pid_t *pids = NULL; -+ size_t len = 0, i; ++ memset(respath, 0, realpath_len); ++ limit_respath = respath + PATH_MAX; + -+ ret = set_cgroup_freezer(cg_ops, "FROZEN"); -+ if (ret < 0 && errno != ENOENT) { -+ WARN("cgroup_set frozen failed"); -+ } -+ -+ ret = get_all_pids(cg_ops, &pids, &len); -+ if (ret < 0) { -+ WARN("failed to get all pids"); -+ } -+ -+ for (i = 0; i < len; i++) { -+ ret = kill(pids[i], SIGKILL); -+ if (ret < 0 && errno != ESRCH) { -+ WARN("Can not kill process (pid=%d) with SIGKILL for container %s", pids[i], handler->name); ++ if (!IS_ABSOLUTE_FILE_NAME(path)) { ++ if (!getcwd(respath, PATH_MAX)) { ++ ERROR("Failed to getcwd"); ++ respath[0] = '\0'; ++ goto error; ++ } ++ dest = strchr(respath, '\0'); ++ if (dest == NULL) { ++ ERROR("Failed to get the end of respath"); ++ goto error; ++ } ++ if (strlen(path) > (PATH_MAX - strlen(respath) - 1)) { ++ ERROR("Path is too long"); ++ goto error; + } ++ strcat(respath, path); ++ stpos = path; ++ } else { ++ dest = respath; ++ *dest++ = '/'; ++ stpos = path; + } + -+ ret = set_cgroup_freezer(cg_ops, "THAWED"); -+ if (ret < 0 && errno != ENOENT) { -+ WARN("cgroup_set thawed failed"); ++ if (do_clean_path(respath, limit_respath, stpos, &dest)) { ++ goto error; + } + -+ for (i = 0; i < len; i++) { -+ ret = lxc_wait_for_pid_status(pids[i]); -+ if (ret < 0 && errno != ECHILD) { -+ WARN("Failed to wait pid %d for container %s: %s", pids[i], handler->name, strerror(errno)); -+ } ++ if (dest > respath + 1 && ISSLASH(dest[-1])) { ++ --dest; + } ++ *dest = '\0'; + -+ free(pids); ++ return respath; ++ ++error: ++ return NULL; +} -+#endif + - void lxc_end(struct lxc_handler *handler) - { - int ret; -@@ -945,14 +1153,44 @@ void lxc_end(struct lxc_handler *handler) - - handler->lsm_ops->cleanup(handler->lsm_ops, handler->conf, handler->lxcpath); - -+ -+#ifdef HAVE_ISULAD -+ // close maincmd fd before destroy cgroup for isulad -+ if (handler->conf->reboot == REBOOT_NONE) { -+ /* For all new state clients simply close the command socket. -+ * This will inform all state clients that the container is -+ * STOPPED and also prevents a race between a open()/close() on -+ * the command socket causing a new process to get ECONNREFUSED -+ * because we haven't yet closed the command socket. -+ */ -+ close_prot_errno_disarm(handler->conf->maincmd_fd); -+ TRACE("Closed command socket"); -+ } -+ int retry_count = 0; -+ int max_retry = 10; -+retry: -+ if (cgroup_ops != NULL && !cgroup_ops->payload_destroy(cgroup_ops, handler)) { -+ TRACE("Trying to kill all subprocess"); -+ signal_all_processes(handler); -+ TRACE("Finished kill all subprocess"); -+ if (retry_count < max_retry) { -+ usleep(100 * 1000); /* 100 millisecond */ -+ retry_count++; -+ goto retry; -+ } -+ SYSERROR("Failed to destroy cgroup path for container: \"%s\"", handler->name); -+ } -+#else - if (cgroup_ops) { - cgroup_ops->payload_destroy(cgroup_ops, handler); - cgroup_ops->monitor_destroy(cgroup_ops, handler); - } -+#endif - - put_lxc_rootfs(&handler->conf->rootfs, true); - - if (handler->conf->reboot == REBOOT_NONE) { -+#ifndef HAVE_ISULAD - /* For all new state clients simply close the command socket. - * This will inform all state clients that the container is - * STOPPED and also prevents a race between a open()/close() on -@@ -961,12 +1199,23 @@ void lxc_end(struct lxc_handler *handler) - */ - close_prot_errno_disarm(handler->conf->maincmd_fd); - TRACE("Closed command socket"); -+#endif - - /* This function will try to connect to the legacy lxc-monitord - * state server and only exists for backwards compatibility. - */ - lxc_monitor_send_state(name, STOPPED, handler->lxcpath); - -+#ifdef HAVE_ISULAD -+ /* isuald: write exit code to exit fifo */ -+ if (handler->conf->exit_fd >= 0) { -+ ret = write(handler->conf->exit_fd, &handler->exit_code, sizeof(int)); -+ if (ret != sizeof(int)) { -+ SYSERROR("Failed to write to exit code to exit fifo."); -+ } -+ } -+#endif ++static int do_path_realloc(const char *start, const char *end, ++ char **rpath, char **dest, const char **rpath_limit) ++{ ++ long long dest_offset = *dest - *rpath; ++ char *new_rpath = NULL; ++ size_t new_size; ++ int nret = 0; ++ size_t gap = 0; + - /* The command socket is closed so no one can acces the command - * socket anymore so there's no need to lock it. - */ -@@ -1060,6 +1309,25 @@ static int do_start(void *data) - - lxc_sync_fini_parent(handler); - -+#ifdef HAVE_ISULAD -+ sigset_t mask; ++ if (*dest + (end - start) < *rpath_limit) { ++ return 0; ++ } + -+ /*isulad: restore default signal handlers and unblock all signals*/ -+ for (int i = 1; i < NSIG; i++) -+ signal(i, SIG_DFL); ++ gap = (size_t)(end - start) + 1; ++ new_size = (size_t)(*rpath_limit - *rpath); ++ if (new_size > SIZE_MAX - gap) { ++ ERROR("Out of range!"); ++ return -1; ++ } + -+ ret = sigfillset(&mask); -+ if (ret < 0) { -+ SYSERROR("Failed to fill signal mask"); -+ goto out_warn_father; ++ if (gap > PATH_MAX) { ++ new_size += gap; ++ } else { ++ new_size += PATH_MAX; + } -+ ret = sigprocmask(SIG_UNBLOCK, &mask, NULL); -+ if (ret < 0) { -+ SYSERROR("Failed to set signal mask"); -+ goto out_warn_father; ++ nret = lxc_mem_realloc((void **)&new_rpath, new_size, *rpath, PATH_MAX); ++ if (nret) { ++ ERROR("Failed to realloc memory for files limit variables"); ++ return -1; + } -+#endif -+ - if (lxc_abstract_unix_recv_one_fd(data_sock1, &status_fd, NULL, 0) < 0) { - ERROR("Failed to receive status file descriptor from parent process"); - goto out_warn_father; -@@ -1153,7 +1421,11 @@ static int do_start(void *data) - * means that migration won't work, but at least we won't spew output - * where it isn't wanted. - */ -+#ifdef HAVE_ISULAD -+ if (!handler->disable_pty && handler->daemonize && !handler->conf->autodev) { -+#else - if (handler->daemonize && !handler->conf->autodev) { -+#endif - char path[PATH_MAX]; - - ret = strnprintf(path, sizeof(path), "%s/dev/null", -@@ -1269,6 +1541,9 @@ static int do_start(void *data) - /* Setup the container, ip, names, utsname, ... */ - ret = lxc_setup(handler); - if (ret < 0) { -+#ifdef HAVE_ISULAD -+ lxc_write_error_message(handler->conf->errpipe[1], "Failed to setup lxc, please check the config file."); -+#endif - ERROR("Failed to setup container \"%s\"", handler->name); - goto out_warn_father; - } -@@ -1291,6 +1566,43 @@ static int do_start(void *data) - DEBUG("Set PR_SET_NO_NEW_PRIVS to block execve() gainable privileges"); - } - -+#ifdef HAVE_ISULAD -+ /* isulad: dup2 pipe[0][0] to container stdin, pipe[1][1] to container stdout, pipe[2][1] to container stderr */ -+ if (handler->disable_pty) { -+ if (handler->conf->console.pipes[0][1] >= 0) { -+ close(handler->conf->console.pipes[0][1]); -+ handler->conf->console.pipes[0][1] = -1; -+ } ++ *rpath = new_rpath; ++ *rpath_limit = *rpath + new_size; + -+ if (handler->conf->console.pipes[0][0] >= 0) { -+ ret = dup2(handler->conf->console.pipes[0][0], STDIN_FILENO); -+ if (ret < 0) -+ goto out_warn_father; -+ } ++ *dest = *rpath + dest_offset; + -+ if (handler->conf->console.pipes[1][0] >= 0) { -+ close(handler->conf->console.pipes[1][0]); -+ handler->conf->console.pipes[1][0] = -1; -+ } ++ return 0; ++} + -+ if (handler->conf->console.pipes[1][1] >= 0) { -+ ret = dup2(handler->conf->console.pipes[1][1], STDOUT_FILENO); -+ if (ret < 0) -+ goto out_warn_father; -+ } -+ if (handler->conf->console.pipes[2][0] >= 0) { -+ close(handler->conf->console.pipes[2][0]); -+ handler->conf->console.pipes[2][0] = -1; ++static int do_get_symlinks_copy_buf(const char *buf, const char *prefix, size_t prefix_len, ++ char **rpath, char **dest) ++{ ++ if (IS_ABSOLUTE_FILE_NAME(buf)) { ++ if (prefix_len) { ++ memcpy(*rpath, prefix, prefix_len); + } -+ -+ if (handler->conf->console.pipes[2][1] >= 0) { -+ ret = dup2(handler->conf->console.pipes[2][1], STDERR_FILENO); -+ if (ret < 0) -+ goto out_warn_father; ++ *dest = *rpath + prefix_len; ++ *(*dest)++ = '/'; ++ } else { ++ if (*dest > *rpath + prefix_len + 1) { ++ for (--(*dest); *dest > *rpath && !ISSLASH((*dest)[-1]); --(*dest)) { ++ continue; ++ } + } + } -+#endif ++ return 0; ++} + - /* If we mounted a temporary proc, then unmount it now. */ - tmp_proc_unmount(handler->conf); - -@@ -1307,7 +1619,11 @@ static int do_start(void *data) - - close_prot_errno_disarm(handler->sigfd); - -+#ifdef HAVE_ISULAD -+ if (!handler->disable_pty && handler->conf->console.pty < 0 && handler->daemonize) { -+#else - if (handler->conf->console.pty < 0 && handler->daemonize) { -+#endif - if (devnull_fd < 0) { - devnull_fd = open_devnull(); - if (devnull_fd < 0) -@@ -1326,6 +1642,16 @@ static int do_start(void *data) - setsid(); - - if (handler->conf->init_cwd) { -+#ifdef HAVE_ISULAD -+ /* try to craete workdir if not exist */ -+ struct stat st; -+ if (stat(handler->conf->init_cwd, &st) < 0 && mkdir_p(handler->conf->init_cwd, 0755) < 0) { -+ SYSERROR("Try to create directory \"%s\" as workdir failed", handler->conf->init_cwd); -+ lxc_write_error_message(handler->conf->errpipe[1], "%s:%d: Failed to create workdir: %s.", -+ __FILE__, __LINE__, strerror(errno)); -+ goto out_warn_father; -+ } -+#endif - ret = chdir(handler->conf->init_cwd); - if (ret < 0) { - SYSERROR("Could not change directory to \"%s\"", -@@ -1372,12 +1698,26 @@ static int do_start(void *data) - } - } - -+#ifdef HAVE_ISULAD -+ if (prctl(PR_SET_KEEPCAPS, 1) < 0) { -+ SYSERROR("Failed to keep permitted capabilities"); -+ goto out_warn_father; -+ } -+#endif ++static int do_get_symlinks(const char **fullpath, const char *prefix, size_t prefix_len, ++ char **rpath, char **dest, const char **end, ++ int *num_links, char **extra_buf) ++{ ++ char *buf = NULL; ++ size_t len; ++ ssize_t n; ++ int ret = -1; + - /* The container has been setup. We can now switch to an unprivileged - * uid/gid. - */ - new_uid = handler->conf->init_uid; - new_gid = handler->conf->init_gid; - -+#ifdef HAVE_ISULAD -+ // isulad: set env home in container, must before "Avoid unnecessary syscalls." -+ if (lxc_setup_env_home(new_uid) < 0) { -+ goto out_warn_father; ++ if (++(*num_links) > MAXSYMLINKS) { ++ ERROR("Too many links in '%s'", *fullpath); ++ goto out; + } -+#endif + - /* Avoid unnecessary syscalls. */ - if (new_uid == nsuid) - new_uid = LXC_INVALID_UID; -@@ -1419,6 +1759,19 @@ static int do_start(void *data) - goto out_warn_father; - } - -+#ifdef HAVE_ISULAD -+ /* isulad: drop the cap of current process */ -+ if (prctl(PR_SET_KEEPCAPS, 0) < 0) { -+ SYSERROR("Failed to clear permitted capabilities"); -+ goto out_warn_father; ++ buf = lxc_common_calloc_s(PATH_MAX); ++ if (buf == NULL) { ++ ERROR("Out of memory"); ++ goto out; + } + -+ if (lxc_drop_caps(handler->conf)) { -+ SYSERROR("Failed to drop caps"); -+ goto out_warn_father; ++ n = readlink(*rpath, buf, PATH_MAX - 1); ++ if (n < 0) { ++ goto out; + } -+#endif ++ buf[n] = '\0'; + - if (handler->conf->monitor_signal_pdeath != SIGKILL) { - ret = lxc_set_death_signal(handler->conf->monitor_signal_pdeath, - handler->monitor_pid, status_fd); -@@ -1433,7 +1786,12 @@ static int do_start(void *data) - * After this call, we are in error because this ops should not return - * as it execs. - */ -+#ifdef HAVE_ISULAD -+ close_prot_errno_disarm(status_fd); -+ handler->ops->start(handler, handler->data, handler->daemonize ? handler->conf->errpipe[1] : -1); -+#else - handler->ops->start(handler, handler->data); -+#endif - - out_warn_father: - /* -@@ -1604,6 +1962,94 @@ static inline void resolve_cgroup_clone_flags(struct lxc_handler *handler) - handler->ns_unshare_flags |= CLONE_NEWCGROUP; - } - -+#ifdef HAVE_ISULAD -+static int lxc_write_container_info(char *filename, pid_t pid, pid_t p_pid, -+ unsigned long long start_at, unsigned long long p_start_at) -+{ -+ FILE *pid_fp = NULL; -+ int ret = 0; ++ if (*extra_buf == NULL) { ++ *extra_buf = lxc_common_calloc_s(PATH_MAX); ++ if (*extra_buf == NULL) { ++ ERROR("Out of memory"); ++ goto out; ++ } ++ } + -+ pid_fp = lxc_fopen(filename, "w"); -+ if (pid_fp == NULL) { -+ SYSERROR("Failed to create pidfile '%s'",filename); -+ ret = -1; ++ len = strlen(*end); ++ if (len >= PATH_MAX - n) { ++ ERROR("Path is too long"); + goto out; + } + -+ if (fprintf(pid_fp, "%d %llu %d %llu\n", pid, start_at, p_pid, p_start_at) < 0) { -+ SYSERROR("Failed to write '%s'", filename); -+ ret = -1; ++ memmove(&(*extra_buf)[n], *end, len + 1); ++ memcpy(*extra_buf, buf, (size_t)n); ++ ++ *fullpath = *end = *extra_buf; ++ ++ if (do_get_symlinks_copy_buf(buf, prefix, prefix_len, rpath, dest) != 0) { + goto out; + } ++ ++ ret = 0; +out: -+ if (pid_fp) -+ fclose(pid_fp); -+ pid_fp = NULL; ++ free(buf); + return ret; +} + -+static int lxc_check_container_info(char *filename, pid_t pid, pid_t p_pid, -+ unsigned long long start_at, unsigned long long p_start_at) ++static bool do_eval_symlinks_in_scope_is_symlink(const char *path) +{ -+ int ret = 0; -+ int num; -+ char sbuf[1024] = {0}; /* bufs for stat */ -+ int saved_pid; /* process id */ -+ int saved_ppid; /* pid of parent process */ -+ unsigned long long saved_start_time; /* start time of process -- seconds since 1-1-70 */ -+ unsigned long long saved_pstart_time; /* start time of parent process -- seconds since 1-1-70 */ -+ -+ if ((lxc_file2str(filename, sbuf, sizeof(sbuf))) == -1) { -+ SYSERROR("Failed to read pidfile %s", filename); -+ ret = -1; -+ goto out; ++ struct stat st; ++ ++ if (lstat(path, &st) < 0) { ++ return true; + } + -+ num = sscanf(sbuf, "%d %Lu %d %Lu", &saved_pid, &saved_start_time, &saved_ppid, &saved_pstart_time); -+ if (num != 4) { -+ SYSERROR("Call sscanf error"); -+ ret = -1; -+ goto out; ++ if (!S_ISLNK(st.st_mode)) { ++ return true; + } ++ return false; ++} + -+ if (pid != saved_pid || p_pid != saved_ppid -+ || start_at != saved_start_time || p_start_at != saved_pstart_time) { -+ ERROR("Check container info failed"); -+ ret = -1; -+ goto out; ++static void do_eval_symlinks_skip_slash(const char **start, const char **end) ++{ ++ while (ISSLASH(**start)) { ++ ++(*start); + } + -+out: -+ return ret; ++ for (*end = *start; **end && !ISSLASH(**end); ++(*end)) { ++ } +} + -+/* isuald: save pid/ppid info */ -+static int lxc_save_container_info(char *filename, pid_t pid) ++static inline void skip_dest_traling_slash(char **dest, char **rpath, size_t prefix_len) +{ -+ int ret = 0; -+ pid_t p_pid = 0; -+ unsigned long long start_at = 0; -+ unsigned long long p_start_at = 0; ++ if (*dest > *rpath + prefix_len + 1) { ++ for (--(*dest); *dest > *rpath && !ISSLASH((*dest)[-1]); --(*dest)) { ++ continue; ++ } ++ } ++} + -+ start_at = lxc_get_process_startat(pid); -+ p_pid = getpid(); -+ p_start_at = lxc_get_process_startat(p_pid); ++static inline bool is_current_char(const char c) ++{ ++ return c == '.'; ++} + -+ ret = lxc_write_container_info(filename, pid, p_pid, start_at, p_start_at); -+ if (ret != 0) { -+ goto out; -+ } ++static inline bool is_specify_current(const char *end, const char *start) ++{ ++ return (end - start == 1) && is_current_char(start[0]); ++} + -+ ret = lxc_check_container_info(filename, pid, p_pid, start_at, p_start_at); -+ if (ret != 0) { -+ goto out; -+ } ++static inline bool is_specify_parent(const char *end, const char *start) ++{ ++ return (end - start == 2) && is_current_char(start[0]) && is_current_char(start[1]); ++} ++ ++static int do_eval_symlinks_in_scope(const char *fullpath, const char *prefix, ++ size_t prefix_len, ++ char **rpath, char **dest, const char *rpath_limit) ++{ ++ const char *start = NULL; ++ const char *end = NULL; ++ char *extra_buf = NULL; ++ int nret = 0; ++ int num_links = 0; ++ ++ start = fullpath + prefix_len; ++ for (end = start; *start; start = end) { ++ do_eval_symlinks_skip_slash(&start, &end); ++ if (end - start == 0) { ++ break; ++ } else if (is_specify_current(end, start)) { ++ ; ++ } else if (is_specify_parent(end, start)) { ++ skip_dest_traling_slash(dest, rpath, prefix_len); ++ } else { ++ if (!ISSLASH((*dest)[-1])) { ++ *(*dest)++ = '/'; ++ } ++ ++ nret = do_path_realloc(start, end, rpath, dest, &rpath_limit); ++ if (nret != 0) { ++ nret = -1; ++ goto out; ++ } ++ ++ memcpy(*dest, start, (size_t)(end - start)); ++ *dest += end - start; ++ **dest = '\0'; ++ ++ if (do_eval_symlinks_in_scope_is_symlink(*rpath)) { ++ continue; ++ } + ++ nret = do_get_symlinks(&fullpath, prefix, prefix_len, rpath, dest, &end, &num_links, &extra_buf); ++ if (nret != 0) { ++ nret = -1; ++ goto out; ++ } ++ } ++ } +out: -+ return ret; ++ free(extra_buf); ++ return nret; +} -+#endif ++static char *eval_symlinks_in_scope(const char *fullpath, const char *rootpath) ++{ ++ char resroot[PATH_MAX] = {0}; ++ char *root = NULL; ++ char *rpath = NULL; ++ char *dest = NULL; ++ char *prefix = NULL; ++ const char *rpath_limit = NULL; ++ size_t prefix_len; + - /* lxc_spawn() performs crucial setup tasks and clone()s the new process which - * exec()s the requested container binary. - * Note that lxc_spawn() runs in the parent namespaces. Any operations performed -@@ -1741,6 +2187,32 @@ static int lxc_spawn(struct lxc_handler *handler) - handler->clone_flags &= ~CLONE_PIDFD; - TRACE("Cloned child process %d", handler->pid); - -+#ifdef HAVE_ISULAD -+ /* isulad: close pipe after clone */ -+ if (handler->conf->console.pipes[0][0] >= 0) { -+ close(handler->conf->console.pipes[0][0]); -+ handler->conf->console.pipes[0][0] = -1; ++ if (fullpath == NULL || rootpath == NULL) { ++ return NULL; + } + -+ if (handler->conf->console.pipes[1][1] >= 0) { -+ close(handler->conf->console.pipes[1][1]); -+ handler->conf->console.pipes[1][1] = -1; ++ root = cleanpath(rootpath, resroot, sizeof(resroot)); ++ if (root == NULL) { ++ ERROR("Failed to get cleaned path"); ++ return NULL; + } + -+ if (handler->conf->console.pipes[2][1] >= 0) { -+ close(handler->conf->console.pipes[2][1]); -+ handler->conf->console.pipes[2][1] = -1; ++ if (!strcmp(fullpath, root)) { ++ return safe_strdup(fullpath); + } + -+ /* isulad: save pid/ppid info into file*/ -+ if (handler->conf->container_info_file) { -+ if (lxc_save_container_info(handler->conf->container_info_file, handler->pid)) { -+ ERROR("Failed to save cloned container pid"); -+ goto out_delete_net; -+ } ++ if (strstr(fullpath, root) == NULL) { ++ ERROR("Path '%s' is not in '%s'", fullpath, root); ++ return NULL; + } -+#endif + - ret = core_scheduling(handler); - if (ret < 0) - goto out_delete_net; -@@ -1757,6 +2229,13 @@ static int lxc_spawn(struct lxc_handler *handler) - if (ret < 0) - SYSERROR("Failed to set environment variable: LXC_PID=%s", pidstr); - -+#ifdef HAVE_ISULAD -+ if (handler->cgroup_ops->container_cgroup) { -+ if (setenv("LXC_CGROUP_PATH", handler->cgroup_ops->container_cgroup, 1)) -+ SYSERROR("Failed to set environment variable: LXC_CGROUP_PATH=%s.", handler->cgroup_ops->container_cgroup); ++ rpath = lxc_common_calloc_s(PATH_MAX); ++ if (rpath == NULL) { ++ ERROR("Out of memory"); ++ goto out; + } -+#endif ++ rpath_limit = rpath + PATH_MAX; + - for (i = 0; i < LXC_NS_MAX; i++) - if (handler->ns_on_clone_flags & ns_info[i].clone_flag) - INFO("Cloned %s", ns_info[i].flag_name); -@@ -1848,7 +2327,11 @@ static int lxc_spawn(struct lxc_handler *handler) - goto out_delete_net; - } - -+#ifdef HAVE_ISULAD -+ ret = setup_resource_limits(conf, handler->pid, conf->errpipe[1]); -+#else - ret = setup_resource_limits(conf, handler->pid); -+#endif - if (ret < 0) { - ERROR("Failed to setup resource limits"); - goto out_delete_net; -@@ -1911,6 +2394,27 @@ static int lxc_spawn(struct lxc_handler *handler) - goto out_delete_net; - } - -+#ifdef HAVE_ISULAD -+ /* isulad: Run oci prestart hook at here */ -+ ret = run_oci_hooks(name, "oci-prestart", conf, lxcpath); -+ if (ret < 0) { -+ ERROR("Failed to run oci prestart hooks"); -+ goto out_delete_net; ++ prefix = root; ++ prefix_len = (size_t)strlen(prefix); ++ if (!strcmp(prefix, "/")) { ++ prefix_len = 0; + } + -+ if (START_TIMEOUT == global_timeout_state) { -+ lxc_write_error_message(conf->errpipe[1], "Starting the container \"%s\" timeout.", name); -+ ERROR("Starting the container \"%s\" timeout.", name); -+ goto out_delete_net; ++ dest = rpath; ++ if (prefix_len) { ++ memcpy(rpath, prefix, prefix_len); ++ dest += prefix_len; + } ++ *dest++ = '/'; + -+ /* Tell the child to continue its initialization. We'll get -+ * LXC_SYNC_POST_OCI_PRESTART_HOOK when it is ready for us to run oci prestart hooks. -+ */ -+ if (lxc_sync_barrier_child(handler, LXC_SYNC_POST_OCI_PRESTART_HOOK)) -+ goto out_delete_net; -+#endif -+ - if (!lxc_sync_wake_child(handler, START_SYNC_FDS)) - goto out_delete_net; - -@@ -1969,6 +2473,22 @@ static int lxc_spawn(struct lxc_handler *handler) - if (ret < 0) - goto out_abort; - -+#ifdef HAVE_ISULAD -+ /* isulad: Run oci prestart hook at here */ -+ ret = run_oci_hooks(name, "oci-poststart", conf, lxcpath); -+ if (ret < 0) { -+ ERROR("Failed to run oci poststart hooks"); -+ goto out_abort; ++ if (do_eval_symlinks_in_scope(fullpath, prefix, prefix_len, &rpath, &dest, ++ rpath_limit)) { ++ goto out; + } + -+ if (START_TIMEOUT == global_timeout_state) { -+ lxc_write_error_message(conf->errpipe[1], "Starting the container \"%s\" timeout.", name); -+ ERROR("Starting the container \"%s\" timeout.", name); -+ goto out_abort; ++ if (dest > rpath + prefix_len + 1 && ISSLASH(dest[-1])) { ++ --dest; + } ++ *dest = '\0'; ++ return rpath; + -+#endif ++out: ++ free(rpath); ++ return NULL; ++} + - ret = lxc_set_state(name, handler, RUNNING); - if (ret < 0) { - ERROR("Failed to set state to \"%s\"", lxc_state2str(RUNNING)); -@@ -2014,9 +2534,82 @@ static int lxc_inherit_namespaces(struct lxc_handler *handler) - return 0; - } - -+#ifdef HAVE_ISULAD -+/* isulad: start timeout thread function */ -+static void* wait_start_timeout(void *arg) ++// FollowSymlinkInScope is a wrapper around evalSymlinksInScope that returns an ++// absolute path. This function handles paths in a platform-agnostic manner. ++char *follow_symlink_in_scope(const char *fullpath, const char *rootpath) +{ -+ struct start_timeout_conf *conf = (struct start_timeout_conf *)arg; -+ -+ sem_post(&global_timeout_sem); -+ -+ if (!conf || conf->timeout < 1) -+ goto out; ++ char resfull[PATH_MAX] = {0}, *full = NULL; ++ char resroot[PATH_MAX] = {0}, *root = NULL; + -+ sleep(conf->timeout); ++ full = cleanpath(fullpath, resfull, PATH_MAX); ++ if (!full) { ++ ERROR("Failed to get cleaned path"); ++ return NULL; ++ } + -+ global_timeout_state = START_TIMEOUT; ++ root = cleanpath(rootpath, resroot, PATH_MAX); ++ if (!root) { ++ ERROR("Failed to get cleaned path"); ++ return NULL; ++ } + -+out: -+ free(conf); -+ return ((void *)0); ++ return eval_symlinks_in_scope(full, root); +} + -+/* isulad: create start timeout thread */ -+static int create_start_timeout_thread(struct lxc_conf *conf, unsigned int start_timeout) ++// GetResourcePath evaluates `path` in the scope of the container's rootpath, with proper path ++// sanitisation. Symlinks are all scoped to the rootpath of the container, as ++// though the container's rootpath was `/`. ++// ++// The BaseFS of a container is the host-facing path which is bind-mounted as ++// `/` inside the container. This method is essentially used to access a ++// particular path inside the container as though you were a process in that ++// container. ++int get_resource_path(const char *rootpath, const char *path, ++ char **scopepath) +{ -+ int ret = 0; -+ pthread_t ptid; -+ pthread_attr_t attr; -+ struct start_timeout_conf *timeout_conf = NULL; ++ char resolved[PATH_MAX] = {0}, *cleanedpath = NULL; ++ char *fullpath = NULL; ++ size_t len; + -+ if (sem_init(&global_timeout_sem, 0, 0)) { -+ ERROR("Failed to init start timeout semaphore");/*lint !e613*/ -+ ret = -1; -+ return ret; -+ } ++ if (!rootpath || !path || !scopepath) ++ return -1; + -+ timeout_conf = malloc(sizeof(struct start_timeout_conf)); -+ if (timeout_conf == NULL) { -+ ERROR("Failed to malloc start timeout conf"); -+ ret = -1; -+ goto out; -+ } ++ *scopepath = NULL; + -+ memset(timeout_conf, 0, sizeof(struct start_timeout_conf)); -+ timeout_conf->errfd = conf->errpipe[1]; -+ timeout_conf->timeout = start_timeout; ++ cleanedpath = cleanpath(path, resolved, PATH_MAX); ++ if (!cleanedpath) { ++ ERROR("Failed to get cleaned path"); ++ return -1; ++ } + -+ pthread_attr_init(&attr); -+ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); -+ ret = pthread_create(&ptid, &attr, wait_start_timeout, timeout_conf); -+ pthread_attr_destroy(&attr); -+ if (ret != 0) { -+ ERROR("Create start wait timeout thread failed"); -+ free(timeout_conf); -+ goto out; ++ len = strlen(rootpath) + strlen(cleanedpath) + 1; ++ fullpath = malloc(len); ++ if (!fullpath) { ++ ERROR("Out of memory"); ++ return -1; + } ++ snprintf(fullpath, len, "%s%s", rootpath, cleanedpath); + -+ sem_wait(&global_timeout_sem); -+out: -+ sem_destroy(&global_timeout_sem); -+ return ret; -+} ++ *scopepath = follow_symlink_in_scope(fullpath, rootpath); + -+// isulad: send '128 + signal' if container is killed by signal. -+#define EXIT_SIGNAL_OFFSET 128 -+#endif ++ free(fullpath); ++ return 0; ++} + -+#ifdef HAVE_ISULAD -+int __lxc_start(struct lxc_handler *handler, struct lxc_operations *ops, -+ void *data, const char *lxcpath, bool daemonize, int *error_num, -+ unsigned int start_timeout) ++// Rel returns a relative path that is lexically equivalent to targpath when ++// joined to basepath with an intervening separator. That is, ++// Join(basepath, Rel(basepath, targpath)) is equivalent to targpath itself. ++// On success, the returned path will always be relative to basepath, ++// even if basepath and targpath share no elements. ++// An error is returned if targpath can't be made relative to basepath or if ++// knowing the current working directory would be necessary to compute it. ++// Rel calls Clean on the result. ++char *path_relative(const char *basepath, const char *targpath) +{ -+ int exit_code; -+#else - int __lxc_start(struct lxc_handler *handler, struct lxc_operations *ops, - void *data, const char *lxcpath, bool daemonize, int *error_num) - { -+#endif - int ret, status; - const char *name = handler->name; - struct lxc_conf *conf = handler->conf; -@@ -2032,6 +2625,17 @@ int __lxc_start(struct lxc_handler *handler, struct lxc_operations *ops, - handler->daemonize = daemonize; - cgroup_ops = handler->cgroup_ops; - -+#ifdef HAVE_ISULAD -+ /* isulad: add start timeout limit */ -+ if (start_timeout > 0) { -+ ret = create_start_timeout_thread(conf, start_timeout); -+ if (ret) { -+ ERROR("Failed to create start timeout thread for container \"%s\".", name); -+ goto out_abort; ++ char resbase[PATH_MAX] = {0}, *base = NULL; ++ char restarg[PATH_MAX] = {0}, *targ = NULL; ++ size_t bl = 0, tl = 0, b0 = 0, bi = 0, t0 = 0, ti = 0; ++ ++ base = cleanpath(basepath, resbase, PATH_MAX); ++ if (!base) { ++ ERROR("Failed to get cleaned path"); ++ return NULL; ++ } ++ ++ targ = cleanpath(targpath, restarg, PATH_MAX); ++ if (!targ) { ++ ERROR("Failed to get cleaned path"); ++ return NULL; ++ } ++ ++ if (strcmp(base, targ) == 0) ++ return safe_strdup("."); ++ ++ bl = strlen(base); ++ tl = strlen(targ); ++ while(true) { ++ while(bi < bl && !ISSLASH(base[bi])) ++ bi++; ++ while(ti < tl && !ISSLASH(targ[ti])) ++ ti++; ++ //not the same string ++ if (((bi - b0) != (ti - t0)) || strncmp(base + b0, targ + t0, bi - b0)) ++ break; ++ if (bi < bl) ++ bi++; ++ if (ti < tl) ++ ti++; ++ b0 = bi; ++ t0 = ti; ++ } ++ ++ if (b0 != bl) { ++ // Base elements left. Must go up before going down. ++ int seps = 0, i; ++ size_t ncopyed = 0, seps_size; ++ char *buf = NULL; ++ ++ for (bi = b0; bi < bl; bi++) { ++ if (ISSLASH(base[bi])) ++ seps++; ++ } ++ //strlen(..) + strlen(/..) + '\0' ++ seps_size = 2 + seps * 3 + 1; ++ if (t0 != tl) ++ seps_size += 1 + tl - t0; ++ ++ buf = calloc(seps_size, 1); ++ if (!buf) { ++ ERROR("Out of memory"); ++ return NULL; + } ++ buf[ncopyed++] = '.'; ++ buf[ncopyed++] = '.'; ++ for (i = 0; i < seps; i++) { ++ buf[ncopyed++] = '/'; ++ buf[ncopyed++] = '.'; ++ buf[ncopyed++] = '.'; ++ } ++ if (t0 != tl) { ++ buf[ncopyed++] = '/'; ++ memcpy(buf + ncopyed, targ + t0, tl - t0 + 1); ++ } ++ return buf; + } -+#endif + - if (!attach_block_device(handler->conf)) { - ERROR("Failed to attach block device"); - ret = -1; -@@ -2116,11 +2720,13 @@ int __lxc_start(struct lxc_handler *handler, struct lxc_operations *ops, - goto out_delete_network; - } - -+#ifndef HAVE_ISULAD - if (!handler->init_died && handler->pid > 0) { - ERROR("Child process is not killed"); - ret = -1; - goto out_delete_network; - } -+#endif ++ return safe_strdup(targ + t0); ++} +\ No newline at end of file +diff --git a/src/lxc/storage/dir.c b/src/lxc/storage/dir.c +index 18a10a4..dc642a4 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, - status = lxc_wait_for_pid_status(handler->pid); - if (status < 0) -@@ -2130,6 +2736,20 @@ int __lxc_start(struct lxc_handler *handler, struct lxc_operations *ops, - * reboot. This should mean it was an lxc-execute which simply exited. - * In any case, treat it as a 'halt'. - */ + int dir_destroy(struct lxc_storage *orig) + { +#ifdef HAVE_ISULAD -+ // isulad: recored log for container init exit -+ if (WIFSIGNALED(status)) { -+ int signal_nr = WTERMSIG(status); -+ exit_code = EXIT_SIGNAL_OFFSET + signal_nr; -+ ERROR("Container \"%s\" init exited with signal %d", name, signal_nr); -+ } else if (WIFEXITED(status)) { -+ exit_code = WEXITSTATUS(status); -+ ERROR("Container \"%s\" init exited with status %d", name, exit_code); -+ } else { -+ exit_code = -1; -+ ERROR("Container \"%s\" init exited with unknown status", name); -+ } ++ // isulad: do not destroy rootfs for directory, it should be managed by caller +#else - if (WIFSIGNALED(status)) { - int signal_nr = WTERMSIG(status); - switch(signal_nr) { -@@ -2148,16 +2768,25 @@ int __lxc_start(struct lxc_handler *handler, struct lxc_operations *ops, - break; - } - } -+#endif + int ret; + const char *src; - ret = lxc_restore_phys_nics_to_netns(handler); +@@ -102,6 +105,7 @@ int dir_destroy(struct lxc_storage *orig) + ret = lxc_rmdir_onedev(src, NULL); if (ret < 0) - ERROR("Failed to move physical network devices back to parent network namespace"); - -+#ifdef HAVE_ISULAD -+ lxc_monitor_send_exit_code(name, exit_code, handler->lxcpath); -+#else - lxc_monitor_send_exit_code(name, status, handler->lxcpath); + return log_error_errno(ret, errno, "Failed to delete \"%s\"", src); +#endif - lxc_error_set_and_log(handler->pid, status); - if (error_num) - *error_num = handler->exit_status; -+#ifdef HAVE_ISULAD -+ handler->exit_code = exit_code; /* record exit code */ -+#endif -+ - lxc_delete_network(handler); - detach_block_device(handler->conf); - lxc_end(handler); -@@ -2187,7 +2816,11 @@ struct start_args { - char *const *argv; - }; + return 0; + } +@@ -124,6 +128,35 @@ bool dir_detect(const char *path) + return false; + } +#ifdef HAVE_ISULAD -+static int start(struct lxc_handler *handler, void* data, int fd) ++int dir_mount(struct lxc_storage *bdev) ++{ ++ __do_free char *mntdata = NULL; ++ unsigned long mntflags = 0, pflags = 0; ++ int ret; ++ const char *src; ++ ++ if (strcmp(bdev->type, "dir")) ++ return -22; ++ ++ if (!bdev->src || !bdev->dest) ++ return -22; ++ ++ ret = parse_mntopts(bdev->mntopts, &mntflags, &pflags, &mntdata); ++ if (ret < 0) ++ return log_error_errno(ret, errno, "Failed to parse mount options \"%s\"", bdev->mntopts); ++ ++ src = lxc_storage_get_path(bdev->src, bdev->type); ++ ++ ret = mount(src, bdev->dest, "bind", MS_BIND | MS_REC | (mntflags & ~MS_RDONLY) | pflags, mntdata); ++ if (ret < 0) { ++ return log_error_errno(-errno, errno, "Failed to mount \"%s\" on \"%s\"", src, bdev->dest); ++ } ++ TRACE("Mounted \"%s\" on \"%s\"", src, bdev->dest); ++ ++ return 0; ++} +#else - static int start(struct lxc_handler *handler, void* data) -+#endif + int dir_mount(struct lxc_storage *bdev) { - struct start_args *arg = data; - -@@ -2195,6 +2828,9 @@ static int start(struct lxc_handler *handler, void* data) - - execvp(arg->argv[0], arg->argv); - SYSERROR("Failed to exec \"%s\"", arg->argv[0]); -+#ifdef HAVE_ISULAD -+ lxc_write_error_message(fd, "exec: \"%s\": %s.", arg->argv[0], strerror(errno)); -+#endif + __do_free char *mntdata = NULL; +@@ -166,6 +199,7 @@ int dir_mount(struct lxc_storage *bdev) + src ? src : "(none)", bdev->dest ? bdev->dest : "(none)", mntdata, mflags, pflags); return 0; } ++#endif -@@ -2212,14 +2848,22 @@ static struct lxc_operations start_ops = { - }; - - int lxc_start(char *const argv[], struct lxc_handler *handler, + int dir_umount(struct lxc_storage *bdev) + { +diff --git a/src/lxc/storage/loop.c b/src/lxc/storage/loop.c +index eebc1b6..3a97c1d 100644 +--- a/src/lxc/storage/loop.c ++++ b/src/lxc/storage/loop.c +@@ -21,6 +21,9 @@ + #include "memory_utils.h" + #include "storage.h" + #include "storage_utils.h" +#ifdef HAVE_ISULAD -+ const char *lxcpath, bool daemonize, int *error_num, unsigned int start_timeout) -+#else - const char *lxcpath, bool daemonize, int *error_num) ++#include "lxclock.h" +#endif - { - struct start_args start_arg = { - .argv = argv, - }; + #include "utils.h" - TRACE("Doing lxc_start"); + lxc_log_define(loop, lxc); +@@ -216,7 +219,13 @@ bool loop_detect(const char *path) + + int loop_mount(struct lxc_storage *bdev) + { +#ifdef HAVE_ISULAD -+ return __lxc_start(handler, &start_ops, &start_arg, lxcpath, daemonize, error_num, start_timeout); ++ int ret = 0; ++ int loopfd, lret; ++ struct lxc_lock *l = NULL; +#else - return __lxc_start(handler, &start_ops, &start_arg, lxcpath, daemonize, error_num); + int ret, loopfd; +#endif - } + char loname[PATH_MAX]; + const char *src; - static void lxc_destroy_container_on_signal(struct lxc_handler *handler, -@@ -2291,3 +2935,261 @@ static bool do_destroy_container(struct lxc_handler *handler) +@@ -226,13 +235,35 @@ int loop_mount(struct lxc_storage *bdev) + if (!bdev->src || !bdev->dest) + return -22; - return storage_destroy(handler->conf); - } -+ +#ifdef HAVE_ISULAD -+/*isulad: set env for clean resources */ -+static int clean_resource_set_env(struct lxc_handler *handler) -+{ -+ const char *name = handler->name; -+ struct lxc_conf *conf = handler->conf; -+ char bufstr[PATH_MAX + 1]; -+ int i = 0; -+ int j = 0; -+ int len = 2; //set "LXC_PID" and "LXC_CGNS_AWARE" -+ -+ if (conf == NULL || conf->ocihooks == NULL || conf->ocihooks->poststop_len == 0) { -+ return 0; -+ } -+ -+ if (name) { -+ len++; -+ } -+ if (conf->rcfile) { -+ len++; -+ } -+ if (conf->rootfs.mount) { -+ len++; -+ } -+ if (conf->rootfs.path) { -+ len++; -+ } -+ if (conf->console.path) { -+ len++; -+ } -+ if (conf->console.log_path) { -+ len++; -+ } -+ if (handler->cgroup_ops->container_cgroup) { -+ len++; -+ } -+ -+ for (; i < conf->ocihooks->poststop_len; i++) { -+ size_t cap = conf->ocihooks->poststop[i]->env_len; -+ size_t newcap = cap + len + 1; -+ if (lxc_grow_array((void ***)&(conf->ocihooks->poststop[i]->env), &cap, newcap, 1) != 0) { -+ return -1; -+ } -+ j = conf->ocihooks->poststop[i]->env_len; -+ /* Start of environment variable setup for hooks. */ -+ if (name) { -+ snprintf(bufstr, PATH_MAX + 1, "LXC_NAME=%s", name); -+ conf->ocihooks->poststop[i]->env[j++] = safe_strdup(bufstr); -+ } -+ if (conf->rcfile) { -+ snprintf(bufstr, PATH_MAX + 1, "LXC_CONFIG_FILE=%s", conf->rcfile); -+ conf->ocihooks->poststop[i]->env[j++] = safe_strdup(bufstr); -+ } -+ if (conf->rootfs.mount) { -+ snprintf(bufstr, PATH_MAX + 1, "LXC_ROOTFS_MOUNT=%s", conf->rootfs.mount); -+ conf->ocihooks->poststop[i]->env[j++] = safe_strdup(bufstr); -+ } -+ if (conf->rootfs.path) { -+ snprintf(bufstr, PATH_MAX + 1, "LXC_ROOTFS_PATH=%s", conf->rootfs.path); -+ conf->ocihooks->poststop[i]->env[j++] = safe_strdup(bufstr); -+ } -+ if (conf->console.path) { -+ snprintf(bufstr, PATH_MAX + 1, "LXC_CONSOLE=%s", conf->console.path); -+ conf->ocihooks->poststop[i]->env[j++] = safe_strdup(bufstr); -+ } -+ if (conf->console.log_path) { -+ snprintf(bufstr, PATH_MAX + 1, "LXC_CONSOLE_LOGPATH=%s", conf->console.log_path); -+ conf->ocihooks->poststop[i]->env[j++] = safe_strdup(bufstr); -+ } -+ conf->ocihooks->poststop[i]->env[j++] = safe_strdup("LXC_CGNS_AWARE=1"); -+ -+ snprintf(bufstr, PATH_MAX + 1, "LXC_PID=%d", handler->pid); -+ conf->ocihooks->poststop[i]->env[j++] = safe_strdup(bufstr); -+ if (handler->cgroup_ops->container_cgroup) { -+ snprintf(bufstr, PATH_MAX + 1, "LXC_CGROUP_PATH=%s", handler->cgroup_ops->container_cgroup); -+ conf->ocihooks->poststop[i]->env[j++] = safe_strdup(bufstr); -+ } -+ conf->ocihooks->poststop[i]->env_len = j; -+ /* End of environment variable setup for hooks. */ -+ } -+ return 0; -+} -+ -+/*isulad: init handler for clean */ -+static struct lxc_handler *lxc_init_clean_handler(char *name, char *lxcpath, struct lxc_conf *conf, pid_t pid) -+{ -+ int i; -+ struct lxc_handler *handler; -+ -+ handler = malloc(sizeof(*handler)); -+ if (handler == NULL) -+ return NULL; -+ -+ memset(handler, 0, sizeof(*handler)); -+ -+ /* Note that am_guest_unpriv() checks the effective uid. We -+ * probably don't care if we are real root only if we are running -+ * as root so this should be fine. -+ */ -+ handler->am_root = !am_guest_unpriv(); -+ handler->data_sock[0] = handler->data_sock[1] = -1; -+ handler->conf = conf; -+ handler->lxcpath = lxcpath; -+ handler->pinfd = -1; -+ handler->sigfd = -EBADF; -+ handler->pidfd = -EBADF; -+ handler->init_died = false; -+ handler->monitor_status_fd = -EBADF; -+ handler->pid = pid; -+ handler->state_socket_pair[0] = handler->state_socket_pair[1] = -1; -+ if (handler->conf->reboot == REBOOT_NONE) -+ lxc_list_init(&handler->conf->state_clients); -+ -+ for (i = 0; i < LXC_NS_MAX; i++) -+ handler->nsfd[i] = -1; -+ -+ handler->name = name; -+ handler->exit_code = -1; /* isulad: record exit code of container */ -+ -+ handler->cgroup_ops = cgroup_init(conf); -+ if (!handler->cgroup_ops) { -+ ERROR("Failed to initialize cgroup driver"); -+ goto on_error; -+ } -+ -+ INFO("Container \"%s\" 's clean handler is initialized.", name); -+ -+ return handler; -+ -+on_error: -+ lxc_put_handler(handler); -+ -+ return NULL; -+} -+ -+/*isulad: init handler for clean */ -+static struct lxc_handler *lxc_init_pids_handler(char *name, char *lxcpath, struct lxc_conf *conf) -+{ -+ int i; -+ struct lxc_handler *handler; -+ -+ handler = malloc(sizeof(*handler)); -+ if (handler == NULL) -+ return NULL; -+ -+ memset(handler, 0, sizeof(*handler)); -+ -+ /* Note that am_guest_unpriv() checks the effective uid. We -+ * probably don't care if we are real root only if we are running -+ * as root so this should be fine. -+ */ -+ handler->am_root = !am_guest_unpriv(); -+ handler->data_sock[0] = handler->data_sock[1] = -1; -+ handler->conf = conf; -+ handler->lxcpath = lxcpath; -+ handler->pinfd = -1; -+ handler->sigfd = -EBADF; -+ handler->init_died = false; -+ handler->state_socket_pair[0] = handler->state_socket_pair[1] = -1; -+ handler->monitor_status_fd = -EBADF; -+ handler->pidfd = -EBADF; -+ if (handler->conf->reboot == REBOOT_NONE) -+ lxc_list_init(&handler->conf->state_clients); -+ -+ for (i = 0; i < LXC_NS_MAX; i++) -+ handler->nsfd[i] = -1; -+ -+ handler->name = name; -+ handler->exit_code = -1; /* isulad: record exit code of container */ -+ -+ handler->cgroup_ops = cgroup_init(conf); -+ if (!handler->cgroup_ops) { -+ ERROR("Failed to initialize cgroup driver"); -+ goto on_error; ++ /* 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; + } + -+ INFO("Container \"%s\" 's clean handler is initialized.", name); -+ -+ return handler; -+ -+on_error: -+ lxc_put_handler(handler); -+ -+ return NULL; -+} -+ -+/*isulad: do_lxcapi_clean_resource */ -+int do_lxcapi_clean_resource(char *name, char *lxcpath, struct lxc_conf *conf, pid_t pid) -+{ -+ int ret = 0; -+ struct lxc_handler *handler = NULL; -+ int retry_count = 0; -+ int max_retry = 10; -+ -+ handler = lxc_init_clean_handler(name, lxcpath, conf, pid); -+ if (!handler) { -+ ERROR("Failed to init container %s clean handler", name); ++ lret = lxclock(l, 0); ++ if (lret) { ++ SYSERROR("try to lock failed when mount fs"); + ret = -1; + goto out; + } ++#endif + -+ if (clean_resource_set_env(handler) != 0) { -+ ERROR("Failed to set env for poststop hooks"); + /* 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 + ret = -1; + goto out; -+ } -+ -+ if (run_oci_hooks(handler->name, "oci-poststop", handler->conf, handler->lxcpath)) { -+ ERROR("Failed to run lxc.hook.post-stop for container \"%s\".", handler->name); -+ ret = -1; -+ } -+ -+retry: -+ if (!handler->cgroup_ops->payload_destroy(handler->cgroup_ops, handler)) { -+ TRACE("Trying to kill all subprocess"); -+ signal_all_processes(handler); -+ TRACE("Finished kill all subprocess"); -+ if (retry_count < max_retry) { -+ usleep(100 * 1000); /* 100 millisecond */ -+ retry_count++; -+ goto retry; -+ } -+ SYSERROR("Failed to destroy cgroup path for container: \"%s\"", handler->name); ++#else + return -1; ++#endif + } + DEBUG("Prepared loop device \"%s\"", loname); + +@@ -241,14 +272,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 + ret = -1; -+ } -+ ++ 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 +out: -+ lxc_put_handler(handler); -+ return ret; -+} -+ -+/*isulad: do_lxcapi_get_pids */ -+int do_lxcapi_get_pids(char *name, char *lxcpath, struct lxc_conf *conf, pid_t **pids,size_t *pids_len) -+{ -+ int ret = 0; -+ struct lxc_handler *handler = NULL; -+ struct cgroup_ops *cg_ops = NULL; -+ -+ handler = lxc_init_pids_handler(name, lxcpath, conf); -+ if (!handler) { -+ ERROR("Failed to init container %s clean handler", name); ++ lret = lxcunlock(l); ++ if (lret) { ++ SYSERROR("try to unlock failed when mount fs"); + ret = -1; -+ goto out; -+ } -+ -+ cg_ops = handler->cgroup_ops; -+ ret = get_all_pids(cg_ops, pids, pids_len); -+ if (ret < 0) { -+ WARN("failed to get all pids"); + } -+ -+out: -+ lxc_put_handler(handler); ++ lxc_putlock(l); + return ret; -+} -+ ++#else + return 0; +#endif -diff --git a/src/lxc/start.h b/src/lxc/start.h -index bbd1a83..d03e5d5 100644 ---- a/src/lxc/start.h -+++ b/src/lxc/start.h -@@ -153,7 +153,11 @@ struct execute_args { - }; + } - struct lxc_operations { + int loop_umount(struct lxc_storage *bdev) +diff --git a/src/lxc/storage/storage.c b/src/lxc/storage/storage.c +index 3f1b713..371513d 100644 +--- a/src/lxc/storage/storage.c ++++ b/src/lxc/storage/storage.c +@@ -41,6 +41,9 @@ + #include "storage_utils.h" + #include "utils.h" + #include "zfs.h" +#ifdef HAVE_ISULAD -+ int (*start)(struct lxc_handler *, void *, int); -+#else - int (*start)(struct lxc_handler *, void *); ++#include "block.h" +#endif - int (*post_start)(struct lxc_handler *, void *); - }; -@@ -184,12 +188,26 @@ static inline int inherit_fds(struct lxc_handler *handler, bool closeall) - ARRAY_SIZE(handler->keep_fds)); - } + #ifndef HAVE_STRLCPY + #include "include/strlcpy.h" +@@ -94,6 +97,22 @@ static const struct lxc_storage_ops loop_ops = { + .can_backup = true, + }; +#ifdef HAVE_ISULAD -+__hidden extern int __lxc_start(struct lxc_handler *handler, -+ struct lxc_operations* ops, void *data, const char *lxcpath, -+ bool daemonize, int *error_num, unsigned int start_timeout); -+#else - __hidden extern int __lxc_start(struct lxc_handler *, struct lxc_operations *, void *, const char *, - bool, int *); ++/* block */ ++static const struct lxc_storage_ops blk_ops = { ++ .detect = &blk_detect, ++ .mount = &blk_mount, ++ .umount = &blk_umount, ++ .clone_paths = NULL, ++ .destroy = &blk_destroy, ++ .create = NULL, ++ .copy = NULL, ++ .snapshot = NULL, ++ .can_snapshot = false, ++ .can_backup = true, ++}; ++#endif ++ + /* lvm */ + static const struct lxc_storage_ops lvm_ops = { + .detect = &lvm_detect, +@@ -179,6 +198,10 @@ static const struct lxc_storage_type bdevs[] = { + { .name = "overlayfs", .ops = &ovl_ops, }, + { .name = "loop", .ops = &loop_ops, }, + { .name = "nbd", .ops = &nbd_ops, }, ++#ifdef HAVE_ISULAD ++ //isulad: block device ++ { .name = "blk", .ops = &blk_ops, } +#endif + }; - __hidden extern int resolve_clone_flags(struct lxc_handler *handler); - __hidden extern void lxc_expose_namespace_environment(const struct lxc_handler *handler); + static const size_t numbdevs = sizeof(bdevs) / sizeof(struct lxc_storage_type); +@@ -570,9 +593,15 @@ bool storage_destroy(struct lxc_conf *conf) + int destroy_rv = 0; + r = storage_init(conf); +#ifdef HAVE_ISULAD -+/*isulad: do_lxcapi_clean_resource */ -+extern int do_lxcapi_clean_resource(char *name, char *lxcpath, struct lxc_conf *conf, pid_t pid); -+ -+/*isulad: do_lxcapi_get_pids */ -+extern int do_lxcapi_get_pids(char *name, char *lxcpath, struct lxc_conf *conf, pid_t **pids,size_t *pids_len); ++ 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 -+ - static inline bool container_uses_namespace(const struct lxc_handler *handler, - unsigned int ns_flag) - { + destroy_rv = r->ops->destroy(r); + if (destroy_rv == 0) + ret = true; -- 2.25.1 diff --git a/0005-fix-compile-error.patch b/0005-fix-compile-error.patch deleted file mode 100644 index 751e9b22f1aa6a57b7151407c6695190903f9fe3..0000000000000000000000000000000000000000 --- a/0005-fix-compile-error.patch +++ /dev/null @@ -1,5774 +0,0 @@ -From edc766541e03d457ce61cda5f4e8e201a6d2a738 Mon Sep 17 00:00:00 2001 -From: zhangxiaoyu -Date: Tue, 1 Aug 2023 09:36:57 +0800 -Subject: [PATCH] fix compile error - -Signed-off-by: zhangxiaoyu ---- - meson.build | 2 +- - src/lxc/af_unix.c | 66 + - src/lxc/af_unix.h | 2 + - src/lxc/attach.c | 27 +- - src/lxc/attach_options.h | 3 + - src/lxc/cgroups/cgfsng.c | 3 + - src/lxc/cgroups/cgroup.h | 5 + - src/lxc/cgroups/isulad_cgfsng.c | 2784 ++++++++++++++++++++----------- - src/lxc/commands.c | 4 +- - src/lxc/conf.c | 197 ++- - src/lxc/conf.h | 4 + - src/lxc/confile.c | 35 +- - src/lxc/exec_commands.c | 23 +- - src/lxc/exec_commands.h | 4 +- - src/lxc/execute.c | 15 + - src/lxc/isulad_utils.c | 6 +- - src/lxc/isulad_utils.h | 8 +- - src/lxc/lsm/lsm.c | 28 + - src/lxc/lsm/lsm.h | 5 + - src/lxc/lsm/selinux.c | 2 +- - src/lxc/lxc.h | 11 + - src/lxc/lxccontainer.c | 4 + - src/lxc/mainloop.c | 2 +- - src/lxc/mainloop.h | 2 +- - src/lxc/seccomp.c | 52 + - src/lxc/start.c | 56 +- - src/lxc/sync.c | 6 + - src/lxc/sync.h | 13 +- - src/lxc/terminal.c | 373 ++++- - src/lxc/tools/lxc_ls.c | 2 +- - src/lxc/utils.c | 3 + - src/tests/aa.c | 4 + - src/tests/capabilities.c | 12 + - src/tests/mount_injection.c | 4 + - src/tests/proc_pid.c | 4 + - src/tests/rootfs_options.c | 4 + - src/tests/sys_mixed.c | 4 + - src/tests/sysctls.c | 4 + - 38 files changed, 2700 insertions(+), 1083 deletions(-) - -diff --git a/meson.build b/meson.build -index fda8045..05bcbb2 100644 ---- a/meson.build -+++ b/meson.build -@@ -231,7 +231,7 @@ possible_link_flags = [ - ] - - if want_isulad -- possible_cc_flags += ['-D_FORTIFY_SOURCE=2'] -+ possible_cc_flags += ['-D_FORTIFY_SOURCE=2', '-O2'] - yajldep = dependency('yajl', version : '>=2') - srcconf.set('HAVE_ISULAD', yajldep.found()) - liblxc_dependencies += yajldep -diff --git a/src/lxc/af_unix.c b/src/lxc/af_unix.c -index 6db1864..e0a4892 100644 ---- a/src/lxc/af_unix.c -+++ b/src/lxc/af_unix.c -@@ -175,10 +175,18 @@ int __lxc_abstract_unix_send_two_fds(int fd, int fd_first, int fd_second, - return lxc_abstract_unix_send_fds(fd, fd_send, 2, data, size); - } - -+#ifdef HAVE_ISULAD -+static ssize_t lxc_abstract_unix_recv_fds_iov(int fd, -+ struct unix_fds *ret_fds, -+ struct iovec *ret_iov, -+ size_t size_ret_iov, -+ unsigned int timeout) -+#else - static ssize_t lxc_abstract_unix_recv_fds_iov(int fd, - struct unix_fds *ret_fds, - struct iovec *ret_iov, - size_t size_ret_iov) -+#endif - { - __do_free char *cmsgbuf = NULL; - ssize_t ret; -@@ -209,6 +217,22 @@ static ssize_t lxc_abstract_unix_recv_fds_iov(int fd, - msg.msg_iov = ret_iov; - msg.msg_iovlen = size_ret_iov; - -+#ifdef HAVE_ISULAD -+ struct timeval out; -+ if (timeout > 0) { -+ memset(&out, 0, sizeof(out)); -+ out.tv_sec = timeout / 1000000; -+ out.tv_usec = timeout % 1000000; -+ ret = setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, -+ (const void *)&out, sizeof(out)); -+ if (ret < 0) { -+ ERROR("Failed to set %u timeout on containter " -+ "state socket", timeout); -+ return -1; -+ } -+ } -+#endif -+ - again: - ret = recvmsg(fd, &msg, MSG_CMSG_CLOEXEC); - if (ret < 0) { -@@ -329,7 +353,11 @@ ssize_t lxc_abstract_unix_recv_fds(int fd, struct unix_fds *ret_fds, - }; - ssize_t ret; - -+#ifdef HAVE_ISULAD -+ ret = lxc_abstract_unix_recv_fds_iov(fd, ret_fds, &iov, 1, 0); -+#else - ret = lxc_abstract_unix_recv_fds_iov(fd, ret_fds, &iov, 1); -+#endif - if (ret < 0) - return ret; - -@@ -351,7 +379,11 @@ ssize_t lxc_abstract_unix_recv_one_fd(int fd, int *ret_fd, void *ret_data, - .fd_count_max = 1, - }; - -+#ifdef HAVE_ISULAD -+ ret = lxc_abstract_unix_recv_fds_iov(fd, fds, &iov, 1, 0); -+#else - ret = lxc_abstract_unix_recv_fds_iov(fd, fds, &iov, 1); -+#endif - if (ret < 0) - return ret; - -@@ -381,7 +413,11 @@ ssize_t __lxc_abstract_unix_recv_two_fds(int fd, int *fd_first, int *fd_second, - .fd_count_max = 2, - }; - -+#ifdef HAVE_ISULAD -+ ret = lxc_abstract_unix_recv_fds_iov(fd, fds, &iov, 1, 0); -+#else - ret = lxc_abstract_unix_recv_fds_iov(fd, fds, &iov, 1); -+#endif - if (ret < 0) - return ret; - -@@ -551,6 +587,36 @@ int lxc_socket_set_timeout(int fd, int rcv_timeout, int snd_timeout) - } - - #ifdef HAVE_ISULAD -+ssize_t lxc_abstract_unix_recv_one_fd_timeout(int fd, int *ret_fd, void *ret_data, -+ size_t size_ret_data, unsigned int timeout) -+{ -+ call_cleaner(put_unix_fds) struct unix_fds *fds = NULL; -+ char buf[1] = {}; -+ struct iovec iov = { -+ .iov_base = ret_data ? ret_data : buf, -+ .iov_len = ret_data ? size_ret_data : sizeof(buf), -+ }; -+ ssize_t ret; -+ -+ fds = &(struct unix_fds){ -+ .fd_count_max = 1, -+ }; -+ -+ ret = lxc_abstract_unix_recv_fds_iov(fd, fds, &iov, 1, timeout); -+ if (ret < 0) -+ return ret; -+ -+ if (ret == 0) -+ return ret_errno(ENODATA); -+ -+ if (fds->fd_count_ret != fds->fd_count_max) -+ *ret_fd = -EBADF; -+ else -+ *ret_fd = move_fd(fds->fd[0]); -+ -+ return ret; -+} -+ - int lxc_named_unix_open(const char *path, int type, int flags) - { - __do_close int fd = -EBADF; -diff --git a/src/lxc/af_unix.h b/src/lxc/af_unix.h -index 605afc2..de5731f 100644 ---- a/src/lxc/af_unix.h -+++ b/src/lxc/af_unix.h -@@ -169,6 +169,8 @@ static inline void put_unix_fds(struct unix_fds *fds) - define_cleanup_function(struct unix_fds *, put_unix_fds); - - #ifdef HAVE_ISULAD -+__hidden extern ssize_t lxc_abstract_unix_recv_one_fd_timeout(int fd, int *ret_fd, void *ret_data, -+ size_t size_ret_data, unsigned int timeout); - __hidden extern int lxc_named_unix_open(const char *path, int type, int flags); - __hidden extern int lxc_named_unix_connect(const char *path); - #endif -diff --git a/src/lxc/attach.c b/src/lxc/attach.c -index 1a89001..066eb5c 100644 ---- a/src/lxc/attach.c -+++ b/src/lxc/attach.c -@@ -1203,10 +1203,10 @@ __noreturn static void do_attach(struct attach_payload *ap) - sigset_t mask; - - /*isulad: record errpipe fd*/ -- msg_fd = init_ctx->container->lxc_conf->errpipe[1]; -- init_ctx->container->lxc_conf->errpipe[1] = -1; -+ msg_fd = ctx->container->lxc_conf->errpipe[1]; -+ ctx->container->lxc_conf->errpipe[1] = -1; - /*isulad: set system umask */ -- umask(init_ctx->container->lxc_conf->umask); -+ umask(ctx->container->lxc_conf->umask); - - /*isulad: restore default signal handlers and unblock all signals*/ - for (int i = 1; i < NSIG; i++) -@@ -1528,7 +1528,11 @@ __noreturn static void do_attach(struct attach_payload *ap) - put_attach_payload(ap); - - /* We're done, so we can now do whatever the user intended us to do. */ -+#ifdef HAVE_ISULAD -+ _exit(attach_function(attach_function_args, msg_fd)); -+#else - _exit(attach_function(attach_function_args)); -+#endif - - on_error: - ERROR("Failed to attach to container"); -@@ -1668,7 +1672,7 @@ out: - } - - static int attach_signal_handler(int fd, uint32_t events, void *data, -- struct lxc_epoll_descr *descr) -+ struct lxc_async_descr *descr) - { - int ret; - siginfo_t info; -@@ -1703,7 +1707,7 @@ static int isulad_setup_signal_fd(sigset_t *oldmask) - if (ret < 0) - return -EBADF; - -- for (int sig = 0; sig < (sizeof(signals) / sizeof(signals[0])); sig++) { -+ for (size_t sig = 0; sig < (sizeof(signals) / sizeof(signals[0])); sig++) { - ret = sigdelset(&mask, signals[sig]); - if (ret < 0) - return -EBADF; -@@ -1753,7 +1757,7 @@ int lxc_attach(struct lxc_container *container, lxc_attach_exec_t exec_function, - - int isulad_sigfd; - sigset_t isulad_oldmask; -- struct lxc_epoll_descr isulad_descr = {0}; -+ struct lxc_async_descr isulad_descr = {0}; - #endif - - if (!container) -@@ -1786,9 +1790,9 @@ int lxc_attach(struct lxc_container *container, lxc_attach_exec_t exec_function, - - #ifdef HAVE_ISULAD - // always switch uid and gid for attach -- if (options->uid == -1) -+ if (options->uid == (uid_t)-1) - options->uid = conf->init_uid; -- if (options->gid == -1) -+ if (options->gid == (gid_t)-1) - options->gid = conf->init_gid; - #endif - -@@ -2111,7 +2115,11 @@ int lxc_attach(struct lxc_container *container, lxc_attach_exec_t exec_function, - goto on_error; - - /* Setup resource limits */ -+#ifdef HAVE_ISULAD -+ ret = setup_resource_limits(conf, pid, -1); -+#else - ret = setup_resource_limits(conf, pid); -+#endif - if (ret < 0) - goto on_error; - -@@ -2228,7 +2236,8 @@ int lxc_attach(struct lxc_container *container, lxc_attach_exec_t exec_function, - goto close_mainloop; - } - if (options->attach_flags & LXC_ATTACH_TERMINAL) { -- ret = lxc_mainloop_add_handler(&descr, isulad_sigfd, attach_signal_handler, &tmp_pid); -+ ret = lxc_mainloop_add_handler(&descr, isulad_sigfd, attach_signal_handler, default_cleanup_handler, &tmp_pid, -+ "attach_signal_handler"); - if (ret < 0) { - ERROR("Failed to add signal handler for %d to mainloop", tmp_pid); - goto close_mainloop; -diff --git a/src/lxc/attach_options.h b/src/lxc/attach_options.h -index a4052fb..fe8bf6d 100644 ---- a/src/lxc/attach_options.h -+++ b/src/lxc/attach_options.h -@@ -4,6 +4,9 @@ - #define __LXC_ATTACH_OPTIONS_H - - #include -+#ifdef HAVE_ISULAD -+#include -+#endif - - #ifdef __cplusplus - extern "C" { -diff --git a/src/lxc/cgroups/cgfsng.c b/src/lxc/cgroups/cgfsng.c -index cecc9bc..4e4ae0c 100644 ---- a/src/lxc/cgroups/cgfsng.c -+++ b/src/lxc/cgroups/cgfsng.c -@@ -3634,6 +3634,9 @@ static int __initialize_cgroups(struct cgroup_ops *ops, bool relative, - controller_list = unified_controllers(dfd, "cgroup.controllers"); - if (!controller_list) { - TRACE("No controllers are enabled for delegation in the unified hierarchy"); -+#ifdef HAVE_ISULAD -+ ops->no_controller = true; -+#endif - controller_list = list_new(); - if (!controller_list) - return syserror_set(-ENOMEM, "Failed to create empty controller list"); -diff --git a/src/lxc/cgroups/cgroup.h b/src/lxc/cgroups/cgroup.h -index ebfd3a1..d9159f4 100644 ---- a/src/lxc/cgroups/cgroup.h -+++ b/src/lxc/cgroups/cgroup.h -@@ -208,6 +208,11 @@ struct cgroup_ops { - char *container_limit_cgroup; - char *monitor_cgroup; - -+#ifdef HAVE_ISULAD -+ int errfd; -+ bool no_controller; -+#endif -+ - /* @hierarchies - * - A NULL-terminated array of struct hierarchy, one per legacy - * hierarchy. No duplicates. First sufficient, writeable mounted -diff --git a/src/lxc/cgroups/isulad_cgfsng.c b/src/lxc/cgroups/isulad_cgfsng.c -index 38ad677..1160af5 100644 ---- a/src/lxc/cgroups/isulad_cgfsng.c -+++ b/src/lxc/cgroups/isulad_cgfsng.c -@@ -34,6 +34,7 @@ - #include - #include - #include -+#include - #include - #include - -@@ -43,41 +44,55 @@ - #include "cgroup2_devices.h" - #include "cgroup_utils.h" - #include "commands.h" -+#include "commands_utils.h" - #include "conf.h" - #include "config.h" - #include "log.h" - #include "macro.h" - #include "mainloop.h" - #include "memory_utils.h" -+#include "open_utils.h" - #include "storage/storage.h" - #include "utils.h" - --#ifndef HAVE_STRLCPY -+#if !HAVE_STRLCPY - #include "include/strlcpy.h" - #endif - --#ifndef HAVE_STRLCAT -+#if !HAVE_STRLCAT - #include "include/strlcat.h" - #endif - -+#if HAVE_LIBSYSTEMD -+#include -+#include -+#endif -+ - lxc_log_define(isulad_cgfsng, cgroup); - --/* Given a pointer to a null-terminated array of pointers, realloc to add one -+/* -+ * Given a pointer to a null-terminated array of pointers, realloc to add one - * entry, and point the new entry to NULL. Do not fail. Return the index to the - * second-to-last entry - that is, the one which is now available for use - * (keeping the list null-terminated). - */ --static int append_null_to_list(void ***list) -+static int cg_list_add(void ***list) - { -- int newentry = 0; -+ int idx = 0; -+ void **p; - - if (*list) -- for (; (*list)[newentry]; newentry++) -+ for (; (*list)[idx]; idx++) - ; - -- *list = must_realloc(*list, (newentry + 2) * sizeof(void **)); -- (*list)[newentry + 1] = NULL; -- return newentry; -+ p = realloc(*list, (idx + 2) * sizeof(void **)); -+ if (!p) -+ return ret_errno(ENOMEM); -+ -+ p[idx + 1] = NULL; -+ *list = p; -+ -+ return idx; - } - - /* Given a null-terminated array of strings, check whether @entry is one of the -@@ -95,63 +110,10 @@ static bool string_in_list(char **list, const char *entry) - return false; - } - --/* Return a copy of @entry prepending "name=", i.e. turn "systemd" into -- * "name=systemd". Do not fail. -- */ --static char *cg_legacy_must_prefix_named(char *entry) --{ -- size_t len; -- char *prefixed; -- -- len = strlen(entry); -- prefixed = must_realloc(NULL, len + 6); -- -- memcpy(prefixed, "name=", STRLITERALLEN("name=")); -- memcpy(prefixed + STRLITERALLEN("name="), entry, len); -- prefixed[len + 5] = '\0'; -- -- return prefixed; --} -- --/* Append an entry to the clist. Do not fail. @clist must be NULL the first time -- * we are called. -- * -- * We also handle named subsystems here. Any controller which is not a kernel -- * subsystem, we prefix "name=". Any which is both a kernel and named subsystem, -- * we refuse to use because we're not sure which we have here. -- * (TODO: We could work around this in some cases by just remounting to be -- * unambiguous, or by comparing mountpoint contents with current cgroup.) -- * -- * The last entry will always be NULL. -- */ --static void must_append_controller(char **klist, char **nlist, char ***clist, -- char *entry) --{ -- int newentry; -- char *copy; -- -- if (string_in_list(klist, entry) && string_in_list(nlist, entry)) { -- ERROR("Refusing to use ambiguous controller \"%s\"", entry); -- ERROR("It is both a named and kernel subsystem"); -- return; -- } -- -- newentry = append_null_to_list((void ***)clist); -- -- if (strncmp(entry, "name=", 5) == 0) -- copy = must_copy_string(entry); -- else if (string_in_list(klist, entry)) -- copy = must_copy_string(entry); -- else -- copy = cg_legacy_must_prefix_named(entry); -- -- (*clist)[newentry] = copy; --} -- - /* Given a handler's cgroup data, return the struct hierarchy for the controller - * @c, or NULL if there is none. - */ --struct hierarchy *get_hierarchy(struct cgroup_ops *ops, const char *controller) -+static struct hierarchy *get_hierarchy(const struct cgroup_ops *ops, const char *controller) - { - if (!ops->hierarchies) - return log_trace_errno(NULL, errno, "There are no useable cgroup controllers"); -@@ -159,15 +121,28 @@ struct hierarchy *get_hierarchy(struct cgroup_ops *ops, const char *controller) - for (int i = 0; ops->hierarchies[i]; i++) { - if (!controller) { - /* This is the empty unified hierarchy. */ -- if (ops->hierarchies[i]->controllers && -- !ops->hierarchies[i]->controllers[0]) -+ if (ops->hierarchies[i]->controllers && !ops->hierarchies[i]->controllers[0]) - return ops->hierarchies[i]; -+ - continue; -- } else if (pure_unified_layout(ops) && -- strcmp(controller, "devices") == 0) { -- if (ops->unified->bpf_device_controller) -- return ops->unified; -- break; -+ } -+ -+ /* -+ * Handle controllers with significant implementation changes -+ * from cgroup to cgroup2. -+ */ -+ if (pure_unified_layout(ops)) { -+ if (strequal(controller, "devices")) { -+ if (device_utility_controller(ops->unified)) -+ return ops->unified; -+ -+ break; -+ } else if (strequal(controller, "freezer")) { -+ if (freezer_utility_controller(ops->unified)) -+ return ops->unified; -+ -+ break; -+ } - } - - if (string_in_list(ops->hierarchies[i]->controllers, controller)) -@@ -182,6 +157,38 @@ struct hierarchy *get_hierarchy(struct cgroup_ops *ops, const char *controller) - return ret_set_errno(NULL, ENOENT); - } - -+int prepare_cgroup_fd(const struct cgroup_ops *ops, struct cgroup_fd *fd, bool limit) -+{ -+ int dfd; -+ const struct hierarchy *h; -+ -+ h = get_hierarchy(ops, fd->controller); -+ if (!h) -+ return ret_errno(ENOENT); -+ -+ /* -+ * The client requested that the controller must be in a specific -+ * cgroup version. -+ */ -+ if (fd->type != 0 && (cgroupfs_type_magic_t)fd->type != h->fs_type) -+ return ret_errno(EINVAL); -+ -+ if (limit) -+ dfd = h->dfd_con; -+ else -+ dfd = h->dfd_lim; -+ if (dfd < 0) -+ return ret_errno(EBADF); -+ -+ fd->layout = ops->cgroup_layout; -+ fd->type = h->fs_type; -+ if (fd->type == UNIFIED_HIERARCHY) -+ fd->utilities = h->utilities; -+ fd->fd = dfd; -+ -+ return 0; -+} -+ - #define BATCH_SIZE 50 - static void batch_realloc(char **mem, size_t oldlen, size_t newlen) - { -@@ -223,44 +230,24 @@ static char *read_file(const char *fnam) - - static inline bool is_unified_hierarchy(const struct hierarchy *h) - { -- return h->version == CGROUP2_SUPER_MAGIC; --} -- --/* Given two null-terminated lists of strings, return true if any string is in -- * both. -- */ --static bool controller_lists_intersect(char **l1, char **l2) --{ -- if (!l1 || !l2) -- return false; -- -- for (int i = 0; l1[i]; i++) -- if (string_in_list(l2, l1[i])) -- return true; -- -- return false; -+ return h->fs_type == UNIFIED_HIERARCHY; - } - --/* For a null-terminated list of controllers @clist, return true if any of those -- * controllers is already listed the null-terminated list of hierarchies @hlist. -- * Realistically, if one is present, all must be present. -- */ --static bool controller_list_is_dup(struct hierarchy **hlist, char **clist) -+static char *trim(char *s) - { -- if (!hlist) -- return false; -+ size_t len; - -- for (int i = 0; hlist[i]; i++) -- if (controller_lists_intersect(hlist[i]->controllers, clist)) -- return true; -+ len = strlen(s); -+ while ((len > 1) && (s[len - 1] == '\n')) -+ s[--len] = '\0'; - -- return false; -+ return s; - } - - /* Return true if the controller @entry is found in the null-terminated list of - * hierarchies @hlist. - */ --static bool controller_found(struct hierarchy **hlist, char *entry) -+static bool controller_available(struct hierarchy **hlist, char *entry) - { - if (!hlist) - return false; -@@ -272,10 +259,7 @@ static bool controller_found(struct hierarchy **hlist, char *entry) - return false; - } - --/* Return true if all of the controllers which we require have been found. The -- * required list is freezer and anything in lxc.cgroup.use. -- */ --static bool all_controllers_found(struct cgroup_ops *ops) -+static bool controllers_available(struct cgroup_ops *ops) - { - struct hierarchy **hlist; - -@@ -284,335 +268,139 @@ static bool all_controllers_found(struct cgroup_ops *ops) - - hlist = ops->hierarchies; - for (char **cur = ops->cgroup_use; cur && *cur; cur++) -- if (!controller_found(hlist, *cur)) -- return log_error(false, "No %s controller mountpoint found", *cur); -+ if (!controller_available(hlist, *cur)) -+ return log_error(false, "The %s controller found", *cur); - - return true; - } - --/* Get the controllers from a mountinfo line There are other ways we could get -- * this info. For lxcfs, field 3 is /cgroup/controller-list. For cgroupfs, we -- * could parse the mount options. But we simply assume that the mountpoint must -- * be /sys/fs/cgroup/controller-list -- */ --static char **cg_hybrid_get_controllers(char **klist, char **nlist, char *line, -- int type) -+static char **list_new(void) - { -- /* The fourth field is /sys/fs/cgroup/comma-delimited-controller-list -- * for legacy hierarchies. -- */ -- __do_free_string_list char **aret = NULL; -- int i; -- char *p2, *tok; -- char *p = line, *sep = ","; -- -- for (i = 0; i < 4; i++) { -- p = strchr(p, ' '); -- if (!p) -- return NULL; -- p++; -- } -- -- /* Note, if we change how mountinfo works, then our caller will need to -- * verify /sys/fs/cgroup/ in this field. -- */ -- if (strncmp(p, DEFAULT_CGROUP_MOUNTPOINT "/", 15) != 0) -- return log_warn(NULL, "Found hierarchy not under " DEFAULT_CGROUP_MOUNTPOINT ": \"%s\"", p); -- -- p += 15; -- p2 = strchr(p, ' '); -- if (!p2) -- return log_error(NULL, "Corrupt mountinfo"); -- *p2 = '\0'; -- -- if (type == CGROUP_SUPER_MAGIC) { -- __do_free char *dup = NULL; -- -- /* strdup() here for v1 hierarchies. Otherwise -- * lxc_iterate_parts() will destroy mountpoints such as -- * "/sys/fs/cgroup/cpu,cpuacct". -- */ -- dup = must_copy_string(p); -- if (!dup) -- return NULL; -- -- lxc_iterate_parts (tok, dup, sep) -- must_append_controller(klist, nlist, &aret, tok); -- } -- *p2 = ' '; -- -- return move_ptr(aret); --} -+ __do_free_string_list char **list = NULL; -+ int idx; - --static char **cg_unified_make_empty_controller(void) --{ -- __do_free_string_list char **aret = NULL; -- int newentry; -+ idx = cg_list_add((void ***)&list); -+ if (idx < 0) -+ return NULL; - -- newentry = append_null_to_list((void ***)&aret); -- aret[newentry] = NULL; -- return move_ptr(aret); -+ list[idx] = NULL; -+ return move_ptr(list); - } - --static char **cg_unified_get_controllers(const char *file) -+static int list_add_string(char ***list, char *entry) - { -- __do_free char *buf = NULL; -- __do_free_string_list char **aret = NULL; -- char *sep = " \t\n"; -- char *tok; -- -- buf = read_file(file); -- if (!buf) -- return NULL; -+ __do_free char *dup = NULL; -+ int idx; - -- lxc_iterate_parts(tok, buf, sep) { -- int newentry; -- char *copy; -+ dup = strdup(entry); -+ if (!dup) -+ return ret_errno(ENOMEM); - -- newentry = append_null_to_list((void ***)&aret); -- copy = must_copy_string(tok); -- aret[newentry] = copy; -- } -+ idx = cg_list_add((void ***)list); -+ if (idx < 0) -+ return idx; - -- return move_ptr(aret); -+ (*list)[idx] = move_ptr(dup); -+ return 0; - } - --static struct hierarchy *add_hierarchy(struct hierarchy ***h, char **clist, char *mountpoint, -- char *container_base_path, int type) -+static char **list_add_controllers(char *controllers) - { -- struct hierarchy *new; -- int newentry; -+ __do_free_string_list char **list = NULL; -+ char *it; - -- new = zalloc(sizeof(*new)); -- new->controllers = clist; -- 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; -- return new; --} -- --/* Get a copy of the mountpoint from @line, which is a line from -- * /proc/self/mountinfo. -- */ --static char *cg_hybrid_get_mountpoint(char *line) --{ -- char *p = line, *sret = NULL; -- size_t len; -- char *p2; -+ lxc_iterate_parts(it, controllers, ", \t\n") { -+ int ret; - -- for (int i = 0; i < 4; i++) { -- p = strchr(p, ' '); -- if (!p) -+ ret = list_add_string(&list, it); -+ if (ret < 0) - return NULL; -- p++; - } - -- if (strncmp(p, DEFAULT_CGROUP_MOUNTPOINT "/", 15) != 0) -- return NULL; -- -- p2 = strchr(p + 15, ' '); -- if (!p2) -- return NULL; -- *p2 = '\0'; -- -- len = strlen(p); -- sret = must_realloc(NULL, len + 1); -- memcpy(sret, p, len); -- sret[len] = '\0'; -- -- return sret; -+ return move_ptr(list); - } - --/* Given a multi-line string, return a null-terminated copy of the current line. */ --static char *copy_to_eol(char *p) -+static char **unified_controllers(int dfd, const char *file) - { -- char *p2, *sret; -- size_t len; -+ __do_free char *buf = NULL; - -- p2 = strchr(p, '\n'); -- if (!p2) -+ buf = read_file_at(dfd, file, PROTECT_OPEN, 0); -+ if (!buf) - return NULL; - -- len = p2 - p; -- sret = must_realloc(NULL, len + 1); -- memcpy(sret, p, len); -- sret[len] = '\0'; -- -- return sret; -+ return list_add_controllers(buf); - } - --/* cgline: pointer to character after the first ':' in a line in a \n-terminated -- * /proc/self/cgroup file. Check whether controller c is present. -- */ --static bool controller_in_clist(char *cgline, char *c) -+static bool skip_hierarchy(const struct cgroup_ops *ops, char **controllers) - { -- __do_free char *tmp = NULL; -- char *tok, *eol; -- size_t len; -- -- eol = strchr(cgline, ':'); -- if (!eol) -+ if (!ops->cgroup_use) - return false; - -- len = eol - cgline; -- tmp = must_realloc(NULL, len + 1); -- memcpy(tmp, cgline, len); -- tmp[len] = '\0'; -- -- lxc_iterate_parts(tok, tmp, ",") -- if (strcmp(tok, c) == 0) -- return true; -- -- return false; --} -- --/* @basecginfo is a copy of /proc/$$/cgroup. Return the current cgroup for -- * @controller. -- */ --static char *cg_hybrid_get_current_cgroup(char *basecginfo, char *controller, -- int type) --{ -- char *p = basecginfo; -- -- for (;;) { -- bool is_cgv2_base_cgroup = false; -- -- /* cgroup v2 entry in "/proc//cgroup": "0::/some/path" */ -- if ((type == CGROUP2_SUPER_MAGIC) && (*p == '0')) -- is_cgv2_base_cgroup = true; -+ for (char **cur_ctrl = controllers; cur_ctrl && *cur_ctrl; cur_ctrl++) { -+ bool found = false; - -- p = strchr(p, ':'); -- if (!p) -- return NULL; -- p++; -+ for (char **cur_use = ops->cgroup_use; cur_use && *cur_use; cur_use++) { -+ if (!strequal(*cur_use, *cur_ctrl)) -+ continue; - -- if (is_cgv2_base_cgroup || (controller && controller_in_clist(p, controller))) { -- p = strchr(p, ':'); -- if (!p) -- return NULL; -- p++; -- return copy_to_eol(p); -+ found = true; -+ break; - } - -- p = strchr(p, '\n'); -- if (!p) -- return NULL; -- p++; -- } --} -- --static void must_append_string(char ***list, char *entry) --{ -- int newentry; -- char *copy; -- -- newentry = append_null_to_list((void ***)list); -- copy = must_copy_string(entry); -- (*list)[newentry] = copy; --} -- --static int get_existing_subsystems(char ***klist, char ***nlist) --{ -- __do_free char *line = NULL; -- __do_fclose FILE *f = NULL; -- size_t len = 0; -- -- f = fopen("/proc/self/cgroup", "re"); -- if (!f) -- return -1; -- -- while (getline(&line, &len, f) != -1) { -- char *p, *p2, *tok; -- p = strchr(line, ':'); -- if (!p) -- continue; -- p++; -- p2 = strchr(p, ':'); -- if (!p2) -- continue; -- *p2 = '\0'; -- -- /* If the kernel has cgroup v2 support, then /proc/self/cgroup -- * contains an entry of the form: -- * -- * 0::/some/path -- * -- * In this case we use "cgroup2" as controller name. -- */ -- if ((p2 - p) == 0) { -- must_append_string(klist, "cgroup2"); -+ if (found) - continue; -- } - -- lxc_iterate_parts(tok, p, ",") { -- if (strncmp(tok, "name=", 5) == 0) -- must_append_string(nlist, tok); -- else -- must_append_string(klist, tok); -- } -+ return true; - } - -- return 0; -+ return false; - } - --static char *trim(char *s) -+static int cgroup_hierarchy_add(struct cgroup_ops *ops, int dfd_mnt, char *mnt, -+ int dfd_base, char *base_cgroup, -+ char **controllers, cgroupfs_type_magic_t fs_type) - { -- size_t len; -- -- len = strlen(s); -- while ((len > 1) && (s[len - 1] == '\n')) -- s[--len] = '\0'; -+ __do_free struct hierarchy *new = NULL; -+ int idx; - -- return s; --} -+ if (abspath(base_cgroup)) -+ return syserror_set(-EINVAL, "Container base path must be relative to controller mount"); - --static void lxc_cgfsng_print_hierarchies(struct cgroup_ops *ops) --{ -- int i; -- struct hierarchy **it; -+ new = zalloc(sizeof(*new)); -+ if (!new) -+ return ret_errno(ENOMEM); - -- if (!ops->hierarchies) { -- TRACE(" No hierarchies found"); -- return; -- } -+ new->dfd_con = -EBADF; -+ new->dfd_lim = -EBADF; -+ new->dfd_mon = -EBADF; - -- TRACE(" Hierarchies:"); -- for (i = 0, it = ops->hierarchies; it && *it; it++, i++) { -- int j; -- char **cit; -+ new->fs_type = fs_type; -+ new->controllers = controllers; -+ new->at_mnt = mnt; -+ new->at_base = base_cgroup; - -- 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); -- } --} -+ new->dfd_mnt = dfd_mnt; -+ new->dfd_base = dfd_base; - --static void lxc_cgfsng_print_basecg_debuginfo(char *basecginfo, char **klist, -- char **nlist) --{ -- int k; -- char **it; -+ TRACE("Adding cgroup hierarchy mounted at %s and base cgroup %s", -+ mnt, maybe_empty(base_cgroup)); -+ for (char *const *it = new->controllers; it && *it; it++) -+ TRACE("The hierarchy contains the %s controller", *it); - -- TRACE("basecginfo is:"); -- TRACE("%s", basecginfo); -+ idx = cg_list_add((void ***)&ops->hierarchies); -+ if (idx < 0) -+ return ret_errno(idx); - -- for (k = 0, it = klist; it && *it; it++, k++) -- TRACE("kernel subsystem %d: %s", k, *it); -+ if (fs_type == UNIFIED_HIERARCHY) -+ ops->unified = new; -+ (ops->hierarchies)[idx] = move_ptr(new); - -- for (k = 0, it = nlist; it && *it; it++, k++) -- TRACE("named subsystem %d: %s", k, *it); -+ return 0; - } - - struct generic_userns_exec_data { - struct hierarchy **hierarchies; -- const char *container_cgroup; -+ const char *path_prune; - struct lxc_conf *conf; - uid_t origuid; /* target uid in parent namespace */ - char *path; -@@ -655,7 +443,7 @@ static int isulad_cgroup_tree_remove_wrapper(void *data) - gid_t nsgid = (arg->conf->root_nsgid_map != NULL) ? 0 : arg->conf->init_gid; - int ret; - -- if (!lxc_setgroups(0, NULL) && errno != EPERM) -+ if (!lxc_drop_groups() && errno != EPERM) - return log_error_errno(-1, errno, "Failed to setgroups(0, NULL)"); - - ret = setresgid(nsgid, nsgid, nsgid); -@@ -668,7 +456,7 @@ static int isulad_cgroup_tree_remove_wrapper(void *data) - return log_error_errno(-1, errno, "Failed to setresuid(%d, %d, %d)", - (int)nsuid, (int)nsuid, (int)nsuid); - -- return isulad_cgroup_tree_remove(arg->hierarchies, arg->container_cgroup); -+ return isulad_cgroup_tree_remove(arg->hierarchies, arg->path_prune); - } - - __cgfsng_ops static bool isulad_cgfsng_payload_destroy(struct cgroup_ops *ops, -@@ -707,10 +495,10 @@ __cgfsng_ops static bool isulad_cgfsng_payload_destroy(struct cgroup_ops *ops, - WARN("Failed to detach bpf program from cgroup"); - #endif - -- if (handler->conf && !lxc_list_empty(&handler->conf->id_map)) { -+ if (!list_empty(&handler->conf->id_map) && !handler->am_root) { - struct generic_userns_exec_data wrap = { - .conf = handler->conf, -- .container_cgroup = ops->container_cgroup, -+ .path_prune = ops->container_limit_cgroup, - .hierarchies = ops->hierarchies, - .origuid = 0, - }; -@@ -733,58 +521,408 @@ __cgfsng_ops static void isulad_cgfsng_monitor_destroy(struct cgroup_ops *ops, - return; - } - --__cgfsng_ops static inline bool isulad_cgfsng_monitor_create(struct cgroup_ops *ops, -- struct lxc_handler *handler) -+#define SYSTEMD_SCOPE_FAILED 2 -+#define SYSTEMD_SCOPE_UNSUPP 1 -+#define SYSTEMD_SCOPE_SUCCESS 0 -+ -+#if HAVE_LIBSYSTEMD -+struct sd_callback_data { -+ char *scope_name; -+ bool job_complete; -+}; -+ -+static int systemd_jobremoved_callback(sd_bus_message *m, void *userdata, sd_bus_error *error) - { -- return true; -+ char *path, *unit, *result; -+ struct sd_callback_data *sd_data = userdata; -+ uint32_t id; -+ int r; -+ -+ r = sd_bus_message_read(m, "uoss", &id, &path, &unit, &result); -+ if (r < 0) -+ return log_error(-1, "bad message received in callback: %s", strerror(-r)); -+ -+ if (sd_data->scope_name && strcmp(unit, sd_data->scope_name) != 0) -+ return log_trace(-1, "unit was '%s' not '%s'", unit, sd_data->scope_name); -+ if (strcmp(result, "done") == 0) { -+ sd_data->job_complete = true; -+ return log_info(1, "job is done"); -+ } -+ return log_debug(0, "result was '%s', not 'done'", result); - } - --static bool isulad_copy_parent_file(char *path, char *file) -+#define DESTINATION "org.freedesktop.systemd1" -+#define PATH "/org/freedesktop/systemd1" -+#define INTERFACE "org.freedesktop.systemd1.Manager" -+#define MEMBER "StartTransientUnit" -+static bool start_scope(sd_bus *bus, struct sd_callback_data *data, struct sd_event *event) - { -- int ret; -- int len = 0; -- char *value = NULL; -- char *current = NULL; -- char *fpath = NULL; -- char *lastslash = NULL; -- char oldv; -- -- fpath = must_make_path(path, file, NULL); -- current = read_file(fpath); -- -- if (current == NULL) { -- SYSERROR("Failed to read file \"%s\"", fpath); -- free(fpath); -- return false; -+ __attribute__((__cleanup__(sd_bus_error_free))) sd_bus_error error = SD_BUS_ERROR_NULL;; -+ __attribute__((__cleanup__(sd_bus_message_unrefp))) sd_bus_message *reply = NULL; -+ __attribute__((__cleanup__(sd_bus_message_unrefp))) sd_bus_message *m = NULL; -+ char *path = NULL; -+ int r; -+ -+ r = sd_bus_message_new_method_call(bus, &m, -+ DESTINATION, PATH, INTERFACE, MEMBER); -+ if (r < 0) -+ return log_error(false, "Failed creating sdbus message"); -+ -+ r = sd_bus_message_append(m, "ss", data->scope_name, "fail"); -+ if (r < 0) -+ return log_error(false, "Failed setting systemd scope name"); -+ -+ r = sd_bus_message_open_container(m, 'a', "(sv)"); -+ if (r < 0) -+ return log_error(false, "Failed allocating sdbus msg properties"); -+ -+ r = sd_bus_message_append(m, "(sv)(sv)(sv)", -+ "PIDs", "au", 1, getpid(), -+ "Delegate", "b", 1, -+ "CollectMode", "s", "inactive-or-failed"); -+ if (r < 0) -+ return log_error(false, "Failed setting properties on sdbus message"); -+ -+ r = sd_bus_message_close_container(m); -+ if (r < 0) -+ return log_error(false, "Failed closing sdbus message properties"); -+ -+ r = sd_bus_message_append(m, "a(sa(sv))", 0); -+ if (r < 0) -+ return log_error(false, "Failed appending aux boilerplate\n"); -+ -+ r = sd_bus_call(NULL, m, 0, &error, &reply); -+ if (r < 0) -+ return log_error(false, "Failed sending sdbus message: %s", error.message); -+ -+ /* Parse the response message */ -+ r = sd_bus_message_read(reply, "o", &path); -+ if (r < 0) -+ return log_error(false, "Failed to parse response message: %s", strerror(-r)); -+ -+ /* Now spin up a mini-event-loop to wait for the "job completed" message */ -+ int tries = 0; -+ -+ while (!data->job_complete) { -+ r = sd_event_run(event, 1000 * 1000); -+ if (r < 0) { -+ log_debug(stderr, "Error waiting for JobRemoved: %s\n", strerror(-r)); -+ continue; -+ } -+ if (data->job_complete || tries == 5) -+ break; -+ if (r > 0) { -+ log_trace(stderr, "Debug: we processed an event (%d), but not the one we wanted\n", r); -+ continue; -+ } -+ if (r == 0) // timeout -+ tries++; - } -- -- if (strcmp(current, "\n") != 0) { -- free(fpath); -- free(current); -- return true; -+ if (!data->job_complete) { -+ return log_error(false, "Error: %s job was never removed", data->scope_name); - } -+ return true; -+} - -- free(fpath); -- free(current); -+static bool string_pure_unified_system(char *contents) -+{ -+ char *p; -+ bool first_line_read = false; - -- lastslash = strrchr(path, '/'); -- if (lastslash == NULL) { -- ERROR("Failed to detect \"/\" in \"%s\"", path); -- return false; -+ lxc_iterate_parts(p, contents, "\n") { -+ if (first_line_read) // if >1 line, this is not pure unified -+ return false; -+ first_line_read = true; -+ -+ if (strlen(p) > 3 && strncmp(p, "0:", 2) == 0) -+ return true; - } -- oldv = *lastslash; -- *lastslash = '\0'; -- fpath = must_make_path(path, file, NULL); -- *lastslash = oldv; -- len = lxc_read_from_file(fpath, NULL, 0); -- if (len <= 0) -- goto on_error; - -- value = must_realloc(NULL, len + 1); -- ret = lxc_read_from_file(fpath, value, len); -- if (ret != len) -- goto on_error; -- free(fpath); -+ return false; -+} -+ -+/* -+ * Only call get_current_unified_cgroup() when we are in a pure -+ * unified (v2-only) cgroup -+ */ -+static char *get_current_unified_cgroup(void) -+{ -+ __do_free char *buf = NULL; -+ __do_free_string_list char **list = NULL; -+ char *p; -+ -+ buf = read_file_at(-EBADF, "/proc/self/cgroup", PROTECT_OPEN, 0); -+ if (!buf) -+ return NULL; -+ -+ if (!string_pure_unified_system(buf)) -+ return NULL; -+ -+ // 0::/user.slice/user-1000.slice/session-136.scope -+ // Get past the "0::" -+ p = buf; -+ if (strnequal(p, "0::", STRLITERALLEN("0::"))) -+ p += STRLITERALLEN("0::"); -+ -+ return strdup(p); -+} -+ -+static bool pure_unified_system(void) -+{ -+ __do_free char *buf = NULL; -+ -+ buf = read_file_at(-EBADF, "/proc/self/cgroup", PROTECT_OPEN, 0); -+ if (!buf) -+ return false; -+ -+ return string_pure_unified_system(buf); -+} -+ -+#define MEMBER_JOIN "AttachProcessesToUnit" -+static bool enter_scope(char *scope_name, pid_t pid) -+{ -+ __attribute__((__cleanup__(sd_bus_unrefp))) sd_bus *bus = NULL; -+ __attribute__((__cleanup__(sd_bus_error_free))) sd_bus_error error = SD_BUS_ERROR_NULL;; -+ __attribute__((__cleanup__(sd_bus_message_unrefp))) sd_bus_message *reply = NULL; -+ __attribute__((__cleanup__(sd_bus_message_unrefp))) sd_bus_message *m = NULL; -+ int r; -+ -+ r = sd_bus_open_user(&bus); -+ if (r < 0) -+ return log_error(false, "Failed to connect to user bus: %s", strerror(-r)); -+ -+ r = sd_bus_message_new_method_call(bus, &m, -+ DESTINATION, PATH, INTERFACE, MEMBER_JOIN); -+ if (r < 0) -+ return log_error(false, "Failed creating sdbus message"); -+ -+ r = sd_bus_message_append(m, "ssau", scope_name, "/init", 1, pid); -+ if (r < 0) -+ return log_error(false, "Failed setting systemd scope name"); -+ -+ -+ r = sd_bus_call(NULL, m, 0, &error, &reply); -+ if (r < 0) -+ return log_error(false, "Failed sending sdbus message: %s", error.message); -+ -+ return true; -+} -+ -+static bool enable_controllers_delegation(int fd_dir, char *cg) -+{ -+ __do_free char *rbuf = NULL; -+ __do_free char *wbuf = NULL; -+ __do_free_string_list char **cpulist = NULL; -+ char *controller; -+ size_t full_len = 0; -+ bool first = true; -+ int ret; -+ -+ rbuf = read_file_at(fd_dir, "cgroup.controllers", PROTECT_OPEN, 0); -+ if (!rbuf) -+ return false; -+ -+ lxc_iterate_parts(controller, rbuf, " ") { -+ full_len += strlen(controller) + 2; -+ wbuf = must_realloc(wbuf, full_len + 1); -+ if (first) { -+ wbuf[0] = '\0'; -+ first = false; -+ } else { -+ (void)strlcat(wbuf, " ", full_len + 1); -+ } -+ strlcat(wbuf, "+", full_len + 1); -+ strlcat(wbuf, controller, full_len + 1); -+ } -+ if (!wbuf) -+ return log_debug(true, "No controllers to delegate!"); -+ -+ ret = lxc_writeat(fd_dir, "cgroup.subtree_control", wbuf, strlen(wbuf)); -+ if (ret < 0) -+ return log_error_errno(false, errno, "Failed to write \"%s\" to %s/cgroup.subtree_control", wbuf, cg); -+ -+ return true; -+} -+ -+/* -+ * systemd places us in say .../lxc-1.scope. We create lxc-1.scope/init, -+ * move ourselves to there, then enable controllers in lxc-1.scope -+ */ -+static bool move_and_delegate_unified(char *parent_cgroup) -+{ -+ __do_free char *buf = NULL; -+ __do_close int fd_parent = -EBADF; -+ int ret; -+ -+ fd_parent = open_at(-EBADF, parent_cgroup, O_DIRECTORY, 0, 0); -+ if (fd_parent < 0) -+ return syserror_ret(false, "Failed opening cgroup dir \"%s\"", parent_cgroup); -+ -+ ret = mkdirat(fd_parent, "init", 0755); -+ if (ret < 0 && errno != EEXIST) -+ return syserror_ret(false, "Failed to create \"%d/init\" cgroup", fd_parent); -+ -+ buf = read_file_at(fd_parent, "cgroup.procs", PROTECT_OPEN, 0); -+ if (!buf) -+ return false; -+ -+ ret = lxc_writeat(fd_parent, "init/cgroup.procs", buf, strlen(buf)); -+ if (ret) -+ return syserror_ret(false, "Failed to escape to cgroup \"init/cgroup.procs\""); -+ -+ /* enable controllers in parent_cgroup */ -+ return enable_controllers_delegation(fd_parent, parent_cgroup); -+} -+ -+static int unpriv_systemd_create_scope(struct cgroup_ops *ops, struct lxc_conf *conf) -+{ -+ __do_free char *full_scope_name = NULL; -+ __do_free char *fs_cg_path = NULL; -+ sd_event *event = NULL; -+ __attribute__((__cleanup__(sd_bus_unrefp))) sd_bus *bus = NULL; // free the bus before the names it references, just to be sure -+ struct sd_callback_data sd_data; -+ int idx = 0; -+ size_t len; -+ int r; -+ -+ if (geteuid() == 0) -+ return log_info(SYSTEMD_SCOPE_UNSUPP, "Running privileged, not using a systemd unit"); -+ // Pure_unified_layout() can't be used as that info is not yet setup. At -+ // the same time, we don't want to calculate current cgroups until after -+ // we optionally enter a new systemd user scope. So let's just do a quick -+ // check for pure unified cgroup system: single line /proc/self/cgroup with -+ // only index '0:' -+ if (!pure_unified_system()) -+ return log_info(SYSTEMD_SCOPE_UNSUPP, "Not in unified layout, not using a systemd unit"); -+ -+ r = sd_bus_open_user(&bus); -+ if (r < 0) -+ return log_error(SYSTEMD_SCOPE_FAILED, "Failed to connect to user bus: %s", strerror(-r)); -+ -+ r = sd_bus_call_method_async(bus, NULL, DESTINATION, PATH, INTERFACE, "Subscribe", NULL, NULL, NULL); -+ if (r < 0) -+ return log_error(SYSTEMD_SCOPE_FAILED, "Failed to subscribe to signals: %s", strerror(-r)); -+ -+ sd_data.job_complete = false; -+ sd_data.scope_name = NULL; -+ r = sd_bus_match_signal(bus, -+ NULL, // no slot -+ DESTINATION, PATH, INTERFACE, "JobRemoved", -+ systemd_jobremoved_callback, &sd_data); -+ if (r < 0) -+ return log_error(SYSTEMD_SCOPE_FAILED, "Failed to register systemd event loop signal handler: %s", strerror(-r)); -+ -+ // NEXT: create and attach event -+ r = sd_event_new(&event); -+ if (r < 0) -+ return log_error(SYSTEMD_SCOPE_FAILED, "Failed allocating new event: %s\n", strerror(-r)); -+ r = sd_bus_attach_event(bus, event, SD_EVENT_PRIORITY_NORMAL); -+ if (r < 0) { -+ // bus won't clean up event since the attach failed -+ sd_event_unrefp(&event); -+ return log_error(SYSTEMD_SCOPE_FAILED, "Failed attaching event: %s\n", strerror(-r)); -+ } -+ -+ // "lxc-" + (conf->name) + "-NN" + ".scope" + '\0' -+ len = STRLITERALLEN("lxc-") + strlen(conf->name) + 3 + STRLITERALLEN(".scope") + 1; -+ full_scope_name = malloc(len); -+ if (!full_scope_name) -+ return syserror("Out of memory"); -+ -+ do { -+ r = strnprintf(full_scope_name, len, "lxc-%s-%d.scope", conf->name, idx); -+ if (r < 0) -+ return log_error_errno(-1, errno, "Failed to build scope name for \"%s\"", conf->name); -+ sd_data.scope_name = full_scope_name; -+ if (start_scope(bus, &sd_data, event)) { -+ conf->cgroup_meta.systemd_scope = get_current_unified_cgroup(); -+ if (!conf->cgroup_meta.systemd_scope) -+ return log_trace(SYSTEMD_SCOPE_FAILED, "Out of memory"); -+ fs_cg_path = must_make_path("/sys/fs/cgroup", conf->cgroup_meta.systemd_scope, NULL); -+ if (!move_and_delegate_unified(fs_cg_path)) -+ return log_error(SYSTEMD_SCOPE_FAILED, "Failed delegating the controllers to our cgroup"); -+ return log_trace(SYSTEMD_SCOPE_SUCCESS, "Created systemd scope %s", full_scope_name); -+ } -+ idx++; -+ } while (idx < 99); -+ -+ return SYSTEMD_SCOPE_FAILED; // failed, let's try old-school after all -+} -+#else /* !HAVE_LIBSYSTEMD */ -+static int unpriv_systemd_create_scope(struct cgroup_ops *ops, struct lxc_conf *conf) -+{ -+ TRACE("unpriv_systemd_create_scope: no systemd support"); -+ return SYSTEMD_SCOPE_UNSUPP; // not supported -+} -+#endif /* HAVE_LIBSYSTEMD */ -+ -+// Return a duplicate of cgroup path @cg without leading /, so -+// that caller can own+free it and be certain it's not abspath. -+static char *cgroup_relpath(char *cg) -+{ -+ char *p; -+ -+ if (!cg || strequal(cg, "/")) -+ return NULL; -+ p = strdup(deabs(cg)); -+ if (!p) -+ return ERR_PTR(-ENOMEM); -+ -+ return p; -+} -+ -+__cgfsng_ops static inline bool isulad_cgfsng_monitor_create(struct cgroup_ops *ops, -+ struct lxc_handler *handler) -+{ -+ return true; -+} -+ -+static bool isulad_copy_parent_file(char *path, char *file) -+{ -+ int ret; -+ int len = 0; -+ char *value = NULL; -+ char *current = NULL; -+ char *fpath = NULL; -+ char *lastslash = NULL; -+ char oldv; -+ -+ fpath = must_make_path(path, file, NULL); -+ current = read_file(fpath); -+ -+ if (current == NULL) { -+ SYSERROR("Failed to read file \"%s\"", fpath); -+ free(fpath); -+ return false; -+ } -+ -+ if (strcmp(current, "\n") != 0) { -+ free(fpath); -+ free(current); -+ return true; -+ } -+ -+ free(fpath); -+ free(current); -+ -+ lastslash = strrchr(path, '/'); -+ if (lastslash == NULL) { -+ ERROR("Failed to detect \"/\" in \"%s\"", path); -+ return false; -+ } -+ oldv = *lastslash; -+ *lastslash = '\0'; -+ fpath = must_make_path(path, file, NULL); -+ *lastslash = oldv; -+ len = lxc_read_from_file(fpath, NULL, 0); -+ if (len <= 0) -+ goto on_error; -+ -+ value = must_realloc(NULL, len + 1); -+ ret = lxc_read_from_file(fpath, value, len); -+ if (ret != len) -+ goto on_error; -+ free(fpath); - - fpath = must_make_path(path, file, NULL); - ret = lxc_write_to_file(fpath, value, len, false, 0666); -@@ -926,8 +1064,8 @@ static bool create_path_for_hierarchy(struct hierarchy *h, char *cgname, int err - return false; - } - -- h->cgfd_con = lxc_open_dirfd(path); -- if (h->cgfd_con < 0) -+ h->dfd_con = lxc_open_dirfd(path); -+ if (h->dfd_con < 0) - return log_error_errno(false, errno, "Failed to open %s", path); - - if (h->path_con == NULL) { -@@ -1071,7 +1209,7 @@ static int chown_cgroup_wrapper(void *data) - uid_t nsuid = (arg->conf->root_nsuid_map != NULL) ? 0 : arg->conf->init_uid; - gid_t nsgid = (arg->conf->root_nsgid_map != NULL) ? 0 : arg->conf->init_gid; - -- if (!lxc_setgroups(0, NULL) && errno != EPERM) -+ if (!lxc_drop_groups() && errno != EPERM) - return log_error_errno(-1, errno, "Failed to setgroups(0, NULL)"); - - ret = setresgid(nsgid, nsgid, nsgid); -@@ -1089,7 +1227,10 @@ static int chown_cgroup_wrapper(void *data) - destuid = 0; - - for (int i = 0; arg->hierarchies[i]; i++) { -- int dirfd = arg->hierarchies[i]->cgfd_con; -+ int dirfd = arg->hierarchies[i]->dfd_con; -+ -+ if (dirfd < 0) -+ return syserror_set(-EBADF, "Invalid cgroup file descriptor"); - - (void)fchowmodat(dirfd, "", destuid, nsgid, 0775); - -@@ -1101,15 +1242,15 @@ static int chown_cgroup_wrapper(void *data) - * files (which systemd in wily insists on doing). - */ - -- if (arg->hierarchies[i]->fs_type == CGROUP_SUPER_MAGIC) -+ if (arg->hierarchies[i]->fs_type == LEGACY_HIERARCHY) - (void)fchowmodat(dirfd, "tasks", destuid, nsgid, 0664); - - (void)fchowmodat(dirfd, "cgroup.procs", destuid, nsgid, 0664); - -- if (arg->hierarchies[i]->fs_type != CGROUP2_SUPER_MAGIC) -+ if (arg->hierarchies[i]->fs_type != UNIFIED_HIERARCHY) - continue; - -- for (char **p = arg->hierarchies[i]->cgroup2_chown; p && *p; p++) -+ for (char **p = arg->hierarchies[i]->delegate; p && *p; p++) - (void)fchowmodat(dirfd, *p, destuid, nsgid, 0664); - } - -@@ -1133,7 +1274,7 @@ __cgfsng_ops static bool isulad_cgfsng_chown(struct cgroup_ops *ops, - if (!conf) - return ret_set_errno(false, EINVAL); - -- if (lxc_list_empty(&conf->id_map)) -+ if (list_empty(&conf->id_map)) - return true; - - wrap.origuid = geteuid(); -@@ -1147,7 +1288,7 @@ __cgfsng_ops static bool isulad_cgfsng_chown(struct cgroup_ops *ops, - return true; - } - --__cgfsng_ops void isulad_cgfsng_payload_finalize(struct cgroup_ops *ops) -+__cgfsng_ops static void isulad_cgfsng_finalize(struct cgroup_ops *ops) - { - if (!ops) - return; -@@ -1164,15 +1305,33 @@ __cgfsng_ops void isulad_cgfsng_payload_finalize(struct cgroup_ops *ops) - - for (int i = 0; ops->hierarchies[i]; i++) { - struct hierarchy *h = ops->hierarchies[i]; -- /* -- * we don't keep the fds for non-unified hierarchies around -- * mainly because we don't make use of them anymore after the -- * core cgroup setup is done but also because there are quite a -- * lot of them. -- */ -- if (!is_unified_hierarchy(h)) -- close_prot_errno_disarm(h->cgfd_con); -+ -+ /* Close all monitor cgroup file descriptors. */ -+ close_prot_errno_disarm(h->dfd_mon); - } -+ /* Close the cgroup root file descriptor. */ -+ close_prot_errno_disarm(ops->dfd_mnt); -+ -+ /* -+ * The checking for freezer support should obviously be done at cgroup -+ * initialization time but that doesn't work reliable. The freezer -+ * controller has been demoted (rightly so) to a simple file located in -+ * each non-root cgroup. At the time when the container is created we -+ * might still be located in /sys/fs/cgroup and so checking for -+ * cgroup.freeze won't tell us anything because this file doesn't exist -+ * in the root cgroup. We could then iterate through /sys/fs/cgroup and -+ * find an already existing cgroup and then check within that cgroup -+ * for the existence of cgroup.freeze but that will only work on -+ * systemd based hosts. Other init systems might not manage cgroups and -+ * so no cgroup will exist. So we defer until we have created cgroups -+ * for our container which means we check here. -+ */ -+ if (pure_unified_layout(ops) && -+ !faccessat(ops->unified->dfd_con, "cgroup.freeze", F_OK, -+ AT_SYMLINK_NOFOLLOW)) { -+ TRACE("Unified hierarchy supports freezer"); -+ ops->unified->utilities |= FREEZER_CONTROLLER; -+ } - } - - /* cgroup-full:* is done, no need to create subdirs */ -@@ -1235,6 +1394,118 @@ static int cg_legacy_mount_controllers(int type, struct hierarchy *h, - return 0; - } - -+/* __cgroupfs_mount -+ * -+ * Mount cgroup hierarchies directly without using bind-mounts. The main -+ * uses-cases are mounting cgroup hierarchies in cgroup namespaces and mounting -+ * cgroups for the LXC_AUTO_CGROUP_FULL option. -+ */ -+static int __cgroupfs_mount(int cgroup_automount_type, struct hierarchy *h, -+ struct lxc_rootfs *rootfs, int dfd_mnt_cgroupfs, -+ const char *hierarchy_mnt) -+{ -+ __do_close int fd_fs = -EBADF; -+ unsigned int flags = 0; -+ char *fstype; -+ int ret; -+ -+ if (dfd_mnt_cgroupfs < 0) -+ return ret_errno(EINVAL); -+ -+ flags |= MOUNT_ATTR_NOSUID; -+ flags |= MOUNT_ATTR_NOEXEC; -+ flags |= MOUNT_ATTR_NODEV; -+ flags |= MOUNT_ATTR_RELATIME; -+ -+ if ((cgroup_automount_type == LXC_AUTO_CGROUP_RO) || -+ (cgroup_automount_type == LXC_AUTO_CGROUP_FULL_RO) || -+ (cgroup_automount_type == LXC_AUTO_CGROUP2_RO)) -+ flags |= MOUNT_ATTR_RDONLY; -+ -+ if (is_unified_hierarchy(h)) -+ fstype = "cgroup2"; -+ else -+ fstype = "cgroup"; -+ -+ if (can_use_mount_api()) { -+ fd_fs = fs_prepare(fstype, -EBADF, "", 0, 0); -+ if (fd_fs < 0) -+ return log_error_errno(-errno, errno, "Failed to prepare filesystem context for %s", fstype); -+ -+ if (!is_unified_hierarchy(h)) { -+ for (const char **it = (const char **)h->controllers; it && *it; it++) { -+ if (strnequal(*it, "name=", STRLITERALLEN("name="))) -+ ret = fs_set_property(fd_fs, "name", *it + STRLITERALLEN("name=")); -+ else -+ ret = fs_set_property(fd_fs, *it, ""); -+ if (ret < 0) -+ return log_error_errno(-errno, errno, "Failed to add %s controller to cgroup filesystem context %d(dev)", *it, fd_fs); -+ } -+ } -+ -+ ret = fs_attach(fd_fs, dfd_mnt_cgroupfs, hierarchy_mnt, -+ PROTECT_OPATH_DIRECTORY, PROTECT_LOOKUP_BENEATH, -+ flags); -+ } else { -+ __do_free char *controllers = NULL, *target = NULL; -+ unsigned int old_flags = 0; -+ const char *rootfs_mnt; -+ -+ if (!is_unified_hierarchy(h)) { -+ controllers = lxc_string_join(",", (const char **)h->controllers, false); -+ if (!controllers) -+ return ret_errno(ENOMEM); -+ } -+ -+ rootfs_mnt = get_rootfs_mnt(rootfs); -+ ret = mnt_attributes_old(flags, &old_flags); -+ if (ret) -+ return log_error_errno(-EINVAL, EINVAL, "Unsupported mount properties specified"); -+ -+ target = must_make_path(rootfs_mnt, DEFAULT_CGROUP_MOUNTPOINT, hierarchy_mnt, NULL); -+#ifdef HAVE_ISULAD -+ ret = safe_mount(NULL, target, fstype, old_flags, controllers, rootfs_mnt, NULL); -+#else -+ ret = safe_mount(NULL, target, fstype, old_flags, controllers, rootfs_mnt); -+#endif -+ } -+ if (ret < 0) -+ return log_error_errno(ret, errno, "Failed to mount %s filesystem onto %d(%s)", -+ fstype, dfd_mnt_cgroupfs, maybe_empty(hierarchy_mnt)); -+ -+ DEBUG("Mounted cgroup filesystem %s onto %d(%s)", -+ fstype, dfd_mnt_cgroupfs, maybe_empty(hierarchy_mnt)); -+ return 0; -+} -+ -+static inline int cgroupfs_mount(int cgroup_automount_type, struct hierarchy *h, -+ struct lxc_rootfs *rootfs, -+ int dfd_mnt_cgroupfs, const char *hierarchy_mnt) -+{ -+ return __cgroupfs_mount(cgroup_automount_type, h, rootfs, -+ dfd_mnt_cgroupfs, hierarchy_mnt); -+} -+ -+static inline int cgroupfs_bind_mount(int cgroup_automount_type, struct hierarchy *h, -+ struct lxc_rootfs *rootfs, -+ int dfd_mnt_cgroupfs, -+ const char *hierarchy_mnt) -+{ -+ switch (cgroup_automount_type) { -+ case LXC_AUTO_CGROUP_FULL_RO: -+ break; -+ case LXC_AUTO_CGROUP_FULL_RW: -+ break; -+ case LXC_AUTO_CGROUP_FULL_MIXED: -+ break; -+ default: -+ return 0; -+ } -+ -+ return __cgroupfs_mount(cgroup_automount_type, h, rootfs, -+ dfd_mnt_cgroupfs, hierarchy_mnt); -+} -+ - /* __cg_mount_direct - * - * Mount cgroup hierarchies directly without using bind-mounts. The main -@@ -1289,139 +1560,300 @@ static inline int cg_mount_cgroup_full(int type, struct hierarchy *h, - } - - __cgfsng_ops static bool isulad_cgfsng_mount(struct cgroup_ops *ops, -- struct lxc_handler *handler, -- const char *root, int type) --{ -- int i, ret; -- char *tmpfspath = NULL; -- char *systemdpath = NULL; -- char *unifiedpath = NULL; -- bool has_cgns = false, retval = false, wants_force_mount = false; -+ struct lxc_handler *handler, int cg_flags) -+{ -+ __do_close int dfd_mnt_tmpfs = -EBADF, fd_fs = -EBADF; -+ __do_free char *cgroup_root = NULL; -+ int cgroup_automount_type; -+ bool in_cgroup_ns = false, wants_force_mount = false; -+ struct lxc_conf *conf = handler->conf; -+ struct lxc_rootfs *rootfs = &conf->rootfs; -+ const char *rootfs_mnt = get_rootfs_mnt(rootfs); -+ int ret; -+#ifdef HAVE_ISULAD - char **merged = NULL; -+ __do_free char *systemdpath = NULL; -+ __do_free char *unifiedpath = NULL; -+#endif -+ -+ if (!ops) -+ return ret_set_errno(false, ENOENT); - -- if ((type & LXC_AUTO_CGROUP_MASK) == 0) -+ if (!ops->hierarchies) - return true; - -- if (type & LXC_AUTO_CGROUP_FORCE) { -- type &= ~LXC_AUTO_CGROUP_FORCE; -+ if (!conf) -+ return ret_set_errno(false, EINVAL); -+ -+ if ((cg_flags & LXC_AUTO_CGROUP_MASK) == 0) -+ return log_trace(true, "No cgroup mounts requested"); -+ -+ if (cg_flags & LXC_AUTO_CGROUP_FORCE) { -+ cg_flags &= ~LXC_AUTO_CGROUP_FORCE; - wants_force_mount = true; - } - -+ switch (cg_flags) { -+ case LXC_AUTO_CGROUP_RO: -+ TRACE("Read-only cgroup mounts requested"); -+ break; -+ case LXC_AUTO_CGROUP_RW: -+ TRACE("Read-write cgroup mounts requested"); -+ break; -+ case LXC_AUTO_CGROUP_MIXED: -+ TRACE("Mixed cgroup mounts requested"); -+ break; -+ case LXC_AUTO_CGROUP_FULL_RO: -+ TRACE("Full read-only cgroup mounts requested"); -+ break; -+ case LXC_AUTO_CGROUP_FULL_RW: -+ TRACE("Full read-write cgroup mounts requested"); -+ break; -+ case LXC_AUTO_CGROUP_FULL_MIXED: -+ TRACE("Full mixed cgroup mounts requested"); -+ break; -+ case LXC_AUTO_CGROUP2_RW: -+ TRACE("Read-write cgroup2 mount requested"); -+ break; -+ case LXC_AUTO_CGROUP2_RO: -+ TRACE("Read-only cgroup2 mount requested"); -+ break; -+ default: -+ return log_error_errno(false, EINVAL, "Invalid cgroup mount options specified"); -+ } -+ cgroup_automount_type = cg_flags; -+ - if (!wants_force_mount) { -- if (!lxc_list_empty(&handler->conf->keepcaps)) -- wants_force_mount = !in_caplist(CAP_SYS_ADMIN, &handler->conf->keepcaps); -- else -- wants_force_mount = in_caplist(CAP_SYS_ADMIN, &handler->conf->caps); -+ wants_force_mount = !lxc_wants_cap(CAP_SYS_ADMIN, conf); -+ -+ /* -+ * Most recent distro versions currently have init system that -+ * do support cgroup2 but do not mount it by default unless -+ * explicitly told so even if the host is cgroup2 only. That -+ * means they often will fail to boot. Fix this by pre-mounting -+ * cgroup2 by default. We will likely need to be doing this a -+ * few years until all distros have switched over to cgroup2 at -+ * which point we can safely assume that their init systems -+ * will mount it themselves. -+ */ -+ if (pure_unified_layout(ops)) -+ wants_force_mount = true; - } - -- has_cgns = cgns_supported(); -- if (has_cgns && !wants_force_mount) -- return true; -+ if (cgns_supported() && container_uses_namespace(handler, CLONE_NEWCGROUP)) -+ in_cgroup_ns = true; - -- if (type == LXC_AUTO_CGROUP_NOSPEC) -- type = LXC_AUTO_CGROUP_MIXED; -- else if (type == LXC_AUTO_CGROUP_FULL_NOSPEC) -- type = LXC_AUTO_CGROUP_FULL_MIXED; -+ if (in_cgroup_ns && !wants_force_mount) -+ return log_trace(true, "Mounting cgroups not requested or needed"); - -- /* Mount tmpfs */ -- tmpfspath = must_make_path(root, "/sys/fs/cgroup", NULL); -- if (mkdir_p(tmpfspath, 0755) < 0) { -- ERROR("Failed to create directory: %s", tmpfspath); -- goto on_error; -+ /* This is really the codepath that we want. */ -+ if (pure_unified_layout(ops) || -+ (cgroup_automount_type == LXC_AUTO_CGROUP2_RW) || -+ (cgroup_automount_type == LXC_AUTO_CGROUP2_RO)) { -+ __do_close int dfd_mnt_unified = -EBADF; -+ -+ if (!ops->unified) -+ return log_error_errno(false, EINVAL, "No unified cgroup hierarchy mounted on the host"); -+ -+ dfd_mnt_unified = open_at(rootfs->dfd_mnt, DEFAULT_CGROUP_MOUNTPOINT_RELATIVE, -+ PROTECT_OPATH_DIRECTORY, PROTECT_LOOKUP_BENEATH_XDEV, 0); -+ if (dfd_mnt_unified < 0) -+ return syserror_ret(false, "Failed to open %d(%s)", -+ rootfs->dfd_mnt, DEFAULT_CGROUP_MOUNTPOINT_RELATIVE); -+ /* -+ * If cgroup namespaces are supported but the container will -+ * not have CAP_SYS_ADMIN after it has started we need to mount -+ * the cgroups manually. -+ * -+ * Note that here we know that wants_force_mount is true. -+ * Otherwise we would've returned early above. -+ */ -+ if (in_cgroup_ns) { -+ /* -+ * 1. cgroup:rw:force -> Mount the cgroup2 filesystem. -+ * 2. cgroup:ro:force -> Mount the cgroup2 filesystem read-only. -+ * 3. cgroup:mixed:force -> See comment above how this -+ * does not apply so -+ * cgroup:mixed is equal to -+ * cgroup:rw when cgroup -+ * namespaces are supported. -+ -+ * 4. cgroup:rw -> No-op; init system responsible for mounting. -+ * 5. cgroup:ro -> No-op; init system responsible for mounting. -+ * 6. cgroup:mixed -> No-op; init system responsible for mounting. -+ * -+ * 7. cgroup-full:rw -> Not supported. -+ * 8. cgroup-full:ro -> Not supported. -+ * 9. cgroup-full:mixed -> Not supported. -+ -+ * 10. cgroup-full:rw:force -> Not supported. -+ * 11. cgroup-full:ro:force -> Not supported. -+ * 12. cgroup-full:mixed:force -> Not supported. -+ * -+ * 13. cgroup2 -> No-op; init system responsible for mounting. -+ * 14. cgroup2:ro -> No-op; init system responsible for mounting. -+ * 15. cgroup2:force -> Mount the cgroup2 filesystem read-write -+ * 16. cgroup2:ro:force -> Mount the cgroup2 filesystem read-only -+ */ -+ ret = cgroupfs_mount(cgroup_automount_type, ops->unified, rootfs, dfd_mnt_unified, ""); -+ if (ret < 0) -+ return syserror_ret(false, "Failed to force mount cgroup filesystem in cgroup namespace"); -+ -+ return log_trace(true, "Force mounted cgroup filesystem in new cgroup namespace"); -+ } else { -+ /* -+ * Either no cgroup namespace supported (highly -+ * unlikely unless we're dealing with a Frankenkernel. -+ * Or the user requested to keep the cgroup namespace -+ * of the host or another container. -+ */ -+ errno = EOPNOTSUPP; -+ if (wants_force_mount) -+ SYSWARN("Force-mounting the unified cgroup hierarchy without cgroup namespace support is currently not supported"); -+ else -+ SYSWARN("Mounting the unified cgroup hierarchy without cgroup namespace support is currently not supported"); -+ } -+ -+ return syserror_ret(false, "Failed to mount cgroups"); - } - -- if (ops->cgroup_layout == CGROUP_LAYOUT_UNIFIED) { -- if (has_cgns && wants_force_mount) { -- /* -- * If cgroup namespaces are supported but the container -- * will not have CAP_SYS_ADMIN after it has started we -- * need to mount the cgroups manually. -- */ -- return cg_mount_in_cgroup_namespace(type, ops->unified, tmpfspath) == 0; -- } -+ /* -+ * Mount a tmpfs over DEFAULT_CGROUP_MOUNTPOINT. Note that we're -+ * relying on RESOLVE_BENEATH so we need to skip the leading "/" in the -+ * DEFAULT_CGROUP_MOUNTPOINT define. -+ */ -+ if (can_use_mount_api()) { -+ fd_fs = fs_prepare("tmpfs", -EBADF, "", 0, 0); -+ if (fd_fs < 0) -+ return log_error_errno(false, errno, "Failed to create new filesystem context for tmpfs"); - -- return cg_mount_cgroup_full(type, ops->unified, tmpfspath) == 0; -- } -+ ret = fs_set_property(fd_fs, "mode", "0755"); -+ if (ret < 0) -+ return log_error_errno(false, errno, "Failed to mount tmpfs onto %d(dev)", fd_fs); -+ -+ ret = fs_set_property(fd_fs, "size", "10240k"); -+ if (ret < 0) -+ return log_error_errno(false, errno, "Failed to mount tmpfs onto %d(dev)", fd_fs); - -- ret = safe_mount(NULL, tmpfspath, "tmpfs", -- MS_NOSUID | MS_NODEV | MS_NOEXEC | MS_RELATIME, -- "size=10240k,mode=755", root, handler->conf->lsm_se_mount_context); -+ ret = fs_attach(fd_fs, rootfs->dfd_mnt, DEFAULT_CGROUP_MOUNTPOINT_RELATIVE, -+ PROTECT_OPATH_DIRECTORY, PROTECT_LOOKUP_BENEATH_XDEV, -+ MOUNT_ATTR_NOSUID | MOUNT_ATTR_NODEV | -+ MOUNT_ATTR_NOEXEC | MOUNT_ATTR_RELATIME); -+ } else { -+ cgroup_root = must_make_path(rootfs_mnt, DEFAULT_CGROUP_MOUNTPOINT, NULL); -+ ret = safe_mount(NULL, cgroup_root, "tmpfs", -+ MS_NOSUID | MS_NODEV | MS_NOEXEC | MS_RELATIME, -+ "size=10240k,mode=755", rootfs_mnt, handler->conf->rootfs.lsm_se_mount_context); -+ } - if (ret < 0) -- goto on_error; -+ return log_error_errno(false, errno, "Failed to mount tmpfs on %s", -+ DEFAULT_CGROUP_MOUNTPOINT_RELATIVE); - -- for (i = 0; ops->hierarchies[i]; i++) { -- char *controllerpath = NULL; -- char *path2 = NULL; -- struct hierarchy *h = ops->hierarchies[i]; -- char *controller = strrchr(h->at_mnt, '/'); -+ dfd_mnt_tmpfs = open_at(rootfs->dfd_mnt, DEFAULT_CGROUP_MOUNTPOINT_RELATIVE, -+ PROTECT_OPATH_DIRECTORY, PROTECT_LOOKUP_BENEATH_XDEV, 0); -+ if (dfd_mnt_tmpfs < 0) -+ return syserror_ret(false, "Failed to open %d(%s)", -+ rootfs->dfd_mnt, DEFAULT_CGROUP_MOUNTPOINT_RELATIVE); - -- if (!controller) -- continue; -- controller++; -+ for (int i = 0; ops->hierarchies[i]; i++) { -+ __do_free char *hierarchy_mnt = NULL, *path2 = NULL; -+ struct hierarchy *h = ops->hierarchies[i]; - -+#ifdef HAVE_ISULAD - // isulad: symlink subcgroup -- if (strchr(controller, ',') != NULL) { -+ if (strchr(h->at_mnt, ',') != NULL) { - int pret; -- pret = lxc_append_string(&merged, controller); -+ pret = lxc_append_string(&merged, h->at_mnt); - if (pret < 0) -- goto on_error; -- } -- -- controllerpath = must_make_path(tmpfspath, controller, NULL); -- if (dir_exists(controllerpath)) { -- free(controllerpath); -- continue; -+ return false; - } -+#endif - -- ret = mkdir(controllerpath, 0755); -+ ret = mkdirat(dfd_mnt_tmpfs, h->at_mnt, 0000); -+#ifdef HAVE_ISULAD - if (ret < 0) { -- SYSERROR("Error creating cgroup path: %s", controllerpath); -- free(controllerpath); -- goto on_error; -+ lxc_free_array((void **)merged, free); -+ return syserror_ret(false, "Failed to create cgroup at_mnt %d(%s)", dfd_mnt_tmpfs, h->at_mnt); - } -+#else -+ if (ret < 0) -+ return syserror_ret(false, "Failed to create cgroup at_mnt %d(%s)", dfd_mnt_tmpfs, h->at_mnt); -+#endif - -- if (has_cgns && wants_force_mount) { -- /* If cgroup namespaces are supported but the container -+ if (in_cgroup_ns && wants_force_mount) { -+ /* -+ * If cgroup namespaces are supported but the container - * will not have CAP_SYS_ADMIN after it has started we - * need to mount the cgroups manually. - */ -- ret = cg_mount_in_cgroup_namespace(type, h, controllerpath); -- free(controllerpath); -+ ret = cgroupfs_mount(cgroup_automount_type, h, rootfs, -+ dfd_mnt_tmpfs, h->at_mnt); -+#ifdef HAVE_ISULAD -+ if (ret < 0) { -+ lxc_free_array((void **)merged, free); -+ return false; -+ } -+#else - if (ret < 0) -- goto on_error; -- -+ return false; -+#endif - continue; - } - -- ret = cg_mount_cgroup_full(type, h, controllerpath); -+ /* Here is where the ancient kernel section begins. */ -+ ret = cgroupfs_bind_mount(cgroup_automount_type, h, rootfs, -+ dfd_mnt_tmpfs, h->at_mnt); -+#ifdef HAVE_ISULAD - if (ret < 0) { -- free(controllerpath); -- goto on_error; -+ lxc_free_array((void **)merged, free); -+ return false; - } -+#else -+ if (ret < 0) -+ return false; -+#endif - -- if (!cg_mount_needs_subdirs(type)) { -- free(controllerpath); -+ if (!cg_mount_needs_subdirs(cgroup_automount_type)) - continue; -- } - -+ if (!cgroup_root) -+ cgroup_root = must_make_path(rootfs_mnt, DEFAULT_CGROUP_MOUNTPOINT, NULL); -+ -+ hierarchy_mnt = must_make_path(cgroup_root, h->at_mnt, NULL); -+#ifdef HAVE_ISULAD - // isulad: ignore ops->container_cgroup so we will not see directory lxc after /sys/fs/cgroup/xxx 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); -+ // isulad: ignore h->container_base_path so we will not see subgroup of /sys/fs/cgroup/xxx/subgroup in container -+ path2 = must_make_path(h->at_mnt, NULL); -+#else -+ path2 = must_make_path(hierarchy_mnt, h->at_base, -+ ops->container_cgroup, NULL); -+#endif - ret = mkdir_p(path2, 0755); -- if (ret < 0) { -- free(controllerpath); -- free(path2); -- goto on_error; -+#ifdef HAVE_ISULAD -+ if (ret < 0 && (errno != EEXIST)) { -+ lxc_free_array((void **)merged, free); -+ return false; - } -+#else -+ if (ret < 0 && (errno != EEXIST)) -+ return false; -+#endif - -- ret = cg_legacy_mount_controllers(type, h, controllerpath, -- path2, ops->container_cgroup); -- free(controllerpath); -- free(path2); -+ ret = cg_legacy_mount_controllers(cgroup_automount_type, h, -+ hierarchy_mnt, path2, -+ ops->container_cgroup); -+#ifdef HAVE_ISULAD -+ if (ret < 0) { -+ lxc_free_array((void **)merged, free); -+ return false; -+ } -+#else - if (ret < 0) -- goto on_error; -+ return false; -+#endif - } - -+#ifdef HAVE_ISULAD - // isulad: symlink subcgroup - if (merged) { - char **mc = NULL; -@@ -1431,13 +1863,14 @@ __cgfsng_ops static bool isulad_cgfsng_mount(struct cgroup_ops *ops, - lxc_iterate_parts(token, copy, ",") { - int mret; - char *link; -- link = must_make_path(tmpfspath, token, NULL); -+ link = must_make_path(cgroup_root, token, NULL); - mret = symlink(*mc, link); - if (mret < 0 && errno != EEXIST) { - SYSERROR("Failed to create link %s for target %s", link, *mc); - free(copy); - free(link); -- goto on_error; -+ lxc_free_array((void **)merged, free); -+ return false; - } - free(link); - } -@@ -1445,59 +1878,49 @@ __cgfsng_ops static bool isulad_cgfsng_mount(struct cgroup_ops *ops, - } - } - -- - // isulad: remount /sys/fs/cgroup to readonly -- if (type == LXC_AUTO_CGROUP_FULL_RO || type == LXC_AUTO_CGROUP_RO) { -- ret = mount(tmpfspath, tmpfspath, "bind", -+ if (cg_flags == LXC_AUTO_CGROUP_FULL_RO || cg_flags == LXC_AUTO_CGROUP_RO) { -+ ret = mount(cgroup_root, cgroup_root, "bind", - MS_NOSUID|MS_NODEV|MS_NOEXEC|MS_RELATIME|MS_RDONLY|MS_BIND|MS_REMOUNT, NULL); - if (ret < 0) { - SYSERROR("Failed to remount /sys/fs/cgroup."); -- goto on_error; -+ lxc_free_array((void **)merged, free); -+ return false; - } - } - - // isulad: remount /sys/fs/cgroup/systemd to readwrite for system container - if (handler->conf->systemd != NULL && strcmp(handler->conf->systemd, "true") == 0) - { -- unifiedpath = must_make_path(root, "/sys/fs/cgroup/unified", NULL); -+ unifiedpath = must_make_path(get_rootfs_mnt(rootfs), "/sys/fs/cgroup/unified", NULL); - if (dir_exists(unifiedpath)) - { - ret = umount2(unifiedpath, MNT_DETACH); - if (ret < 0) - { - SYSERROR("Failed to umount /sys/fs/cgroup/unified."); -- goto on_error; -+ lxc_free_array((void **)merged, free); -+ return false; - } - } - -- systemdpath = must_make_path(root, "/sys/fs/cgroup/systemd", NULL); -+ systemdpath = must_make_path(get_rootfs_mnt(rootfs), "/sys/fs/cgroup/systemd", NULL); - ret = mount(systemdpath, systemdpath, "bind", - MS_NOSUID | MS_NODEV | MS_NOEXEC | MS_RELATIME | MS_BIND | MS_REMOUNT, NULL); - if (ret < 0) - { - SYSERROR("Failed to remount /sys/fs/cgroup/systemd."); -- goto on_error; -+ lxc_free_array((void **)merged, free); -+ return false; - } - } -+#endif - -- retval = true; -- --on_error: -- free(tmpfspath); -- if (systemdpath != NULL) -- { -- free(systemdpath); -- } -- if (unifiedpath != NULL) -- { -- free(unifiedpath); -- } -- lxc_free_array((void **)merged, free); -- return retval; -+ return true; - } - - /* Only root needs to escape to the cgroup of its init. */ --__cgfsng_ops static bool isulad_cgfsng_escape(const struct cgroup_ops *ops, -+__cgfsng_ops static bool isulad_cgfsng_criu_escape(const struct cgroup_ops *ops, - struct lxc_conf *conf) - { - if (!ops) -@@ -1528,7 +1951,7 @@ __cgfsng_ops static bool isulad_cgfsng_escape(const struct cgroup_ops *ops, - return true; - } - --__cgfsng_ops static int isulad_cgfsng_num_hierarchies(struct cgroup_ops *ops) -+__cgfsng_ops static int isulad_cgfsng_criu_num_hierarchies(struct cgroup_ops *ops) - { - int i = 0; - -@@ -1544,7 +1967,7 @@ __cgfsng_ops static int isulad_cgfsng_num_hierarchies(struct cgroup_ops *ops) - return i; - } - --__cgfsng_ops static bool isulad_cgfsng_get_hierarchies(struct cgroup_ops *ops, int n, -+__cgfsng_ops static bool isulad_cgfsng_criu_get_hierarchies(struct cgroup_ops *ops, int n, - char ***out) - { - int i; -@@ -1578,7 +2001,7 @@ static bool cg_legacy_freeze(struct cgroup_ops *ops) - } - - static int freezer_cgroup_events_cb(int fd, uint32_t events, void *cbdata, -- struct lxc_epoll_descr *descr) -+ struct lxc_async_descr *descr) - { - __do_close int duped_fd = -EBADF; - __do_free char *line = NULL; -@@ -1614,9 +2037,9 @@ static int freezer_cgroup_events_cb(int fd, uint32_t events, void *cbdata, - static int cg_unified_freeze(struct cgroup_ops *ops, int timeout) - { - __do_close int fd = -EBADF; -- call_cleaner(lxc_mainloop_close) struct lxc_epoll_descr *descr_ptr = NULL; -+ call_cleaner(lxc_mainloop_close) struct lxc_async_descr *descr_ptr = NULL; - int ret; -- struct lxc_epoll_descr descr; -+ struct lxc_async_descr descr; - struct hierarchy *h; - - h = ops->unified; -@@ -1641,7 +2064,8 @@ static int cg_unified_freeze(struct cgroup_ops *ops, int timeout) - /* automatically cleaned up now */ - descr_ptr = &descr; - -- ret = lxc_mainloop_add_handler(&descr, fd, freezer_cgroup_events_cb, INT_TO_PTR((int){1})); -+ ret = lxc_mainloop_add_handler(&descr, fd, freezer_cgroup_events_cb, default_cleanup_handler, -+ INT_TO_PTR((int){1}), "freezer_cgroup_events"); - if (ret < 0) - return log_error_errno(-1, errno, "Failed to add cgroup.events fd handler to mainloop"); - } -@@ -1682,9 +2106,9 @@ static int cg_legacy_unfreeze(struct cgroup_ops *ops) - static int cg_unified_unfreeze(struct cgroup_ops *ops, int timeout) - { - __do_close int fd = -EBADF; -- call_cleaner(lxc_mainloop_close)struct lxc_epoll_descr *descr_ptr = NULL; -+ call_cleaner(lxc_mainloop_close)struct lxc_async_descr *descr_ptr = NULL; - int ret; -- struct lxc_epoll_descr descr; -+ struct lxc_async_descr descr; - struct hierarchy *h; - - h = ops->unified; -@@ -1709,7 +2133,8 @@ static int cg_unified_unfreeze(struct cgroup_ops *ops, int timeout) - /* automatically cleaned up now */ - descr_ptr = &descr; - -- ret = lxc_mainloop_add_handler(&descr, fd, freezer_cgroup_events_cb, INT_TO_PTR((int){0})); -+ ret = lxc_mainloop_add_handler(&descr, fd, freezer_cgroup_events_cb, default_cleanup_handler, -+ INT_TO_PTR((int){0}), "freezer_cgroup_events"); - if (ret < 0) - return log_error_errno(-1, errno, "Failed to add cgroup.events fd handler to mainloop"); - } -@@ -1816,7 +2241,7 @@ static int cgroup_attach_leaf(const struct lxc_conf *conf, int unified_fd, pid_t - * that a short write would cause a buffer overrun. So be on - * the safe side. - */ -- if (ret < STRLITERALLEN(".lxc-/cgroup.procs")) -+ if ((size_t)ret < STRLITERALLEN(".lxc-/cgroup.procs")) - return log_error_errno(-EINVAL, EINVAL, "Unexpected short write would cause buffer-overrun"); - - slash = &attach_cgroup[ret] - STRLITERALLEN("/cgroup.procs"); -@@ -1848,7 +2273,7 @@ static int cgroup_attach_leaf(const struct lxc_conf *conf, int unified_fd, pid_t - } - - static int cgroup_attach_create_leaf(const struct lxc_conf *conf, -- int unified_fd, int *sk_fd) -+ int unified_fd, int *sk_fd, bool unprivileged) - { - __do_close int sk = *sk_fd, target_fd0 = -EBADF, target_fd1 = -EBADF; - int target_fds[2]; -@@ -1857,73 +2282,116 @@ static int cgroup_attach_create_leaf(const struct lxc_conf *conf, - /* Create leaf cgroup. */ - ret = mkdirat(unified_fd, ".lxc", 0755); - if (ret < 0 && errno != EEXIST) -- return log_error_errno(-1, errno, "Failed to create leaf cgroup \".lxc\""); -+ return syserror("Failed to create leaf cgroup \".lxc\""); - -- target_fd0 = openat(unified_fd, ".lxc/cgroup.procs", O_WRONLY | O_CLOEXEC | O_NOFOLLOW); -- if (target_fd0 < 0) -- return log_error_errno(-errno, errno, "Failed to open \".lxc/cgroup.procs\""); -- target_fds[0] = target_fd0; -+ if (unprivileged) { -+ target_fd0 = open_at(unified_fd, ".lxc/cgroup.procs", PROTECT_OPEN_W, PROTECT_LOOKUP_BENEATH, 0); -+ if (target_fd0 < 0) -+ return syserror("Failed to open \".lxc/cgroup.procs\""); -+ target_fds[0] = target_fd0; - -- target_fd1 = openat(unified_fd, "cgroup.procs", O_WRONLY | O_CLOEXEC | O_NOFOLLOW); -- if (target_fd1 < 0) -- return log_error_errno(-errno, errno, "Failed to open \".lxc/cgroup.procs\""); -- target_fds[1] = target_fd1; -+ target_fd1 = open_at(unified_fd, "cgroup.procs", PROTECT_OPEN_W, PROTECT_LOOKUP_BENEATH, 0); -+ if (target_fd1 < 0) -+ return syserror("Failed to open \".lxc/cgroup.procs\""); -+ target_fds[1] = target_fd1; - -- ret = lxc_abstract_unix_send_fds(sk, target_fds, 2, NULL, 0); -- if (ret <= 0) -- return log_error_errno(-errno, errno, "Failed to send \".lxc/cgroup.procs\" fds %d and %d", -- target_fd0, target_fd1); -+ ret = lxc_abstract_unix_send_fds(sk, target_fds, 2, NULL, 0); -+ if (ret <= 0) -+ return syserror("Failed to send \".lxc/cgroup.procs\" fds %d and %d", -+ target_fd0, target_fd1); - -- return log_debug(0, "Sent target cgroup fds %d and %d", target_fd0, target_fd1); -+ TRACE("Sent cgroup file descriptors %d and %d", target_fd0, target_fd1); -+ } else { -+ ret = lxc_abstract_unix_send_credential(sk, NULL, 0); -+ if (ret < 0) -+ return syserror("Failed to inform parent that we are done setting up mounts"); -+ -+ TRACE("Informed parent process that cgroup has been created"); -+ } -+ -+ return 0; - } - - static int cgroup_attach_move_into_leaf(const struct lxc_conf *conf, -- int *sk_fd, pid_t pid) -+ const char *lxcpath, -+ int unified_fd, int *sk_fd, pid_t pid, -+ bool unprivileged) - { - __do_close int sk = *sk_fd, target_fd0 = -EBADF, target_fd1 = -EBADF; -- int target_fds[2]; - char pidstr[INTTYPE_TO_STRLEN(int64_t) + 1]; - size_t pidstr_len; -+#if HAVE_LIBSYSTEMD -+ __do_free char *scope = NULL; -+#endif - ssize_t ret; - -- ret = lxc_abstract_unix_recv_fds(sk, target_fds, 2, NULL, 0); -- if (ret <= 0) -- return log_error_errno(-1, errno, "Failed to receive target cgroup fd"); -- target_fd0 = target_fds[0]; -- target_fd1 = target_fds[1]; -+#if HAVE_LIBSYSTEMD -+ scope = lxc_cmd_get_systemd_scope(conf->name, lxcpath); -+ if (scope) { -+ TRACE("%s:%s is running under systemd-created scope '%s'. Attaching...", lxcpath, conf->name, scope); -+ if (enter_scope(scope, pid)) -+ TRACE("Successfully entered scope '%s'", scope); -+ else -+ ERROR("Failed entering scope '%s'", scope); -+ } else { -+ TRACE("%s:%s is not running under a systemd-created scope", lxcpath, conf->name); -+ } -+#endif -+ if (unprivileged) { -+ ret = lxc_abstract_unix_recv_two_fds(sk, &target_fd0, &target_fd1); -+ if (ret < 0) -+ return log_error_errno(-1, errno, "Failed to receive target cgroup fd"); -+ } else { -+ ret = lxc_abstract_unix_rcv_credential(sk, NULL, 0); -+ if (ret < 0) -+ return syserror("Failed to receive notification from parent process"); -+ -+ TRACE("Child process informed us that cgroup has been created"); -+ -+ target_fd0 = open_at(unified_fd, ".lxc/cgroup.procs", PROTECT_OPEN_W, PROTECT_LOOKUP_BENEATH, 0); -+ if (target_fd0 < 0) -+ return syserror("Failed to open \".lxc/cgroup.procs\""); -+ -+ target_fd1 = open_at(unified_fd, "cgroup.procs", PROTECT_OPEN_W, PROTECT_LOOKUP_BENEATH, 0); -+ if (target_fd1 < 0) -+ return syserror("Failed to open \".lxc/cgroup.procs\""); -+ -+ TRACE("Opened target cgroup file descriptors %d and %d", target_fd0, target_fd1); -+ } - - pidstr_len = sprintf(pidstr, INT64_FMT, (int64_t)pid); - - ret = lxc_write_nointr(target_fd0, pidstr, pidstr_len); -- if (ret > 0 && ret == pidstr_len) -+ if (ret > 0 && (size_t)ret == pidstr_len) - return log_debug(0, "Moved process into target cgroup via fd %d", target_fd0); - - ret = lxc_write_nointr(target_fd1, pidstr, pidstr_len); -- if (ret > 0 && ret == pidstr_len) -+ if (ret > 0 && (size_t)ret == pidstr_len) - return log_debug(0, "Moved process into target cgroup via fd %d", target_fd1); - -- return log_debug_errno(-1, errno, "Failed to move process into target cgroup via fd %d and %d", -- target_fd0, target_fd1); -+ return syserror("Failed to move process into target cgroup via fd %d and %d", target_fd0, target_fd1); - } - - struct userns_exec_unified_attach_data { - const struct lxc_conf *conf; -+ const char *lxcpath; - int unified_fd; - int sk_pair[2]; - pid_t pid; -+ bool unprivileged; - }; - - static int cgroup_unified_attach_child_wrapper(void *data) - { - struct userns_exec_unified_attach_data *args = data; - -- if (!args->conf || args->unified_fd < 0 || args->pid <= 0 || -- args->sk_pair[0] < 0 || args->sk_pair[1] < 0) -+ if (!args->conf || !args->lxcpath || args->unified_fd < 0 || -+ args->pid <= 0 || args->sk_pair[0] < 0 || args->sk_pair[1] < 0) - return ret_errno(EINVAL); - - close_prot_errno_disarm(args->sk_pair[0]); - return cgroup_attach_create_leaf(args->conf, args->unified_fd, -- &args->sk_pair[1]); -+ &args->sk_pair[1], args->unprivileged); - } - - static int cgroup_unified_attach_parent_wrapper(void *data) -@@ -1935,44 +2403,10 @@ static int cgroup_unified_attach_parent_wrapper(void *data) - return ret_errno(EINVAL); - - close_prot_errno_disarm(args->sk_pair[1]); -- return cgroup_attach_move_into_leaf(args->conf, &args->sk_pair[0], -- args->pid); --} -- --int cgroup_attach(const struct lxc_conf *conf, const char *name, -- const char *lxcpath, pid_t pid) --{ -- __do_close int unified_fd = -EBADF; -- int ret; -- -- if (!conf || !name || !lxcpath || pid <= 0) -- return ret_errno(EINVAL); -- -- unified_fd = lxc_cmd_get_cgroup2_fd(name, lxcpath); -- if (unified_fd < 0) -- return ret_errno(EBADF); -- -- if (!lxc_list_empty(&conf->id_map)) { -- struct userns_exec_unified_attach_data args = { -- .conf = conf, -- .unified_fd = unified_fd, -- .pid = pid, -- }; -- -- ret = socketpair(PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0, args.sk_pair); -- if (ret < 0) -- return -errno; -- -- ret = userns_exec_minimal(conf, -- cgroup_unified_attach_parent_wrapper, -- &args, -- cgroup_unified_attach_child_wrapper, -- &args); -- } else { -- ret = cgroup_attach_leaf(conf, unified_fd, pid); -- } -- -- return ret; -+ return cgroup_attach_move_into_leaf(args->conf, args->lxcpath, -+ args->unified_fd, -+ &args->sk_pair[0], args->pid, -+ args->unprivileged); - } - - /* Technically, we're always at a delegation boundary here (This is especially -@@ -1999,7 +2433,8 @@ static int __cg_unified_attach(const struct hierarchy *h, - ret = cgroup_attach(conf, name, lxcpath, pid); - if (ret == 0) - return log_trace(0, "Attached to unified cgroup via command handler"); -- if (ret != -EBADF) -+ TRACE("__cg_unified_attach: cgroup_attach returned %d", ret); -+ if (!ERRNO_IS_NOT_SUPPORTED(ret) && ret != -ENOCGROUP2) - return log_error_errno(ret, errno, "Failed to attach to unified cgroup"); - - /* Fall back to retrieving the path for the unified cgroup. */ -@@ -2007,18 +2442,21 @@ static int __cg_unified_attach(const struct hierarchy *h, - /* not running */ - if (!cgroup) - return 0; -+ TRACE("lxc_cmd_get_cgroup_path returned %s", cgroup); - -- path = must_make_path(h->at_mnt, cgroup, NULL); -+ path = make_cgroup_path(h, cgroup, NULL); - - unified_fd = open(path, O_PATH | O_DIRECTORY | O_CLOEXEC); - if (unified_fd < 0) - return ret_errno(EBADF); - -- if (!lxc_list_empty(&conf->id_map)) { -+ if (!list_empty(&conf->id_map)) { - struct userns_exec_unified_attach_data args = { - .conf = conf, - .unified_fd = unified_fd, - .pid = pid, -+ .unprivileged = am_guest_unpriv(), -+ .lxcpath = lxcpath, - }; - - ret = socketpair(PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0, args.sk_pair); -@@ -2152,32 +2590,26 @@ static int device_cgroup_parse_access(struct device_item *device, const char *va - return 0; - } - --int device_cgroup_rule_parse(struct device_item *device, const char *key, -+static int device_cgroup_rule_parse(struct device_item *device, const char *key, - const char *val) - { -- int count, ret; -+ size_t count; -+ int ret; - char temp[50]; - -- if (strcmp("devices.allow", key) == 0) -- device->allow = 1; -+ if (strequal("devices.allow", key)) -+ device->allow = 1; /* allow the device */ - else -- device->allow = 0; -+ device->allow = 0; /* deny the device */ - -- if (strcmp(val, "a") == 0) { -+ if (strequal(val, "a")) { - /* global rule */ - device->type = 'a'; - device->major = -1; - device->minor = -1; -- device->global_rule = device->allow -- ? LXC_BPF_DEVICE_CGROUP_BLACKLIST -- : LXC_BPF_DEVICE_CGROUP_WHITELIST; -- device->allow = -1; - return 0; - } - -- /* local rule */ -- device->global_rule = LXC_BPF_DEVICE_CGROUP_LOCAL_RULE; -- - switch (*val) { - case 'a': - __fallthrough; -@@ -2300,7 +2732,9 @@ static int device_cgroup_rule_parse_devpath(struct device_item *device, - char *p; - struct stat sb; - -- path = must_copy_string(devpath); -+ path = strdup(devpath); -+ if (!path) -+ return ret_errno(ENOMEM); - - /* - * Read path followed by mode. Ignore any trailing text. -@@ -2329,9 +2763,6 @@ static int device_cgroup_rule_parse_devpath(struct device_item *device, - if (device_cgroup_parse_access(device, mode) < 0) - return -1; - -- if (n_parts == 1) -- return ret_set_errno(-1, EINVAL); -- - ret = stat(path, &sb); - if (ret < 0) - return ret_set_errno(-1, errno); -@@ -2351,7 +2782,6 @@ static int device_cgroup_rule_parse_devpath(struct device_item *device, - device->major = MAJOR(sb.st_rdev); - device->minor = MINOR(sb.st_rdev); - device->allow = 1; -- device->global_rule = LXC_BPF_DEVICE_CGROUP_LOCAL_RULE; - - return 0; - } -@@ -2481,15 +2911,38 @@ retry: - return ret; - } - -+/* -+ * Return the list of cgroup_settings sorted according to the following rules -+ * 1. Put memory.limit_in_bytes before memory.memsw.limit_in_bytes -+ */ -+static void sort_cgroup_settings(struct lxc_conf *conf) -+{ -+ LIST_HEAD(memsw_list); -+ struct lxc_cgroup *cgroup, *ncgroup; -+ -+ /* Iterate over the cgroup settings and copy them to the output list. */ -+ list_for_each_entry_safe(cgroup, ncgroup, &conf->cgroup, head) { -+ if (!strequal(cgroup->subsystem, "memory.memsw.limit_in_bytes")) -+ continue; -+ -+ /* Move the memsw entry from the cgroup settings list. */ -+ list_move_tail(&cgroup->head, &memsw_list); -+ } -+ -+ /* -+ * Append all the memsw entries to the end of the cgroup settings list -+ * to make sure they are applied after all memory limit settings. -+ */ -+ list_splice_tail(&memsw_list, &conf->cgroup); -+ -+} -+ - __cgfsng_ops static bool isulad_cgfsng_setup_limits_legacy(struct cgroup_ops *ops, - struct lxc_conf *conf, - bool do_devices) - { -- __do_free struct lxc_list *sorted_cgroup_settings = NULL; -- struct lxc_list *cgroup_settings = &conf->cgroup; -- struct lxc_list *iterator, *next; -- struct lxc_cgroup *cg; -- bool ret = false; -+ struct list_head *cgroup_settings; -+ struct lxc_cgroup *cgroup; - char value[21 + 1] = { 0 }; - long long int readvalue, setvalue; - -@@ -2500,7 +2953,7 @@ __cgfsng_ops static bool isulad_cgfsng_setup_limits_legacy(struct cgroup_ops *op - return ret_set_errno(false, EINVAL); - - cgroup_settings = &conf->cgroup; -- if (lxc_list_empty(cgroup_settings)) -+ if (list_empty(cgroup_settings)) - return true; - - if (!ops->hierarchies) -@@ -2509,75 +2962,63 @@ __cgfsng_ops static bool isulad_cgfsng_setup_limits_legacy(struct cgroup_ops *op - if (pure_unified_layout(ops)) - return true; - -- sorted_cgroup_settings = sort_cgroup_settings(cgroup_settings); -- if (!sorted_cgroup_settings) -- return false; -- -- lxc_list_for_each(iterator, sorted_cgroup_settings) { -- cg = iterator->elem; -- -- if (do_devices == !strncmp("devices", cg->subsystem, 7)) { -- const char *cgvalue = cg->value; -- if (strcmp(cg->subsystem, "files.limit") == 0) { -+ sort_cgroup_settings(conf); -+ list_for_each_entry(cgroup, cgroup_settings, head) { -+ if (do_devices == strnequal("devices", cgroup->subsystem, 7)) { -+ const char *cgvalue = cgroup->value; -+ if (strcmp(cgroup->subsystem, "files.limit") == 0) { - if (lxc_safe_long_long(cgvalue, &setvalue) != 0) { - SYSERROR("Invalid integer value %s", cgvalue); -- goto out; -+ return false; - } - if (setvalue <= 0) { - cgvalue = "max"; - } - } -- if (isulad_cg_legacy_set_data(ops, cg->subsystem, cgvalue)) { -+ if (isulad_cg_legacy_set_data(ops, cgroup->subsystem, cgvalue)) { - if (do_devices && (errno == EACCES || errno == EPERM)) { -- SYSWARN("Failed to set \"%s\" to \"%s\"", cg->subsystem, cgvalue); -+ SYSWARN("Failed to set \"%s\" to \"%s\"", cgroup->subsystem, cgvalue); - continue; - } -- SYSERROR("Failed to set \"%s\" to \"%s\"", cg->subsystem, cgvalue); -- goto out; -+ SYSERROR("Failed to set \"%s\" to \"%s\"", cgroup->subsystem, cgvalue); -+ return false; - } -- DEBUG("Set controller \"%s\" set to \"%s\"", cg->subsystem, cgvalue); -+ DEBUG("Set controller \"%s\" set to \"%s\"", cgroup->subsystem, cgvalue); - } - - // isulad: check cpu shares -- if (strcmp(cg->subsystem, "cpu.shares") == 0) { -- if (isulad_cg_legacy_get_data(ops, cg->subsystem, value, sizeof(value) - 1) < 0) { -- SYSERROR("Error get %s", cg->subsystem); -- goto out; -+ if (strcmp(cgroup->subsystem, "cpu.shares") == 0) { -+ if (isulad_cg_legacy_get_data(ops, cgroup->subsystem, value, sizeof(value) - 1) < 0) { -+ SYSERROR("Error get %s", cgroup->subsystem); -+ return false; - } - trim(value); -- if (lxc_safe_long_long(cg->value, &setvalue) != 0) { -- SYSERROR("Invalid value %s", cg->value); -- goto out; -+ if (lxc_safe_long_long(cgroup->value, &setvalue) != 0) { -+ SYSERROR("Invalid value %s", cgroup->value); -+ return false; - } - if (lxc_safe_long_long(value, &readvalue) != 0) { - SYSERROR("Invalid value %s", value); -- goto out; -+ return false; - } - if (setvalue > readvalue) { - ERROR("The maximum allowed cpu-shares is %s", value); - lxc_write_error_message(ops->errfd, - "%s:%d: setting cgroup config for ready process caused \"The maximum allowed cpu-shares is %s\".", - __FILE__, __LINE__, value); -- goto out; -+ return false; - } else if (setvalue < readvalue) { - ERROR("The minimum allowed cpu-shares is %s", value); - lxc_write_error_message(ops->errfd, - "%s:%d: setting cgroup config for ready process caused \"The minimum allowed cpu-shares is %s\".", - __FILE__, __LINE__, value); -- goto out; -+ return false; - } - } - } - -- ret = true; - INFO("Limits for the legacy cgroup hierarchies have been setup"); --out: -- lxc_list_for_each_safe(iterator, sorted_cgroup_settings, next) { -- lxc_list_del(iterator); -- free(iterator); -- } -- -- return ret; -+ return true; - } - - /* -@@ -2588,31 +3029,35 @@ static int bpf_device_cgroup_prepare(struct cgroup_ops *ops, - struct lxc_conf *conf, const char *key, - const char *val) - { --#ifdef HAVE_STRUCT_BPF_CGROUP_DEV_CTX -- struct device_item device_item = {0}; -+ struct device_item device_item = {}; - int ret; - -- if (strcmp("devices.allow", key) == 0 && *val == '/') -+ if (strequal("devices.allow", key) && abspath(val)) - ret = device_cgroup_rule_parse_devpath(&device_item, val); - else - ret = device_cgroup_rule_parse(&device_item, key, val); - if (ret < 0) -- return log_error_errno(-1, EINVAL, "Failed to parse device string %s=%s", key, val); -+ return syserror_set(EINVAL, "Failed to parse device rule %s=%s", key, val); - -- ret = bpf_list_add_device(conf, &device_item); -+ /* -+ * Note that bpf_list_add_device() returns 1 if it altered the device -+ * list and 0 if it didn't; both return values indicate success. -+ * Only a negative return value indicates an error. -+ */ -+ ret = bpf_list_add_device(&conf->bpf_devices, &device_item); - if (ret < 0) - return -1; --#endif -+ - return 0; - } -- - __cgfsng_ops static bool isulad_cgfsng_setup_limits(struct cgroup_ops *ops, - struct lxc_handler *handler) - { - __do_free char *path = NULL; -- struct lxc_list *cgroup_settings, *iterator; -+ struct list_head *cgroup_settings; - struct hierarchy *h; - struct lxc_conf *conf; -+ struct lxc_cgroup *cg; - - if (!ops) - return ret_set_errno(false, ENOENT); -@@ -2627,7 +3072,7 @@ __cgfsng_ops static bool isulad_cgfsng_setup_limits(struct cgroup_ops *ops, - return ret_set_errno(false, EINVAL); - conf = handler->conf; - -- if (lxc_list_empty(&conf->cgroup2)) -+ if (list_empty(&conf->cgroup2)) - return true; - cgroup_settings = &conf->cgroup2; - -@@ -2638,8 +3083,7 @@ __cgfsng_ops static bool isulad_cgfsng_setup_limits(struct cgroup_ops *ops, - return false; - h = ops->unified; - -- lxc_list_for_each (iterator, cgroup_settings) { -- struct lxc_cgroup *cg = iterator->elem; -+ list_for_each_entry(cg, cgroup_settings, head) { - int ret; - - if (strncmp("devices", cg->subsystem, 7) == 0) { -@@ -2786,7 +3230,7 @@ bool __cgfsng_delegate_controllers(struct cgroup_ops *ops, const char *cgroup) - (void)strlcat(add_controllers, "+", full_len + 1); - (void)strlcat(add_controllers, *it, full_len + 1); - -- if ((it + 1) && *(it + 1)) -+ if (*(it + 1)) - (void)strlcat(add_controllers, " ", full_len + 1); - } - -@@ -2836,333 +3280,490 @@ __cgfsng_ops bool isulad_cgfsng_payload_delegate_controllers(struct cgroup_ops * - return __cgfsng_delegate_controllers(ops, ops->container_cgroup); - } - --static bool cgroup_use_wants_controllers(const struct cgroup_ops *ops, -- char **controllers) -+static inline bool unified_cgroup(const char *line) - { -- if (!ops->cgroup_use) -- return true; -+ return *line == '0'; -+} - -- for (char **cur_ctrl = controllers; cur_ctrl && *cur_ctrl; cur_ctrl++) { -- bool found = false; -+static inline char *current_unified_cgroup(bool relative, char *line) -+{ -+ char *current_cgroup; - -- for (char **cur_use = ops->cgroup_use; cur_use && *cur_use; cur_use++) { -- if (strcmp(*cur_use, *cur_ctrl) != 0) -- continue; -+ line += STRLITERALLEN("0::"); - -- found = true; -- break; -- } -+ if (!abspath(line)) -+ return ERR_PTR(-EINVAL); - -- if (found) -- continue; -+ /* remove init.scope */ -+ if (!relative) -+ line = prune_init_scope(line); - -- return false; -- } -+ /* create a relative path */ -+ line = deabs(line); - -- return true; -+ current_cgroup = strdup(line); -+ if (!current_cgroup) -+ return ERR_PTR(-ENOMEM); -+ -+ return current_cgroup; - } - --static void cg_unified_delegate(char ***delegate) -+static inline const char *unprefix(const char *controllers) - { -+ if (strnequal(controllers, "name=", STRLITERALLEN("name="))) -+ return controllers + STRLITERALLEN("name="); -+ return controllers; -+} -+ -+static int __list_cgroup_delegate(char ***delegate) -+{ -+ __do_free char **list = NULL; - __do_free char *buf = NULL; -- char *standard[] = {"cgroup.subtree_control", "cgroup.threads", NULL}; -+ char *standard[] = { -+ "cgroup.procs", -+ "cgroup.threads", -+ "cgroup.subtree_control", -+ "memory.oom.group", -+ NULL, -+ }; - char *token; -- int idx; -+ int ret; - -- buf = read_file("/sys/kernel/cgroup/delegate"); -+ buf = read_file_at(-EBADF, "/sys/kernel/cgroup/delegate", PROTECT_OPEN, 0); - if (!buf) { - for (char **p = standard; p && *p; p++) { -- idx = append_null_to_list((void ***)delegate); -- (*delegate)[idx] = must_copy_string(*p); -+ ret = list_add_string(&list, *p); -+ if (ret < 0) -+ return ret; - } -- SYSWARN("Failed to read /sys/kernel/cgroup/delegate"); -- return; -+ -+ *delegate = move_ptr(list); -+ return syswarn_ret(0, "Failed to read /sys/kernel/cgroup/delegate"); - } - -- lxc_iterate_parts (token, buf, " \t\n") { -+ lxc_iterate_parts(token, buf, " \t\n") { - /* - * We always need to chown this for both cgroup and - * cgroup2. - */ -- if (strcmp(token, "cgroup.procs") == 0) -+ if (strequal(token, "cgroup.procs")) - continue; - -- idx = append_null_to_list((void ***)delegate); -- (*delegate)[idx] = must_copy_string(token); -+ ret = list_add_string(&list, token); -+ if (ret < 0) -+ return ret; - } -+ -+ *delegate = move_ptr(list); -+ return 0; - } - --/* At startup, parse_hierarchies finds all the info we need about cgroup -- * mountpoints and current cgroups, and stores it in @d. -- */ --static int cg_hybrid_init(struct cgroup_ops *ops, bool relative, bool unprivileged) -+static bool unified_hierarchy_delegated(int dfd_base, char ***ret_files) - { -- __do_free char *basecginfo = NULL, *line = NULL; -- __do_free_string_list char **klist = NULL, **nlist = NULL; -- __do_fclose FILE *f = NULL; -+ __do_free_string_list char **list = NULL; - int ret; -- size_t len = 0; - -- /* Root spawned containers escape the current cgroup, so use init's -- * cgroups as our base in that case. -- */ -- if (!relative && (geteuid() == 0)) -- basecginfo = read_file("/proc/1/cgroup"); -- else -- basecginfo = read_file("/proc/self/cgroup"); -- if (!basecginfo) -- return ret_set_errno(-1, ENOMEM); -- -- ret = get_existing_subsystems(&klist, &nlist); -+ ret = __list_cgroup_delegate(&list); - if (ret < 0) -- return log_error_errno(-1, errno, "Failed to retrieve available legacy cgroup controllers"); -+ return syserror_ret(ret, "Failed to determine unified cgroup delegation requirements"); - -- f = fopen("/proc/self/mountinfo", "re"); -- if (!f) -- return log_error_errno(-1, errno, "Failed to open \"/proc/self/mountinfo\""); -+ for (char *const *s = list; s && *s; s++) { -+ if (!faccessat(dfd_base, *s, W_OK, 0) || errno == ENOENT) -+ continue; - -- lxc_cgfsng_print_basecg_debuginfo(basecginfo, klist, nlist); -+ return sysinfo_ret(false, "The %s file is not writable, skipping unified hierarchy", *s); -+ } - -- while (getline(&line, &len, f) != -1) { -- __do_free char *base_cgroup = NULL, *mountpoint = NULL; -- __do_free_string_list char **controller_list = NULL; -- int type; -- struct hierarchy *new; -+ *ret_files = move_ptr(list); -+ return true; -+} - -- type = get_cgroup_version(line); -- if (type == 0) -- continue; -+static bool legacy_hierarchy_delegated(int dfd_base) -+{ -+ int ret; - -- if (type == CGROUP2_SUPER_MAGIC && ops->unified) -- continue; -+ ret = faccessat(dfd_base, ".", W_OK, 0); -+ if (ret < 0 && errno != ENOENT) -+ return sysinfo_ret(false, "Legacy hierarchy not writable, skipping"); - -- if (ops->cgroup_layout == CGROUP_LAYOUT_UNKNOWN) { -- if (type == CGROUP2_SUPER_MAGIC) -- ops->cgroup_layout = CGROUP_LAYOUT_UNIFIED; -- else if (type == CGROUP_SUPER_MAGIC) -- ops->cgroup_layout = CGROUP_LAYOUT_LEGACY; -- } else if (ops->cgroup_layout == CGROUP_LAYOUT_UNIFIED) { -- if (type == CGROUP_SUPER_MAGIC) -- ops->cgroup_layout = CGROUP_LAYOUT_HYBRID; -- } else if (ops->cgroup_layout == CGROUP_LAYOUT_LEGACY) { -- if (type == CGROUP2_SUPER_MAGIC) -- ops->cgroup_layout = CGROUP_LAYOUT_HYBRID; -- } -+ return true; -+} - -- controller_list = cg_hybrid_get_controllers(klist, nlist, line, type); -- if (!controller_list && type == CGROUP_SUPER_MAGIC) -- continue; -+/** -+ * systemd guarantees that the order of co-mounted controllers is stable. On -+ * some systems the order of the controllers might be reversed though. -+ * -+ * For example, this is how the order is mismatched on CentOS 7: -+ * -+ * [root@localhost ~]# cat /proc/self/cgroup -+ * 11:perf_event:/ -+ * 10:pids:/ -+ * 9:freezer:/ -+ * >>>> 8:cpuacct,cpu:/ -+ * 7:memory:/ -+ * 6:blkio:/ -+ * 5:devices:/ -+ * 4:hugetlb:/ -+ * >>>> 3:net_prio,net_cls:/ -+ * 2:cpuset:/ -+ * 1:name=systemd:/user.slice/user-0.slice/session-c1.scope -+ * -+ * whereas the mountpoint: -+ * -+ * | |-/sys/fs/cgroup tmpfs tmpfs ro,nosuid,nodev,noexec,mode=755 -+ * | | |-/sys/fs/cgroup/systemd cgroup cgroup rw,nosuid,nodev,noexec,relatime,xattr,release_agent=/usr/lib/systemd/systemd-cgroups-agent,name=systemd -+ * | | |-/sys/fs/cgroup/cpuset cgroup cgroup rw,nosuid,nodev,noexec,relatime,cpuset -+ * >>>> | | |-/sys/fs/cgroup/net_cls,net_prio cgroup cgroup rw,nosuid,nodev,noexec,relatime,net_prio,net_cls -+ * | | |-/sys/fs/cgroup/hugetlb cgroup cgroup rw,nosuid,nodev,noexec,relatime,hugetlb -+ * | | |-/sys/fs/cgroup/devices cgroup cgroup rw,nosuid,nodev,noexec,relatime,devices -+ * | | |-/sys/fs/cgroup/blkio cgroup cgroup rw,nosuid,nodev,noexec,relatime,blkio -+ * | | |-/sys/fs/cgroup/memory cgroup cgroup rw,nosuid,nodev,noexec,relatime,memory -+ * >>>> | | |-/sys/fs/cgroup/cpu,cpuacct cgroup cgroup rw,nosuid,nodev,noexec,relatime,cpuacct,cpu -+ * | | |-/sys/fs/cgroup/freezer cgroup cgroup rw,nosuid,nodev,noexec,relatime,freezer -+ * | | |-/sys/fs/cgroup/pids cgroup cgroup rw,nosuid,nodev,noexec,relatime,pids -+ * | | `-/sys/fs/cgroup/perf_event cgroup cgroup rw,nosuid,nodev,noexec,relatime,perf_event -+ * -+ * Ensure that we always use the systemd-guaranteed stable order when checking -+ * for the mountpoint. -+ */ -+#if HAVE_COMPILER_ATTR_NONNULL -+__attribute__((nonnull)) -+#endif -+#if HAVE_COMPILER_ATTR_RETURNS_NONNULL -+__attribute__((returns_nonnull)) -+#endif -+static const char *stable_order(const char *controllers) -+{ -+ if (strequal(controllers, "cpuacct,cpu")) -+ return "cpu,cpuacct"; - -- if (type == CGROUP_SUPER_MAGIC) -- if (controller_list_is_dup(ops->hierarchies, controller_list)) { -- TRACE("Skipping duplicating controller"); -- continue; -- } -+ if (strequal(controllers, "net_prio,net_cls")) -+ return "net_cls,net_prio"; - -- mountpoint = cg_hybrid_get_mountpoint(line); -- if (!mountpoint) { -- WARN("Failed parsing mountpoint from \"%s\"", line); -- continue; -- } -+ return unprefix(controllers); -+} - -- if (type == CGROUP_SUPER_MAGIC) -- base_cgroup = cg_hybrid_get_current_cgroup(basecginfo, controller_list[0], CGROUP_SUPER_MAGIC); -- else -- base_cgroup = cg_hybrid_get_current_cgroup(basecginfo, NULL, CGROUP2_SUPER_MAGIC); -- if (!base_cgroup) { -- WARN("Failed to find current cgroup"); -- continue; -- } -+#define CGFSNG_LAYOUT_LEGACY BIT(0) -+#define CGFSNG_LAYOUT_UNIFIED BIT(1) - -- trim(base_cgroup); -- prune_init_scope(base_cgroup); -+static int __initialize_cgroups(struct cgroup_ops *ops, bool relative, -+ bool unprivileged, struct lxc_conf *conf) -+{ -+ __do_free char *cgroup_info = NULL; -+ unsigned int layout_mask = 0; -+ int ret; -+ char *it; - -- /* isulad: do not test writeable, if we run isulad in docker without cgroup namespace. -- * the base_cgroup will be docker/XXX.., mountpoint+base_cgroup may be not exist */ -+ ret = unpriv_systemd_create_scope(ops, conf); -+ if (ret < 0) -+ return ret_set_errno(false, ret); -+ else if (ret == 0) -+ TRACE("Entered an unpriv systemd scope"); - -- /* -- * reason:base cgroup may be started with /system.slice when cg_hybrid_init -- * read /proc/1/cgroup on host, and cgroup init will set all containers -- * cgroup path under /sys/fs/cgroup//system.slice/xxx/lxc -- * directory, this is not consistent with docker. The default cgroup path -- * should be under /sys/fs/cgroup//lxc directory. -- */ -+ /* -+ * Root spawned containers escape the current cgroup, so use init's -+ * cgroups as our base in that case. -+ */ -+ if (!relative && (geteuid() == 0)) -+ cgroup_info = read_file_at(-EBADF, "/proc/1/cgroup", PROTECT_OPEN, 0); -+ else -+ cgroup_info = read_file_at(-EBADF, "/proc/self/cgroup", PROTECT_OPEN, 0); -+ if (!cgroup_info) -+ return ret_errno(ENOMEM); -+ -+ lxc_iterate_parts(it, cgroup_info, "\n") { -+ __do_close int dfd_base = -EBADF, dfd_mnt = -EBADF; -+ __do_free char *controllers = NULL, *current_cgroup = NULL; -+ __do_free_string_list char **controller_list = NULL, -+ **delegate = NULL; -+ char *line; -+ int dfd, type; -+ -+ /* Handle the unified cgroup hierarchy. */ -+ line = it; -+ if (unified_cgroup(line)) { -+ char *unified_mnt; -+ -+ type = UNIFIED_HIERARCHY; -+ layout_mask |= CGFSNG_LAYOUT_UNIFIED; -+ -+ if (conf->cgroup_meta.systemd_scope) -+ current_cgroup = cgroup_relpath(conf->cgroup_meta.systemd_scope); -+ if (IS_ERR_OR_NULL(current_cgroup)) -+ current_cgroup = current_unified_cgroup(relative, line); -+ if (IS_ERR(current_cgroup)) -+ return PTR_ERR(current_cgroup); -+ -+ if (unified_cgroup_fd(ops->dfd_mnt)) { -+ dfd_mnt = dup_cloexec(ops->dfd_mnt); -+ unified_mnt = ""; -+ } else { -+ dfd_mnt = open_at(ops->dfd_mnt, -+ "unified", -+ PROTECT_OPATH_DIRECTORY, -+ PROTECT_LOOKUP_ABSOLUTE_XDEV, 0); -+ unified_mnt = "unified"; -+ } -+ if (dfd_mnt < 0) { -+ if (errno != ENOENT) -+ return syserror("Failed to open %d/unified", ops->dfd_mnt); - -- if (strlen(base_cgroup) > 1 && base_cgroup[0] == '/') { -- base_cgroup[1] = '\0'; -- } -+ SYSTRACE("Unified cgroup not mounted"); -+ continue; -+ } -+ -+ if (!fhas_fs_type(dfd_mnt, CGROUP2_SUPER_MAGIC)) { -+ SYSTRACE("Opened file descriptor %d is not a cgroup2 mountpoint", dfd_mnt); -+ continue; -+ } - -- if (type == CGROUP2_SUPER_MAGIC) { -- char *cgv2_ctrl_path; -+ dfd = dfd_mnt; -+ -+ if (!is_empty_string(current_cgroup)) { -+ dfd_base = open_at(dfd_mnt, current_cgroup, -+ PROTECT_OPATH_DIRECTORY, -+ PROTECT_LOOKUP_BENEATH_XDEV, 0); -+ if (dfd_base < 0) { -+ if (errno != ENOENT) -+ return syserror("Failed to open %d/%s", -+ dfd_mnt, current_cgroup); -+ -+ SYSTRACE("Current cgroup %d/%s does not exist (funky cgroup layout?)", -+ dfd_mnt, current_cgroup); -+ continue; -+ } -+ dfd = dfd_base; -+ } - -- cgv2_ctrl_path = must_make_path(mountpoint, base_cgroup, -- "cgroup.controllers", -- NULL); -+ if (!unified_hierarchy_delegated(dfd, &delegate)) -+ continue; - -- controller_list = cg_unified_get_controllers(cgv2_ctrl_path); -- free(cgv2_ctrl_path); -+ controller_list = unified_controllers(dfd, "cgroup.controllers"); - if (!controller_list) { -- controller_list = cg_unified_make_empty_controller(); -- TRACE("No controllers are enabled for " -- "delegation in the unified hierarchy"); -+ TRACE("No controllers are enabled for delegation in the unified hierarchy"); -+ controller_list = list_new(); -+ if (!controller_list) -+ return syserror_set(-ENOMEM, "Failed to create empty controller list"); - } -- } - -- /* Exclude all controllers that cgroup use does not want. */ -- if (!cgroup_use_wants_controllers(ops, controller_list)) { -- TRACE("Skipping controller"); -- continue; -- } -+ controllers = strdup(unified_mnt); -+ if (!controllers) -+ return ret_errno(ENOMEM); -+ } else { -+ char *__controllers, *__current_cgroup; -+ -+ type = LEGACY_HIERARCHY; -+ layout_mask |= CGFSNG_LAYOUT_LEGACY; -+ -+ __controllers = strchr(line, ':'); -+ if (!__controllers) -+ return ret_errno(EINVAL); -+ __controllers++; -+ -+ __current_cgroup = strchr(__controllers, ':'); -+ if (!__current_cgroup) -+ return ret_errno(EINVAL); -+ *__current_cgroup = '\0'; -+ __current_cgroup++; -+ -+ controllers = strdup(stable_order(__controllers)); -+ if (!controllers) -+ return ret_errno(ENOMEM); -+ -+ dfd_mnt = open_at(ops->dfd_mnt, -+ controllers, -+ PROTECT_OPATH_DIRECTORY, -+ PROTECT_LOOKUP_ABSOLUTE_XDEV, 0); -+ if (dfd_mnt < 0) { -+ if (errno != ENOENT) -+ return syserror("Failed to open %d/%s", -+ ops->dfd_mnt, controllers); -+ -+ SYSTRACE("%s not mounted", controllers); -+ continue; -+ } - -- new = add_hierarchy(&ops->hierarchies, move_ptr(controller_list), move_ptr(mountpoint), move_ptr(base_cgroup), type); -- if (type == CGROUP2_SUPER_MAGIC && !ops->unified) { -- if (unprivileged) -- cg_unified_delegate(&new->cgroup2_chown); -- ops->unified = new; -- } -- } -+ if (!fhas_fs_type(dfd_mnt, CGROUP_SUPER_MAGIC)) { -+ SYSTRACE("Opened file descriptor %d is not a cgroup mountpoint", dfd_mnt); -+ continue; -+ } - -- TRACE("Writable cgroup hierarchies:"); -- lxc_cgfsng_print_hierarchies(ops); -+ dfd = dfd_mnt; - -- /* verify that all controllers in cgroup.use and all crucial -- * controllers are accounted for -- */ -- if (!all_controllers_found(ops)) -- return log_error_errno(-1, ENOENT, "Failed to find all required controllers"); -+ if (!abspath(__current_cgroup)) -+ return ret_errno(EINVAL); - -- return 0; --} -+ /* remove init.scope */ -+ if (!relative) -+ __current_cgroup = prune_init_scope(__current_cgroup); - --/* Get current cgroup from /proc/self/cgroup for the cgroupfs v2 hierarchy. */ --static char *cg_unified_get_current_cgroup(bool relative) --{ -- __do_free char *basecginfo = NULL; -- char *copy; -- char *base_cgroup; -+ /* create a relative path */ -+ __current_cgroup = deabs(__current_cgroup); - -- if (!relative && (geteuid() == 0)) -- basecginfo = read_file("/proc/1/cgroup"); -- else -- basecginfo = read_file("/proc/self/cgroup"); -- if (!basecginfo) -- return NULL; -+ current_cgroup = strdup(__current_cgroup); -+ if (!current_cgroup) -+ return ret_errno(ENOMEM); - -- base_cgroup = strstr(basecginfo, "0::/"); -- if (!base_cgroup) -- return NULL; -+ if (!is_empty_string(current_cgroup)) { -+ dfd_base = open_at(dfd_mnt, current_cgroup, -+ PROTECT_OPATH_DIRECTORY, -+ PROTECT_LOOKUP_BENEATH_XDEV, 0); -+ if (dfd_base < 0) { -+ if (errno != ENOENT) -+ return syserror("Failed to open %d/%s", -+ dfd_mnt, current_cgroup); - -- base_cgroup = base_cgroup + 3; -- copy = copy_to_eol(base_cgroup); -- if (!copy) -- return NULL; -+ SYSTRACE("Current cgroup %d/%s does not exist (funky cgroup layout?)", -+ dfd_mnt, current_cgroup); -+ continue; -+ } -+ dfd = dfd_base; -+ } - -- return trim(copy); --} -+ if (!legacy_hierarchy_delegated(dfd)) -+ continue; - --static int cg_unified_init(struct cgroup_ops *ops, bool relative, -- bool unprivileged) --{ -- __do_free char *subtree_path = NULL; -- int ret; -- char *mountpoint; -- char **delegatable; -- struct hierarchy *new; -- char *base_cgroup = NULL; -+ /* -+ * We intentionally pass __current_cgroup here and not -+ * controllers because we would otherwise chop the -+ * mountpoint. -+ */ -+ controller_list = list_add_controllers(__controllers); -+ if (!controller_list) -+ return syserror_set(-ENOMEM, "Failed to create controller list from %s", __controllers); - -- ret = unified_cgroup_hierarchy(); -- if (ret == -ENOMEDIUM) -- return ret_errno(ENOMEDIUM); -+ if (skip_hierarchy(ops, controller_list)) -+ continue; - -- if (ret != CGROUP2_SUPER_MAGIC) -- return 0; -+ ops->cgroup_layout = CGROUP_LAYOUT_LEGACY; -+ } - -- base_cgroup = cg_unified_get_current_cgroup(relative); -- if (!base_cgroup) -- return ret_errno(EINVAL); -- if (!relative) -- prune_init_scope(base_cgroup); -+ ret = cgroup_hierarchy_add(ops, dfd_mnt, controllers, dfd, -+ current_cgroup, controller_list, type); -+ if (ret < 0) -+ return syserror_ret(ret, "Failed to add %s hierarchy", controllers); -+ -+ /* Transfer ownership. */ -+ move_fd(dfd_mnt); -+ move_fd(dfd_base); -+ move_ptr(current_cgroup); -+ move_ptr(controllers); -+ move_ptr(controller_list); -+ if (type == UNIFIED_HIERARCHY) -+ ops->unified->delegate = move_ptr(delegate); -+ } - -- /* -- * We assume that the cgroup we're currently in has been delegated to -- * us and we are free to further delege all of the controllers listed -- * in cgroup.controllers further down the hierarchy. -- */ -- mountpoint = must_copy_string(DEFAULT_CGROUP_MOUNTPOINT); -- subtree_path = must_make_path(mountpoint, base_cgroup, "cgroup.controllers", NULL); -- delegatable = cg_unified_get_controllers(subtree_path); -- if (!delegatable) -- delegatable = cg_unified_make_empty_controller(); -- if (!delegatable[0]) { -- TRACE("No controllers are enabled for delegation"); --#ifdef HAVE_ISULAD -- ops->no_controller = true; --#endif -+ /* determine cgroup layout */ -+ if (ops->unified) { -+ if (ops->cgroup_layout == CGROUP_LAYOUT_LEGACY) { -+ ops->cgroup_layout = CGROUP_LAYOUT_HYBRID; -+ } else { -+ if (bpf_devices_cgroup_supported()) -+ ops->unified->utilities |= DEVICES_CONTROLLER; -+ ops->cgroup_layout = CGROUP_LAYOUT_UNIFIED; -+ } - } - -- /* TODO: If the user requested specific controllers via lxc.cgroup.use -- * we should verify here. The reason I'm not doing it right is that I'm -- * not convinced that lxc.cgroup.use will be the future since it is a -- * global property. I much rather have an option that lets you request -- * controllers per container. -+ /* -+ * If we still don't know the cgroup layout at this point it means we -+ * have not found any writable cgroup hierarchies. Infer the layout -+ * from the layout bitmask we created when parsing the cgroups. -+ * -+ * Keep the ordering in the switch otherwise the bistmask-based -+ * matching won't work. - */ -+ if (ops->cgroup_layout == CGROUP_LAYOUT_UNKNOWN) { -+ switch (layout_mask) { -+ case (CGFSNG_LAYOUT_LEGACY | CGFSNG_LAYOUT_UNIFIED): -+ ops->cgroup_layout = CGROUP_LAYOUT_HYBRID; -+ break; -+ case CGFSNG_LAYOUT_LEGACY: -+ ops->cgroup_layout = CGROUP_LAYOUT_LEGACY; -+ break; -+ case CGFSNG_LAYOUT_UNIFIED: -+ ops->cgroup_layout = CGROUP_LAYOUT_UNIFIED; -+ break; -+ } -+ } - -- new = add_hierarchy(&ops->hierarchies, delegatable, mountpoint, base_cgroup, CGROUP2_SUPER_MAGIC); -- if (unprivileged) -- cg_unified_delegate(&new->cgroup2_chown); -- -- if (bpf_devices_cgroup_supported()) -- new->bpf_device_controller = 1; -- -- ops->cgroup_layout = CGROUP_LAYOUT_UNIFIED; -- ops->unified = new; -+ if (!controllers_available(ops)) -+ return syserror_set(-ENOENT, "One or more requested controllers unavailable or not delegated"); - -- return CGROUP2_SUPER_MAGIC; -+ return 0; - } - --static int isulad_cg_init(struct cgroup_ops *ops, struct lxc_conf *conf) -+static int isulad_initialize_cgroups(struct cgroup_ops *ops, struct lxc_conf *conf) - { -+ __do_close int dfd = -EBADF; - int ret; -- const char *tmp; -- bool relative = conf->cgroup_meta.relative; -+ const char *controllers_use; - -- tmp = lxc_global_config_value("lxc.cgroup.use"); -- if (tmp) { -- __do_free char *pin = NULL; -- char *chop, *cur; -+ if (ops->dfd_mnt >= 0) -+ return ret_errno(EBUSY); -+ -+ /* -+ * I don't see the need for allowing symlinks here. If users want to -+ * have their hierarchy available in different locations I strongly -+ * suggest bind-mounts. -+ */ -+ dfd = open_at(-EBADF, DEFAULT_CGROUP_MOUNTPOINT, -+ PROTECT_OPATH_DIRECTORY, PROTECT_LOOKUP_ABSOLUTE_XDEV, 0); -+ if (dfd < 0) -+ return syserror("Failed to open " DEFAULT_CGROUP_MOUNTPOINT); -+ -+ controllers_use = lxc_global_config_value("lxc.cgroup.use"); -+ if (controllers_use) { -+ __do_free char *dup = NULL; -+ char *it; - -- pin = must_copy_string(tmp); -- chop = pin; -+ dup = strdup(controllers_use); -+ if (!dup) -+ return -errno; - -- lxc_iterate_parts(cur, chop, ",") -- must_append_string(&ops->cgroup_use, cur); -+ lxc_iterate_parts(it, dup, ",") { -+ ret = list_add_string(&ops->cgroup_use, it); -+ if (ret < 0) -+ return ret; -+ } - } - -- ret = cg_unified_init(ops, relative, !lxc_list_empty(&conf->id_map)); -- if (ret < 0) -- return -1; -+ /* -+ * Keep dfd referenced by the cleanup function and actually move the fd -+ * once we know the initialization succeeded. So if we fail we clean up -+ * the dfd. -+ */ -+ ops->dfd_mnt = dfd; - -- if (ret == CGROUP2_SUPER_MAGIC) -- return 0; -+ ret = __initialize_cgroups(ops, conf->cgroup_meta.relative, !list_empty(&conf->id_map), conf); -+ if (ret < 0) -+ return syserror_ret(ret, "Failed to initialize cgroups"); - -- return cg_hybrid_init(ops, relative, !lxc_list_empty(&conf->id_map)); -+ /* Transfer ownership to cgroup_ops. */ -+ move_fd(dfd); -+ return 0; - } - - __cgfsng_ops static int isulad_cgfsng_data_init(struct cgroup_ops *ops, struct lxc_conf *conf) - { - const char *cgroup_pattern; -+#ifdef HAVE_ISULAD - const char *cgroup_tree; - __do_free char *container_cgroup = NULL, *__cgroup_tree = NULL; - size_t len; -+#endif - - if (!ops) - return ret_set_errno(-1, ENOENT); - - /* copy system-wide cgroup information */ - cgroup_pattern = lxc_global_config_value("lxc.cgroup.pattern"); -- if (cgroup_pattern && strcmp(cgroup_pattern, "") != 0) -- ops->cgroup_pattern = must_copy_string(cgroup_pattern); -+ if (cgroup_pattern && !strequal(cgroup_pattern, "")) { -+ ops->cgroup_pattern = strdup(cgroup_pattern); -+ if (!ops->cgroup_pattern) -+ return ret_errno(ENOMEM); -+ } - -+#ifdef HAVE_ISULAD - if (conf->cgroup_meta.dir) { - cgroup_tree = conf->cgroup_meta.dir; - container_cgroup = must_concat(&len, cgroup_tree, "/", conf->name, NULL); -@@ -3181,22 +3782,23 @@ __cgfsng_ops static int isulad_cgfsng_data_init(struct cgroup_ops *ops, struct l - return ret_set_errno(-1, ENOMEM); - - ops->container_cgroup = move_ptr(container_cgroup); -+#endif - - return 0; - } - --struct cgroup_ops *cgfsng_ops_init(struct lxc_conf *conf) -+struct cgroup_ops *cgroup_ops_init(struct lxc_conf *conf) - { -- __do_free struct cgroup_ops *cgfsng_ops = NULL; -+ __cleanup_cgroup_ops struct cgroup_ops *cgfsng_ops = NULL; - -- cgfsng_ops = malloc(sizeof(struct cgroup_ops)); -+ cgfsng_ops = zalloc(sizeof(struct cgroup_ops)); - if (!cgfsng_ops) - return ret_set_errno(NULL, ENOMEM); - -- memset(cgfsng_ops, 0, sizeof(struct cgroup_ops)); -- cgfsng_ops->cgroup_layout = CGROUP_LAYOUT_UNKNOWN; -+ cgfsng_ops->cgroup_layout = CGROUP_LAYOUT_UNKNOWN; -+ cgfsng_ops->dfd_mnt = -EBADF; - -- if (isulad_cg_init(cgfsng_ops, conf)) -+ if (isulad_initialize_cgroups(cgfsng_ops, conf)) - return NULL; - - cgfsng_ops->data_init = isulad_cgfsng_data_init; -@@ -3211,10 +3813,7 @@ struct cgroup_ops *cgfsng_ops_init(struct lxc_conf *conf) - cgfsng_ops->payload_delegate_controllers = isulad_cgfsng_payload_delegate_controllers; - cgfsng_ops->payload_create = isulad_cgfsng_payload_create; - cgfsng_ops->payload_enter = isulad_cgfsng_payload_enter; -- cgfsng_ops->payload_finalize = isulad_cgfsng_payload_finalize; -- cgfsng_ops->escape = isulad_cgfsng_escape; -- cgfsng_ops->num_hierarchies = isulad_cgfsng_num_hierarchies; -- cgfsng_ops->get_hierarchies = isulad_cgfsng_get_hierarchies; -+ cgfsng_ops->finalize = isulad_cgfsng_finalize; - cgfsng_ops->get_cgroup = isulad_cgfsng_get_cgroup; - cgfsng_ops->get = isulad_cgfsng_get; - cgfsng_ops->set = isulad_cgfsng_set; -@@ -3229,5 +3828,310 @@ struct cgroup_ops *cgfsng_ops_init(struct lxc_conf *conf) - cgfsng_ops->mount = isulad_cgfsng_mount; - cgfsng_ops->devices_activate = isulad_cgfsng_devices_activate; - -+ cgfsng_ops->criu_escape = isulad_cgfsng_criu_escape; -+ cgfsng_ops->criu_num_hierarchies = isulad_cgfsng_criu_num_hierarchies; -+ cgfsng_ops->criu_get_hierarchies = isulad_cgfsng_criu_get_hierarchies; -+ - return move_ptr(cgfsng_ops); - } -+ -+static int __unified_attach_fd(const struct lxc_conf *conf, const char *lxcpath, int fd_unified, pid_t pid) -+{ -+ int ret; -+ -+ if (!list_empty(&conf->id_map)) { -+ struct userns_exec_unified_attach_data args = { -+ .conf = conf, -+ .unified_fd = fd_unified, -+ .pid = pid, -+ .unprivileged = am_guest_unpriv(), -+ .lxcpath = lxcpath, -+ }; -+ -+ ret = socketpair(PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0, args.sk_pair); -+ if (ret < 0) -+ return -errno; -+ -+ ret = userns_exec_minimal(conf, -+ cgroup_unified_attach_parent_wrapper, -+ &args, -+ cgroup_unified_attach_child_wrapper, -+ &args); -+ } else { -+ ret = cgroup_attach_leaf(conf, fd_unified, pid); -+ } -+ -+ return ret; -+} -+ -+static int __cgroup_attach_many(const struct lxc_conf *conf, const char *name, -+ const char *lxcpath, pid_t pid) -+{ -+ call_cleaner(put_cgroup_ctx) struct cgroup_ctx *ctx = &(struct cgroup_ctx){}; -+ int ret; -+ size_t idx; -+ ssize_t pidstr_len; -+ char pidstr[INTTYPE_TO_STRLEN(pid_t)]; -+ -+ ret = lxc_cmd_get_cgroup_ctx(name, lxcpath, sizeof(struct cgroup_ctx), ctx); -+ if (ret < 0) -+ return ret_errno(ENOSYS); -+ -+ if (ctx->fd_len == 0) -+ return log_trace(0, "Container runs with unwritable %s cgroup layout", -+ cgroup_layout_name(ctx->layout)); -+ -+ pidstr_len = strnprintf(pidstr, sizeof(pidstr), "%d", pid); -+ if (pidstr_len < 0) -+ return pidstr_len; -+ -+ for (idx = 0; idx < ctx->fd_len; idx++) { -+ int dfd_con = ctx->fd[idx]; -+ -+ if (unified_cgroup_fd(dfd_con)) -+ ret = __unified_attach_fd(conf, lxcpath, dfd_con, pid); -+ else -+ ret = lxc_writeat(dfd_con, "cgroup.procs", pidstr, pidstr_len); -+ if (ret) -+ return syserror_ret(ret, "Failed to attach to cgroup fd %d", dfd_con); -+ else -+ TRACE("Attached to cgroup fd %d", dfd_con); -+ } -+ -+ TRACE("Attached to %s cgroup layout", cgroup_layout_name(ctx->layout)); -+ return 0; -+} -+ -+static int __cgroup_attach_unified(const struct lxc_conf *conf, const char *name, -+ const char *lxcpath, pid_t pid) -+{ -+ __do_close int dfd_unified = -EBADF; -+ -+ if (!conf || is_empty_string(name) || is_empty_string(lxcpath) || pid <= 0) -+ return ret_errno(EINVAL); -+ -+ dfd_unified = lxc_cmd_get_cgroup2_fd(name, lxcpath); -+ if (dfd_unified < 0) -+ return ret_errno(ENOSYS); -+ -+ return __unified_attach_fd(conf, lxcpath, dfd_unified, pid); -+} -+ -+int cgroup_attach(const struct lxc_conf *conf, const char *name, -+ const char *lxcpath, pid_t pid) -+{ -+ int ret; -+ -+ ret = __cgroup_attach_many(conf, name, lxcpath, pid); -+ if (ret < 0) { -+ if (!ERRNO_IS_NOT_SUPPORTED(ret)) -+ return ret; -+ -+ ret = __cgroup_attach_unified(conf, name, lxcpath, pid); -+ if (ret < 0 && ERRNO_IS_NOT_SUPPORTED(ret)) -+ return ret_errno(ENOSYS); -+ } -+ -+ return ret; -+} -+ -+/* Connects to command socket therefore isn't callable from command handler. */ -+int cgroup_get(const char *name, const char *lxcpath, const char *key, char *buf, size_t len) -+{ -+ __do_close int dfd = -EBADF; -+ struct cgroup_fd fd = { -+ .fd = -EBADF, -+ }; -+ size_t len_controller; -+ int ret; -+ -+ if (is_empty_string(name) || is_empty_string(lxcpath) || -+ is_empty_string(key)) -+ return ret_errno(EINVAL); -+ -+ if ((buf && !len) || (len && !buf)) -+ return ret_errno(EINVAL); -+ -+ len_controller = strcspn(key, "."); -+ len_controller++; /* Don't forget the \0 byte. */ -+ if (len_controller >= MAX_CGROUP_ROOT_NAMELEN) -+ return ret_errno(EINVAL); -+ (void)strlcpy(fd.controller, key, len_controller); -+ -+ ret = lxc_cmd_get_limit_cgroup_fd(name, lxcpath, sizeof(struct cgroup_fd), &fd); -+ if (ret < 0) { -+ if (!ERRNO_IS_NOT_SUPPORTED(ret)) -+ return ret; -+ -+ dfd = lxc_cmd_get_limit_cgroup2_fd(name, lxcpath); -+ if (dfd < 0) { -+ if (!ERRNO_IS_NOT_SUPPORTED(ret)) -+ return ret; -+ -+ return ret_errno(ENOSYS); -+ } -+ fd.type = UNIFIED_HIERARCHY; -+ fd.fd = move_fd(dfd); -+ } -+ dfd = move_fd(fd.fd); -+ -+ TRACE("Reading %s from %s cgroup hierarchy", key, cgroup_hierarchy_name(fd.type)); -+ -+ if (fd.type == UNIFIED_HIERARCHY && strequal(fd.controller, "devices")) -+ return ret_errno(EOPNOTSUPP); -+ else -+ ret = lxc_read_try_buf_at(dfd, key, buf, len); -+ -+ return ret; -+} -+ -+/* Connects to command socket therefore isn't callable from command handler. */ -+int cgroup_set(const char *name, const char *lxcpath, const char *key, const char *value) -+{ -+ __do_close int dfd = -EBADF; -+ struct cgroup_fd fd = { -+ .fd = -EBADF, -+ }; -+ size_t len_controller; -+ int ret; -+ -+ if (is_empty_string(name) || is_empty_string(lxcpath) || -+ is_empty_string(key) || is_empty_string(value)) -+ return ret_errno(EINVAL); -+ -+ len_controller = strcspn(key, "."); -+ len_controller++; /* Don't forget the \0 byte. */ -+ if (len_controller >= MAX_CGROUP_ROOT_NAMELEN) -+ return ret_errno(EINVAL); -+ (void)strlcpy(fd.controller, key, len_controller); -+ -+ ret = lxc_cmd_get_limit_cgroup_fd(name, lxcpath, sizeof(struct cgroup_fd), &fd); -+ if (ret < 0) { -+ if (!ERRNO_IS_NOT_SUPPORTED(ret)) -+ return ret; -+ -+ dfd = lxc_cmd_get_limit_cgroup2_fd(name, lxcpath); -+ if (dfd < 0) { -+ if (!ERRNO_IS_NOT_SUPPORTED(ret)) -+ return ret; -+ -+ return ret_errno(ENOSYS); -+ } -+ fd.type = UNIFIED_HIERARCHY; -+ fd.fd = move_fd(dfd); -+ } -+ dfd = move_fd(fd.fd); -+ -+ TRACE("Setting %s to %s in %s cgroup hierarchy", key, value, cgroup_hierarchy_name(fd.type)); -+ -+ if (fd.type == UNIFIED_HIERARCHY && strequal(fd.controller, "devices")) { -+ struct device_item device = {}; -+ -+ ret = device_cgroup_rule_parse(&device, key, value); -+ if (ret < 0) -+ return log_error_errno(-1, EINVAL, "Failed to parse device string %s=%s", -+ key, value); -+ -+ ret = lxc_cmd_add_bpf_device_cgroup(name, lxcpath, &device); -+ } else { -+ ret = lxc_writeat(dfd, key, value, strlen(value)); -+ } -+ -+ return ret; -+} -+ -+static int do_cgroup_freeze(int unified_fd, -+ const char *state_string, -+ int state_num, -+ int timeout, -+ const char *epoll_error, -+ const char *wait_error) -+{ -+ __do_close int events_fd = -EBADF; -+ call_cleaner(lxc_mainloop_close) struct lxc_async_descr *descr_ptr = NULL; -+ int ret; -+ struct lxc_async_descr descr = {}; -+ -+ if (timeout != 0) { -+ ret = lxc_mainloop_open(&descr); -+ if (ret) -+ return log_error_errno(-1, errno, "%s", epoll_error); -+ -+ /* automatically cleaned up now */ -+ descr_ptr = &descr; -+ -+ events_fd = open_at(unified_fd, "cgroup.events", PROTECT_OPEN, PROTECT_LOOKUP_BENEATH, 0); -+ if (events_fd < 0) -+ return log_error_errno(-errno, errno, "Failed to open cgroup.events file"); -+ -+ ret = lxc_mainloop_add_handler_events(&descr, events_fd, EPOLLPRI, -+ freezer_cgroup_events_cb, -+ default_cleanup_handler, -+ INT_TO_PTR(state_num), -+ "freezer_cgroup_events_cb"); -+ if (ret < 0) -+ return log_error_errno(-1, errno, "Failed to add cgroup.events fd handler to mainloop"); -+ } -+ -+ ret = lxc_writeat(unified_fd, "cgroup.freeze", state_string, 1); -+ if (ret < 0) -+ return log_error_errno(-1, errno, "Failed to open cgroup.freeze file"); -+ -+ if (timeout != 0) { -+ ret = lxc_mainloop(&descr, timeout); -+ if (ret) -+ return log_error_errno(-1, errno, "%s", wait_error); -+ } -+ -+ return log_trace(0, "Container now %s", (state_num == 1) ? "frozen" : "unfrozen"); -+} -+ -+static inline int __cgroup_freeze(int unified_fd, int timeout) -+{ -+ return do_cgroup_freeze(unified_fd, "1", 1, timeout, -+ "Failed to create epoll instance to wait for container freeze", -+ "Failed to wait for container to be frozen"); -+} -+ -+int cgroup_freeze(const char *name, const char *lxcpath, int timeout) -+{ -+ __do_close int unified_fd = -EBADF; -+ int ret; -+ -+ if (is_empty_string(name) || is_empty_string(lxcpath)) -+ return ret_errno(EINVAL); -+ -+ unified_fd = lxc_cmd_get_limit_cgroup2_fd(name, lxcpath); -+ if (unified_fd < 0) -+ return ret_errno(ENOCGROUP2); -+ -+ lxc_cmd_notify_state_listeners(name, lxcpath, FREEZING); -+ ret = __cgroup_freeze(unified_fd, timeout); -+ lxc_cmd_notify_state_listeners(name, lxcpath, !ret ? FROZEN : RUNNING); -+ return ret; -+} -+ -+int __cgroup_unfreeze(int unified_fd, int timeout) -+{ -+ return do_cgroup_freeze(unified_fd, "0", 0, timeout, -+ "Failed to create epoll instance to wait for container freeze", -+ "Failed to wait for container to be frozen"); -+} -+ -+int cgroup_unfreeze(const char *name, const char *lxcpath, int timeout) -+{ -+ __do_close int unified_fd = -EBADF; -+ int ret; -+ -+ if (is_empty_string(name) || is_empty_string(lxcpath)) -+ return ret_errno(EINVAL); -+ -+ unified_fd = lxc_cmd_get_limit_cgroup2_fd(name, lxcpath); -+ if (unified_fd < 0) -+ return ret_errno(ENOCGROUP2); -+ -+ lxc_cmd_notify_state_listeners(name, lxcpath, THAWED); -+ ret = __cgroup_unfreeze(unified_fd, timeout); -+ lxc_cmd_notify_state_listeners(name, lxcpath, !ret ? RUNNING : FROZEN); -+ return ret; -+} -diff --git a/src/lxc/commands.c b/src/lxc/commands.c -index 2188b31..bf63cac 100644 ---- a/src/lxc/commands.c -+++ b/src/lxc/commands.c -@@ -1991,7 +1991,7 @@ int lxc_cmd_set_terminal_fifos(const char *name, const char *lxcpath, const char - } - - 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_handler *handler, struct lxc_async_descr *descr) - { - struct lxc_cmd_rsp rsp; - memset(&rsp, 0, sizeof(rsp)); -@@ -2037,7 +2037,7 @@ int lxc_cmd_set_terminal_winch(const char *name, const char *lxcpath, unsigned i - } - - 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_handler *handler, struct lxc_async_descr *descr) - { - struct lxc_cmd_rsp rsp; - struct lxc_cmd_set_terminal_winch_request *data = (struct lxc_cmd_set_terminal_winch_request *)(req->data); -diff --git a/src/lxc/conf.c b/src/lxc/conf.c -index 187e60e..34cf90a 100644 ---- a/src/lxc/conf.c -+++ b/src/lxc/conf.c -@@ -299,15 +299,15 @@ static struct limit_opt limit_opt[] = { - static int rootfs_parent_mount_private(char *rootfs); - static int setup_rootfs_ropaths(struct lxc_list *ropaths); - static int setup_rootfs_maskedpaths(struct lxc_list *maskedpaths); --static int remount_proc_sys_mount_entries(struct lxc_list *mount_list, bool lsm_aa_allow_nesting); -+static int remount_proc_sys_mount_entries(struct list_head *mount_entries, bool lsm_aa_allow_nesting); - static int check_mount_destination(const char *rootfs, const char *dest, const char *src); - static int mount_entry_with_loop_dev(const char *src, const char *dest, const char *fstype, - char *mnt_opts, const char *rootfs); --static bool need_setup_proc(const struct lxc_conf *conf, struct lxc_list *mount); --static bool need_setup_dev(const struct lxc_conf *conf, struct lxc_list *mount); -+static bool need_setup_proc(const struct lxc_conf *conf, struct list_head *mount); -+static bool need_setup_dev(const struct lxc_conf *conf, struct list_head *mount); - static int setup_populate_devs(const struct lxc_rootfs *rootfs, struct lxc_list *devs, const char *mount_label); - static int setup_rootfs_mountopts(const struct lxc_rootfs *rootfs); --static int create_mtab_link(); -+static int create_mtab_link(void); - #endif - - static int run_buffer(char *buffer) -@@ -1252,8 +1252,13 @@ static int lxc_send_ttys_to_parent(struct lxc_handler *handler) - /* Just create a path for /dev under $lxcpath/$name and in rootfs If we hit an - * error, log it but don't fail yet. - */ -+#ifdef HAVE_ISULAD -+static int mount_autodev(const char *name, const struct lxc_rootfs *rootfs, -+ int autodevtmpfssize, const char *lxcpath, char *systemd, const char *mount_label) -+#else - static int mount_autodev(const char *name, const struct lxc_rootfs *rootfs, - int autodevtmpfssize, const char *lxcpath) -+#endif - { - #ifndef HAVE_ISULAD - __do_close int fd_fs = -EBADF; -@@ -1905,18 +1910,21 @@ static int lxc_setup_devpts_child(struct lxc_handler *handler) - */ - #ifdef HAVE_ISULAD - if (rootfs->lsm_se_mount_context != NULL) { -- ret = strnprintf(devpts_mntopts, sizeof(devpts_mntopts), "%s,max=%zu,context=\"%s\"", -- default_devpts_mntopts, pty_max, rootfs->lsm_se_mount_context); -+ if (asprintf(&devpts_mntopts, "%s,max=%zu,context=\"%s\"", -+ default_devpts_mntopts, conf->pty_max, conf->rootfs.lsm_se_mount_context) < 0) { -+ return -1; -+ } - } else { -+ if (asprintf(&devpts_mntopts, "%s,max=%zu", default_devpts_mntopts, conf->pty_max) < 0) { -+ return -1; -+ } -+ } - #else - ret = strnprintf(devpts_mntopts, sizeof(devpts_mntopts), "%s,max=%zu", - default_devpts_mntopts, pty_max); --#endif --#ifdef HAVE_ISULAD -- } --#endif - if (ret < 0) - return -1; -+#endif - - /* Create mountpoint for devpts instance. */ - ret = mkdirat(rootfs->dfd_dev, "pts", 0755); -@@ -2079,7 +2087,7 @@ static int bind_mount_console(int fd_devpts, struct lxc_rootfs *rootfs, - __do_free char *mnt_opts = NULL; - - if (rootfs->lsm_se_mount_context != NULL) { -- if (asprintf(mnt_opts, "context=\"%s\"", rootfs->lsm_se_mount_context) < 0) { -+ if (asprintf(&mnt_opts, "context=\"%s\"", rootfs->lsm_se_mount_context) < 0) { - return syserror("Out of memory"); - } - } -@@ -2181,7 +2189,7 @@ static int lxc_setup_ttydir_console(int fd_devpts, struct lxc_rootfs *rootfs, - __do_free char *mnt_opts = NULL; - - if (rootfs->lsm_se_mount_context != NULL) { -- if (asprintf(mnt_opts, "context=\"%s\"", rootfs->lsm_se_mount_context) < 0) { -+ if (asprintf(&mnt_opts, "context=\"%s\"", rootfs->lsm_se_mount_context) < 0) { - return syserror("Out of memory"); - } - } -@@ -2968,8 +2976,13 @@ static int mount_entry_on_relative_rootfs(struct mntent *mntent, - return mount_entry_on_generic(mntent, rootfs->buf, rootfs, lxc_name, lxc_path); - } - -+#ifdef HAVE_ISULAD -+static int mount_file_entries(const struct lxc_conf *conf, struct lxc_rootfs *rootfs, FILE *file, -+ const char *lxc_name, const char *lxc_path) -+#else - static int mount_file_entries(struct lxc_rootfs *rootfs, FILE *file, - const char *lxc_name, const char *lxc_path) -+#endif - { - char buf[PATH_MAX]; - struct mntent mntent; -@@ -3030,8 +3043,13 @@ static inline void __auto_endmntent__(FILE **f) - - #define __do_endmntent __attribute__((__cleanup__(__auto_endmntent__))) - -+#ifdef HAVE_ISULAD -+static int setup_mount_fstab(const struct lxc_conf *conf, struct lxc_rootfs *rootfs, const char *fstab, -+ const char *lxc_name, const char *lxc_path) -+#else - static int setup_mount_fstab(struct lxc_rootfs *rootfs, const char *fstab, - const char *lxc_name, const char *lxc_path) -+#endif - { - __do_endmntent FILE *f = NULL; - int ret; -@@ -3043,7 +3061,11 @@ static int setup_mount_fstab(struct lxc_rootfs *rootfs, const char *fstab, - if (!f) - return log_error_errno(-1, errno, "Failed to open \"%s\"", fstab); - -+#ifdef HAVE_ISULAD -+ ret = mount_file_entries(conf, rootfs, f, lxc_name, lxc_path); -+#else - ret = mount_file_entries(rootfs, f, lxc_name, lxc_path); -+#endif - if (ret < 0) - ERROR("Failed to set up mount entries"); - -@@ -3126,8 +3148,11 @@ static int setup_mount_entries(const struct lxc_conf *conf, - f = make_anonymous_mount_file(&conf->mount_entries, conf->lsm_aa_allow_nesting); - if (!f) - return -1; -- -+#ifdef HAVE_ISULAD -+ return mount_file_entries(conf, rootfs, f, lxc_name, lxc_path); -+#else - return mount_file_entries(rootfs, f, lxc_name, lxc_path); -+#endif - } - - static int __lxc_idmapped_mounts_child(struct lxc_handler *handler, FILE *f) -@@ -3540,7 +3565,11 @@ static int parse_resource(const char *res) - return resid; - } - -+#ifdef HAVE_ISULAD -+int setup_resource_limits(struct lxc_conf *conf, pid_t pid, int errfd) -+#else - int setup_resource_limits(struct lxc_conf *conf, pid_t pid) -+#endif - { - int resid; - struct lxc_limit *lim; -@@ -3554,8 +3583,17 @@ int setup_resource_limits(struct lxc_conf *conf, pid_t pid) - return log_error(-1, "Unknown resource %s", lim->resource); - - #if HAVE_PRLIMIT || HAVE_PRLIMIT64 -+#ifdef HAVE_ISULAD -+ if (prlimit(pid, resid, &lim->limit, NULL) != 0) { -+ lxc_write_error_message(errfd, "%s:%d: Failed to set limit %s %lu %lu: %s.", -+ __FILE__, __LINE__, lim->resource, -+ lim->limit.rlim_cur, lim->limit.rlim_max, strerror(errno)); -+ return log_error_errno(-1, errno, "Failed to set limit %s", lim->resource); -+ } -+#else - if (prlimit(pid, resid, &lim->limit, NULL) != 0) - return log_error_errno(-1, errno, "Failed to set limit %s", lim->resource); -+#endif - - TRACE("Setup \"%s\" limit", lim->resource); - #else -@@ -4099,8 +4137,11 @@ domount: - ret = strnprintf(rootfs->buf, sizeof(rootfs->buf), "%s/proc", rootfs->path ? rootfs->mount : ""); - if (ret < 0) - return ret_errno(EIO); -- -+#ifdef HAVE_ISULAD -+ ret = safe_mount("proc", rootfs->buf, "proc", 0, NULL, rootfs->mount, NULL); -+#else - ret = safe_mount("proc", rootfs->buf, "proc", 0, NULL, rootfs->mount); -+#endif - } - } - if (ret < 0) -@@ -4675,7 +4716,12 @@ int lxc_setup(struct lxc_handler *handler) - } - - if (lxc_conf->autodev > 0) { -+#ifdef HAVE_ISULAD -+ ret = mount_autodev(name, &lxc_conf->rootfs, lxc_conf->autodevtmpfssize, lxcpath, -+ lxc_conf->systemd, lxc_conf->rootfs.lsm_se_mount_context); -+#else - ret = mount_autodev(name, &lxc_conf->rootfs, lxc_conf->autodevtmpfssize, lxcpath); -+#endif - if (ret < 0) - return log_error(-1, "Failed to mount \"/dev\""); - } -@@ -4697,7 +4743,11 @@ int lxc_setup(struct lxc_handler *handler) - return log_error(-1, "Failed to setup remaining automatic mounts"); - #endif - -+#ifdef HAVE_ISULAD -+ ret = setup_mount_fstab(lxc_conf, &lxc_conf->rootfs, lxc_conf->fstab, name, lxcpath); -+#else - ret = setup_mount_fstab(&lxc_conf->rootfs, lxc_conf->fstab, name, lxcpath); -+#endif - if (ret < 0) - return log_error(-1, "Failed to setup mounts"); - -@@ -4750,6 +4800,15 @@ int lxc_setup(struct lxc_handler *handler) - return log_error(-1, "Failed to populate \"/dev\""); - } - -+#ifdef HAVE_ISULAD -+ /* isulad: setup devices which will be populated in the container. */ -+ if (!lxc_list_empty(&lxc_conf->populate_devs) && setup_dev) { -+ if (setup_populate_devs(&lxc_conf->rootfs, &lxc_conf->populate_devs, lxc_conf->rootfs.lsm_se_mount_context) != 0) { -+ return log_error(-1, "Failed to setup devices in the container"); -+ } -+ } -+#endif -+ - /* Make sure any start hooks are in the container */ - if (!verify_start_hooks(lxc_conf)) - return log_error(-1, "Failed to verify start hooks"); -@@ -4796,7 +4855,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_wait_parent(handler, LXC_SYNC_OCI_PRESTART_HOOK)) { -+ if (lxc_sync_barrier_parent(handler, START_SYNC_OCI_PRESTART_HOOK)) { - return log_error(-1, "Failed to sync parent to start host hook"); - } - #endif -@@ -4845,10 +4904,10 @@ int lxc_setup(struct lxc_handler *handler) - } - } - -- //isulad: system container, remount /proc/sys/xxx by mount_list -+ //isulad: system container, remount /proc/sys/xxx by mount_entries - if (lxc_conf->systemd != NULL && strcmp(lxc_conf->systemd, "true") == 0) { -- if (!lxc_list_empty(&lxc_conf->mount_list)) { -- if (remount_proc_sys_mount_entries(&lxc_conf->mount_list, -+ if (!list_empty(&lxc_conf->mount_entries)) { -+ if (remount_proc_sys_mount_entries(&lxc_conf->mount_entries, - lxc_conf->lsm_aa_allow_nesting)) { - return log_error(-1, "failed to remount /proc/sys"); - } -@@ -5250,7 +5309,7 @@ void lxc_conf_free(struct lxc_conf *conf) - if (conf->ocihooks) { - free_oci_runtime_spec_hooks(conf->ocihooks); - } -- free(conf->lsm_se_mount_context); -+ free(conf->rootfs.lsm_se_mount_context); - free(conf->lsm_se_keyring_context); - #endif - -@@ -6184,19 +6243,22 @@ int lxc_drop_caps(struct lxc_conf *conf) - #define __DEF_CAP_TO_MASK(x) (1U << ((x) & 31)) - #if HAVE_LIBCAP - int ret = 0; -- struct lxc_list *iterator = NULL; -- char *keep_entry = NULL; -+ int nret = 0; - size_t i = 0; -- int capid; -- size_t numcaps = (size_t)lxc_caps_last_cap() + 1; -- struct lxc_list *caps = NULL; -+ __u32 capid; -+ __u32 last_cap; -+ size_t numcaps; -+ struct cap_entry *cap_entry; - int *caplist = NULL; - -- if (lxc_list_empty(&conf->keepcaps)) -+ if (!conf->caps.keep) - return 0; - -- caps = &conf->keepcaps; -+ ret = lxc_caps_last_cap(&last_cap); -+ if (ret) -+ return -1; - -+ numcaps = (size_t)last_cap + 1; - if (numcaps <= 0 || numcaps > 200) - return -1; - -@@ -6208,11 +6270,9 @@ int lxc_drop_caps(struct lxc_conf *conf) - } - (void)memset(caplist, 0, numcaps * sizeof(int)); - -- lxc_list_for_each(iterator, caps) { -- -- keep_entry = iterator->elem; -+ list_for_each_entry(cap_entry, &conf->caps.list, head) { - /* isulad: Do not keep any cap*/ -- if (strcmp(keep_entry, "ISULAD_KEEP_NONE") == 0) { -+ if (strcmp(cap_entry->cap_name, "ISULAD_KEEP_NONE") == 0) { - DEBUG("Do not keep any capability"); - for(i = 0; i < numcaps; i++) { - caplist[i] = 0; -@@ -6220,18 +6280,17 @@ int lxc_drop_caps(struct lxc_conf *conf) - break; - } - -- capid = parse_cap(keep_entry); -- -- if (capid == -2) -+ nret = parse_cap(cap_entry->cap_name, &capid); -+ if (nret == -2) - continue; - -- if (capid < 0) { -- ERROR("unknown capability %s", keep_entry); -+ if (nret < 0) { -+ ERROR("unknown capability %s", cap_entry->cap_name); - ret = -1; - goto out; - } - -- DEBUG("keep capability '%s' (%d)", keep_entry, capid); -+ DEBUG("keep capability '%s' (%d)", cap_entry->cap_name, capid); - - caplist[capid] = 1; - } -@@ -6299,7 +6358,7 @@ static bool have_dev_bind_mount_entry(FILE *file) - } - - // returns true if /dev needs to be set up. --static bool need_setup_dev(const struct lxc_conf *conf, struct lxc_list *mount) -+static bool need_setup_dev(const struct lxc_conf *conf, struct list_head *mount) - { - __do_fclose FILE *f = NULL; - -@@ -6344,7 +6403,7 @@ static bool have_proc_bind_mount_entry(FILE *file) - } - - // returns true if /proc needs to be set up. --static bool need_setup_proc(const struct lxc_conf *conf, struct lxc_list *mount) -+static bool need_setup_proc(const struct lxc_conf *conf, struct list_head *mount) - { - __do_fclose FILE *f = NULL; - -@@ -6378,7 +6437,7 @@ static int mount_entry_with_loop_dev(const char *src, const char *dest, const ch - if (srcfd < 0) - return srcfd; - ret = snprintf(srcbuf, sizeof(srcbuf), "/proc/self/fd/%d", srcfd); -- if (ret < 0 || ret > sizeof(srcbuf)) { -+ if (ret < 0 || (size_t)ret > sizeof(srcbuf)) { - close(srcfd); - ERROR("Failed to print string"); - return -EINVAL; -@@ -6397,7 +6456,7 @@ static int mount_entry_with_loop_dev(const char *src, const char *dest, const ch - } - - ret = snprintf(destbuf, sizeof(destbuf), "/proc/self/fd/%d", destfd); -- if (ret < 0 || ret > sizeof(destbuf)) { -+ if (ret < 0 || (size_t)ret > sizeof(destbuf)) { - if (srcfd != -1) - close(srcfd); - close(destfd); -@@ -6584,13 +6643,13 @@ on_error: - return false; - } - --static int remount_proc_sys_mount_entries(struct lxc_list *mount_list, bool lsm_aa_allow_nesting) -+static int remount_proc_sys_mount_entries(struct list_head *mount_entries, bool lsm_aa_allow_nesting) - { - char buf[4096]; - FILE *file; - struct mntent mntent; - -- file = make_anonymous_mount_file(mount_list, lsm_aa_allow_nesting); -+ file = make_anonymous_mount_file(mount_entries, lsm_aa_allow_nesting); - if (!file) - return -1; - -@@ -6824,21 +6883,57 @@ reset_umask: - return ret; - } - -+static void parse_propagationopt(char *opt, unsigned long *flags) -+{ -+ struct mount_opt *mo; -+ -+ /* If opt is found in propagation_opt, set or clear flags. */ -+ for (mo = &propagation_opt[0]; mo->name != NULL; mo++) { -+ if (strncmp(opt, mo->name, strlen(mo->name)) != 0) -+ continue; -+ -+ if (mo->clear) -+ *flags &= ~mo->flag; -+ else -+ *flags |= mo->flag; -+ -+ return; -+ } -+} -+ -+int parse_propagationopts(const char *mntopts, unsigned long *pflags) -+{ -+ __do_free char *s = NULL; -+ char *p; -+ -+ if (!mntopts) -+ return 0; -+ -+ s = strdup(mntopts); -+ if (!s) -+ return log_error_errno(-ENOMEM, errno, "Failed to allocate memory"); -+ -+ *pflags = 0L; -+ lxc_iterate_parts(p, s, ",") -+ parse_propagationopt(p, pflags); -+ -+ return 0; -+} -+ - // isulad: setup rootfs mountopts - static int setup_rootfs_mountopts(const struct lxc_rootfs *rootfs) - { - unsigned long mflags, mntflags, pflags; - __do_free char *mntdata = NULL; - -- if(!rootfs || !rootfs->options) -+ if(!rootfs || !rootfs->mnt_opts.raw_options) - return 0; - -- if (parse_mntopts_legacy(rootfs->options, &mntflags, &mntdata) < 0) { -+ if (parse_mntopts_legacy(rootfs->mnt_opts.raw_options, &mntflags, &mntdata) < 0) { - return -1; - } - -- ret = parse_propagationopts(rootfs->options, &pflags); -- if (ret < 0) { -+ if (parse_propagationopts(rootfs->mnt_opts.raw_options, &pflags) < 0) { - return -EINVAL; - } - -@@ -6853,7 +6948,7 @@ static int setup_rootfs_mountopts(const struct lxc_rootfs *rootfs) - return 0; - } - --static int create_mtab_link() -+static int create_mtab_link(void) - { - ssize_t ret; - int mret; -@@ -6935,7 +7030,7 @@ static char* generate_json_str(const char *name, const char *lxcpath, const char - rc = snprintf(inmsg, size, - "{\"ociVersion\":\"\",\"id\":\"%s\",\"pid\":%s,\"root\":\"%s\",\"bundle\":\"%s/%s\"}", - name, cpid, rootfs, lxcpath, name); -- if (rc < 0 || rc >= size) { -+ if (rc < 0 || (size_t)rc >= size) { - ERROR("Create json string failed"); - ret = -1; - } -@@ -7090,8 +7185,8 @@ static struct lxc_popen_FILE *lxc_popen_ocihook(const char *commandpath, char ** - close(pipe_msg[0]); - pipe_msg[0]= -1; - if (instr) { -- size_t len = strlen(instr); -- if (lxc_write_nointr(pipe_msg[1], instr, len) != len) { -+ int len = lxc_write_nointr(pipe_msg[1], instr, strlen(instr)); -+ if (len < 0 || (size_t)len != strlen(instr)) { - WARN("Write instr: %s failed", instr); - } - } -@@ -7413,7 +7508,7 @@ int run_oci_hooks(const char *name, const char *hookname, struct lxc_conf *conf, - /*isulad clear init args*/ - int lxc_clear_init_args(struct lxc_conf *lxc_conf) - { -- int i; -+ size_t i; - - for (i = 0; i < lxc_conf->init_argc; i++) { - free(lxc_conf->init_argv[i]); -diff --git a/src/lxc/conf.h b/src/lxc/conf.h -index 108e05b..ef4bb05 100644 ---- a/src/lxc/conf.h -+++ b/src/lxc/conf.h -@@ -677,7 +677,11 @@ __hidden extern int lxc_setup_rootfs_prepare_root(struct lxc_conf *conf, const c - const char *lxcpath); - __hidden extern int lxc_setup(struct lxc_handler *handler); - __hidden extern int lxc_setup_parent(struct lxc_handler *handler); -+#ifdef HAVE_ISULAD -+__hidden extern int setup_resource_limits(struct lxc_conf *conf, pid_t pid, int errfd); -+#else - __hidden extern int setup_resource_limits(struct lxc_conf *conf, pid_t pid); -+#endif - __hidden extern int find_unmapped_nsid(const struct lxc_conf *conf, enum idtype idtype); - __hidden extern int mapped_hostid(unsigned id, const struct lxc_conf *conf, enum idtype idtype); - __hidden extern int userns_exec_1(const struct lxc_conf *conf, int (*fn)(void *), void *data, -diff --git a/src/lxc/confile.c b/src/lxc/confile.c -index 1492776..0d0d66c 100644 ---- a/src/lxc/confile.c -+++ b/src/lxc/confile.c -@@ -287,16 +287,16 @@ static struct lxc_config_t config_jump_table[] = { - { "lxc.sysctl", false, set_config_sysctl, get_config_sysctl, clr_config_sysctl, }, - { "lxc.proc", false, set_config_proc, get_config_proc, clr_config_proc, }, - #ifdef HAVE_ISULAD -- { "lxc.isulad.init.args", set_config_init_args, get_config_init_args, clr_config_init_args, }, -- { "lxc.isulad.populate.device", set_config_populate_device, get_config_populate_device, clr_config_populate_device, }, -- { "lxc.isulad.umask", set_config_umask, get_config_umask, clr_config_umask, }, -- { "lxc.isulad.rootfs.maskedpaths", set_config_rootfs_masked_paths, get_config_rootfs_masked_paths, clr_config_rootfs_masked_paths, }, -- { "lxc.isulad.rootfs.ropaths", set_config_rootfs_ro_paths, get_config_rootfs_ro_paths, clr_config_rootfs_ro_paths, }, -- { "lxc.isulad.systemd", set_config_systemd, get_config_systemd, clr_config_systemd, }, -- { "lxc.console.logdriver", set_config_console_log_driver, get_config_console_log_driver, clr_config_console_log_driver, }, -- { "lxc.console.syslog_tag", set_config_console_syslog_tag, get_config_console_syslog_tag, clr_config_console_syslog_tag, }, -- { "lxc.console.syslog_facility", set_config_console_syslog_facility, get_config_console_syslog_facility, clr_config_console_syslog_facility, }, -- { "lxc.selinux.mount_context", set_config_selinux_mount_context, get_config_selinux_mount_context, clr_config_selinux_mount_context, }, -+ { "lxc.isulad.init.args", true, set_config_init_args, get_config_init_args, clr_config_init_args, }, -+ { "lxc.isulad.populate.device", true, set_config_populate_device, get_config_populate_device, clr_config_populate_device, }, -+ { "lxc.isulad.umask", true, set_config_umask, get_config_umask, clr_config_umask, }, -+ { "lxc.isulad.rootfs.maskedpaths", true, set_config_rootfs_masked_paths, get_config_rootfs_masked_paths, clr_config_rootfs_masked_paths, }, -+ { "lxc.isulad.rootfs.ropaths", true, set_config_rootfs_ro_paths, get_config_rootfs_ro_paths, clr_config_rootfs_ro_paths, }, -+ { "lxc.isulad.systemd", true, set_config_systemd, get_config_systemd, clr_config_systemd, }, -+ { "lxc.console.logdriver", true, set_config_console_log_driver, get_config_console_log_driver, clr_config_console_log_driver, }, -+ { "lxc.console.syslog_tag", true, set_config_console_syslog_tag, get_config_console_syslog_tag, clr_config_console_syslog_tag, }, -+ { "lxc.console.syslog_facility", true, set_config_console_syslog_facility, get_config_console_syslog_facility, clr_config_console_syslog_facility, }, -+ { "lxc.selinux.mount_context", true, set_config_selinux_mount_context, get_config_selinux_mount_context, clr_config_selinux_mount_context, }, - #endif - }; - -@@ -3206,7 +3206,7 @@ static int parse_line(char *buffer, void *data) - if (value_decode == NULL) { - ERROR("Value %s decode failed", value); - } -- ret = config->set(key, value_decode ? value_decode: value, plc->conf, NULL); -+ return config->set(key, value_decode ? value_decode: value, plc->conf, NULL); - #else - return config->set(key, value, plc->conf, NULL); - #endif -@@ -6895,7 +6895,8 @@ static int set_config_init_args(const char *key, const char *value, - static int get_config_init_args(const char *key, char *retv, int inlen, - struct lxc_conf *c, void *data) - { -- int i, len, fulllen = 0; -+ size_t i; -+ int len, fulllen = 0; - - if (!retv) - inlen = 0; -@@ -7261,10 +7262,10 @@ static int set_config_selinux_mount_context(const char *key, const char *value, - struct lxc_conf *lxc_conf, void *data) - { - if (value != NULL && strcmp(value, "unconfined_t") == 0) { -- return set_config_string_item(&lxc_conf->lsm_se_mount_context, NULL); -+ return set_config_string_item(&lxc_conf->rootfs.lsm_se_mount_context, NULL); - } - -- return set_config_string_item(&lxc_conf->lsm_se_mount_context, value); -+ return set_config_string_item(&lxc_conf->rootfs.lsm_se_mount_context, value); - } - - static int get_config_console_log_driver(const char *key, char *retv, int inlen, -@@ -7288,7 +7289,7 @@ static int get_config_console_syslog_facility(const char *key, char *retv, int i - static int get_config_selinux_mount_context(const char *key, char *retv, int inlen, - struct lxc_conf *c, void *data) - { -- return lxc_get_conf_str(retv, inlen, c->lsm_se_mount_context); -+ return lxc_get_conf_str(retv, inlen, c->rootfs.lsm_se_mount_context); - } - - static inline int clr_config_console_log_driver(const char *key, -@@ -7317,8 +7318,8 @@ static inline int clr_config_console_syslog_facility(const char *key, - static inline int clr_config_selinux_mount_context(const char *key, - struct lxc_conf *c, void *data) - { -- free(c->lsm_se_mount_context); -- c->lsm_se_mount_context = NULL; -+ free(c->rootfs.lsm_se_mount_context); -+ c->rootfs.lsm_se_mount_context = NULL; - return 0; - } - #endif -diff --git a/src/lxc/exec_commands.c b/src/lxc/exec_commands.c -index bd81d66..5612109 100644 ---- a/src/lxc/exec_commands.c -+++ b/src/lxc/exec_commands.c -@@ -37,6 +37,7 @@ - - #include "af_unix.h" - #include "cgroup.h" -+#include "string_utils.h" - #include "exec_commands.h" - #include "commands_utils.h" - #include "conf.h" -@@ -47,8 +48,6 @@ - #include "lxclock.h" - #include "mainloop.h" - #include "monitor.h" --#include "string_utils.h" --#include "terminal.h" - #include "utils.h" - - lxc_log_define(commands_exec, lxc); -@@ -70,12 +69,7 @@ static int lxc_exec_cmd_rsp_recv(int sock, struct lxc_exec_cmd_rr *cmd) - int ret, rspfd; - struct lxc_exec_cmd_rsp *rsp = &cmd->rsp; - -- /*isulad: add timeout 1s to avoid long block due to [lxc monitor] error*/ -- if (lxc_socket_set_timeout(sock, 1, 1) != 0) { -- return syserror_ret(-1, "Failed to set timeout"); -- } -- -- ret = lxc_cmd_rsp_recv_fds(sock, &rspfd, 1, rsp, sizeof(*rsp)); -+ ret = lxc_abstract_unix_recv_one_fd_timeout(sock, &rspfd, rsp, sizeof(*rsp), 1000 * 1000); - if (ret < 0) { - SYSERROR("Failed to receive response for command \"%s\"", - lxc_exec_cmd_str(cmd->req.cmd)); -@@ -256,7 +250,7 @@ static int lxc_exec_cmd_process(int fd, struct lxc_exec_cmd_req *req, - return cb[req->cmd](fd, req, handler); - } - --static void lxc_exec_cmd_fd_cleanup(int fd, struct lxc_epoll_descr *descr) -+static void lxc_exec_cmd_fd_cleanup(int fd, struct lxc_async_descr *descr) - { - lxc_mainloop_del_handler(descr, fd); - close(fd); -@@ -264,7 +258,7 @@ static void lxc_exec_cmd_fd_cleanup(int fd, struct lxc_epoll_descr *descr) - } - - static int lxc_exec_cmd_handler(int fd, uint32_t events, void *data, -- struct lxc_epoll_descr *descr) -+ struct lxc_async_descr *descr) - { - int ret; - struct lxc_exec_cmd_req req; -@@ -341,7 +335,7 @@ out_close: - } - - static int lxc_exec_cmd_accept(int fd, uint32_t events, void *data, -- struct lxc_epoll_descr *descr) -+ struct lxc_async_descr *descr) - { - int connection = -1; - int opt = 1, ret = -1; -@@ -364,7 +358,8 @@ static int lxc_exec_cmd_accept(int fd, uint32_t events, void *data, - goto out_close; - } - -- ret = lxc_mainloop_add_handler(descr, connection, lxc_exec_cmd_handler, data); -+ ret = lxc_mainloop_add_handler(descr, connection, lxc_exec_cmd_handler, default_cleanup_handler, data, -+ "exec_cmd_handler"); - if (ret) { - ERROR("Failed to add command handler"); - goto out_close; -@@ -462,12 +457,12 @@ int lxc_exec_cmd_init(const char *name, const char *lxcpath, const char *suffix) - } - #endif - --int lxc_exec_cmd_mainloop_add(struct lxc_epoll_descr *descr, struct lxc_exec_command_handler *handler) -+int lxc_exec_cmd_mainloop_add(struct lxc_async_descr *descr, struct lxc_exec_command_handler *handler) - { - int ret; - int fd = handler->maincmd_fd; - -- ret = lxc_mainloop_add_handler(descr, fd, lxc_exec_cmd_accept, handler); -+ ret = lxc_mainloop_add_handler(descr, fd, lxc_exec_cmd_accept, default_cleanup_handler, handler, "exec_cmd_accept"); - if (ret < 0) { - ERROR("Failed to add handler for command socket"); - close(fd); -diff --git a/src/lxc/exec_commands.h b/src/lxc/exec_commands.h -index 3ec2a22..ca3a4d6 100644 ---- a/src/lxc/exec_commands.h -+++ b/src/lxc/exec_commands.h -@@ -63,11 +63,11 @@ struct lxc_exec_cmd_set_terminal_winch_request { - unsigned int width; - }; - --struct lxc_epoll_descr; -+struct lxc_async_descr; - struct lxc_handler; - - extern int lxc_exec_cmd_init(const char *name, const char *lxcpath, const char *suffix); --extern int lxc_exec_cmd_mainloop_add(struct lxc_epoll_descr *descr, struct lxc_exec_command_handler *handler); -+extern int lxc_exec_cmd_mainloop_add(struct lxc_async_descr *descr, struct lxc_exec_command_handler *handler); - extern int lxc_exec_cmd_set_terminal_winch(const char *name, const char *lxcpath, const char *suffix, unsigned int height, unsigned int width); - - #ifdef HAVE_ISULAD -diff --git a/src/lxc/execute.c b/src/lxc/execute.c -index 6a7ae39..2960664 100644 ---- a/src/lxc/execute.c -+++ b/src/lxc/execute.c -@@ -18,7 +18,11 @@ - - lxc_log_define(execute, start); - -+#ifdef HAVE_ISULAD -+static int execute_start(struct lxc_handler *handler, void* data, int fd) -+#else - static int execute_start(struct lxc_handler *handler, void* data) -+#endif - { - int argc = 0; - struct execute_args *my_args = data; -@@ -40,14 +44,25 @@ static struct lxc_operations execute_start_ops = { - .post_start = execute_post_start - }; - -+#ifdef HAVE_ISULAD -+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 - int lxc_execute(const char *name, char *const argv[], int quiet, - struct lxc_handler *handler, const char *lxcpath, - bool daemonize, int *error_num) -+#endif - { - struct execute_args args = {.argv = argv, .quiet = quiet}; - - TRACE("Doing lxc_execute"); - handler->conf->is_execute = true; -+#ifdef HAVE_ISULAD -+ return __lxc_start(handler, &execute_start_ops, &args, lxcpath, -+ daemonize, error_num, start_timeout); -+#else - return __lxc_start(handler, &execute_start_ops, &args, lxcpath, - daemonize, error_num); -+#endif - } -diff --git a/src/lxc/isulad_utils.c b/src/lxc/isulad_utils.c -index 889d912..38dbe2a 100644 ---- a/src/lxc/isulad_utils.c -+++ b/src/lxc/isulad_utils.c -@@ -233,7 +233,7 @@ unsigned long long lxc_get_process_startat(pid_t pid) - char sbuf[1024] = {0}; /* bufs for stat */ - - sret = snprintf(filename, sizeof(filename), "/proc/%d/stat", pid); -- if (sret < 0 || sret >= sizeof(filename)) { -+ if (sret < 0 || (size_t)sret >= sizeof(filename)) { - ERROR("Failed to sprintf filename"); - goto out; - } -@@ -317,7 +317,7 @@ bool lxc_process_alive(pid_t pid, unsigned long long start_time) - return false; - - sret = snprintf(filename, sizeof(filename), "/proc/%d/stat", pid); -- if (sret < 0 || sret >= sizeof(filename)) { -+ if (sret < 0 || (size_t)sret >= sizeof(filename)) { - ERROR("Failed to sprintf filename"); - goto out; - } -@@ -537,7 +537,7 @@ out: - ssize_t lxc_write_nointr_for_fifo(int fd, const char *buf, size_t count) - { - ssize_t nret = 0; -- ssize_t nwritten; -+ size_t nwritten; - - if (buf == NULL) { - return -1; -diff --git a/src/lxc/isulad_utils.h b/src/lxc/isulad_utils.h -index 93174ae..3dfa9f7 100644 ---- a/src/lxc/isulad_utils.h -+++ b/src/lxc/isulad_utils.h -@@ -5,13 +5,15 @@ - * Author: lifeng - * Create: 2020-04-11 - ******************************************************************************/ --#ifndef __iSULAD_UTILS_H --#define __iSULAD_UTILS_H -+#ifndef __ISULAD_UTILS_H -+#define __ISULAD_UTILS_H - - #include - #include - #include - -+#include "compiler.h" -+ - /* isulad: replace space with SPACE_MAGIC_STR */ - #define SPACE_MAGIC_STR "[#)" - -@@ -97,7 +99,7 @@ __hidden extern bool lxc_process_alive(pid_t pid, unsigned long long start_time) - - __hidden extern bool is_non_negative_num(const char *s); - --__hidden int util_getpwent_r(FILE *stream, struct passwd *resbuf, char *buffer, size_t buflen, struct passwd **result); -+__hidden extern int util_getpwent_r(FILE *stream, struct passwd *resbuf, char *buffer, size_t buflen, struct passwd **result); - - __hidden extern ssize_t lxc_write_nointr_for_fifo(int fd, const char *buf, size_t count); - -diff --git a/src/lxc/lsm/lsm.c b/src/lxc/lsm/lsm.c -index d9380c4..db4bb0c 100644 ---- a/src/lxc/lsm/lsm.c -+++ b/src/lxc/lsm/lsm.c -@@ -19,6 +19,10 @@ __hidden extern struct lsm_ops *lsm_apparmor_ops_init(void); - __hidden extern struct lsm_ops *lsm_selinux_ops_init(void); - __hidden extern struct lsm_ops *lsm_nop_ops_init(void); - -+#ifdef HAVE_ISULAD -+static struct lsm_ops *ops_instance = NULL; -+#endif -+ - struct lsm_ops *lsm_init_static(void) - { - struct lsm_ops *ops = NULL; -@@ -35,6 +39,30 @@ struct lsm_ops *lsm_init_static(void) - if (!ops) - ops = lsm_nop_ops_init(); - -+#ifdef HAVE_ISULAD -+ ops_instance = ops; -+#endif -+ - INFO("Initialized LSM security driver %s", ops->name); - return ops; - } -+ -+#ifdef HAVE_ISULAD -+int lsm_file_label_set(const char *path, const char *label) -+{ -+ if (!ops_instance) { -+ ERROR("LSM driver not inited"); -+ return -1; -+ } -+ return ops_instance->file_label_set(path, label); -+} -+ -+int lsm_relabel(const char *path, const char *label, bool share) -+{ -+ if (!ops_instance) { -+ ERROR("LSM driver not inited"); -+ return -1; -+ } -+ return ops_instance->relabel(path, label, share); -+} -+#endif -diff --git a/src/lxc/lsm/lsm.h b/src/lxc/lsm/lsm.h -index 93e1a99..571a92d 100644 ---- a/src/lxc/lsm/lsm.h -+++ b/src/lxc/lsm/lsm.h -@@ -42,4 +42,9 @@ struct lsm_ops { - - __hidden extern struct lsm_ops *lsm_init_static(void); - -+#ifdef HAVE_ISULAD -+__hidden extern int lsm_file_label_set(const char *path, const char *label); -+__hidden extern int lsm_relabel(const char *path, const char *label, bool share); -+#endif -+ - #endif /* __LXC_LSM_H */ -diff --git a/src/lxc/lsm/selinux.c b/src/lxc/lsm/selinux.c -index 5190110..0bdfcff 100644 ---- a/src/lxc/lsm/selinux.c -+++ b/src/lxc/lsm/selinux.c -@@ -272,7 +272,7 @@ static int recurse_set_file_label(const char *basePath, const char *label) - continue; - } else { - int nret = snprintf(base, sizeof(base), "%s/%s", basePath, ptr->d_name); -- if (nret < 0 || nret >= sizeof(base)) { -+ if (nret < 0 || (size_t)nret >= sizeof(base)) { - ERROR("Failed to get path"); - return -1; - } -diff --git a/src/lxc/lxc.h b/src/lxc/lxc.h -index 879e899..74c8aa8 100644 ---- a/src/lxc/lxc.h -+++ b/src/lxc/lxc.h -@@ -39,8 +39,13 @@ struct lxc_handler; - * @daemonize : whether or not the container is daemonized - * Returns 0 on success, < 0 otherwise - */ -+#ifdef HAVE_ISULAD -+__hidden extern int lxc_start(char *const argv[], struct lxc_handler *handler, const char *lxcpath, -+ bool daemonize, int *error_num, unsigned int start_timeout); -+#else - __hidden 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 -@@ -51,9 +56,15 @@ __hidden extern int lxc_start(char *const argv[], struct lxc_handler *handler, c - * @daemonize : whether or not the container is daemonized - * Returns 0 on success, < 0 otherwise - */ -+#ifdef HAVE_ISULAD -+__hidden 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 - __hidden 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 -diff --git a/src/lxc/lxccontainer.c b/src/lxc/lxccontainer.c -index d4495f7..5720cf7 100644 ---- a/src/lxc/lxccontainer.c -+++ b/src/lxc/lxccontainer.c -@@ -6100,7 +6100,11 @@ WRAP_API_1(bool, lxcapi_get_container_metrics, struct lxc_container_metrics *) - - #endif - -+#ifdef HAVE_ISULAD -+static struct lxc_container *do_lxc_container_new(const char *name, const char *configpath, bool load_config) -+#else - struct lxc_container *lxc_container_new(const char *name, const char *configpath) -+#endif - { - struct lxc_container *c; - size_t len; -diff --git a/src/lxc/mainloop.c b/src/lxc/mainloop.c -index 765240e..9522b7d 100644 ---- a/src/lxc/mainloop.c -+++ b/src/lxc/mainloop.c -@@ -534,7 +534,7 @@ void lxc_mainloop_close(struct lxc_async_descr *descr) - } - - #ifdef HAVE_ISULAD --int isulad_safe_mainloop(struct lxc_epoll_descr *descr, int timeout_ms) -+int isulad_safe_mainloop(struct lxc_async_descr *descr, int timeout_ms) - { - int ret; - -diff --git a/src/lxc/mainloop.h b/src/lxc/mainloop.h -index e8ce082..f485a1f 100644 ---- a/src/lxc/mainloop.h -+++ b/src/lxc/mainloop.h -@@ -66,7 +66,7 @@ __hidden extern void lxc_mainloop_close(struct lxc_async_descr *descr); - define_cleanup_function(struct lxc_async_descr *, lxc_mainloop_close); - - #ifdef HAVE_ISULAD --__hidden extern int isulad_safe_mainloop(struct lxc_epoll_descr *descr, int timeout_ms); -+__hidden extern int isulad_safe_mainloop(struct lxc_async_descr *descr, int timeout_ms); - #endif - - #endif -diff --git a/src/lxc/seccomp.c b/src/lxc/seccomp.c -index f0fa297..d952beb 100644 ---- a/src/lxc/seccomp.c -+++ b/src/lxc/seccomp.c -@@ -699,21 +699,33 @@ static int parse_config_v2(FILE *f, char *line, size_t *line_bufsz, struct lxc_c - ctx.architectures[0] = SCMP_ARCH_X86; - ctx.contexts[0] = get_new_ctx(lxc_seccomp_arch_i386, - default_policy_action, -+#ifdef HAVE_ISULAD -+ &ctx.architectures[0]); -+#else - &ctx.needs_merge[0]); -+#endif - if (!ctx.contexts[0]) - goto bad; - - ctx.architectures[1] = SCMP_ARCH_X32; - ctx.contexts[1] = get_new_ctx(lxc_seccomp_arch_x32, - default_policy_action, -+#ifdef HAVE_ISULAD -+ &ctx.architectures[1]); -+#else - &ctx.needs_merge[1]); -+#endif - if (!ctx.contexts[1]) - goto bad; - - ctx.architectures[2] = SCMP_ARCH_X86_64; - ctx.contexts[2] = get_new_ctx(lxc_seccomp_arch_amd64, - default_policy_action, -+#ifdef HAVE_ISULAD -+ &ctx.architectures[2]); -+#else - &ctx.needs_merge[2]); -+#endif - if (!ctx.contexts[2]) - goto bad; - #ifdef SCMP_ARCH_PPC -@@ -723,14 +735,22 @@ static int parse_config_v2(FILE *f, char *line, size_t *line_bufsz, struct lxc_c - ctx.architectures[0] = SCMP_ARCH_PPC; - ctx.contexts[0] = get_new_ctx(lxc_seccomp_arch_ppc, - default_policy_action, -+#ifdef HAVE_ISULAD -+ &ctx.architectures[0]); -+#else - &ctx.needs_merge[0]); -+#endif - if (!ctx.contexts[0]) - goto bad; - - ctx.architectures[2] = SCMP_ARCH_PPC64; - ctx.contexts[2] = get_new_ctx(lxc_seccomp_arch_ppc64, - default_policy_action, -+#ifdef HAVE_ISULAD -+ &ctx.architectures[2]); -+#else - &ctx.needs_merge[2]); -+#endif - if (!ctx.contexts[2]) - goto bad; - #endif -@@ -741,7 +761,11 @@ static int parse_config_v2(FILE *f, char *line, size_t *line_bufsz, struct lxc_c - ctx.architectures[0] = SCMP_ARCH_ARM; - ctx.contexts[0] = get_new_ctx(lxc_seccomp_arch_arm, - default_policy_action, -+#ifdef HAVE_ISULAD -+ &ctx.architectures[0]); -+#else - &ctx.needs_merge[0]); -+#endif - if (!ctx.contexts[0]) - goto bad; - -@@ -749,7 +773,11 @@ static int parse_config_v2(FILE *f, char *line, size_t *line_bufsz, struct lxc_c - ctx.architectures[2] = SCMP_ARCH_AARCH64; - ctx.contexts[2] = get_new_ctx(lxc_seccomp_arch_arm64, - default_policy_action, -+#ifdef HAVE_ISULAD -+ &ctx.architectures[2]); -+#else - &ctx.needs_merge[2]); -+#endif - if (!ctx.contexts[2]) - goto bad; - #endif -@@ -761,21 +789,33 @@ static int parse_config_v2(FILE *f, char *line, size_t *line_bufsz, struct lxc_c - ctx.architectures[0] = SCMP_ARCH_MIPS; - ctx.contexts[0] = get_new_ctx(lxc_seccomp_arch_mips, - default_policy_action, -+#ifdef HAVE_ISULAD -+ &ctx.architectures[0]); -+#else - &ctx.needs_merge[0]); -+#endif - if (!ctx.contexts[0]) - goto bad; - - ctx.architectures[1] = SCMP_ARCH_MIPS64N32; - ctx.contexts[1] = get_new_ctx(lxc_seccomp_arch_mips64n32, - default_policy_action, -+#ifdef HAVE_ISULAD -+ &ctx.architectures[1]); -+#else - &ctx.needs_merge[1]); -+#endif - if (!ctx.contexts[1]) - goto bad; - - ctx.architectures[2] = SCMP_ARCH_MIPS64; - ctx.contexts[2] = get_new_ctx(lxc_seccomp_arch_mips64, - default_policy_action, -+#ifdef HAVE_ISULAD -+ &ctx.architectures[2]); -+#else - &ctx.needs_merge[2]); -+#endif - if (!ctx.contexts[2]) - goto bad; - } else if (native_arch == lxc_seccomp_arch_mipsel64) { -@@ -784,21 +824,33 @@ static int parse_config_v2(FILE *f, char *line, size_t *line_bufsz, struct lxc_c - ctx.architectures[0] = SCMP_ARCH_MIPSEL; - ctx.contexts[0] = get_new_ctx(lxc_seccomp_arch_mipsel, - default_policy_action, -+#ifdef HAVE_ISULAD -+ &ctx.architectures[0]); -+#else - &ctx.needs_merge[0]); -+#endif - if (!ctx.contexts[0]) - goto bad; - - ctx.architectures[1] = SCMP_ARCH_MIPSEL64N32; - ctx.contexts[1] = get_new_ctx(lxc_seccomp_arch_mipsel64n32, - default_policy_action, -+#ifdef HAVE_ISULAD -+ &ctx.architectures[1]); -+#else - &ctx.needs_merge[1]); -+#endif - if (!ctx.contexts[1]) - goto bad; - - ctx.architectures[2] = SCMP_ARCH_MIPSEL64; - ctx.contexts[2] = get_new_ctx(lxc_seccomp_arch_mipsel64, - default_policy_action, -+#ifdef HAVE_ISULAD -+ &ctx.architectures[2]); -+#else - &ctx.needs_merge[2]); -+#endif - if (!ctx.contexts[2]) - goto bad; - #endif -diff --git a/src/lxc/start.c b/src/lxc/start.c -index 70af128..ff9a3fa 100644 ---- a/src/lxc/start.c -+++ b/src/lxc/start.c -@@ -2067,6 +2067,9 @@ static int lxc_spawn(struct lxc_handler *handler) - const char *name = handler->name; - struct lxc_conf *conf = handler->conf; - struct cgroup_ops *cgroup_ops = handler->cgroup_ops; -+#ifdef HAVE_ISULAD -+ const char *lxcpath = handler->lxcpath; -+#endif - - id_map = &conf->id_map; - wants_to_map_ids = !list_empty(id_map); -@@ -2364,6 +2367,30 @@ static int lxc_spawn(struct lxc_handler *handler) - goto out_delete_net; - } - -+#ifdef HAVE_ISULAD -+ if (!lxc_sync_wait_child(handler, START_SYNC_OCI_PRESTART_HOOK)) -+ goto out_delete_net; -+ -+ /* isulad: Run oci prestart hook at here */ -+ ret = run_oci_hooks(name, "oci-prestart", conf, lxcpath); -+ if (ret < 0) { -+ ERROR("Failed to run oci prestart hooks"); -+ goto out_delete_net; -+ } -+ -+ if (START_TIMEOUT == global_timeout_state) { -+ lxc_write_error_message(conf->errpipe[1], "Starting the container \"%s\" timeout.", name); -+ ERROR("Starting the container \"%s\" timeout.", name); -+ goto out_delete_net; -+ } -+ -+ /* Tell the child to continue its initialization. We'll get -+ * START_SYNC_POST_OCI_PRESTART_HOOK when it is ready for us to run oci prestart hooks. -+ */ -+ if (lxc_sync_wake_child(handler, START_SYNC_POST_OCI_PRESTART_HOOK)) -+ goto out_delete_net; -+#endif -+ - if (!lxc_sync_wait_child(handler, START_SYNC_CGROUP_LIMITS)) - goto out_delete_net; - -@@ -2394,27 +2421,6 @@ static int lxc_spawn(struct lxc_handler *handler) - goto out_delete_net; - } - --#ifdef HAVE_ISULAD -- /* isulad: Run oci prestart hook at here */ -- ret = run_oci_hooks(name, "oci-prestart", conf, lxcpath); -- if (ret < 0) { -- ERROR("Failed to run oci prestart hooks"); -- goto out_delete_net; -- } -- -- if (START_TIMEOUT == global_timeout_state) { -- lxc_write_error_message(conf->errpipe[1], "Starting the container \"%s\" timeout.", name); -- ERROR("Starting the container \"%s\" timeout.", name); -- goto out_delete_net; -- } -- -- /* Tell the child to continue its initialization. We'll get -- * LXC_SYNC_POST_OCI_PRESTART_HOOK when it is ready for us to run oci prestart hooks. -- */ -- if (lxc_sync_barrier_child(handler, LXC_SYNC_POST_OCI_PRESTART_HOOK)) -- goto out_delete_net; --#endif -- - if (!lxc_sync_wake_child(handler, START_SYNC_FDS)) - goto out_delete_net; - -@@ -2943,7 +2949,7 @@ static int clean_resource_set_env(struct lxc_handler *handler) - const char *name = handler->name; - struct lxc_conf *conf = handler->conf; - char bufstr[PATH_MAX + 1]; -- int i = 0; -+ size_t i = 0; - int j = 0; - int len = 2; //set "LXC_PID" and "LXC_CGNS_AWARE" - -@@ -3039,7 +3045,6 @@ static struct lxc_handler *lxc_init_clean_handler(char *name, char *lxcpath, str - handler->data_sock[0] = handler->data_sock[1] = -1; - handler->conf = conf; - handler->lxcpath = lxcpath; -- handler->pinfd = -1; - handler->sigfd = -EBADF; - handler->pidfd = -EBADF; - handler->init_died = false; -@@ -3047,7 +3052,7 @@ static struct lxc_handler *lxc_init_clean_handler(char *name, char *lxcpath, str - handler->pid = pid; - handler->state_socket_pair[0] = handler->state_socket_pair[1] = -1; - if (handler->conf->reboot == REBOOT_NONE) -- lxc_list_init(&handler->conf->state_clients); -+ INIT_LIST_HEAD(&handler->conf->state_clients); - - for (i = 0; i < LXC_NS_MAX; i++) - handler->nsfd[i] = -1; -@@ -3091,14 +3096,13 @@ static struct lxc_handler *lxc_init_pids_handler(char *name, char *lxcpath, stru - handler->data_sock[0] = handler->data_sock[1] = -1; - handler->conf = conf; - handler->lxcpath = lxcpath; -- handler->pinfd = -1; - handler->sigfd = -EBADF; - handler->init_died = false; - handler->state_socket_pair[0] = handler->state_socket_pair[1] = -1; - handler->monitor_status_fd = -EBADF; - handler->pidfd = -EBADF; - if (handler->conf->reboot == REBOOT_NONE) -- lxc_list_init(&handler->conf->state_clients); -+ INIT_LIST_HEAD(&handler->conf->state_clients); - - for (i = 0; i < LXC_NS_MAX; i++) - handler->nsfd[i] = -1; -diff --git a/src/lxc/sync.c b/src/lxc/sync.c -index 1075d98..f156809 100644 ---- a/src/lxc/sync.c -+++ b/src/lxc/sync.c -@@ -70,6 +70,12 @@ static inline const char *start_sync_to_string(int state) - return "cgroup-limits"; - case START_SYNC_IDMAPPED_MOUNTS: - return "idmapped-mounts"; -+#ifdef HAVE_ISULAd -+ case START_SYNC_OCI_PRESTART_HOOK: -+ return "oci-prestart-hook"; -+ case START_SYNC_POST_OCI_PRESTART_HOOK: -+ return "post-oci-prestart-hook"; -+#endif - case START_SYNC_FDS: - return "fds"; - case START_SYNC_READY_START: -diff --git a/src/lxc/sync.h b/src/lxc/sync.h -index ef03e1e..6802d32 100644 ---- a/src/lxc/sync.h -+++ b/src/lxc/sync.h -@@ -21,12 +21,13 @@ enum /* start */ { - 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, -+ START_SYNC_OCI_PRESTART_HOOK = 4, -+ START_SYNC_POST_OCI_PRESTART_HOOK = 5, -+ START_SYNC_CGROUP_LIMITS = 6, -+ START_SYNC_FDS = 7, -+ START_SYNC_READY_START = 8, -+ START_SYNC_RESTART = 9, -+ START_SYNC_POST_RESTART = 10, - #else - START_SYNC_CGROUP_LIMITS = 4, - START_SYNC_FDS = 5, -diff --git a/src/lxc/terminal.c b/src/lxc/terminal.c -index 8da00a9..de7ea4f 100644 ---- a/src/lxc/terminal.c -+++ b/src/lxc/terminal.c -@@ -204,11 +204,11 @@ int lxc_set_terminal_winsz(struct lxc_terminal *terminal, unsigned int height, u - int ret = 0; - struct winsize wsz; - -- if (terminal->ptmx < 0) { -+ if (terminal->ptx < 0) { - return 0; - } - -- ret = ioctl(terminal->ptmx, TIOCGWINSZ, &wsz); -+ ret = ioctl(terminal->ptx, TIOCGWINSZ, &wsz); - if (ret < 0) { - WARN("Failed to get window size"); - return -1; -@@ -216,7 +216,7 @@ int lxc_set_terminal_winsz(struct lxc_terminal *terminal, unsigned int height, u - wsz.ws_col = width; - wsz.ws_row = height; - -- ret = ioctl(terminal->ptmx, TIOCSWINSZ, &wsz); -+ ret = ioctl(terminal->ptx, TIOCSWINSZ, &wsz); - if (ret < 0) - WARN("Failed to set window size"); - else -@@ -299,6 +299,359 @@ static int lxc_terminal_rotate_log_file(struct lxc_terminal *terminal) - } - - #ifdef HAVE_ISULAD -+/* get time buffer */ -+static bool get_time_buffer(struct timespec *timestamp, char *timebuffer, -+ size_t maxsize) -+{ -+ struct tm tm_utc = { 0 }; -+ int32_t nanos = 0; -+ time_t seconds; -+ size_t len = 0; -+ int ret = 0; -+ -+ if (!timebuffer || !maxsize) { -+ return false; -+ } -+ -+ seconds = (time_t)timestamp->tv_sec; -+ gmtime_r(&seconds, &tm_utc); -+ strftime(timebuffer, maxsize, "%Y-%m-%dT%H:%M:%S", &tm_utc); -+ -+ nanos = (int32_t)timestamp->tv_nsec; -+ len = strlen(timebuffer); -+ ret = snprintf(timebuffer + len, (maxsize - len), ".%09dZ", nanos); -+ if (ret < 0 || (size_t)ret >= (maxsize - len)) { -+ return false; -+ } -+ -+ return true; -+} -+ -+/* get now time buffer */ -+static bool get_now_time_buffer(char *timebuffer, size_t maxsize) -+{ -+ int err = 0; -+ struct timespec ts; -+ -+ err = clock_gettime(CLOCK_REALTIME, &ts); -+ if (err != 0) { -+ ERROR("failed to get time"); -+ return false; -+ } -+ -+ return get_time_buffer(&ts, timebuffer, maxsize); -+} -+ -+static int isulad_lxc_terminal_rotate_write_data(struct lxc_terminal *terminal, const char *buf, -+ int bytes_read) -+{ -+ int ret; -+ struct stat st; -+ int64_t space_left = -1; -+ -+ if (terminal->log_fd < 0) -+ return 0; -+ -+ /* A log size <= 0 means that there's no limit on the size of the log -+ * file at which point we simply ignore whether the log is supposed to -+ * be rotated or not. -+ */ -+ if (terminal->log_size <= 0) -+ return lxc_write_nointr(terminal->log_fd, buf, bytes_read); -+ -+ /* Get current size of the log file. */ -+ ret = fstat(terminal->log_fd, &st); -+ if (ret < 0) { -+ SYSERROR("Failed to stat the terminal log file descriptor"); -+ return -1; -+ } -+ -+ /* handle non-regular files */ -+ if ((st.st_mode & S_IFMT) != S_IFREG) { -+ /* This isn't a regular file. so rotating the file seems a -+ * dangerous thing to do, size limits are also very -+ * questionable. Let's not risk anything and tell the user that -+ * he's requesting us to do weird stuff. -+ */ -+ if (terminal->log_rotate > 0 || terminal->log_size > 0) -+ return -EINVAL; -+ -+ /* I mean, sure log wherever you want to. */ -+ return lxc_write_nointr(terminal->log_fd, buf, bytes_read); -+ } -+ -+ space_left = terminal->log_size - st.st_size; -+ -+ /* User doesn't want to rotate the log file and there's no more space -+ * left so simply truncate it. -+ */ -+ if (space_left <= 0 && terminal->log_rotate <= 0) { -+ ret = lxc_terminal_truncate_log_file(terminal); -+ if (ret < 0) -+ return ret; -+ -+ if ((uint64_t)bytes_read <= terminal->log_size) -+ return lxc_write_nointr(terminal->log_fd, buf, bytes_read); -+ -+ /* Write as much as we can into the buffer and loose the rest. */ -+ return lxc_write_nointr(terminal->log_fd, buf, terminal->log_size); -+ } -+ -+ /* There's enough space left. */ -+ if (bytes_read <= space_left) -+ return lxc_write_nointr(terminal->log_fd, buf, bytes_read); -+ -+ /* There'd be more to write but we aren't instructed to rotate the log -+ * file so simply return. There's no error on our side here. -+ */ -+ if (terminal->log_rotate > 0) -+ ret = lxc_terminal_rotate_log_file(terminal); -+ else -+ ret = lxc_terminal_truncate_log_file(terminal); -+ if (ret < 0) -+ return ret; -+ -+ if (terminal->log_size < (uint64_t)bytes_read) { -+ /* Well, this is unfortunate because it means that there is more -+ * to write than the user has granted us space. There are -+ * multiple ways to handle this but let's use the simplest one: -+ * write as much as we can, tell the user that there was more -+ * stuff to write and move on. -+ * Note that this scenario shouldn't actually happen with the -+ * standard pty-based terminal that LXC allocates since it will -+ * be switched into raw mode. In raw mode only 1 byte at a time -+ * should be read and written. -+ */ -+ WARN("Size of terminal log file is smaller than the bytes to write"); -+ ret = lxc_write_nointr(terminal->log_fd, buf, terminal->log_size); -+ if (ret < 0) -+ return -1; -+ bytes_read -= ret; -+ return bytes_read; -+ } -+ -+ /* Yay, we made it. */ -+ ret = lxc_write_nointr(terminal->log_fd, buf, bytes_read); -+ if (ret < 0) -+ return -1; -+ bytes_read -= ret; -+ return bytes_read; -+} -+ -+static ssize_t isulad_logger_json_write(struct lxc_terminal *terminal, const char *type, const char *buf, -+ int bytes_read) -+{ -+ logger_json_file *msg = NULL; -+ ssize_t ret = -1; -+ size_t len; -+ char *json = NULL; -+ char timebuffer[64] = { 0 }; -+ parser_error err = NULL; -+ struct parser_context ctx = { GEN_OPTIONS_SIMPLIFY | GEN_OPTIONS_NOT_VALIDATE_UTF8, stderr }; -+ -+ if (bytes_read < 0 || bytes_read >= INT_MAX) { -+ return -1; -+ } -+ msg = calloc(sizeof(logger_json_file), 1); -+ if (msg == NULL) { -+ return -errno; -+ } -+ msg->log = calloc(bytes_read, 1); -+ if (!msg->log) { -+ goto cleanup; -+ } -+ memcpy(msg->log, buf, bytes_read); -+ msg->log_len = bytes_read; -+ msg->stream = type ? safe_strdup(type) : safe_strdup("stdout"); -+ -+ get_now_time_buffer(timebuffer, sizeof(timebuffer)); -+ msg->time = safe_strdup(timebuffer); -+ -+ json = logger_json_file_generate_json(msg, &ctx, &err); -+ if (!json) { -+ ERROR("Failed to generate json: %s", err); -+ goto cleanup; -+ } -+ len = strlen(json); -+ json[len] = '\n'; -+ ret = isulad_lxc_terminal_rotate_write_data(terminal, json, len + 1); -+cleanup: -+ free(json); -+ free_logger_json_file(msg); -+ free(err); -+ return ret; -+} -+ -+static inline bool is_syslog(const char *driver) -+{ -+ if (driver == NULL) { -+ return false; -+ } -+ -+ return (strcmp("syslog", driver) == 0); -+} -+ -+static ssize_t isulad_logger_syslog_write(struct lxc_terminal *terminal, const char *buf) -+{ -+ syslog(LOG_INFO, "%s", buf); -+ return 0; -+} -+ -+static inline ssize_t isulad_logger_write(struct lxc_terminal *terminal, const char *type, const char *buf, -+ int bytes_read) -+{ -+ if (is_syslog(terminal->log_driver)) { -+ return isulad_logger_syslog_write(terminal, buf); -+ } -+ -+ return isulad_logger_json_write(terminal, type, buf, bytes_read); -+} -+ -+static int isulad_lxc_terminal_write_log_file(struct lxc_terminal *terminal, const char *type, char *buf, -+ int bytes_read) -+{ -+#define __BUF_CACHE_SIZE (16 * LXC_TERMINAL_BUFFER_SIZE) -+ static char cache[__BUF_CACHE_SIZE]; -+ static int size = 0; -+ int upto, index; -+ int begin = 0, buf_readed = 0, buf_left = 0; -+ int ret; -+ -+ if (buf != NULL && bytes_read > 0) { -+ /* Work out how much more data we are okay with reading this time. */ -+ upto = size + bytes_read; -+ if (upto > __BUF_CACHE_SIZE) { -+ upto = __BUF_CACHE_SIZE; -+ } -+ -+ if (upto > size) { -+ buf_readed = upto - size; -+ memcpy(cache + size, buf, buf_readed); -+ buf_left = bytes_read - buf_readed; -+ size += buf_readed; -+ } -+ } -+ -+ // If we have no data to log, and there's no more coming, we're done. -+ if (size == 0) -+ return 0; -+ -+ // Break up the data that we've buffered up into lines, and log each in turn. -+ for (index = 0; index < size; index++) { -+ if (cache[index] == '\n') { -+ ret = isulad_logger_write(terminal, type, cache + begin, index - begin + 1); -+ if (ret < 0) { -+ WARN("Failed to log msg"); -+ } -+ begin = index + 1; -+ } -+ } -+ /* If there's no more coming, or the buffer is full but -+ * has no newlines, log whatever we haven't logged yet, -+ * noting that it's a partial log line. */ -+ if (buf == NULL || (begin == 0 && size == __BUF_CACHE_SIZE)) { -+ if (begin < size) { -+ ret = isulad_logger_write(terminal, type, cache + begin, size - begin); -+ if (ret < 0) { -+ WARN("Failed to log msg"); -+ } -+ begin = 0; -+ size = 0; -+ } -+ if (buf == NULL) { -+ return 0; -+ } -+ } -+ /* Move any unlogged data to the front of the buffer in preparation for another read. */ -+ if (begin > 0) { -+ memcpy(cache, cache + begin, size - begin); -+ size -= begin; -+ } -+ /* Move left data to cache buffer */ -+ if (buf_left > 0) { -+ memcpy(cache + size, buf + buf_readed, buf_left); -+ size += buf_left; -+ } -+ return 0; -+} -+ -+/* isulad: forward data to all fifos */ -+static void lxc_forward_data_to_fifo(struct lxc_list *list, bool is_err, const char *buf, int r) -+{ -+ struct lxc_list *it = NULL; -+ struct lxc_list *next = NULL; -+ struct lxc_fifos_fd *elem = NULL; -+ ssize_t w = 0; -+ -+ lxc_list_for_each_safe(it, list, next) { -+ elem = it->elem; -+ if (is_err) { -+ if (elem->err_fd >= 0) { -+ w = lxc_write_nointr_for_fifo(elem->err_fd, buf, r); -+ if (w != r) { -+ WARN("Failed to write to fifo fd %d with error: %s", elem->err_fd, strerror(errno)); -+ } -+ } -+ } else { -+ if (elem->out_fd >= 0) { -+ w = lxc_write_nointr_for_fifo(elem->out_fd, buf, r); -+ if (w != r) { -+ WARN("Failed to write to fifo fd %d with error: %s", elem->out_fd, strerror(errno)); -+ } -+ } -+ } -+ } -+ -+ return; -+} -+ -+/* isulad: judge the fd whether is fifo */ -+static bool lxc_terminal_is_fifo(int fd, struct lxc_list *list) -+{ -+ struct lxc_list *it = NULL; -+ struct lxc_list *next = NULL; -+ struct lxc_fifos_fd *elem = NULL; -+ -+ lxc_list_for_each_safe(it, list, next) { -+ elem = it->elem; -+ if (elem->in_fd == fd) -+ return true; -+ } -+ -+ return false; -+} -+ -+/* isulad: if fd == -1, means delete all the fifos*/ -+int lxc_terminal_delete_fifo(int fd, struct lxc_list *list) -+{ -+ struct lxc_list *it = NULL; -+ struct lxc_list *next = NULL; -+ struct lxc_fifos_fd *elem = NULL; -+ -+ lxc_list_for_each_safe(it, list, next) { -+ elem = it->elem; -+ if (elem->in_fd == fd || -1 == fd) { -+ INFO("Delete fifo fd %d", fd); -+ lxc_list_del(it); -+ if (elem->in_fifo) -+ free(elem->in_fifo); -+ if (elem->out_fifo) -+ free(elem->out_fifo); -+ if (elem->err_fifo) -+ free(elem->err_fifo); -+ if (elem->in_fd >= 0) -+ close(elem->in_fd); -+ if (elem->out_fd >= 0) -+ close(elem->out_fd); -+ if (elem->err_fd >= 0) -+ close(elem->err_fd); -+ free(elem); -+ } -+ } -+ -+ return 0; -+} -+ - static int do_isulad_io(int fd, struct lxc_terminal *terminal) - { - char buf[LXC_TERMINAL_BUFFER_SIZE]; -@@ -373,7 +726,6 @@ static int do_isulad_io(int fd, struct lxc_terminal *terminal) - 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); -@@ -491,7 +843,11 @@ static int lxc_terminal_write_log_file(struct lxc_terminal *terminal, char *buf, - } - #endif - -+#ifdef HAVE_ISULAD -+static int lxc_terminal_ptx_io(struct lxc_terminal *terminal, int fd) -+#else - static int lxc_terminal_ptx_io(struct lxc_terminal *terminal) -+#endif - { - char buf[LXC_TERMINAL_BUFFER_SIZE]; - int r, w, w_log, w_rbuf; -@@ -576,7 +932,11 @@ static int lxc_terminal_ptx_io_handler(int fd, uint32_t events, void *data, - struct lxc_terminal *terminal = data; - int ret; - -+#ifdef HAVE_ISULAD -+ ret = lxc_terminal_ptx_io(data, fd); -+#else - ret = lxc_terminal_ptx_io(data); -+#endif - if (ret < 0) - return log_info(LXC_MAINLOOP_CLOSE, - "Terminal client on fd %d has exited", -@@ -1408,7 +1768,7 @@ int lxc_terminal_add_fifos(struct lxc_conf *conf, const char *fifonames) - } - - if (lxc_mainloop_add_handler(terminal->descr, fifofd_in, -- lxc_terminal_io_cb, terminal)) { -+ lxc_terminal_ptx_cb, default_cleanup_handler, terminal, "fifofd_in")) { - ERROR("console fifo not added to mainloop"); - lxc_terminal_delete_fifo(fifofd_in, &terminal->fifos); - ret = -1; -@@ -1599,6 +1959,7 @@ int lxc_terminal_parent(struct lxc_conf *conf) - return lxc_terminal_map_ids(conf, &conf->console); - } - -+#ifndef HAVE_ISULAD - static int lxc_terminal_create_native(const char *name, const char *lxcpath, - struct lxc_terminal *terminal) - { -@@ -1627,6 +1988,7 @@ static int lxc_terminal_create_native(const char *name, const char *lxcpath, - - return 0; - } -+#endif - - int lxc_terminal_create(const char *name, const char *lxcpath, - struct lxc_conf *conf, struct lxc_terminal *terminal) -@@ -1635,6 +1997,7 @@ int lxc_terminal_create(const char *name, const char *lxcpath, - if (!lxc_terminal_create_native(name, lxcpath, terminal)) - return 0; - #else -+ int ret; - /* isulad: open default fifos */ - ret = lxc_terminal_fifo_default(terminal); - if (ret < 0) { -diff --git a/src/lxc/tools/lxc_ls.c b/src/lxc/tools/lxc_ls.c -index 86a453d..505ed95 100644 ---- a/src/lxc/tools/lxc_ls.c -+++ b/src/lxc/tools/lxc_ls.c -@@ -1004,7 +1004,7 @@ static int my_parser(struct lxc_arguments *args, int c, char *arg) - } - - #ifdef HAVE_ISULAD --static int ls_get_wrapper(void *wrap, int msgfd); -+static int ls_get_wrapper(void *wrap, int msgfd) - #else - static int ls_get_wrapper(void *wrap) - #endif -diff --git a/src/lxc/utils.c b/src/lxc/utils.c -index 25cb0d1..397638e 100644 ---- a/src/lxc/utils.c -+++ b/src/lxc/utils.c -@@ -37,6 +37,9 @@ - #include "process_utils.h" - #include "syscall_wrappers.h" - #include "utils.h" -+#ifdef HAVE_ISULAD -+#include "lsm/lsm.h" -+#endif - - #if !HAVE_STRLCPY - #include "strlcpy.h" -diff --git a/src/tests/aa.c b/src/tests/aa.c -index 417f3fc..f766640 100644 ---- a/src/tests/aa.c -+++ b/src/tests/aa.c -@@ -40,7 +40,11 @@ static void try_to_remove(void) - } - } - -+#ifdef HAVE_ISULAD -+static int test_attach_write_file(void* payload, int msg_fd) -+#else - static int test_attach_write_file(void* payload) -+#endif - { - char *fnam = payload; - FILE *f; -diff --git a/src/tests/capabilities.c b/src/tests/capabilities.c -index 5704942..c54a051 100644 ---- a/src/tests/capabilities.c -+++ b/src/tests/capabilities.c -@@ -41,7 +41,11 @@ - __u32 *cap_bset_bits = NULL; - __u32 last_cap = 0; - -+#ifdef HAVE_ISULAD -+static int capabilities_allow(void *payload, int msg_fd) -+#else - static int capabilities_allow(void *payload) -+#endif - { - for (__u32 cap = 0; cap <= last_cap; cap++) { - bool bret; -@@ -62,7 +66,11 @@ static int capabilities_allow(void *payload) - return EXIT_SUCCESS; - } - -+#ifdef HAVE_ISULAD -+static int capabilities_deny(void *payload, int msg_fd) -+#else - static int capabilities_deny(void *payload) -+#endif - { - for (__u32 cap = 0; cap <= last_cap; cap++) { - bool bret; -@@ -83,7 +91,11 @@ static int capabilities_deny(void *payload) - return EXIT_SUCCESS; - } - -+#ifdef HAVE_ISULAD -+static int run(int (*test)(void *, int), bool allow) -+#else - static int run(int (*test)(void *), bool allow) -+#endif - { - int fd_log = -EBADF, fret = -1; - lxc_attach_options_t attach_options = LXC_ATTACH_OPTIONS_DEFAULT; -diff --git a/src/tests/mount_injection.c b/src/tests/mount_injection.c -index f98370b..5e852eb 100644 ---- a/src/tests/mount_injection.c -+++ b/src/tests/mount_injection.c -@@ -70,7 +70,11 @@ static int comp_field(char *line, const char *str, int nfields) - return ret; - } - -+#ifdef HAVE_ISULAD -+static int find_in_proc_mounts(void *data, int msg_fd) -+#else - static int find_in_proc_mounts(void *data) -+#endif - { - char buf[LXC_LINELEN]; - FILE *f; -diff --git a/src/tests/proc_pid.c b/src/tests/proc_pid.c -index 9531ec2..56bbf52 100644 ---- a/src/tests/proc_pid.c -+++ b/src/tests/proc_pid.c -@@ -15,7 +15,11 @@ - #define PROC_INIT_PATH "/proc/1/oom_score_adj" - #define PROC_SELF_PATH "/proc/self/oom_score_adj" - -+#ifdef HAVE_ISULAD -+static int check_oom_score_adj(void *payload, int msg_fd) -+#else - static int check_oom_score_adj(void *payload) -+#endif - { - __do_close int fd = -EBADF; - char buf[INTTYPE_TO_STRLEN(__s64)]; -diff --git a/src/tests/rootfs_options.c b/src/tests/rootfs_options.c -index 55f86ab..73b88f9 100644 ---- a/src/tests/rootfs_options.c -+++ b/src/tests/rootfs_options.c -@@ -60,7 +60,11 @@ static int has_mount_properties(const char *path, unsigned int flags) - #endif - } - -+#ifdef HAVE_ISULAD -+static int rootfs_options(void *payload, int msg_fd) -+#else - static int rootfs_options(void *payload) -+#endif - { - int ret; - -diff --git a/src/tests/sys_mixed.c b/src/tests/sys_mixed.c -index b51f28c..8a6ae53 100644 ---- a/src/tests/sys_mixed.c -+++ b/src/tests/sys_mixed.c -@@ -56,7 +56,11 @@ static int is_read_only(const char *path) - #endif - } - -+#ifdef HAVE_ISULAD -+static int sys_mixed(void *payload, int msg_fd) -+#else - static int sys_mixed(void *payload) -+#endif - { - int ret; - -diff --git a/src/tests/sysctls.c b/src/tests/sysctls.c -index da4538f..6a715a3 100644 ---- a/src/tests/sysctls.c -+++ b/src/tests/sysctls.c -@@ -16,7 +16,11 @@ - #define SYSCTL_CONFIG_KEY "lxc.sysctl.net.ipv4.ip_forward" - #define SYSCTL_CONFIG_VALUE "1" - -+#ifdef HAVE_ISULAD -+static int check_sysctls(void *payload, int msg_fd) -+#else - static int check_sysctls(void *payload) -+#endif - { - __do_close int fd = -EBADF; - char buf[INTTYPE_TO_STRLEN(__u64)]; --- -2.25.1 - diff --git a/0005-refactor-patch-code-of-attach-and-seccomp.patch b/0005-refactor-patch-code-of-attach-and-seccomp.patch new file mode 100644 index 0000000000000000000000000000000000000000..46c3e2bbdd08a6d951abe830e3b417094560e8db --- /dev/null +++ b/0005-refactor-patch-code-of-attach-and-seccomp.patch @@ -0,0 +1,1517 @@ +From ad33756d6190df4f1aad9b6468b0b59086e916b5 Mon Sep 17 00:00:00 2001 +From: zhangxiaoyu +Date: Tue, 19 Jul 2022 15:23:34 +0800 +Subject: [PATCH] refactor patch code of attach and seccomp + +Signed-off-by: zhangxiaoyu +--- + src/lxc/attach.c | 517 +++++++++++++++++++++++++++++++++++++++ + src/lxc/lsm/nop.c | 14 ++ + src/lxc/seccomp.c | 555 ++++++++++++++++++++++++++++++++++++++++++ + src/lxc/storage/zfs.c | 9 + + 4 files changed, 1095 insertions(+) + +diff --git a/src/lxc/attach.c b/src/lxc/attach.c +index 38e16f2..8a2c52a 100644 +--- a/src/lxc/attach.c ++++ b/src/lxc/attach.c +@@ -49,6 +49,25 @@ + #include + #endif + ++#ifdef HAVE_ISULAD ++#include "exec_commands.h" ++ ++typedef enum { ++ ATTACH_INIT, ++ ATTACH_TIMEOUT, ++ ATTACH_MAX, ++} attach_timeout_t; ++ ++static volatile attach_timeout_t g_attach_timeout_state = ATTACH_INIT; ++ ++struct attach_timeout_conf { ++ int64_t timeout; ++ unsigned long long start_time; ++ pid_t pid; ++}; ++ ++#endif ++ + lxc_log_define(attach, lxc); + + /* Define default options if no options are supplied by the user. */ +@@ -630,6 +649,9 @@ struct attach_clone_payload { + struct lxc_proc_context_info *init_ctx; + lxc_attach_exec_t exec_function; + void *exec_payload; ++#ifdef HAVE_ISULAD ++ struct lxc_terminal *terminal; ++#endif + }; + + static void lxc_put_attach_clone_payload(struct attach_clone_payload *p) +@@ -642,6 +664,48 @@ static void lxc_put_attach_clone_payload(struct attach_clone_payload *p) + } + } + ++#ifdef HAVE_ISULAD ++static int isulad_set_attach_pipes(struct lxc_terminal *terminal) ++{ ++ int ret = 0; ++ if (terminal->pipes[0][1] >= 0) { ++ close(terminal->pipes[0][1]); ++ terminal->pipes[0][1] = -1; ++ } ++ ++ if (terminal->pipes[0][0] >= 0) { ++ ret = dup2(terminal->pipes[0][0], STDIN_FILENO); ++ if (ret < 0) ++ goto out; ++ } ++ ++ if (terminal->pipes[1][0] >= 0) { ++ close(terminal->pipes[1][0]); ++ terminal->pipes[1][0] = -1; ++ } ++ ++ if (terminal->pipes[1][1] >= 0) { ++ ret = dup2(terminal->pipes[1][1], STDOUT_FILENO); ++ if (ret < 0) ++ goto out; ++ } ++ if (terminal->pipes[2][0] >= 0) { ++ close(terminal->pipes[2][0]); ++ terminal->pipes[2][0] = -1; ++ } ++ ++ if (terminal->pipes[2][1] >= 0) { ++ ret = dup2(terminal->pipes[2][1], STDERR_FILENO); ++ if (ret < 0) ++ goto out; ++ } ++ ++ setsid(); ++out: ++ return ret; ++} ++#endif ++ + static int attach_child_main(struct attach_clone_payload *payload) + { + int lsm_fd, ret; +@@ -654,6 +718,31 @@ static int attach_child_main(struct attach_clone_payload *payload) + bool needs_lsm = (options->namespaces & CLONE_NEWNS) && + (options->attach_flags & LXC_ATTACH_LSM) && + init_ctx->lsm_label; ++#ifdef HAVE_ISULAD ++ int msg_fd = -1; ++ sigset_t mask; ++ ++ /*isulad: record errpipe fd*/ ++ msg_fd = init_ctx->container->lxc_conf->errpipe[1]; ++ init_ctx->container->lxc_conf->errpipe[1] = -1; ++ /*isulad: set system umask */ ++ umask(init_ctx->container->lxc_conf->umask); ++ ++ /*isulad: restore default signal handlers and unblock all signals*/ ++ for (int i = 1; i < NSIG; i++) ++ signal(i, SIG_DFL); ++ ++ ret = sigfillset(&mask); ++ if (ret < 0) { ++ SYSERROR("Failed to fill signal mask"); ++ goto on_error;; ++ } ++ ret = sigprocmask(SIG_UNBLOCK, &mask, NULL); ++ if (ret < 0) { ++ SYSERROR("Failed to set signal mask"); ++ goto on_error; ++ } ++#endif + + /* A description of the purpose of this functionality is provided in the + * lxc-attach(1) manual page. We have to remount here and not in the +@@ -695,6 +784,28 @@ static int attach_child_main(struct attach_clone_payload *payload) + TRACE("Dropped capabilities"); + } + ++#ifdef HAVE_ISULAD ++ /* isulad: set workdir */ ++ if (options->initial_cwd || init_ctx->container->lxc_conf->init_cwd) { ++ char *init_cwd; ++ init_cwd = options->initial_cwd ? options->initial_cwd : init_ctx->container->lxc_conf->init_cwd; ++ /* try to create workdir if not exist */ ++ struct stat st; ++ if (stat(init_cwd, &st) < 0 && mkdir_p(init_cwd, 0750) < 0) { ++ SYSERROR("Try to create directory \"%s\" as workdir failed when attach", init_cwd); ++ lxc_write_error_message(msg_fd, "Try to create directory \"%s\" as workdir failed when attach: %s", ++ init_cwd, strerror(errno)); ++ goto on_error; ++ } ++ if (chdir(init_cwd)) { ++ SYSERROR("Could not change directory to \"%s\" when attach", init_cwd); ++ lxc_write_error_message(msg_fd, "Could not change directory to \"%s\" when attach: %s", ++ init_cwd, strerror(errno)); ++ goto on_error; ++ } ++ } ++#endif ++ + /* Always set the environment (specify (LXC_ATTACH_KEEP_ENV, NULL, NULL) + * if you want this to be a no-op). + */ +@@ -736,8 +847,10 @@ static int attach_child_main(struct attach_clone_payload *payload) + goto on_error; + } + ++#ifndef HAVE_ISULAD + if (!lxc_setgroups(0, NULL) && errno != EPERM) + goto on_error; ++#endif + + if (options->namespaces & CLONE_NEWUSER) { + /* Check whether nsuid 0 has a mapping. */ +@@ -770,6 +883,13 @@ static int attach_child_main(struct attach_clone_payload *payload) + else + new_gid = ns_root_gid; + ++#ifdef HAVE_ISULAD ++ // isulad: set env home in container ++ if (lxc_setup_env_home(new_uid) < 0) { ++ goto on_error; ++ } ++#endif ++ + if ((init_ctx->container && init_ctx->container->lxc_conf && + init_ctx->container->lxc_conf->no_new_privs) || + (options->attach_flags & LXC_ATTACH_NO_NEW_PRIVS)) { +@@ -810,10 +930,12 @@ static int attach_child_main(struct attach_clone_payload *payload) + goto on_error; + } + ++#ifndef HAVE_ISULAD + close(payload->ipc_socket); + payload->ipc_socket = -EBADF; + lxc_proc_put_context_info(init_ctx); + payload->init_ctx = NULL; ++#endif + + /* The following is done after the communication socket is shut down. + * That way, all errors that might (though unlikely) occur up until this +@@ -856,6 +978,24 @@ static int attach_child_main(struct attach_clone_payload *payload) + } + + if (options->attach_flags & LXC_ATTACH_TERMINAL) { ++#ifdef HAVE_ISULAD ++ /* isulad: dup2 pipe[0][0] to container stdin, pipe[1][1] to container stdout, pipe[2][1] to container stderr */ ++ if (payload->terminal->disable_pty) { ++ ret = isulad_set_attach_pipes(payload->terminal); ++ if (ret < 0) { ++ SYSERROR("Failed to prepare terminal file pipes"); ++ goto on_error; ++ } ++ } ++ ++ if(!payload->terminal->disable_pty && payload->terminal_pts_fd >= 0) { ++ ret = lxc_terminal_prepare_login(payload->terminal_pts_fd); ++ if (ret < 0) { ++ SYSERROR("Failed to prepare terminal file descriptor %d", payload->terminal_pts_fd); ++ goto on_error; ++ } ++ } ++#else + ret = lxc_terminal_prepare_login(payload->terminal_pts_fd); + if (ret < 0) { + SYSERROR("Failed to prepare terminal file descriptor %d", payload->terminal_pts_fd); +@@ -863,6 +1003,7 @@ static int attach_child_main(struct attach_clone_payload *payload) + } + + TRACE("Prepared terminal file descriptor %d", payload->terminal_pts_fd); ++#endif + } + + /* Avoid unnecessary syscalls. */ +@@ -872,6 +1013,17 @@ static int attach_child_main(struct attach_clone_payload *payload) + if (new_gid == ns_root_gid) + new_gid = LXC_INVALID_GID; + ++#ifdef HAVE_ISULAD ++ if (prctl(PR_SET_KEEPCAPS, 1) < 0) { ++ SYSERROR("Failed to keep permitted capabilities"); ++ goto on_error; ++ } ++ ++ if (!lxc_setgroups(init_ctx->container->lxc_conf->init_groups_len, ++ init_ctx->container->lxc_conf->init_groups)) ++ goto on_error; ++#endif ++ + /* Make sure that the processes STDIO is correctly owned by the user that we are switching to */ + ret = fix_stdio_permissions(new_uid); + if (ret) +@@ -880,21 +1032,63 @@ static int attach_child_main(struct attach_clone_payload *payload) + if (!lxc_switch_uid_gid(new_uid, new_gid)) + goto on_error; + ++#ifdef HAVE_ISULAD ++ if (prctl(PR_SET_KEEPCAPS, 0) < 0) { ++ SYSERROR("Failed to clear permitted capabilities"); ++ goto on_error; ++ } ++ ++ if (lxc_drop_caps(init_ctx->container->lxc_conf) != 0) { ++ ERROR("Failed to drop caps."); ++ goto on_error; ++ } ++ ++ close(payload->ipc_socket); ++ payload->ipc_socket = -EBADF; ++ lxc_proc_put_context_info(init_ctx); ++ payload->init_ctx = NULL; ++ _exit(payload->exec_function(payload->exec_payload, msg_fd)); ++#else + /* We're done, so we can now do whatever the user intended us to do. */ + _exit(payload->exec_function(payload->exec_payload)); ++#endif + + on_error: + lxc_put_attach_clone_payload(payload); + _exit(EXIT_FAILURE); + } + ++#ifdef HAVE_ISULAD ++static int lxc_attach_terminal(struct lxc_conf *conf, ++ struct lxc_terminal *terminal, lxc_attach_options_t *options) ++#else + static int lxc_attach_terminal(struct lxc_conf *conf, + struct lxc_terminal *terminal) ++#endif + { + int ret; + + lxc_terminal_init(terminal); + ++#ifdef HAVE_ISULAD ++ /* isulad: if we pass fifo in option, use them as init fifos */ ++ if (options->init_fifo[0]) { ++ free(terminal->init_fifo[0]); ++ terminal->init_fifo[0] = safe_strdup(options->init_fifo[0]); ++ } ++ if (options->init_fifo[1]) { ++ free(terminal->init_fifo[1]); ++ terminal->init_fifo[1] = safe_strdup(options->init_fifo[1]); ++ } ++ if (options->init_fifo[2]) { ++ free(terminal->init_fifo[2]); ++ terminal->init_fifo[2] = safe_strdup(options->init_fifo[2]); ++ } ++ ++ terminal->disable_pty = options->disable_pty; ++ terminal->open_stdin = options->open_stdin; ++#endif ++ + ret = lxc_terminal_create(terminal); + if (ret < 0) + return log_error(-1, "Failed to create terminal"); +@@ -952,9 +1146,126 @@ static inline void lxc_attach_terminal_close_log(struct lxc_terminal *terminal) + close_prot_errno_disarm(terminal->log_fd); + } + ++#ifdef HAVE_ISULAD ++/* isulad: attach timeout thread function */ ++static void* wait_attach_timeout(void *arg) ++{ ++ struct attach_timeout_conf *conf = (struct attach_timeout_conf *)arg; ++ ++ if (!conf || conf->timeout < 1) ++ goto out; ++ sleep(conf->timeout); ++ if (lxc_process_alive(conf->pid, conf->start_time)) { ++ g_attach_timeout_state = ATTACH_TIMEOUT; ++ if (kill(conf->pid, SIGKILL) < 0) { ++ ERROR("Failed to send signal %d to pid %d", SIGKILL, conf->pid); ++ } ++ } ++ ++out: ++ free(conf); ++ return ((void *)0); ++} ++ ++/* isulad: create attach timeout thread */ ++static int create_attach_timeout_thread(int64_t attach_timeout, pid_t pid) ++{ ++ int ret = 0; ++ pthread_t ptid; ++ pthread_attr_t attr; ++ struct attach_timeout_conf *timeout_conf = NULL; ++ ++ timeout_conf = malloc(sizeof(struct attach_timeout_conf)); ++ if (timeout_conf == NULL) { ++ ERROR("Failed to malloc attach timeout conf"); ++ ret = -1; ++ goto out; ++ } ++ ++ memset(timeout_conf, 0, sizeof(struct attach_timeout_conf)); ++ timeout_conf->timeout = attach_timeout; ++ timeout_conf->pid = pid; ++ timeout_conf->start_time = lxc_get_process_startat(pid); ++ ++ pthread_attr_init(&attr); ++ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); ++ ret = pthread_create(&ptid, &attr, wait_attach_timeout, timeout_conf); ++ pthread_attr_destroy(&attr); ++ if (ret != 0) { ++ ERROR("Create attach wait timeout thread failed"); ++ free(timeout_conf); ++ goto out; ++ } ++ ++out: ++ return ret; ++} ++ ++static int attach_signal_handler(int fd, uint32_t events, void *data, ++ struct lxc_epoll_descr *descr) ++{ ++ int ret; ++ siginfo_t info; ++ struct signalfd_siginfo siginfo; ++ pid_t *pid = data; ++ ++ ret = lxc_read_nointr(fd, &siginfo, sizeof(siginfo)); ++ if (ret < 0) ++ return log_error(LXC_MAINLOOP_ERROR, "Failed to read signal info from signal file descriptor %d", fd); ++ ++ if (ret != sizeof(siginfo)) ++ return log_error(LXC_MAINLOOP_ERROR, "Unexpected size for struct signalfd_siginfo"); ++ ++ /* Check whether init is running. */ ++ info.si_pid = 0; ++ ret = waitid(P_PID, *pid, &info, WEXITED | WNOWAIT | WNOHANG); ++ if (ret == 0 && info.si_pid == *pid) { ++ return log_warn(LXC_MAINLOOP_CLOSE, "Container attach init process %d exited", *pid); ++ } ++ ++ return LXC_MAINLOOP_CONTINUE; ++} ++ ++static int isulad_setup_signal_fd(sigset_t *oldmask) ++{ ++ int ret; ++ sigset_t mask; ++ const int signals[] = {SIGBUS, SIGILL, SIGSEGV, SIGWINCH, SIGTERM}; ++ ++ /* Block everything except serious error signals. */ ++ ret = sigfillset(&mask); ++ if (ret < 0) ++ return -EBADF; ++ ++ for (int sig = 0; sig < (sizeof(signals) / sizeof(signals[0])); sig++) { ++ ret = sigdelset(&mask, signals[sig]); ++ if (ret < 0) ++ return -EBADF; ++ } ++ ++ ret = pthread_sigmask(SIG_BLOCK, &mask, oldmask); ++ if (ret < 0) ++ return log_error_errno(-EBADF, errno, ++ "Failed to set signal mask"); ++ ++ ret = signalfd(-1, &mask, SFD_CLOEXEC); ++ if (ret < 0) ++ return log_error_errno(-EBADF, ++ errno, "Failed to create signal file descriptor"); ++ ++ TRACE("Created signal file descriptor %d", ret); ++ ++ return ret; ++} ++ ++int lxc_attach(struct lxc_container *container, lxc_attach_exec_t exec_function, ++ void *exec_payload, lxc_attach_options_t *options, ++ pid_t *attached_process, char **err_msg) ++#else + int lxc_attach(struct lxc_container *container, lxc_attach_exec_t exec_function, + void *exec_payload, lxc_attach_options_t *options, + pid_t *attached_process) ++#endif + { + int i, ret, status; + int ipc_sockets[2]; +@@ -966,6 +1277,13 @@ int lxc_attach(struct lxc_container *container, lxc_attach_exec_t exec_function, + struct lxc_conf *conf; + char *name, *lxcpath; + struct attach_clone_payload payload = {0}; ++#ifdef HAVE_ISULAD ++ struct lxc_exec_command_handler exec_command; ++ const char *suffix = options->suffix; ++ ++ exec_command.maincmd_fd = -1; ++ exec_command.terminal = &terminal; ++#endif + + ret = access("/proc/self/ns", X_OK); + if (ret) +@@ -1017,6 +1335,14 @@ int lxc_attach(struct lxc_container *container, lxc_attach_exec_t exec_function, + if (!conf) + return log_error_errno(-EINVAL, EINVAL, "Missing container confifg"); + ++#ifdef HAVE_ISULAD ++ // always switch uid and gid for attach ++ if (options->uid == -1) ++ options->uid = init_ctx->container->lxc_conf->init_uid; ++ if (options->gid == -1) ++ options->gid = init_ctx->container->lxc_conf->init_gid; ++#endif ++ + if (!fetch_seccomp(init_ctx->container, options)) + WARN("Failed to get seccomp policy"); + +@@ -1090,7 +1416,11 @@ int lxc_attach(struct lxc_container *container, lxc_attach_exec_t exec_function, + } + + if (options->attach_flags & LXC_ATTACH_TERMINAL) { ++#ifdef HAVE_ISULAD ++ ret = lxc_attach_terminal(conf, &terminal, options); ++#else + ret = lxc_attach_terminal(conf, &terminal); ++#endif + if (ret < 0) { + ERROR("Failed to setup new terminal"); + free(cwd); +@@ -1099,6 +1429,12 @@ int lxc_attach(struct lxc_container *container, lxc_attach_exec_t exec_function, + } + + terminal.log_fd = options->log_fd; ++#ifdef HAVE_ISULAD ++ if (suffix != NULL) { ++ exec_command.maincmd_fd = lxc_exec_cmd_init(name, lxcpath, suffix); ++ exec_command.terminal = &terminal; ++ } ++#endif + } else { + lxc_terminal_init(&terminal); + } +@@ -1139,10 +1475,40 @@ int lxc_attach(struct lxc_container *container, lxc_attach_exec_t exec_function, + ret = socketpair(PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0, ipc_sockets); + if (ret < 0) { + SYSERROR("Could not set up required IPC mechanism for attaching"); ++#ifdef HAVE_ISULAD ++ if (options->attach_flags & LXC_ATTACH_TERMINAL) { ++ lxc_terminal_delete(&terminal); ++ lxc_terminal_conf_free(&terminal); ++ if (exec_command.maincmd_fd != -1) { ++ close(exec_command.maincmd_fd); ++ } ++ lxc_exec_unix_sock_delete(name, suffix); ++ } ++#endif ++ free(cwd); ++ lxc_proc_put_context_info(init_ctx); ++ return -1; ++ } ++ ++#ifdef HAVE_ISULAD ++ /* isulad: pipdfd for get error message of child or grandchild process. */ ++ if (pipe2(conf->errpipe, O_CLOEXEC) != 0) { ++ SYSERROR("Failed to init errpipe"); ++ if (options->attach_flags & LXC_ATTACH_TERMINAL) { ++ lxc_terminal_delete(&terminal); ++ lxc_terminal_conf_free(&terminal); ++ if (exec_command.maincmd_fd != -1) { ++ close(exec_command.maincmd_fd); ++ } ++ lxc_exec_unix_sock_delete(name, suffix); ++ } ++ close(ipc_sockets[0]); ++ close(ipc_sockets[1]); + free(cwd); + lxc_proc_put_context_info(init_ctx); + return -1; + } ++#endif + + /* Create intermediate subprocess, two reasons: + * 1. We can't setns() in the child itself, since we want to make +@@ -1154,6 +1520,18 @@ int lxc_attach(struct lxc_container *container, lxc_attach_exec_t exec_function, + pid = fork(); + if (pid < 0) { + SYSERROR("Failed to create first subprocess"); ++#ifdef HAVE_ISULAD ++ if (options->attach_flags & LXC_ATTACH_TERMINAL) { ++ lxc_terminal_delete(&terminal); ++ lxc_terminal_conf_free(&terminal); ++ if (exec_command.maincmd_fd != -1) { ++ close(exec_command.maincmd_fd); ++ } ++ lxc_exec_unix_sock_delete(name, suffix); ++ } ++ close(ipc_sockets[0]); ++ close(ipc_sockets[1]); ++#endif + free(cwd); + lxc_proc_put_context_info(init_ctx); + return -1; +@@ -1163,10 +1541,35 @@ int lxc_attach(struct lxc_container *container, lxc_attach_exec_t exec_function, + int ret_parent = -1; + pid_t to_cleanup_pid = pid; + struct lxc_epoll_descr descr = {0}; ++#ifdef HAVE_ISULAD ++ int isulad_sigfd; ++ sigset_t isulad_oldmask; ++ struct lxc_epoll_descr isulad_descr = {0}; ++#endif + + /* close unneeded file descriptors */ + close(ipc_sockets[1]); + free(cwd); ++#ifdef HAVE_ISULAD ++ /* isulad: close errpipe */ ++ close(conf->errpipe[1]); ++ conf->errpipe[1] = -1; ++ /* isulad: close pipe after clone */ ++ if (terminal.pipes[0][0] >= 0) { ++ close(terminal.pipes[0][0]); ++ terminal.pipes[0][0] = -1; ++ } ++ ++ if (terminal.pipes[1][1] >= 0) { ++ close(terminal.pipes[1][1]); ++ terminal.pipes[1][1] = -1; ++ } ++ ++ if (terminal.pipes[2][1] >= 0) { ++ close(terminal.pipes[2][1]); ++ terminal.pipes[2][1] = -1; ++ } ++#endif + lxc_proc_close_ns_fd(init_ctx); + if (options->attach_flags & LXC_ATTACH_TERMINAL) + lxc_attach_terminal_close_pts(&terminal); +@@ -1200,7 +1603,11 @@ int lxc_attach(struct lxc_container *container, lxc_attach_exec_t exec_function, + + /* Setup resource limits */ + if (!lxc_list_empty(&conf->limits)) { ++#ifdef HAVE_ISULAD ++ ret = setup_resource_limits(&conf->limits, pid, -1); ++#else + ret = setup_resource_limits(&conf->limits, pid); ++#endif + if (ret < 0) + goto on_error; + } +@@ -1210,9 +1617,28 @@ int lxc_attach(struct lxc_container *container, lxc_attach_exec_t exec_function, + if (ret < 0) + goto on_error; + ++#ifdef HAVE_ISULAD ++ ret = lxc_attach_terminal_mainloop_init(&terminal, &isulad_descr); ++ if (ret < 0) ++ goto on_error; ++ ++ if (suffix != NULL) { ++ (void)lxc_exec_cmd_mainloop_add(&descr, &exec_command); ++ } ++#endif + TRACE("Initialized terminal mainloop"); + } + ++#ifdef HAVE_ISULAD ++ /* The signal fd has to be created before forking otherwise if the child ++ * process exits before we setup the signal fd, the event will be lost ++ * and the command will be stuck. ++ */ ++ isulad_sigfd = isulad_setup_signal_fd(&isulad_oldmask); ++ if (isulad_sigfd < 0) ++ goto close_mainloop; ++#endif ++ + /* Let the child process know to go ahead. */ + status = 0; + ret = lxc_write_nointr(ipc_sockets[0], &status, sizeof(status)); +@@ -1290,6 +1716,34 @@ int lxc_attach(struct lxc_container *container, lxc_attach_exec_t exec_function, + + *attached_process = attached_pid; + ++#ifdef HAVE_ISULAD ++ if (options->timeout > 0) { ++ ret = create_attach_timeout_thread(options->timeout, *attached_process); ++ if (ret) { ++ ERROR("Failed to create attach timeout thread for container."); ++ goto close_mainloop; ++ } ++ } ++ /* isulad: read error msg from pipe */ ++ ssize_t size_read; ++ char errbuf[BUFSIZ + 1] = {0}; ++ pid_t tmp_pid = *attached_process; ++ ++ size_read = read(conf->errpipe[0], errbuf, BUFSIZ); ++ if (size_read > 0) { ++ if (err_msg) ++ *err_msg = safe_strdup(errbuf); ++ goto close_mainloop; ++ } ++ if (options->attach_flags & LXC_ATTACH_TERMINAL) { ++ ret = lxc_mainloop_add_handler(&descr, isulad_sigfd, attach_signal_handler, &tmp_pid); ++ if (ret < 0) { ++ ERROR("Failed to add signal handler for %d to mainloop", tmp_pid); ++ goto close_mainloop; ++ } ++ } ++#endif ++ + /* Now shut down communication with child, we're done. */ + shutdown(ipc_sockets[0], SHUT_RDWR); + close(ipc_sockets[0]); +@@ -1298,17 +1752,44 @@ int lxc_attach(struct lxc_container *container, lxc_attach_exec_t exec_function, + ret_parent = 0; + to_cleanup_pid = -1; + ++#ifdef HAVE_ISULAD ++ // iSulad: close stdin pipe if we do not want open_stdin with container stdin ++ if (!terminal.open_stdin) { ++ if (terminal.pipes[0][1] > 0) { ++ close(terminal.pipes[0][1]); ++ terminal.pipes[0][1] = -1; ++ } ++ } ++#endif + if (options->attach_flags & LXC_ATTACH_TERMINAL) { ++#ifdef HAVE_ISULAD ++ ret = isulad_safe_mainloop(&descr, -1); ++#else + ret = lxc_mainloop(&descr, -1); ++#endif + if (ret < 0) { + ret_parent = -1; + to_cleanup_pid = attached_pid; + } + } + ++#ifdef HAVE_ISULAD ++ // do lxc_mainloop to make sure we do not lose any output ++ (void)isulad_safe_mainloop(&isulad_descr, 100); ++ if (g_attach_timeout_state == ATTACH_TIMEOUT && err_msg != NULL && *err_msg == NULL) { ++ *err_msg = safe_strdup("Attach exceeded timeout"); ++ } ++#endif + close_mainloop: ++#ifdef HAVE_ISULAD ++ if (options->attach_flags & LXC_ATTACH_TERMINAL) { ++ lxc_mainloop_close(&isulad_descr); ++ lxc_mainloop_close(&descr); ++ } ++#else + if (options->attach_flags & LXC_ATTACH_TERMINAL) + lxc_mainloop_close(&descr); ++#endif + + on_error: + if (ipc_sockets[0] >= 0) { +@@ -1322,6 +1803,12 @@ int lxc_attach(struct lxc_container *container, lxc_attach_exec_t exec_function, + if (options->attach_flags & LXC_ATTACH_TERMINAL) { + lxc_terminal_delete(&terminal); + lxc_terminal_conf_free(&terminal); ++#ifdef HAVE_ISULAD ++ if (exec_command.maincmd_fd != -1) { ++ close(exec_command.maincmd_fd); ++ } ++ lxc_exec_unix_sock_delete(name, suffix); ++#endif + } + + lxc_proc_put_context_info(init_ctx); +@@ -1331,10 +1818,21 @@ int lxc_attach(struct lxc_container *container, lxc_attach_exec_t exec_function, + /* close unneeded file descriptors */ + close_prot_errno_disarm(ipc_sockets[0]); + ++#ifdef HAVE_ISULAD ++ /* isulad: close errpipe */ ++ close(conf->errpipe[0]); ++ conf->errpipe[0] = -1; ++#endif ++ + if (options->attach_flags & LXC_ATTACH_TERMINAL) { + lxc_attach_terminal_close_ptmx(&terminal); + lxc_attach_terminal_close_peer(&terminal); + lxc_attach_terminal_close_log(&terminal); ++#ifdef HAVE_ISULAD ++ if (exec_command.maincmd_fd != -1) { ++ close(exec_command.maincmd_fd); ++ } ++#endif + } + + /* Wait for the parent to have setup cgroups. */ +@@ -1380,6 +1878,9 @@ int lxc_attach(struct lxc_container *container, lxc_attach_exec_t exec_function, + payload.terminal_pts_fd = terminal.pts; + payload.exec_function = exec_function; + payload.exec_payload = exec_payload; ++#ifdef HAVE_ISULAD ++ payload.terminal = &terminal; ++#endif + + pid = lxc_raw_clone(CLONE_PARENT, NULL); + if (pid < 0) { +@@ -1390,7 +1891,11 @@ int lxc_attach(struct lxc_container *container, lxc_attach_exec_t exec_function, + } + + if (pid == 0) { ++#ifdef HAVE_ISULAD ++ if (options->attach_flags & LXC_ATTACH_TERMINAL && terminal.tty_state) { ++#else + if (options->attach_flags & LXC_ATTACH_TERMINAL) { ++#endif + ret = pthread_sigmask(SIG_SETMASK, + &terminal.tty_state->oldmask, NULL); + if (ret < 0) { +@@ -1430,7 +1935,11 @@ int lxc_attach(struct lxc_container *container, lxc_attach_exec_t exec_function, + _exit(EXIT_SUCCESS); + } + ++#ifdef HAVE_ISULAD ++int lxc_attach_run_command(void *payload, int msg_fd) ++#else + int lxc_attach_run_command(void *payload) ++#endif + { + int ret = -1; + lxc_attach_command_t *cmd = payload; +@@ -1446,11 +1955,19 @@ int lxc_attach_run_command(void *payload) + break; + } + } ++#ifdef HAVE_ISULAD ++ /* isulad: write error messages */ ++ lxc_write_error_message(msg_fd, "exec: \"%s\": %s.", cmd->program, strerror(errno)); ++#endif + + return log_error_errno(ret, errno, "Failed to exec \"%s\"", cmd->program); + } + ++#ifdef HAVE_ISULAD ++int lxc_attach_run_shell(void* payload, int msg_fd) ++#else + int lxc_attach_run_shell(void* payload) ++#endif + { + __do_free char *buf = NULL; + uid_t uid; +diff --git a/src/lxc/lsm/nop.c b/src/lxc/lsm/nop.c +index 5b345b9..188945d 100644 +--- a/src/lxc/lsm/nop.c ++++ b/src/lxc/lsm/nop.c +@@ -24,11 +24,25 @@ static int nop_enabled(void) + return 0; + } + ++#ifdef HAVE_ISULAD ++static int nop_file_label_set(const char *path, const char *label) { ++ return 0; ++} ++ ++static int nop_relabel(const char *path, const char *label, bool shared) { ++ return 0; ++} ++#endif ++ + static struct lsm_drv nop_drv = { + .name = "nop", + .enabled = nop_enabled, + .process_label_get = nop_process_label_get, + .process_label_set = nop_process_label_set, ++#ifdef HAVE_ISULAD ++ .file_label_set = nop_file_label_set, ++ .relabel = nop_relabel, ++#endif + }; + + struct lsm_drv *lsm_nop_drv_init(void) +diff --git a/src/lxc/seccomp.c b/src/lxc/seccomp.c +index 7820db8..a6e6d42 100644 +--- a/src/lxc/seccomp.c ++++ b/src/lxc/seccomp.c +@@ -351,8 +351,13 @@ int get_hostarch(void) + return lxc_seccomp_arch_unknown; + } + ++#ifdef HAVE_ISULAD ++scmp_filter_ctx get_new_ctx(enum lxc_hostarch_t n_arch, ++ uint32_t default_policy_action, uint32_t *architectures) ++#else + scmp_filter_ctx get_new_ctx(enum lxc_hostarch_t n_arch, + uint32_t default_policy_action, bool *needs_merge) ++#endif + { + int ret; + uint32_t arch; +@@ -476,9 +481,17 @@ scmp_filter_ctx get_new_ctx(enum lxc_hostarch_t n_arch, + } + TRACE("Removed native arch from main seccomp context"); + ++#ifdef HAVE_ISULAD ++ *architectures = arch; ++#else + *needs_merge = true; ++#endif + } else { ++#ifdef HAVE_ISULAD ++ *architectures = SCMP_ARCH_NATIVE; ++#else + *needs_merge = false; ++#endif + TRACE("Arch %d already present in main seccomp context", (int)n_arch); + } + +@@ -510,7 +523,11 @@ bool do_resolve_add_rule(uint32_t arch, char *line, scmp_filter_ctx ctx, + if (ret < 0) { + errno = -ret; + SYSERROR("Failed loading rule to reject force umount"); ++#ifdef HAVE_ISULAD ++ return true; ++#else + return false; ++#endif + } + + INFO("Set seccomp rule to reject force umounts"); +@@ -519,24 +536,42 @@ bool do_resolve_add_rule(uint32_t arch, char *line, scmp_filter_ctx ctx, + + nr = seccomp_syscall_resolve_name(line); + if (nr == __NR_SCMP_ERROR) { ++#ifdef HAVE_ISULAD ++ DEBUG("Failed to resolve syscall \"%s\"", line); ++ DEBUG("This syscall will NOT be handled by seccomp"); ++#else + WARN("Failed to resolve syscall \"%s\"", line); + WARN("This syscall will NOT be handled by seccomp"); ++#endif + return true; + } + + if (nr < 0) { ++#ifdef HAVE_ISULAD ++ DEBUG("Got negative return value %d for syscall \"%s\"", nr, line); ++ DEBUG("This syscall will NOT be handled by seccomp"); ++#else + WARN("Got negative return value %d for syscall \"%s\"", nr, line); + WARN("This syscall will NOT be handled by seccomp"); ++#endif + return true; + } + + memset(&arg_cmp, 0, sizeof(arg_cmp)); + for (i = 0; i < rule->args_num; i++) { ++#ifdef HAVE_ISULAD ++ DEBUG("arg_cmp[%d]: SCMP_CMP(%u, %llu, %llu, %llu)", i, ++ rule->args_value[i].index, ++ (long long unsigned int)rule->args_value[i].op, ++ (long long unsigned int)rule->args_value[i].mask, ++ (long long unsigned int)rule->args_value[i].value); ++#else + INFO("arg_cmp[%d]: SCMP_CMP(%u, %llu, %llu, %llu)", i, + rule->args_value[i].index, + (long long unsigned int)rule->args_value[i].op, + (long long unsigned int)rule->args_value[i].mask, + (long long unsigned int)rule->args_value[i].value); ++#endif + + if (SCMP_CMP_MASKED_EQ == rule->args_value[i].op) + arg_cmp[i] = SCMP_CMP(rule->args_value[i].index, +@@ -553,14 +588,43 @@ bool do_resolve_add_rule(uint32_t arch, char *line, scmp_filter_ctx ctx, + rule->args_num, arg_cmp); + if (ret < 0) { + errno = -ret; ++#ifdef HAVE_ISULAD ++ DEBUG("Failed loading rule for %s (nr %d action %d (%s))", ++ line, nr, rule->action, get_action_name(rule->action)); ++ return true; ++#else + SYSERROR("Failed loading rule for %s (nr %d action %d (%s))", + line, nr, rule->action, get_action_name(rule->action)); + return false; ++#endif + } + + return true; + } + ++#ifdef HAVE_ISULAD ++#define SCMP_ARCH_INDEX_MAX 3 ++ ++struct scmp_ctx_info { ++ uint32_t architectures[SCMP_ARCH_INDEX_MAX]; ++ enum lxc_hostarch_t lxc_arch[SCMP_ARCH_INDEX_MAX]; ++ scmp_filter_ctx contexts[SCMP_ARCH_INDEX_MAX]; ++ bool needs_merge[SCMP_ARCH_INDEX_MAX]; ++}; ++ ++static int get_arch_index(enum lxc_hostarch_t arch, struct scmp_ctx_info *ctx) ++{ ++ int i; ++ ++ for (i = 0; i < SCMP_ARCH_INDEX_MAX; i++) { ++ if (ctx->lxc_arch[i] == arch) ++ return i; ++ } ++ ++ return -1; ++} ++#endif ++ + /* + * v2 consists of + * [x86] +@@ -575,6 +639,494 @@ bool do_resolve_add_rule(uint32_t arch, char *line, scmp_filter_ctx ctx, + * write + * close + */ ++#ifdef HAVE_ISULAD ++static int parse_config_v2(FILE *f, char *line, size_t *line_bufsz, struct lxc_conf *conf) ++{ ++ int ret; ++ char *p; ++ enum lxc_hostarch_t cur_rule_arch, native_arch; ++ bool blacklist = false; ++ uint32_t default_policy_action = -1, default_rule_action = -1; ++ struct seccomp_v2_rule rule; ++ struct scmp_ctx_info ctx; ++ ++ if (strncmp(line, "blacklist", 9) == 0) ++ blacklist = true; ++ else if (strncmp(line, "whitelist", 9) != 0) { ++ ERROR("Bad seccomp policy style \"%s\"", line); ++ return -1; ++ } ++ ++ p = strchr(line, ' '); ++ if (p) { ++ default_policy_action = get_v2_default_action(p + 1); ++ if (default_policy_action == -2) ++ return -1; ++ } ++ ++ /* for blacklist, allow any syscall which has no rule */ ++ if (blacklist) { ++ if (default_policy_action == -1) ++ default_policy_action = SCMP_ACT_ALLOW; ++ ++ if (default_rule_action == -1) ++ default_rule_action = SCMP_ACT_KILL; ++ } else { ++ if (default_policy_action == -1) ++ default_policy_action = SCMP_ACT_KILL; ++ ++ if (default_rule_action == -1) ++ default_rule_action = SCMP_ACT_ALLOW; ++ } ++ ++ memset(&ctx, 0, sizeof(ctx)); ++ ctx.architectures[0] = SCMP_ARCH_NATIVE; ++ ctx.architectures[1] = SCMP_ARCH_NATIVE; ++ ctx.architectures[2] = SCMP_ARCH_NATIVE; ++ native_arch = get_hostarch(); ++ cur_rule_arch = native_arch; ++ if (native_arch == lxc_seccomp_arch_amd64) { ++ cur_rule_arch = lxc_seccomp_arch_all; ++ ++ ctx.lxc_arch[0] = lxc_seccomp_arch_i386; ++ ctx.contexts[0] = get_new_ctx(lxc_seccomp_arch_i386, ++ default_policy_action, &ctx.architectures[0]); ++ if (!ctx.contexts[0]) ++ goto bad; ++ ++ ctx.lxc_arch[1] = lxc_seccomp_arch_x32; ++ ctx.contexts[1] = get_new_ctx(lxc_seccomp_arch_x32, ++ default_policy_action, &ctx.architectures[1]); ++ if (!ctx.contexts[1]) ++ goto bad; ++ ++ ctx.lxc_arch[2] = lxc_seccomp_arch_amd64; ++ ctx.contexts[2] = get_new_ctx(lxc_seccomp_arch_amd64, ++ default_policy_action, &ctx.architectures[2]); ++ if (!ctx.contexts[2]) ++ goto bad; ++#ifdef SCMP_ARCH_PPC ++ } else if (native_arch == lxc_seccomp_arch_ppc64) { ++ cur_rule_arch = lxc_seccomp_arch_all; ++ ++ ctx.lxc_arch[0] = lxc_seccomp_arch_ppc; ++ ctx.contexts[0] = get_new_ctx(lxc_seccomp_arch_ppc, ++ default_policy_action, &ctx.architectures[0]); ++ if (!ctx.contexts[0]) ++ goto bad; ++ ++ ctx.lxc_arch[1] = lxc_seccomp_arch_ppc64; ++ ctx.contexts[1] = get_new_ctx(lxc_seccomp_arch_ppc64, ++ default_policy_action, &ctx.architectures[1]); ++ if (!ctx.contexts[1]) ++ goto bad; ++#endif ++#ifdef SCMP_ARCH_ARM ++ } else if (native_arch == lxc_seccomp_arch_arm64) { ++ cur_rule_arch = lxc_seccomp_arch_all; ++ ++ ctx.lxc_arch[0] = lxc_seccomp_arch_arm; ++ ctx.contexts[0] = get_new_ctx(lxc_seccomp_arch_arm, ++ default_policy_action, &ctx.architectures[0]); ++ if (!ctx.contexts[0]) ++ goto bad; ++ ++#ifdef SCMP_ARCH_AARCH64 ++ ctx.lxc_arch[1] = lxc_seccomp_arch_arm64; ++ ctx.contexts[1] = get_new_ctx(lxc_seccomp_arch_arm64, ++ default_policy_action, &ctx.architectures[1]); ++ if (!ctx.contexts[1]) ++ goto bad; ++#endif ++#endif ++#ifdef SCMP_ARCH_MIPS ++ } else if (native_arch == lxc_seccomp_arch_mips64) { ++ cur_rule_arch = lxc_seccomp_arch_all; ++ ++ ctx.lxc_arch[0] = lxc_seccomp_arch_mips; ++ ctx.contexts[0] = get_new_ctx(lxc_seccomp_arch_mips, ++ default_policy_action, &ctx.architectures[0]); ++ if (!ctx.contexts[0]) ++ goto bad; ++ ++ ctx.lxc_arch[1] = lxc_seccomp_arch_mips64n32; ++ ctx.contexts[1] = get_new_ctx(lxc_seccomp_arch_mips64n32, ++ default_policy_action, &ctx.architectures[1]); ++ if (!ctx.contexts[1]) ++ goto bad; ++ ++ ctx.lxc_arch[2] = lxc_seccomp_arch_mips64; ++ ctx.contexts[2] = get_new_ctx(lxc_seccomp_arch_mips64, ++ default_policy_action, &ctx.architectures[2]); ++ if (!ctx.contexts[2]) ++ goto bad; ++ } else if (native_arch == lxc_seccomp_arch_mipsel64) { ++ cur_rule_arch = lxc_seccomp_arch_all; ++ ctx.lxc_arch[0] = lxc_seccomp_arch_mipsel; ++ ctx.contexts[0] = get_new_ctx(lxc_seccomp_arch_mipsel, ++ default_policy_action, &ctx.architectures[0]); ++ if (!ctx.contexts[0]) ++ goto bad; ++ ++ ctx.lxc_arch[1] = lxc_seccomp_arch_mipsel64n32; ++ ctx.contexts[1] = get_new_ctx(lxc_seccomp_arch_mipsel64n32, ++ default_policy_action, &ctx.architectures[1]); ++ if (!ctx.contexts[1]) ++ goto bad; ++ ++ ctx.lxc_arch[2] = lxc_seccomp_arch_mipsel64; ++ ctx.contexts[2] = get_new_ctx(lxc_seccomp_arch_mipsel64, ++ default_policy_action, &ctx.architectures[2]); ++ if (!ctx.contexts[2]) ++ goto bad; ++#endif ++ } ++ ++ if (default_policy_action != SCMP_ACT_KILL) { ++ ret = seccomp_reset(conf->seccomp.seccomp_ctx, default_policy_action); ++ if (ret != 0) { ++ ERROR("Error re-initializing Seccomp"); ++ return -1; ++ } ++ ++ ret = seccomp_attr_set(conf->seccomp.seccomp_ctx, SCMP_FLTATR_CTL_NNP, 0); ++ if (ret < 0) { ++ errno = -ret; ++ SYSERROR("Failed to turn off no-new-privs"); ++ return -1; ++ } ++ ++#ifdef SCMP_FLTATR_ATL_TSKIP ++ ret = seccomp_attr_set(conf->seccomp.seccomp_ctx, SCMP_FLTATR_ATL_TSKIP, 1); ++ if (ret < 0) { ++ errno = -ret; ++ SYSWARN("Failed to turn on seccomp nop-skip, continuing"); ++ } ++#endif ++ } ++ ++ while (getline(&line, line_bufsz, f) != -1) { ++ if (line[0] == '#') ++ continue; ++ ++ if (line[0] == '\0') ++ continue; ++ ++ remove_trailing_newlines(line); ++ ++ DEBUG("Processing \"%s\"", line); ++ ++ if (line[0] == '[') { ++ /* Read the architecture for next set of rules. */ ++ if (strcmp(line, "[x86]") == 0 || ++ strcmp(line, "[X86]") == 0) { ++ if (native_arch != lxc_seccomp_arch_i386 && ++ native_arch != lxc_seccomp_arch_amd64) { ++ cur_rule_arch = lxc_seccomp_arch_unknown; ++ continue; ++ } ++ ++ cur_rule_arch = lxc_seccomp_arch_i386; ++ } else if (strcmp(line, "[x32]") == 0 || ++ strcmp(line, "[X32]") == 0) { ++ if (native_arch != lxc_seccomp_arch_amd64) { ++ cur_rule_arch = lxc_seccomp_arch_unknown; ++ continue; ++ } ++ ++ cur_rule_arch = lxc_seccomp_arch_x32; ++ } else if (strcmp(line, "[X86_64]") == 0 || ++ strcmp(line, "[x86_64]") == 0) { ++ if (native_arch != lxc_seccomp_arch_amd64) { ++ cur_rule_arch = lxc_seccomp_arch_unknown; ++ continue; ++ } ++ ++ cur_rule_arch = lxc_seccomp_arch_amd64; ++ } else if (strcmp(line, "[all]") == 0 || ++ strcmp(line, "[ALL]") == 0) { ++ cur_rule_arch = lxc_seccomp_arch_all; ++ } ++#ifdef SCMP_ARCH_ARM ++ else if (strcmp(line, "[arm]") == 0 || ++ strcmp(line, "[ARM]") == 0) { ++ if (native_arch != lxc_seccomp_arch_arm && ++ native_arch != lxc_seccomp_arch_arm64) { ++ cur_rule_arch = lxc_seccomp_arch_unknown; ++ continue; ++ } ++ ++ cur_rule_arch = lxc_seccomp_arch_arm; ++ } ++#endif ++#ifdef SCMP_ARCH_AARCH64 ++ else if (strcmp(line, "[arm64]") == 0 || ++ strcmp(line, "[ARM64]") == 0) { ++ if (native_arch != lxc_seccomp_arch_arm64) { ++ cur_rule_arch = lxc_seccomp_arch_unknown; ++ continue; ++ } ++ ++ cur_rule_arch = lxc_seccomp_arch_arm64; ++ } ++#endif ++#ifdef SCMP_ARCH_PPC64LE ++ else if (strcmp(line, "[ppc64le]") == 0 || ++ strcmp(line, "[PPC64LE]") == 0) { ++ if (native_arch != lxc_seccomp_arch_ppc64le) { ++ cur_rule_arch = lxc_seccomp_arch_unknown; ++ continue; ++ } ++ ++ cur_rule_arch = lxc_seccomp_arch_ppc64le; ++ } ++#endif ++#ifdef SCMP_ARCH_PPC64 ++ else if (strcmp(line, "[ppc64]") == 0 || ++ strcmp(line, "[PPC64]") == 0) { ++ if (native_arch != lxc_seccomp_arch_ppc64) { ++ cur_rule_arch = lxc_seccomp_arch_unknown; ++ continue; ++ } ++ ++ cur_rule_arch = lxc_seccomp_arch_ppc64; ++ } ++#endif ++#ifdef SCMP_ARCH_PPC ++ else if (strcmp(line, "[ppc]") == 0 || ++ strcmp(line, "[PPC]") == 0) { ++ if (native_arch != lxc_seccomp_arch_ppc && ++ native_arch != lxc_seccomp_arch_ppc64) { ++ cur_rule_arch = lxc_seccomp_arch_unknown; ++ continue; ++ } ++ ++ cur_rule_arch = lxc_seccomp_arch_ppc; ++ } ++#endif ++#ifdef SCMP_ARCH_MIPS ++ else if (strcmp(line, "[mips64]") == 0 || ++ strcmp(line, "[MIPS64]") == 0) { ++ if (native_arch != lxc_seccomp_arch_mips64) { ++ cur_rule_arch = lxc_seccomp_arch_unknown; ++ continue; ++ } ++ ++ cur_rule_arch = lxc_seccomp_arch_mips64; ++ } else if (strcmp(line, "[mips64n32]") == 0 || ++ strcmp(line, "[MIPS64N32]") == 0) { ++ if (native_arch != lxc_seccomp_arch_mips64) { ++ cur_rule_arch = lxc_seccomp_arch_unknown; ++ continue; ++ } ++ ++ cur_rule_arch = lxc_seccomp_arch_mips64n32; ++ } else if (strcmp(line, "[mips]") == 0 || ++ strcmp(line, "[MIPS]") == 0) { ++ if (native_arch != lxc_seccomp_arch_mips && ++ native_arch != lxc_seccomp_arch_mips64) { ++ cur_rule_arch = lxc_seccomp_arch_unknown; ++ continue; ++ } ++ ++ cur_rule_arch = lxc_seccomp_arch_mips; ++ } else if (strcmp(line, "[mipsel64]") == 0 || ++ strcmp(line, "[MIPSEL64]") == 0) { ++ if (native_arch != lxc_seccomp_arch_mipsel64) { ++ cur_rule_arch = lxc_seccomp_arch_unknown; ++ continue; ++ } ++ ++ cur_rule_arch = lxc_seccomp_arch_mipsel64; ++ } else if (strcmp(line, "[mipsel64n32]") == 0 || ++ strcmp(line, "[MIPSEL64N32]") == 0) { ++ if (native_arch != lxc_seccomp_arch_mipsel64) { ++ cur_rule_arch = lxc_seccomp_arch_unknown; ++ continue; ++ } ++ ++ cur_rule_arch = lxc_seccomp_arch_mipsel64n32; ++ } else if (strcmp(line, "[mipsel]") == 0 || ++ strcmp(line, "[MIPSEL]") == 0) { ++ if (native_arch != lxc_seccomp_arch_mipsel && ++ native_arch != lxc_seccomp_arch_mipsel64) { ++ cur_rule_arch = lxc_seccomp_arch_unknown; ++ continue; ++ } ++ ++ cur_rule_arch = lxc_seccomp_arch_mipsel; ++ } ++#endif ++#ifdef SCMP_ARCH_S390X ++ else if (strcmp(line, "[s390x]") == 0 || ++ strcmp(line, "[S390X]") == 0) { ++ if (native_arch != lxc_seccomp_arch_s390x) { ++ cur_rule_arch = lxc_seccomp_arch_unknown; ++ continue; ++ } ++ ++ cur_rule_arch = lxc_seccomp_arch_s390x; ++ } ++#endif ++ else { ++ goto bad_arch; ++ } ++ ++ continue; ++ } ++ ++ /* irrelevant arch - i.e. arm on i386 */ ++ if (cur_rule_arch == lxc_seccomp_arch_unknown) ++ continue; ++ ++ memset(&rule, 0, sizeof(rule)); ++ /* read optional action which follows the syscall */ ++ ret = parse_v2_rules(line, default_rule_action, &rule); ++ if (ret != 0) { ++ ERROR("Failed to interpret seccomp rule"); ++ goto bad_rule; ++ } ++ ++ if (cur_rule_arch == native_arch) { ++ /* add for native arch */ ++ if (!do_resolve_add_rule(SCMP_ARCH_NATIVE, line, ++ conf->seccomp.seccomp_ctx, &rule)) ++ goto bad_rule; ++ ++ DEBUG("Added native rule for arch %d for %s action %d(%s)", ++ SCMP_ARCH_NATIVE, line, rule.action, ++ get_action_name(rule.action)); ++ } else if (cur_rule_arch != lxc_seccomp_arch_all) { ++ /* add for compat specified arch */ ++ int arch_index = get_arch_index(cur_rule_arch, &ctx); ++ if (arch_index < 0) ++ goto bad_arch; ++ ++ if (!do_resolve_add_rule(ctx.architectures[arch_index], line, ++ ctx.contexts[arch_index], &rule)) ++ goto bad_rule; ++ ++ DEBUG("Added compat rule for arch %d for %s action %d(%s)", ++ ctx.architectures[arch_index], line, rule.action, ++ get_action_name(rule.action)); ++ ctx.needs_merge[arch_index] = true; ++ } else { ++ /* add for all compat archs */ ++ if (!do_resolve_add_rule(SCMP_ARCH_NATIVE, line, ++ conf->seccomp.seccomp_ctx, &rule)) ++ goto bad_rule; ++ ++ DEBUG("Added native rule for arch %d for %s action %d(%s)", ++ SCMP_ARCH_NATIVE, line, rule.action, ++ get_action_name(rule.action)); ++ ++ if (ctx.architectures[0] != SCMP_ARCH_NATIVE) { ++ if (!do_resolve_add_rule(ctx.architectures[0], line, ++ ctx.contexts[0], &rule)) ++ goto bad_rule; ++ ++ DEBUG("Added compat rule for arch %d for %s action %d(%s)", ++ ctx.architectures[0], line, rule.action, ++ get_action_name(rule.action)); ++ ctx.needs_merge[0] = true; ++ } ++ ++ if (ctx.architectures[1] != SCMP_ARCH_NATIVE) { ++ if (!do_resolve_add_rule(ctx.architectures[1], line, ++ ctx.contexts[1], &rule)) ++ goto bad_rule; ++ ++ DEBUG("Added compat rule for arch %d for %s action %d(%s)", ++ ctx.architectures[1], line, rule.action, ++ get_action_name(rule.action)); ++ ctx.needs_merge[1] = true; ++ } ++ ++ if (ctx.architectures[2] != SCMP_ARCH_NATIVE) { ++ if (!do_resolve_add_rule(ctx.architectures[2], line, ++ ctx.contexts[2], &rule)) ++ goto bad_rule; ++ ++ DEBUG("Added native rule for arch %d for %s action %d(%s)", ++ ctx.architectures[2], line, rule.action, ++ get_action_name(rule.action)); ++ ctx.needs_merge[2] = true; ++ } ++ } ++ ++ } ++ ++ INFO("Merging compat seccomp contexts into main context"); ++ if (ctx.contexts[0]) { ++ if (ctx.needs_merge[0]) { ++ ret = seccomp_merge(conf->seccomp.seccomp_ctx, ctx.contexts[0]); ++ if (ret < 0) { ++ ERROR("%s - Failed to merge first compat seccomp " ++ "context into main context", strerror(-ret)); ++ goto bad; ++ } ++ ++ TRACE("Merged first compat seccomp context into main context"); ++ } else { ++ seccomp_release(ctx.contexts[0]); ++ ctx.contexts[0] = NULL; ++ } ++ } ++ ++ if (ctx.contexts[1]) { ++ if (ctx.needs_merge[1]) { ++ ret = seccomp_merge(conf->seccomp.seccomp_ctx, ctx.contexts[1]); ++ if (ret < 0) { ++ ERROR("%s - Failed to merge second compat seccomp " ++ "context into main context", strerror(-ret)); ++ goto bad; ++ } ++ ++ TRACE("Merged second compat seccomp context into main context"); ++ } else { ++ seccomp_release(ctx.contexts[1]); ++ ctx.contexts[1] = NULL; ++ } ++ } ++ ++ if (ctx.contexts[2]) { ++ if (ctx.needs_merge[2]) { ++ ret = seccomp_merge(conf->seccomp.seccomp_ctx, ctx.contexts[2]); ++ if (ret < 0) { ++ ERROR("%s - Failed to merge third compat seccomp " ++ "context into main context", strerror(-ret)); ++ goto bad; ++ } ++ ++ TRACE("Merged third compat seccomp context into main context"); ++ } else { ++ seccomp_release(ctx.contexts[2]); ++ ctx.contexts[2] = NULL; ++ } ++ } ++ ++ free(line); ++ return 0; ++ ++bad_arch: ++ ERROR("Unsupported architecture \"%s\"", line); ++ ++bad_rule: ++bad: ++ if (ctx.contexts[0]) ++ seccomp_release(ctx.contexts[0]); ++ ++ if (ctx.contexts[1]) ++ seccomp_release(ctx.contexts[1]); ++ ++ if (ctx.contexts[2]) ++ seccomp_release(ctx.contexts[2]); ++ ++ free(line); ++ ++ return -1; ++} ++#else + static int parse_config_v2(FILE *f, char *line, size_t *line_bufsz, struct lxc_conf *conf) + { + int ret; +@@ -1067,6 +1619,7 @@ bad: + + return -1; + } ++#endif + #else /* HAVE_DECL_SECCOMP_SYSCALL_RESOLVE_NAME_ARCH */ + static int parse_config_v2(FILE *f, char *line, struct lxc_conf *conf) + { +@@ -1288,6 +1841,7 @@ void lxc_seccomp_free(struct lxc_seccomp *seccomp) + seccomp_notify_free(seccomp->notifier.req_buf, seccomp->notifier.rsp_buf); + seccomp->notifier.req_buf = NULL; + seccomp->notifier.rsp_buf = NULL; ++ free_disarm(seccomp->notifier.cookie); + #endif + } + +@@ -1498,6 +2052,7 @@ void seccomp_conf_init(struct lxc_conf *conf) + sizeof(conf->seccomp.notifier.proxy_addr)); + conf->seccomp.notifier.req_buf = NULL; + conf->seccomp.notifier.rsp_buf = NULL; ++ conf->seccomp.notifier.cookie = NULL; + #endif + } + +diff --git a/src/lxc/storage/zfs.c b/src/lxc/storage/zfs.c +index ee9e32d..903937a 100644 +--- a/src/lxc/storage/zfs.c ++++ b/src/lxc/storage/zfs.c +@@ -167,13 +167,22 @@ int zfs_mount(struct lxc_storage *bdev) + const char *src; + char cmd_output[PATH_MAX] = {0}; + ++#ifdef HAVE_ISULAD ++ unsigned long pflags = 0; ++#endif ++ + if (strcmp(bdev->type, "zfs")) + return -22; + + if (!bdev->src || !bdev->dest) + return -22; + ++#ifdef HAVE_ISULAD ++ ret = parse_mntopts(bdev->mntopts, &mntflags, &pflags, &mntdata); ++#else + ret = parse_mntopts(bdev->mntopts, &mntflags, &mntdata); ++#endif ++ + if (ret < 0) { + ERROR("Failed to parse mount options"); + return -22; +-- +2.25.1 + diff --git a/0006-fix-run-container-failed-by-isulad.patch b/0006-fix-run-container-failed-by-isulad.patch new file mode 100644 index 0000000000000000000000000000000000000000..28dc76445cb203bb2df1ebb79486978b73a86b88 --- /dev/null +++ b/0006-fix-run-container-failed-by-isulad.patch @@ -0,0 +1,86 @@ +From e7fc0b635c8f964bd139aae47d9debb77c39cc3f Mon Sep 17 00:00:00 2001 +From: zhangxiaoyu +Date: Tue, 1 Aug 2023 14:59:16 +0800 +Subject: [PATCH] fix run container failed by isulad + +Signed-off-by: zhangxiaoyu +--- + src/lxc/confile.c | 34 ++++++++++++++++++++++------------ + 1 file changed, 22 insertions(+), 12 deletions(-) + +diff --git a/src/lxc/confile.c b/src/lxc/confile.c +index 0d0d66c..ae1a264 100644 +--- a/src/lxc/confile.c ++++ b/src/lxc/confile.c +@@ -287,16 +287,18 @@ static struct lxc_config_t config_jump_table[] = { + { "lxc.sysctl", false, set_config_sysctl, get_config_sysctl, clr_config_sysctl, }, + { "lxc.proc", false, set_config_proc, get_config_proc, clr_config_proc, }, + #ifdef HAVE_ISULAD +- { "lxc.isulad.init.args", true, set_config_init_args, get_config_init_args, clr_config_init_args, }, +- { "lxc.isulad.populate.device", true, set_config_populate_device, get_config_populate_device, clr_config_populate_device, }, +- { "lxc.isulad.umask", true, set_config_umask, get_config_umask, clr_config_umask, }, +- { "lxc.isulad.rootfs.maskedpaths", true, set_config_rootfs_masked_paths, get_config_rootfs_masked_paths, clr_config_rootfs_masked_paths, }, +- { "lxc.isulad.rootfs.ropaths", true, set_config_rootfs_ro_paths, get_config_rootfs_ro_paths, clr_config_rootfs_ro_paths, }, +- { "lxc.isulad.systemd", true, set_config_systemd, get_config_systemd, clr_config_systemd, }, +- { "lxc.console.logdriver", true, set_config_console_log_driver, get_config_console_log_driver, clr_config_console_log_driver, }, +- { "lxc.console.syslog_tag", true, set_config_console_syslog_tag, get_config_console_syslog_tag, clr_config_console_syslog_tag, }, +- { "lxc.console.syslog_facility", true, set_config_console_syslog_facility, get_config_console_syslog_facility, clr_config_console_syslog_facility, }, +- { "lxc.selinux.mount_context", true, set_config_selinux_mount_context, get_config_selinux_mount_context, clr_config_selinux_mount_context, }, ++ { "lxc.isulad.init.args", true, set_config_init_args, get_config_init_args, clr_config_init_args, }, ++ { "lxc.isulad.populate.device", true, set_config_populate_device, get_config_populate_device, clr_config_populate_device, }, ++ { "lxc.isulad.umask", true, set_config_umask, get_config_umask, clr_config_umask, }, ++ { "lxc.isulad.rootfs.maskedpaths", true, set_config_rootfs_masked_paths, get_config_rootfs_masked_paths, clr_config_rootfs_masked_paths, }, ++ { "lxc.isulad.rootfs.ropaths", true, set_config_rootfs_ro_paths, get_config_rootfs_ro_paths, clr_config_rootfs_ro_paths, }, ++ { "lxc.isulad.systemd", true, set_config_systemd, get_config_systemd, clr_config_systemd, }, ++ { "lxc.console.logdriver", true, set_config_console_log_driver, get_config_console_log_driver, clr_config_console_log_driver, }, ++ { "lxc.console.syslog_tag", true, set_config_console_syslog_tag, get_config_console_syslog_tag, clr_config_console_syslog_tag, }, ++ { "lxc.console.syslog_facility", true, set_config_console_syslog_facility, get_config_console_syslog_facility, clr_config_console_syslog_facility, }, ++ { "lxc.selinux.mount_context", true, set_config_selinux_mount_context, get_config_selinux_mount_context, clr_config_selinux_mount_context, }, ++ // same to lxc.init.groups ++ { "lxc.isulad.init.groups", true, set_config_init_groups, get_config_init_groups, clr_config_init_groups, }, + #endif + }; + +@@ -1343,7 +1345,11 @@ static int set_config_init_groups(const char *key, const char *value, + if (!value_dup) + return -ENOMEM; + ++#ifdef HAVE_ISULAD ++ lxc_iterate_parts(token, value_dup, " \t") ++#else + lxc_iterate_parts(token, value_dup, ",") ++#endif + num_groups++; + + if (num_groups == INT_MAX) +@@ -1368,7 +1374,11 @@ static int set_config_init_groups(const char *key, const char *value, + /* Restore duplicated value so we can call lxc_iterate_parts() again. */ + strcpy(value_dup, value); + ++#ifdef HAVE_ISULAD ++ lxc_iterate_parts(token, value_dup, " \t") { ++#else + lxc_iterate_parts(token, value_dup, ",") { ++#endif + int ret; + + gid_t group; +@@ -2000,13 +2010,13 @@ static int set_config_cgroup_dir(const char *key, const char *value, + + if (lxc_config_value_empty(value)) + return clr_config_cgroup_dir(key, lxc_conf, NULL); +- ++#ifndef HAVE_ISULAD + if (abspath(value)) + return syserror_set(-EINVAL, "%s paths may not be absolute", key); + + if (dotdot(value)) + return syserror_set(-EINVAL, "%s paths may not walk upwards via \"../\"", key); +- ++#endif + return set_config_path_item(&lxc_conf->cgroup_meta.dir, value); + } + +-- +2.25.1 + diff --git a/0006-refactor-patch-about-namespace-log-terminal.patch b/0006-refactor-patch-about-namespace-log-terminal.patch new file mode 100644 index 0000000000000000000000000000000000000000..d3db741e7cdf4b7a5d47734500fb790b268b986f --- /dev/null +++ b/0006-refactor-patch-about-namespace-log-terminal.patch @@ -0,0 +1,1164 @@ +From 2b4dbd3fc30be08459b8ab34f84935e37ceb34ec Mon Sep 17 00:00:00 2001 +From: "Neil.wrz" +Date: Tue, 19 Jul 2022 04:02:57 -0700 +Subject: [PATCH] refactor patch about namespace log terminal + +Signed-off-by: Neil.wrz +--- + configure.ac | 30 ++++++++++- + src/lxc/Makefile.am | 44 ++++++++++++++- + src/lxc/af_unix.c | 89 ++++++++++++++++++++++++++++++ + src/lxc/commands_utils.c | 57 ++++++++++++++++++++ + src/lxc/exec_commands.h | 77 ++++++++++++++++++++++++++ + src/lxc/file_utils.h | 4 ++ + src/lxc/json/read-file.c | 95 +++++++++++++++++++++++++++++++++ + src/lxc/log.c | 56 +++++++++++++++++++ + src/lxc/path.h | 65 ++++++++++++++++++++++ + src/lxc/start.h | 30 +++++++++++ + src/lxc/storage/block.c | 86 +++++++++++++++++++++++++++++ + src/lxc/storage/block.h | 41 ++++++++++++++ + src/lxc/storage/storage_utils.c | 60 +++++++++++++++++++++ + src/lxc/terminal.h | 35 ++++++++++++ + 14 files changed, 766 insertions(+), 3 deletions(-) + create mode 100644 src/lxc/exec_commands.h + create mode 100644 src/lxc/json/read-file.c + create mode 100644 src/lxc/path.h + create mode 100644 src/lxc/storage/block.c + create mode 100644 src/lxc/storage/block.h + +diff --git a/configure.ac b/configure.ac +index 059d57d..ce8854e 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -43,6 +43,7 @@ AM_INIT_AUTOMAKE([-Wall -Werror -Wno-portability subdir-objects]) + AC_CANONICAL_HOST + AM_PROG_CC_C_O + AC_USE_SYSTEM_EXTENSIONS ++CFLAGS=`echo "${CFLAGS#\-g}"` + + # Test if we have a new enough compiler. + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ +@@ -119,6 +120,9 @@ AM_CONDITIONAL([DISTRO_UBUNTU], [test "x$with_distro" = "xubuntu"]) + + AC_CONFIG_LINKS([config/etc/default.conf:config/etc/${distroconf}]) + ++# Check yajl ++PKG_CHECK_MODULES([YAJL], [yajl >= 2],[],[AC_MSG_ERROR([You must install yajl >= 2])]) ++ + # Check for init system type + AC_MSG_CHECKING([for init system type]) + AC_ARG_WITH([init-script], +@@ -187,6 +191,11 @@ AC_ARG_ENABLE([werror], + [AS_HELP_STRING([--disable-werror], [do not treat warnings as errors])], + [enable_werror=$enableval], [enable_werror=yes]) + ++AC_ARG_ENABLE([debug], ++ [AC_HELP_STRING([--enable-debug], ++ [set -g into cflags [default=no]])], ++ [], [enable_debug=no]) ++ + # Allow disabling rpath + AC_ARG_ENABLE([rpath], + [AS_HELP_STRING([--enable-rpath], [set rpath in executables [default=no]])], +@@ -756,6 +765,7 @@ AX_CHECK_COMPILE_FLAG([-Wnested-externs], [CFLAGS="$CFLAGS -Wnested-externs"],,[ + AX_CHECK_COMPILE_FLAG([-fasynchronous-unwind-tables], [CFLAGS="$CFLAGS -fasynchronous-unwind-tables"],,[-Werror]) + AX_CHECK_COMPILE_FLAG([-pipe], [CFLAGS="$CFLAGS -pipe"],,[-Werror]) + AX_CHECK_COMPILE_FLAG([-fexceptions], [CFLAGS="$CFLAGS -fexceptions"],,[-Werror]) ++AX_CHECK_COMPILE_FLAG([-g], [CFLAGS="$CFLAGS -g"],,[-Werror]) + AX_CHECK_COMPILE_FLAG([-Warray-bounds], [CFLAGS="$CFLAGS -Warray-bounds"],,[-Werror]) + AX_CHECK_COMPILE_FLAG([-Wrestrict], [CFLAGS="$CFLAGS -Wrestrict"],,[-Werror]) + AX_CHECK_COMPILE_FLAG([-Wreturn-local-addr], [CFLAGS="$CFLAGS -Wreturn-local-addr"],,[-Werror]) +@@ -763,12 +773,18 @@ AX_CHECK_COMPILE_FLAG([-Wstringop-overflow], [CFLAGS="$CFLAGS -Wstringop-overflo + + AX_CHECK_LINK_FLAG([-z relro], [LDFLAGS="$LDFLAGS -z relro"],,[]) + AX_CHECK_LINK_FLAG([-z now], [LDFLAGS="$LDFLAGS -z now"],,[]) ++AX_CHECK_LINK_FLAG([-z noexecstack], [LDFLAGS="$LDFLAGS -z noexecstack"],,[]) + +-CFLAGS="$CFLAGS -Wvla -std=gnu11 -fms-extensions" ++CFLAGS="$CFLAGS -Wvla -std=gnu11 -D_FORTIFY_SOURCE=2 -Wall -fPIC -fPIE" ++LDFLAGS="$LDFLAGS -pie" + if test "x$enable_werror" = "xyes"; then + CFLAGS="$CFLAGS -Werror" + fi + ++if test "x$enable_debug" = "xyes"; then ++ CFLAGS="$CFLAGS -g" ++fi ++ + AC_ARG_ENABLE([thread-safety], + [AS_HELP_STRING([--enable-thread-safety], [enforce thread-safety otherwise fail the build [default=yes]])], + [enable_thread_safety=$enableval], [enable_thread_safety=yes]) +@@ -815,6 +831,18 @@ else + AC_MSG_RESULT([no]) + fi + ++AC_MSG_CHECKING([Whether adapt to iSulad]) ++AC_ARG_ENABLE([isulad], ++ [AC_HELP_STRING([--enable-isulad], [enable adapt to iSulad [default=yes]])], ++ [adapt_isulad=$enableval], [adapt_isulad=yes]) ++AM_CONDITIONAL([HAVE_ISULAD], [test "x$adapt_isulad" = "xyes"]) ++if test "x$adapt_isulad" = "xyes"; then ++ AC_DEFINE([HAVE_ISULAD], 1, [adapt to iSulad]) ++ AC_MSG_RESULT([yes]) ++else ++ AC_MSG_RESULT([no]) ++fi ++ + # Files requiring some variable expansion + AC_CONFIG_FILES([ + Makefile +diff --git a/src/lxc/Makefile.am b/src/lxc/Makefile.am +index d1e2364..b9a8750 100644 +--- a/src/lxc/Makefile.am ++++ b/src/lxc/Makefile.am +@@ -52,6 +52,16 @@ noinst_HEADERS = api_extensions.h \ + utils.h \ + uuid.h + ++if HAVE_ISULAD ++noinst_HEADERS += isulad_utils.h path.h \ ++ json/json_common.h json/defs.h \ ++ json/oci_runtime_hooks.h \ ++ json/logger_json_file.h \ ++ json/oci_runtime_spec.h \ ++ json/read-file.h \ ++ exec_commands.h ++endif ++ + if IS_BIONIC + noinst_HEADERS += ../include/fexecve.h \ + ../include/lxcmntent.h \ +@@ -97,7 +107,6 @@ liblxc_la_SOURCES = af_unix.c af_unix.h \ + api_extensions.h \ + attach.c attach.h \ + caps.c caps.h \ +- cgroups/cgfsng.c \ + cgroups/cgroup.c cgroups/cgroup.h \ + cgroups/cgroup2_devices.c cgroups/cgroup2_devices.h \ + cgroups/cgroup_utils.c cgroups/cgroup_utils.h \ +@@ -154,6 +163,22 @@ liblxc_la_SOURCES = af_unix.c af_unix.h \ + version.h \ + $(LSM_SOURCES) + ++if HAVE_ISULAD ++liblxc_la_SOURCES += isulad_utils.c isulad_utils.h \ ++ storage/block.c storage/block.h \ ++ path.c path.h \ ++ json/json_common.c json/json_common.h \ ++ json/defs.h json/defs.c \ ++ json/oci_runtime_hooks.c json/oci_runtime_hooks.h \ ++ json/logger_json_file.c json/logger_json_file.h \ ++ json/oci_runtime_spec.c json/oci_runtime_spec.h \ ++ json/read-file.c json/read-file.h \ ++ cgroups/isulad_cgfsng.c \ ++ exec_commands.c exec_commands.h ++else ++liblxc_la_SOURCES += cgroups/cgfsng.c ++endif ++ + if IS_BIONIC + liblxc_la_SOURCES += ../include/fexecve.c ../include/fexecve.h \ + ../include/lxcmntent.c ../include/lxcmntent.h \ +@@ -212,6 +237,10 @@ AM_CFLAGS = -DLXCROOTFSMOUNT=\"$(LXCROOTFSMOUNT)\" \ + -I $(top_srcdir)/src/lxc/storage \ + -I $(top_srcdir)/src/lxc/cgroups + ++if HAVE_ISULAD ++AM_CFLAGS += -I $(top_srcdir)/src/lxc/json ++AM_CFLAGS += -DHAVE_ISULAD ++endif + if ENABLE_APPARMOR + AM_CFLAGS += -DHAVE_APPARMOR + endif +@@ -249,6 +278,10 @@ liblxc_la_CFLAGS += -fsanitize=address \ + -fno-omit-frame-pointer + endif + ++if HAVE_ISULAD ++liblxc_la_CFLAGS += -D_FORTIFY_SOURCE=2 -Wall ++endif ++ + if ENABLE_UBSAN + liblxc_la_CFLAGS += -fsanitize=undefined + endif +@@ -258,6 +291,12 @@ liblxc_la_LDFLAGS = -pthread \ + -Wl,-soname,liblxc.so.$(firstword $(subst ., ,@LXC_ABI@)) \ + -version-info @LXC_ABI_MAJOR@ + ++if HAVE_ISULAD ++liblxc_la_LDFLAGS += @YAJL_LIBS@ -Wl,-z,relro \ ++ -Wl,-z,now \ ++ -Wl,-z,noexecstack ++endif ++ + liblxc_la_LIBADD = $(CAP_LIBS) \ + $(OPENSSL_LIBS) \ + $(SELINUX_LIBS) \ +@@ -321,7 +360,8 @@ LDADD = liblxc.la \ + @OPENSSL_LIBS@ \ + @SECCOMP_LIBS@ \ + @SELINUX_LIBS@ \ +- @DLOG_LIBS@ ++ @DLOG_LIBS@ \ ++ @YAJL_LIBS@ + + if ENABLE_TOOLS + lxc_attach_SOURCES = tools/lxc_attach.c \ +diff --git a/src/lxc/af_unix.c b/src/lxc/af_unix.c +index 5cf5491..cb4233e 100644 +--- a/src/lxc/af_unix.c ++++ b/src/lxc/af_unix.c +@@ -167,8 +167,13 @@ int lxc_unix_send_fds(int fd, int *sendfds, int num_sendfds, void *data, + return lxc_abstract_unix_send_fds(fd, sendfds, num_sendfds, data, size); + } + ++#ifdef HAVE_ISULAD ++static int lxc_abstract_unix_recv_fds_iov(int fd, int *recvfds, int num_recvfds, ++ struct iovec *iov, size_t iovlen, unsigned int timeout) ++#else + static int lxc_abstract_unix_recv_fds_iov(int fd, int *recvfds, int num_recvfds, + struct iovec *iov, size_t iovlen) ++#endif + { + __do_free char *cmsgbuf = NULL; + int ret; +@@ -188,6 +193,22 @@ static int lxc_abstract_unix_recv_fds_iov(int fd, int *recvfds, int num_recvfds, + msg.msg_iov = iov; + msg.msg_iovlen = iovlen; + ++#ifdef HAVE_ISULAD ++ struct timeval out; ++ if (timeout > 0) { ++ memset(&out, 0, sizeof(out)); ++ out.tv_sec = timeout / 1000000; ++ out.tv_usec = timeout % 1000000; ++ ret = setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, ++ (const void *)&out, sizeof(out)); ++ if (ret < 0) { ++ ERROR("Failed to set %u timeout on containter " ++ "state socket", timeout); ++ return ret; ++ } ++ } ++#endif ++ + do { + ret = recvmsg(fd, &msg, MSG_CMSG_CLOEXEC); + } while (ret < 0 && errno == EINTR); +@@ -220,8 +241,25 @@ int lxc_abstract_unix_recv_fds(int fd, int *recvfds, int num_recvfds, + .iov_base = data ? data : buf, + .iov_len = data ? size : sizeof(buf), + }; ++#ifdef HAVE_ISULAD ++ return lxc_abstract_unix_recv_fds_iov(fd, recvfds, num_recvfds, &iov, 1, 0); ++#else + return lxc_abstract_unix_recv_fds_iov(fd, recvfds, num_recvfds, &iov, 1); ++#endif ++} ++ ++#ifdef HAVE_ISULAD ++int lxc_abstract_unix_recv_fds_timeout(int fd, int *recvfds, int num_recvfds, ++ void *data, size_t size, unsigned int timeout) ++{ ++ char buf[1] = {0}; ++ struct iovec iov = { ++ .iov_base = data ? data : buf, ++ .iov_len = data ? size : sizeof(buf), ++ }; ++ return lxc_abstract_unix_recv_fds_iov(fd, recvfds, num_recvfds, &iov, 1, timeout); + } ++#endif + + int lxc_abstract_unix_send_credential(int fd, void *data, size_t size) + { +@@ -343,12 +381,63 @@ int lxc_unix_connect_type(struct sockaddr_un *addr, int type) + ret = connect(fd, (struct sockaddr *)addr, + offsetof(struct sockaddr_un, sun_path) + len); + if (ret < 0) ++#ifdef HAVE_ISULAD ++ return log_error_errno(-1, errno, ++ "Failed to connect new AF_UNIX socket"); ++#else + return log_error_errno(-1, errno, + "Failed to bind new AF_UNIX socket"); ++#endif + + return move_fd(fd); + } + ++#ifdef HAVE_ISULAD ++int lxc_named_unix_open(const char *path, int type, int flags) ++{ ++ __do_close int fd = -EBADF; ++ int ret; ++ ssize_t len; ++ struct sockaddr_un addr; ++ ++ fd = socket(PF_UNIX, type | SOCK_CLOEXEC, 0); ++ if (fd < 0) ++ return -1; ++ ++ if (!path) ++ return move_fd(fd); ++ ++ len = lxc_unix_sockaddr(&addr, path); ++ if (len < 0) ++ return -1; ++ ++ ret = bind(fd, (struct sockaddr *)&addr, len); ++ if (ret < 0) ++ return -1; ++ ++ if (chmod(path, 0600) < 0) ++ return -1; ++ ++ if (type == SOCK_STREAM) { ++ ret = listen(fd, 100); ++ if (ret < 0) ++ return -1; ++ } ++ ++ return move_fd(fd); ++} ++ ++int lxc_named_unix_connect(const char *path) ++{ ++ struct sockaddr_un addr; ++ ++ if (lxc_unix_sockaddr(&addr, path) < 0) ++ return -1; ++ ++ return lxc_unix_connect_type(&addr, SOCK_STREAM); ++} ++#endif ++ + int lxc_unix_connect(struct sockaddr_un *addr, int type) + { + return lxc_unix_connect_type(addr, SOCK_STREAM); +diff --git a/src/lxc/commands_utils.c b/src/lxc/commands_utils.c +index 2af722c..9de9a84 100644 +--- a/src/lxc/commands_utils.c ++++ b/src/lxc/commands_utils.c +@@ -140,12 +140,69 @@ int lxc_make_abstract_socket_name(char *path, size_t pathlen, + return 0; + } + ++#ifdef HAVE_ISULAD ++char *generate_named_unix_sock_dir(const char *name) ++{ ++ __do_free char *exec_sock_dir = NULL; ++ __do_free char *rundir = NULL; ++ ++ rundir = get_rundir(); ++ if (!rundir) ++ rundir = strdup("/var/run"); ++ ++ if (asprintf(&exec_sock_dir, "%s/lxc/%s", rundir, name) < 0) { ++ return log_error_errno(NULL, errno, "Failed to allocate memory"); ++ } ++ ++ return move_ptr(exec_sock_dir); ++} ++ ++int generate_named_unix_sock_path(const char *container_name, const char *sock_name, ++ char *out_path, size_t len) ++{ ++#define MAX_SOCK_NAME_LENGTH 12 ++ int ret; ++ __do_free char *sock_dir = NULL; ++ __do_free char *short_sock_name = NULL; ++ ++ if (container_name == NULL || sock_name == NULL) ++ return -1; ++ ++ sock_dir = generate_named_unix_sock_dir(container_name); ++ if (sock_dir == NULL) ++ return -1; ++ ++ short_sock_name = strdup(sock_name); ++ if (strlen(short_sock_name) > MAX_SOCK_NAME_LENGTH) ++ short_sock_name[MAX_SOCK_NAME_LENGTH] = '\0'; ++ ++ ret = snprintf(out_path, len, "%s/%s.sock", sock_dir, short_sock_name); ++ if (ret < 0 || (size_t)ret >= len) ++ return log_error_errno(-1, errno, "Failed to allocate memory"); ++ ++ return 0; ++} ++#endif ++ + int lxc_cmd_connect(const char *name, const char *lxcpath, + const char *hashed_sock_name, const char *suffix) + { + int ret, client_fd; + char path[LXC_AUDS_ADDR_LEN] = {0}; + ++#ifdef HAVE_ISULAD ++ if (generate_named_unix_sock_path(name, suffix, path, sizeof(path)) != 0) ++ return -1; ++ ++ if (file_exists(path)) { ++ client_fd = lxc_named_unix_connect(path); ++ if (client_fd < 0) ++ return -1; ++ ++ return client_fd; ++ } ++#endif ++ + ret = lxc_make_abstract_socket_name(path, sizeof(path), name, lxcpath, + hashed_sock_name, suffix); + if (ret < 0) +diff --git a/src/lxc/exec_commands.h b/src/lxc/exec_commands.h +new file mode 100644 +index 0000000..3ec2a22 +--- /dev/null ++++ b/src/lxc/exec_commands.h +@@ -0,0 +1,77 @@ ++/****************************************************************************** ++ * Copyright (c) Huawei Technologies Co., Ltd. 2019. All rights reserved. ++ * Author: lifeng ++ * Create: 2019-12-08 ++ * Description: provide container definition ++ * lxc: linux Container library ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2.1 of the License, or (at your option) any later version. ++ * ++ * This library is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with this library; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ++ ******************************************************************************/ ++ ++#ifndef __LXC_EXEC_COMMANDS_H ++#define __LXC_EXEC_COMMANDS_H ++ ++#include ++#include ++#include ++ ++#include "lxccontainer.h" ++#include "macro.h" ++#include "state.h" ++#include "terminal.h" ++ ++struct lxc_exec_command_handler { ++ int maincmd_fd; ++ struct lxc_terminal *terminal; ++}; ++ ++typedef enum { ++ LXC_EXEC_CMD_SET_TERMINAL_WINCH, ++ LXC_EXEC_CMD_MAX, ++} lxc_exec_cmd_t; ++ ++struct lxc_exec_cmd_req { ++ lxc_exec_cmd_t cmd; ++ int datalen; ++ const void *data; ++}; ++ ++struct lxc_exec_cmd_rsp { ++ int ret; /* 0 on success, -errno on failure */ ++ int datalen; ++ void *data; ++}; ++ ++struct lxc_exec_cmd_rr { ++ struct lxc_exec_cmd_req req; ++ struct lxc_exec_cmd_rsp rsp; ++}; ++ ++struct lxc_exec_cmd_set_terminal_winch_request { ++ unsigned int height; ++ unsigned int width; ++}; ++ ++struct lxc_epoll_descr; ++struct lxc_handler; ++ ++extern int lxc_exec_cmd_init(const char *name, const char *lxcpath, const char *suffix); ++extern int lxc_exec_cmd_mainloop_add(struct lxc_epoll_descr *descr, struct lxc_exec_command_handler *handler); ++extern int lxc_exec_cmd_set_terminal_winch(const char *name, const char *lxcpath, const char *suffix, unsigned int height, unsigned int width); ++ ++#ifdef HAVE_ISULAD ++extern int lxc_exec_unix_sock_delete(const char *name, const char *suffix); ++#endif ++ ++#endif /* __exec_commands_h */ +diff --git a/src/lxc/file_utils.h b/src/lxc/file_utils.h +index f9c8abe..37cd79e 100644 +--- a/src/lxc/file_utils.h ++++ b/src/lxc/file_utils.h +@@ -83,4 +83,8 @@ extern FILE *fdopen_cached(int fd, const char *mode, void **caller_freed_buffer) + extern FILE *fopen_cached(const char *path, const char *mode, + void **caller_freed_buffer); + ++#ifdef HAVE_ISULAD ++extern ssize_t lxc_write_nointr_for_fifo(int fd, const char *buf, size_t count); ++#endif ++ + #endif /* __LXC_FILE_UTILS_H */ +diff --git a/src/lxc/json/read-file.c b/src/lxc/json/read-file.c +new file mode 100644 +index 0000000..34ebeed +--- /dev/null ++++ b/src/lxc/json/read-file.c +@@ -0,0 +1,95 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include "read-file.h" ++ ++#ifndef O_CLOEXEC ++#define O_CLOEXEC 02000000 ++#endif ++ ++char *fread_file(FILE *stream, size_t *length) ++{ ++ char *buf = NULL, *tmpbuf = NULL; ++ size_t off = 0; ++ ++ while (1) { ++ size_t ret, newsize; ++ ++ newsize = off + BUFSIZ + 1; ++ tmpbuf = (char *)calloc(1, newsize); ++ if (tmpbuf == NULL) { ++ goto out; ++ } ++ ++ if (buf) { ++ memcpy(tmpbuf, buf, off); ++ ++ memset(buf, 0, off); ++ ++ free(buf); ++ } ++ ++ buf = tmpbuf; ++ ret = fread(buf + off, 1, BUFSIZ, stream); ++ if (!ret && ferror(stream)) { ++ tmpbuf = NULL; ++ goto out; ++ } ++ if (ret < BUFSIZ || feof(stream)) { ++ *length = off + ret + 1; ++ buf[*length - 1] = '\0'; ++ return buf; ++ } ++ off += BUFSIZ; ++ } ++out: ++ if (buf) { ++ free(buf); ++ } ++ if (tmpbuf) { ++ free(tmpbuf); ++ } ++ return NULL; ++ ++} ++ ++char *read_file(const char *path, size_t *length) ++{ ++ char *buf = NULL; ++ char rpath[PATH_MAX + 1] = {0}; ++ int fd = -1; ++ int tmperrno; ++ FILE *fp = NULL; ++ ++ if (!path || !length) { ++ return NULL; ++ } ++ ++ if (strlen(path) > PATH_MAX || NULL == realpath(path, rpath)) { ++ return NULL; ++ } ++ ++ fd = open(rpath, O_RDONLY | O_CLOEXEC); ++ if (fd < 0) { ++ return NULL; ++ } ++ ++ fp = fdopen(fd, "r"); ++ tmperrno = errno; ++ if (!fp) { ++ close(fd); ++ errno = tmperrno; ++ return NULL; ++ } ++ ++ buf = fread_file(fp, length); ++ fclose(fp); ++ return buf; ++} +diff --git a/src/lxc/log.c b/src/lxc/log.c +index 59644aa..e643f26 100644 +--- a/src/lxc/log.c ++++ b/src/lxc/log.c +@@ -55,6 +55,38 @@ static char *log_vmname = NULL; + + lxc_log_define(log, lxc); + ++#ifdef HAVE_ISULAD ++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) { +@@ -321,6 +353,12 @@ static int log_append_logfile(const struct lxc_log_appender *appender, + #endif + + 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; +@@ -333,9 +371,13 @@ static int log_append_logfile(const struct lxc_log_appender *appender, + return ret; + + 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), +@@ -589,6 +631,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. +@@ -598,7 +647,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; + +@@ -694,6 +747,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/path.h b/src/lxc/path.h +new file mode 100644 +index 0000000..2c60fb9 +--- /dev/null ++++ b/src/lxc/path.h +@@ -0,0 +1,65 @@ ++/* 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_PATH_H_ ++#define __ISULAD_PATH_H_ ++ ++#include ++ ++bool specify_current_dir(const char *path); ++ ++bool has_traling_path_separator(const char *path); ++ ++// PreserveTrailingDotOrSeparator returns the given cleaned path ++// and appends a trailing `/.` or `/` if its corresponding original ++// path ends with a trailing `/.` or `/`. If the cleaned ++// path already ends in a `.` path segment, then another is not added. If the ++// clean path already ends in a path separator, then another is not added. ++char *preserve_trailing_dot_or_separator(const char *cleanedpath, ++ const char *originalpath); ++ ++ ++// Split splits path immediately following the final Separator, ++// separating it into a directory and file name component. ++// If there is no Separator in path, Split returns an empty dir ++// and file set to path. ++// The returned values have the property that path = dir+file. ++bool filepath_split(const char *path, char **dir, char **base); ++ ++/* ++ * cleanpath is similar to realpath of glibc, but not expands symbolic links, ++ * and not check the existence of components of the path. ++ */ ++char *cleanpath(const char *path, char *realpath, size_t realpath_len); ++ ++ ++// FollowSymlinkInScope is a wrapper around evalSymlinksInScope that returns an ++// absolute path. This function handles paths in a platform-agnostic manner. ++char *follow_symlink_in_scope(const char *fullpath, const char *rootpath); ++ ++// GetResourcePath evaluates `path` in the scope of the container's rootpath, with proper path ++// sanitisation. Symlinks are all scoped to the rootpath of the container, as ++// though the container's rootpath was `/`. ++// ++// The BaseFS of a container is the host-facing path which is bind-mounted as ++// `/` inside the container. This method is essentially used to access a ++// particular path inside the container as though you were a process in that ++// container. ++int get_resource_path(const char *rootpath, const char *path, ++ char **scopepath); ++ ++// Rel returns a relative path that is lexically equivalent to targpath when ++// joined to basepath with an intervening separator. That is, ++// Join(basepath, Rel(basepath, targpath)) is equivalent to targpath itself. ++// On success, the returned path will always be relative to basepath, ++// even if basepath and targpath share no elements. ++// An error is returned if targpath can't be made relative to basepath or if ++// knowing the current working directory would be necessary to compute it. ++// Rel calls Clean on the result. ++char *path_relative(const char *basepath, const char *targpath); ++ ++#endif +diff --git a/src/lxc/start.h b/src/lxc/start.h +index ece4aac..c7a0a55 100644 +--- a/src/lxc/start.h ++++ b/src/lxc/start.h +@@ -124,8 +124,17 @@ struct lxc_handler { + + struct cgroup_ops *cgroup_ops; + ++#ifdef HAVE_ISULAD ++ int exit_code;/* isulad: record the exit code of container */ ++ /* Indicates whether should we using pipes or pty dup to std{in,out,err} for console log. */ ++ bool disable_pty; ++ /* Indicates whether should we keep stdin active. */ ++ bool open_stdin; ++ bool image_type_oci; ++#else + /* Internal fds that always need to stay open. */ + int keep_fds[3]; ++#endif + }; + + struct execute_args { +@@ -136,7 +145,11 @@ struct execute_args { + }; + + struct lxc_operations { ++#ifdef HAVE_ISULAD ++ int (*start)(struct lxc_handler *, void *, int); ++#else + int (*start)(struct lxc_handler *, void *); ++#endif + int (*post_start)(struct lxc_handler *, void *); + }; + +@@ -164,14 +177,31 @@ extern void lxc_end(struct lxc_handler *handler); + */ + extern int lxc_check_inherited(struct lxc_conf *conf, bool closeall, + int *fds_to_ignore, size_t len_fds); ++#ifndef HAVE_ISULAD + static inline int inherit_fds(struct lxc_handler *handler, bool closeall) + { + return lxc_check_inherited(handler->conf, closeall, handler->keep_fds, + ARRAY_SIZE(handler->keep_fds)); + } ++#endif ++ ++#ifdef HAVE_ISULAD ++extern int __lxc_start(struct lxc_handler *handler, ++ struct lxc_operations* ops, void *data, const char *lxcpath, ++ bool daemonize, int *error_num, unsigned int start_timeout); ++#else + extern int __lxc_start(struct lxc_handler *, struct lxc_operations *, void *, + const char *, bool, int *); + ++#endif + extern int resolve_clone_flags(struct lxc_handler *handler); + ++#ifdef HAVE_ISULAD ++/*isulad: do_lxcapi_clean_resource */ ++extern int do_lxcapi_clean_resource(char *name, char *lxcpath, struct lxc_conf *conf, pid_t pid); ++ ++/*isulad: do_lxcapi_get_pids */ ++extern int do_lxcapi_get_pids(char *name, char *lxcpath, struct lxc_conf *conf, pid_t **pids,size_t *pids_len); ++#endif ++ + #endif +diff --git a/src/lxc/storage/block.c b/src/lxc/storage/block.c +new file mode 100644 +index 0000000..eb75e70 +--- /dev/null ++++ b/src/lxc/storage/block.c +@@ -0,0 +1,86 @@ ++/* ++ * lxc: linux Container library ++ * ++ * (C) Copyright IBM Corp. 2007, 2008 ++ * ++ * Authors: ++ * Daniel Lezcano ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2.1 of the License, or (at your option) any later version. ++ * ++ * This library is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with this library; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++#ifndef _GNU_SOURCE ++#define _GNU_SOURCE 1 ++#endif ++#include ++#include ++ ++#include "config.h" ++#include "log.h" ++#include "storage.h" ++#include "storage_utils.h" ++#include "utils.h" ++ ++lxc_log_define(blk, lxc); ++ ++int blk_destroy(struct lxc_storage *orig) ++{ ++ return 0; ++} ++ ++bool blk_detect(const char *path) ++{ ++ struct stat statbuf; ++ int ret; ++ ++ if (!strncmp(path, "blk:", 4)) ++ return true; ++ ++ ret = stat(path, &statbuf); ++ if (ret == -1 && errno == EPERM) { ++ SYSERROR("blk_detect: failed to look at \"%s\"", path); ++ return false; ++ } ++ ++ if (ret == 0 && S_ISBLK(statbuf.st_mode)) ++ return true; ++ ++ return false; ++} ++ ++int blk_mount(struct lxc_storage *bdev) ++{ ++ const char *src; ++ if (strcmp(bdev->type, "blk")) ++ return -22; ++ ++ if (!bdev->src || !bdev->dest) ++ return -22; ++ ++ src = lxc_storage_get_path(bdev->src, bdev->type); ++ ++ return mount_unknown_fs(src, bdev->dest, bdev->mntopts); ++} ++ ++int blk_umount(struct lxc_storage *bdev) ++{ ++ if (strcmp(bdev->type, "blk")) ++ return -22; ++ ++ if (!bdev->src || !bdev->dest) ++ return -22; ++ ++ return umount(bdev->dest); ++} +diff --git a/src/lxc/storage/block.h b/src/lxc/storage/block.h +new file mode 100644 +index 0000000..2fa7565 +--- /dev/null ++++ b/src/lxc/storage/block.h +@@ -0,0 +1,41 @@ ++/* ++ * lxc: linux Container library ++ * ++ * (C) Copyright IBM Corp. 2007, 2008 ++ * ++ * Authors: ++ * Daniel Lezcano ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2.1 of the License, or (at your option) any later version. ++ * ++ * This library is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with this library; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++#ifndef __LXC_BLK_H ++#define __LXC_BLK_H ++ ++#include ++#include ++ ++struct lxc_storage; ++ ++struct bdev_specs; ++ ++struct lxc_conf; ++ ++extern int blk_destroy(struct lxc_storage *orig); ++extern bool blk_detect(const char *path); ++extern int blk_mount(struct lxc_storage *bdev); ++extern int blk_umount(struct lxc_storage *bdev); ++ ++#endif /* __LXC_BLK_H */ +diff --git a/src/lxc/storage/storage_utils.c b/src/lxc/storage/storage_utils.c +index f96bd52..696c6e5 100644 +--- a/src/lxc/storage/storage_utils.c ++++ b/src/lxc/storage/storage_utils.c +@@ -256,10 +256,17 @@ int is_blktype(struct lxc_storage *b) + return 0; + } + ++#ifdef HAVE_ISULAD ++static char **mount_errors = NULL; ++#endif ++ + int mount_unknown_fs(const char *rootfs, const char *target, + const char *options) + { + size_t i; ++#ifdef HAVE_ISULAD ++ char *errs = NULL; ++#endif + int ret; + struct cbarg { + const char *rootfs; +@@ -288,14 +295,41 @@ int mount_unknown_fs(const char *rootfs, const char *target, + ret = lxc_file_for_each_line(fsfile[i], find_fstype_cb, &cbarg); + if (ret < 0) { + ERROR("Failed to parse \"%s\"", fsfile[i]); ++#ifdef HAVE_ISULAD ++ lxc_free_array((void**)mount_errors, free); ++ mount_errors = NULL; ++#endif + return -1; + } + ++#ifdef HAVE_ISULAD ++ if (ret) { ++ lxc_free_array((void**)mount_errors, free); ++ mount_errors = NULL; ++ return 0; ++ } ++#else + if (ret) + return 0; ++#endif ++ } ++ ++#ifdef HAVE_ISULAD ++ if (mount_errors != NULL) { ++ errs = lxc_string_join("\n", (const char **)mount_errors, false); ++ if (errs == NULL) { ++ ERROR("failed to join mount errors"); ++ } + } + ++ ERROR("Failed to determine FSType for \"%s\": %s", rootfs, errs ? errs : "unknown reason"); ++ ++ free(errs); ++ lxc_free_array((void**)mount_errors, free); ++ mount_errors = NULL; ++#else + ERROR("Failed to determine FSType for \"%s\"", rootfs); ++#endif + + return -1; + } +@@ -316,6 +350,11 @@ int find_fstype_cb(char *buffer, void *data) + char *mntdata = NULL; + char *fstype; + ++#ifdef HAVE_ISULAD ++ char mount_err[BUFSIZ] = {0}; ++ int ret; ++ unsigned long pflags = 0; ++#endif + /* we don't try 'nodev' entries */ + if (strstr(buffer, "nodev")) + return 0; +@@ -327,14 +366,35 @@ int find_fstype_cb(char *buffer, void *data) + DEBUG("Trying to mount \"%s\"->\"%s\" with FSType \"%s\"", cbarg->rootfs, + cbarg->target, fstype); + ++#ifdef HAVE_ISULAD ++ if (parse_mntopts(cbarg->options, &mntflags, &pflags, &mntdata) < 0) { ++#else + if (parse_mntopts(cbarg->options, &mntflags, &mntdata) < 0) { ++#endif + free(mntdata); + return 0; + } + ++#ifdef HAVE_ISULAD ++ if (mount(cbarg->rootfs, cbarg->target, fstype, (mntflags & ~MS_RDONLY), mntdata)) { ++#else + if (mount(cbarg->rootfs, cbarg->target, fstype, mntflags, mntdata)) { ++#endif + SYSDEBUG("Failed to mount"); + free(mntdata); ++#ifdef HAVE_ISULAD ++ // isulad: recored error ++ ret = snprintf(mount_err, BUFSIZ, "\t\tmount %s onto %s with FSType %s failed: %s", ++ cbarg->rootfs, cbarg->target, fstype, strerror(errno)); ++ if (ret < 0 || (size_t)ret >= BUFSIZ) { ++ ERROR("failed to format output mount error"); ++ return 0; ++ } ++ ++ if (lxc_append_string(&mount_errors, mount_err) < 0) { ++ ERROR("failed to append mount error"); ++ } ++#endif + return 0; + } + +diff --git a/src/lxc/terminal.h b/src/lxc/terminal.h +index 4d21f33..c835e9a 100644 +--- a/src/lxc/terminal.h ++++ b/src/lxc/terminal.h +@@ -79,6 +79,16 @@ 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 */ { +@@ -88,7 +98,27 @@ 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 +@@ -254,4 +284,9 @@ extern void lxc_terminal_init(struct lxc_terminal *terminal); + extern int lxc_terminal_map_ids(struct lxc_conf *c, + struct lxc_terminal *terminal); + ++#ifdef HAVE_ISULAD ++int lxc_terminal_add_fifos(struct lxc_conf *conf, const char *fifonames); ++int lxc_set_terminal_winsz(struct lxc_terminal *terminal, unsigned int height, unsigned int width); ++#endif ++ + #endif /* __LXC_TERMINAL_H */ +-- +2.25.1 + diff --git a/0007-refactor-patches-on-terminal.c-start.c-and-so-on.patch b/0007-refactor-patches-on-terminal.c-start.c-and-so-on.patch new file mode 100644 index 0000000000000000000000000000000000000000..84f70485aee537b2cfff4764cb96a4780588be54 --- /dev/null +++ b/0007-refactor-patches-on-terminal.c-start.c-and-so-on.patch @@ -0,0 +1,2726 @@ +From 06b071d6bc7683023d3131d4e428210005333c8c Mon Sep 17 00:00:00 2001 +From: chengzrz +Date: Wed, 20 Jul 2022 15:03:45 +0800 +Subject: [PATCH] refactor patches on terminal.c, start.c and so on + +Signed-off-by: chengzrz +--- + hooks/Makefile.am | 3 + + src/lxc/attach.h | 6 + + src/lxc/cgroups/cgroup.c | 4 + + src/lxc/commands_utils.h | 6 + + src/lxc/initutils.c | 4 + + src/lxc/lsm/lsm.h | 8 + + src/lxc/lxclock.h | 4 + + src/lxc/mainloop.h | 4 + + src/lxc/start.c | 958 ++++++++++++++++++++++++++++++++++++ + src/lxc/storage/btrfs.c | 11 + + src/lxc/storage/overlay.c | 8 + + src/lxc/sync.h | 4 + + src/lxc/terminal.c | 990 ++++++++++++++++++++++++++++++++++++++ + src/tests/Makefile.am | 4 + + src/tests/attach.c | 11 + + 15 files changed, 2025 insertions(+) + +diff --git a/hooks/Makefile.am b/hooks/Makefile.am +index 5ae73d7..ddfd4bc 100644 +--- a/hooks/Makefile.am ++++ b/hooks/Makefile.am +@@ -10,6 +10,8 @@ hooks_SCRIPTS = \ + squid-deb-proxy-client \ + nvidia + ++ ++if !HAVE_ISULAD + binhooks_PROGRAMS = \ + unmount-namespace + +@@ -20,5 +22,6 @@ if IS_BIONIC + unmount_namespace_SOURCES += \ + ../src/include/lxcmntent.c ../src/include/lxcmntent.h + endif ++endif + + EXTRA_DIST=$(hooks_SCRIPTS) +diff --git a/src/lxc/attach.h b/src/lxc/attach.h +index ef5a6c1..8316344 100644 +--- a/src/lxc/attach.h ++++ b/src/lxc/attach.h +@@ -20,9 +20,15 @@ struct lxc_proc_context_info { + int ns_fd[LXC_NS_MAX]; + }; + ++#ifdef HAVE_ISULAD ++extern int lxc_attach(struct lxc_container *container, ++ lxc_attach_exec_t exec_function, void *exec_payload, ++ lxc_attach_options_t *options, pid_t *attached_process, char **err_msg); ++#else + extern int lxc_attach(struct lxc_container *container, + lxc_attach_exec_t exec_function, void *exec_payload, + lxc_attach_options_t *options, pid_t *attached_process); ++#endif + + extern int lxc_attach_remount_sys_proc(void); + +diff --git a/src/lxc/cgroups/cgroup.c b/src/lxc/cgroups/cgroup.c +index 7c94fd8..5aa2c3c 100644 +--- a/src/lxc/cgroups/cgroup.c ++++ b/src/lxc/cgroups/cgroup.c +@@ -31,7 +31,11 @@ struct cgroup_ops *cgroup_init(struct lxc_conf *conf) + if (!cgroup_ops) + return log_error_errno(NULL, errno, "Failed to initialize cgroup driver"); + ++#ifdef HAVE_ISULAD ++ if (cgroup_ops->data_init(cgroup_ops, conf)) { ++#else + if (cgroup_ops->data_init(cgroup_ops)) { ++#endif + cgroup_exit(cgroup_ops); + return log_error_errno(NULL, errno, + "Failed to initialize cgroup data"); +diff --git a/src/lxc/commands_utils.h b/src/lxc/commands_utils.h +index 3ef7920..c836ead 100644 +--- a/src/lxc/commands_utils.h ++++ b/src/lxc/commands_utils.h +@@ -65,4 +65,10 @@ extern int lxc_add_state_client(int state_client_fd, + extern int lxc_cmd_connect(const char *name, const char *lxcpath, + const char *hashed_sock_name, const char *suffix); + ++#ifdef HAVE_ISULAD ++extern char *generate_named_unix_sock_dir(const char *name); ++extern int generate_named_unix_sock_path(const char *container_name, ++ const char *sock_name, char *out_path, size_t len); ++#endif ++ + #endif /* __LXC_COMMANDS_UTILS_H */ +diff --git a/src/lxc/initutils.c b/src/lxc/initutils.c +index 5549c2e..76f0048 100644 +--- a/src/lxc/initutils.c ++++ b/src/lxc/initutils.c +@@ -54,11 +54,15 @@ const char *lxc_global_config_value(const char *option_name) + { NULL, NULL }, + }; + ++#ifdef HAVE_ISULAD ++ static const char *values[sizeof(options) / sizeof(options[0])] = {0}; ++#else + /* placed in the thread local storage pool for non-bionic targets */ + #ifdef HAVE_TLS + static thread_local const char *values[sizeof(options) / sizeof(options[0])] = {0}; + #else + static const char *values[sizeof(options) / sizeof(options[0])] = {0}; ++#endif + #endif + + /* user_config_path is freed as soon as it is used */ +diff --git a/src/lxc/lsm/lsm.h b/src/lxc/lsm/lsm.h +index ee578bb..4872f55 100644 +--- a/src/lxc/lsm/lsm.h ++++ b/src/lxc/lsm/lsm.h +@@ -17,6 +17,10 @@ struct lsm_drv { + char *(*process_label_get)(pid_t pid); + int (*process_label_set)(const char *label, struct lxc_conf *conf, + bool on_exec); ++#ifdef HAVE_ISULAD ++ int (*file_label_set)(const char *path, const char *label); ++ int (*relabel)(const char *path, const char *label, bool share); ++#endif + int (*keyring_label_set)(char* label); + int (*prepare)(struct lxc_conf *conf, const char *lxcpath); + void (*cleanup)(struct lxc_conf *conf, const char *lxcpath); +@@ -32,6 +36,10 @@ extern int lsm_process_label_set(const char *label, struct lxc_conf *conf, + extern int lsm_process_label_fd_get(pid_t pid, bool on_exec); + extern int lsm_process_label_set_at(int label_fd, const char *label, + bool on_exec); ++#ifdef HAVE_ISULAD ++extern int lsm_file_label_set(const char *path, const char *label); ++extern int lsm_relabel(const char *path, const char *label, bool share); ++#endif + extern void lsm_process_cleanup(struct lxc_conf *conf, const char *lxcpath); + extern int lsm_keyring_label_set(char *label); + +diff --git a/src/lxc/lxclock.h b/src/lxc/lxclock.h +index 9f9bc3b..6a71d7c 100644 +--- a/src/lxc/lxclock.h ++++ b/src/lxc/lxclock.h +@@ -154,4 +154,8 @@ extern int container_disk_lock(struct lxc_container *c); + */ + extern void container_disk_unlock(struct lxc_container *c); + ++#ifdef HAVE_ISULAD ++int container_disk_removelock(struct lxc_container *c); ++#endif ++ + #endif +diff --git a/src/lxc/mainloop.h b/src/lxc/mainloop.h +index e6ab9a6..aa41a93 100644 +--- a/src/lxc/mainloop.h ++++ b/src/lxc/mainloop.h +@@ -38,4 +38,8 @@ extern void lxc_mainloop_close(struct lxc_epoll_descr *descr); + + define_cleanup_function(struct lxc_epoll_descr *, lxc_mainloop_close); + ++#ifdef HAVE_ISULAD ++extern int isulad_safe_mainloop(struct lxc_epoll_descr *descr, int timeout_ms); ++#endif ++ + #endif +diff --git a/src/lxc/start.c b/src/lxc/start.c +index fd969c4..f82df34 100644 +--- a/src/lxc/start.c ++++ b/src/lxc/start.c +@@ -304,7 +304,11 @@ static int setup_signal_fd(sigset_t *oldmask) + { + int ret; + sigset_t mask; ++#ifdef HAVE_ISULAD ++ const int signals[] = {SIGBUS, SIGILL, SIGSEGV, SIGWINCH, SIGTERM}; ++#else + const int signals[] = {SIGBUS, SIGILL, SIGSEGV, SIGWINCH}; ++#endif + + /* Block everything except serious error signals. */ + ret = sigfillset(&mask); +@@ -590,13 +594,27 @@ int lxc_poll(const char *name, struct lxc_handler *handler) + + TRACE("Mainloop is ready"); + ++#ifdef HAVE_ISULAD ++ // iSulad: close stdin pipe if we do not want open_stdin with container stdin ++ if (!handler->conf->console.open_stdin) { ++ if (handler->conf->console.pipes[0][1] > 0) { ++ close(handler->conf->console.pipes[0][1]); ++ handler->conf->console.pipes[0][1] = -1; ++ } ++ } ++#endif ++ + ret = lxc_mainloop(&descr, -1); + close_prot_errno_disarm(descr.epfd); + if (ret < 0 || !handler->init_died) + goto out_mainloop_console; + + if (has_console) ++#ifdef HAVE_ISULAD ++ ret = isulad_safe_mainloop(&descr_console, 100); ++#else + ret = lxc_mainloop(&descr_console, 0); ++#endif + + out_mainloop_console: + if (has_console) { +@@ -637,7 +655,9 @@ struct lxc_handler *lxc_init_handler(struct lxc_handler *old, + const char *name, struct lxc_conf *conf, + const char *lxcpath, bool daemonize) + { ++#ifndef HAVE_ISULAD + int nr_keep_fds = 0; ++#endif + int ret; + struct lxc_handler *handler; + +@@ -671,6 +691,12 @@ struct lxc_handler *lxc_init_handler(struct lxc_handler *old, + handler->nsfd[i] = -EBADF; + + handler->name = name; ++ ++#ifdef HAVE_ISULAD ++ handler->exit_code = -1; /* isulad: record exit code of container */ ++ handler->image_type_oci = false; ++#endif ++ + if (daemonize) + handler->transient_pid = lxc_raw_getpid(); + else +@@ -691,8 +717,10 @@ struct lxc_handler *lxc_init_handler(struct lxc_handler *old, + TRACE("Created anonymous pair {%d,%d} of unix sockets", + handler->state_socket_pair[0], + handler->state_socket_pair[1]); ++#ifndef HAVE_ISULAD + handler->keep_fds[nr_keep_fds++] = handler->state_socket_pair[0]; + handler->keep_fds[nr_keep_fds++] = handler->state_socket_pair[1]; ++#endif + } + + if (handler->conf->reboot == REBOOT_NONE) { +@@ -701,7 +729,9 @@ struct lxc_handler *lxc_init_handler(struct lxc_handler *old, + ERROR("Failed to set up command socket"); + goto on_error; + } ++#ifndef HAVE_ISULAD + handler->keep_fds[nr_keep_fds++] = handler->conf->maincmd_fd; ++#endif + } + + TRACE("Unix domain socket %d for command server is ready", +@@ -721,6 +751,10 @@ int lxc_init(const char *name, struct lxc_handler *handler) + int ret; + const char *loglevel; + struct lxc_conf *conf = handler->conf; ++#ifdef HAVE_ISULAD ++ conf->console.disable_pty = handler->disable_pty; ++ conf->console.open_stdin = handler->open_stdin; ++#endif + + handler->monitor_pid = lxc_raw_getpid(); + status_fd = open("/proc/self/status", O_RDONLY | O_CLOEXEC); +@@ -810,6 +844,9 @@ int lxc_init(const char *name, struct lxc_handler *handler) + ret = lxc_terminal_setup(conf); + if (ret < 0) { + ERROR("Failed to create console"); ++#ifdef HAVE_ISULAD ++ lxc_write_error_message(conf->errpipe[1], "Failed to create console for container \"%s\".", name); ++#endif + goto out_restore_sigmask; + } + TRACE("Created console"); +@@ -853,6 +890,185 @@ out_restore_sigmask: + return -1; + } + ++#ifdef HAVE_ISULAD ++/* isulad: start timeout thread */ ++typedef enum { ++ START_INIT, ++ START_TIMEOUT, ++ START_MAX, ++} start_timeout_t; ++ ++static start_timeout_t global_timeout_state = START_INIT; ++static sem_t global_timeout_sem; ++ ++struct start_timeout_conf { ++ unsigned int timeout; ++ int errfd; ++}; ++ ++void trim_line(char *s) ++{ ++ size_t len; ++ ++ len = strlen(s); ++ while ((len > 1) && (s[len - 1] == '\n')) ++ s[--len] = '\0'; ++} ++ ++static int _read_procs_file(const char *path, pid_t **pids, size_t *len) ++{ ++ FILE *f; ++ char *line = NULL; ++ size_t sz = 0; ++ pid_t *tmp_pids = NULL; ++ ++ f = fopen_cloexec(path, "r"); ++ if (!f) ++ return -1; ++ ++ while (getline(&line, &sz, f) != -1) { ++ pid_t pid; ++ trim_line(line); ++ pid = (pid_t)atoll(line); ++ if (lxc_mem_realloc((void **)&tmp_pids, sizeof(pid_t) * (*len + 1), *pids, sizeof(pid_t) * (*len)) != 0) { ++ free(*pids); ++ *pids = NULL; ++ ERROR("out of memory"); ++ free(line); ++ fclose(f); ++ return -1; ++ } ++ *pids = tmp_pids; ++ ++ (*pids)[*len] = pid; ++ (*len)++; ++ } ++ ++ free(line); ++ fclose(f); ++ return 0; ++} ++ ++static int _recursive_read_cgroup_procs(const char *dirpath, pid_t **pids, size_t *len) ++{ ++ struct dirent *direntp = NULL; ++ DIR *dir = NULL; ++ int ret, failed = 0; ++ char pathname[PATH_MAX]; ++ ++ dir = opendir(dirpath); ++ if (dir == NULL) { ++ WARN("Failed to open \"%s\"", dirpath); ++ return 0; ++ } ++ ++ while ((direntp = readdir(dir))) { ++ struct stat mystat; ++ int rc; ++ ++ if (!strcmp(direntp->d_name, ".") || ++ !strcmp(direntp->d_name, "..")) ++ continue; ++ ++ rc = snprintf(pathname, PATH_MAX, "%s/%s", dirpath, direntp->d_name); ++ if (rc < 0 || rc >= PATH_MAX) { ++ failed = 1; ++ continue; ++ } ++ ++ if (strcmp(direntp->d_name, "cgroup.procs") == 0) { ++ if (_read_procs_file(pathname, pids, len)) { ++ failed = 1; ++ ++ } ++ continue; ++ } ++ ++ ret = lstat(pathname, &mystat); ++ if (ret) { ++ failed = 1; ++ continue; ++ } ++ ++ if (S_ISDIR(mystat.st_mode)) { ++ if (_recursive_read_cgroup_procs(pathname, pids, len) < 0) ++ failed = 1; ++ } ++ } ++ ++ ret = closedir(dir); ++ if (ret) { ++ WARN("Failed to close directory \"%s\"", dirpath); ++ failed = 1; ++ } ++ ++ return failed ? -1 : 0; ++} ++ ++int get_all_pids(struct cgroup_ops *cg_ops, pid_t **pids, size_t *len) ++{ ++ const char *devices_path = NULL; ++ ++ devices_path = cg_ops->get_cgroup_full_path(cg_ops, "devices"); ++ if (!file_exists(devices_path)) { ++ return 0; ++ } ++ ++ return _recursive_read_cgroup_procs(devices_path, pids, len); ++} ++ ++static int set_cgroup_freezer(struct cgroup_ops *cg_ops, const char *value) ++{ ++ char *fullpath; ++ int ret; ++ ++ fullpath = must_make_path(cg_ops->get_cgroup_full_path(cg_ops, "freezer"), "freezer.state", NULL); ++ ret = lxc_write_to_file(fullpath, value, strlen(value), false, 0666); ++ free(fullpath); ++ return ret; ++} ++ ++/* isulad: kill all process in container cgroup path */ ++static void signal_all_processes(struct lxc_handler *handler) ++{ ++ int ret; ++ struct cgroup_ops *cg_ops = handler->cgroup_ops; ++ pid_t *pids = NULL; ++ size_t len = 0, i; ++ ++ ret = set_cgroup_freezer(cg_ops, "FROZEN"); ++ if (ret < 0 && errno != ENOENT) { ++ WARN("cgroup_set frozen failed"); ++ } ++ ++ ret = get_all_pids(cg_ops, &pids, &len); ++ if (ret < 0) { ++ WARN("failed to get all pids"); ++ } ++ ++ for (i = 0; i < len; i++) { ++ ret = kill(pids[i], SIGKILL); ++ if (ret < 0 && errno != ESRCH) { ++ WARN("Can not kill process (pid=%d) with SIGKILL for container %s", pids[i], handler->name); ++ } ++ } ++ ++ ret = set_cgroup_freezer(cg_ops, "THAWED"); ++ if (ret < 0 && errno != ENOENT) { ++ WARN("cgroup_set thawed failed"); ++ } ++ ++ for (i = 0; i < len; i++) { ++ ret = lxc_wait_for_pid_status(pids[i]); ++ if (ret < 0 && errno != ECHILD) { ++ WARN("Failed to wait pid %d for container %s: %s", pids[i], handler->name, strerror(errno)); ++ } ++ } ++ ++ free(pids); ++} ++#endif ++ + void lxc_end(struct lxc_handler *handler) + { + int ret; +@@ -926,6 +1142,33 @@ void lxc_end(struct lxc_handler *handler) + + lsm_process_cleanup(handler->conf, handler->lxcpath); + ++#ifdef HAVE_ISULAD ++ // close maincmd fd before destroy cgroup for isulad ++ if (handler->conf->reboot == REBOOT_NONE) { ++ /* For all new state clients simply close the command socket. ++ * This will inform all state clients that the container is ++ * STOPPED and also prevents a race between a open()/close() on ++ * the command socket causing a new process to get ECONNREFUSED ++ * because we haven't yet closed the command socket. ++ */ ++ close_prot_errno_disarm(handler->conf->maincmd_fd); ++ TRACE("Closed command socket"); ++ } ++ int retry_count = 0; ++ int max_retry = 10; ++retry: ++ if (cgroup_ops != NULL && !cgroup_ops->payload_destroy(cgroup_ops, handler)) { ++ TRACE("Trying to kill all subprocess"); ++ signal_all_processes(handler); ++ TRACE("Finished kill all subprocess"); ++ if (retry_count < max_retry) { ++ usleep(100 * 1000); /* 100 millisecond */ ++ retry_count++; ++ goto retry; ++ } ++ SYSERROR("Failed to destroy cgroup path for container: \"%s\"", handler->name); ++ } ++#else + if (cgroup_ops) { + cgroup_ops->payload_destroy(cgroup_ops, handler); + cgroup_ops->monitor_destroy(cgroup_ops, handler); +@@ -940,12 +1183,25 @@ void lxc_end(struct lxc_handler *handler) + */ + close_prot_errno_disarm(handler->conf->maincmd_fd); + TRACE("Closed command socket"); ++ } ++#endif + ++ if (handler->conf->reboot == REBOOT_NONE) { + /* This function will try to connect to the legacy lxc-monitord + * state server and only exists for backwards compatibility. + */ + lxc_monitor_send_state(name, STOPPED, handler->lxcpath); + ++#ifdef HAVE_ISULAD ++ /* isuald: write exit code to exit fifo */ ++ if (handler->conf->exit_fd >= 0) { ++ ret = write(handler->conf->exit_fd, &handler->exit_code, sizeof(int)); ++ if (ret != sizeof(int)) { ++ SYSERROR("Failed to write to exit code to exit fifo."); ++ } ++ } ++#endif ++ + /* The command socket is closed so no one can acces the command + * socket anymore so there's no need to lock it. + */ +@@ -1042,6 +1298,25 @@ static int do_start(void *data) + + lxc_sync_fini_parent(handler); + ++#ifdef HAVE_ISULAD ++ sigset_t mask; ++ ++ /*isulad: restore default signal handlers and unblock all signals*/ ++ for (int i = 1; i < NSIG; i++) ++ signal(i, SIG_DFL); ++ ++ ret = sigfillset(&mask); ++ if (ret < 0) { ++ SYSERROR("Failed to fill signal mask"); ++ goto out_warn_father; ++ } ++ ret = sigprocmask(SIG_UNBLOCK, &mask, NULL); ++ if (ret < 0) { ++ SYSERROR("Failed to set signal mask"); ++ goto out_warn_father; ++ } ++#endif ++ + if (lxc_abstract_unix_recv_fds(data_sock1, &status_fd, 1, NULL, 0) < 0) { + ERROR("Failed to receive status file descriptor to child process"); + goto out_warn_father; +@@ -1155,7 +1430,11 @@ static int do_start(void *data) + * means that migration won't work, but at least we won't spew output + * where it isn't wanted. + */ ++#ifdef HAVE_ISULAD ++ if (!handler->disable_pty && handler->daemonize && !handler->conf->autodev) { ++#else + if (handler->daemonize && !handler->conf->autodev) { ++#endif + char path[PATH_MAX]; + + ret = snprintf(path, sizeof(path), "%s/dev/null", +@@ -1221,6 +1500,9 @@ static int do_start(void *data) + /* Setup the container, ip, names, utsname, ... */ + ret = lxc_setup(handler); + if (ret < 0) { ++#ifdef HAVE_ISULAD ++ lxc_write_error_message(handler->conf->errpipe[1], "Failed to setup lxc, please check the config file."); ++#endif + ERROR("Failed to setup container \"%s\"", handler->name); + goto out_warn_father; + } +@@ -1243,12 +1525,70 @@ static int do_start(void *data) + DEBUG("Set PR_SET_NO_NEW_PRIVS to block execve() gainable privileges"); + } + ++#ifdef HAVE_ISULAD ++ /* isulad: dup2 pipe[0][0] to container stdin, pipe[1][1] to container stdout, pipe[2][1] to container stderr */ ++ if (handler->disable_pty) { ++ if (handler->conf->console.pipes[0][1] >= 0) { ++ close(handler->conf->console.pipes[0][1]); ++ handler->conf->console.pipes[0][1] = -1; ++ } ++ ++ if (handler->conf->console.pipes[0][0] >= 0) { ++ ret = dup2(handler->conf->console.pipes[0][0], STDIN_FILENO); ++ if (ret < 0) ++ goto out_warn_father; ++ } ++ ++ if (handler->conf->console.pipes[1][0] >= 0) { ++ close(handler->conf->console.pipes[1][0]); ++ handler->conf->console.pipes[1][0] = -1; ++ } ++ ++ if (handler->conf->console.pipes[1][1] >= 0) { ++ ret = dup2(handler->conf->console.pipes[1][1], STDOUT_FILENO); ++ if (ret < 0) ++ goto out_warn_father; ++ } ++ if (handler->conf->console.pipes[2][0] >= 0) { ++ close(handler->conf->console.pipes[2][0]); ++ handler->conf->console.pipes[2][0] = -1; ++ } ++ ++ if (handler->conf->console.pipes[2][1] >= 0) { ++ ret = dup2(handler->conf->console.pipes[2][1], STDERR_FILENO); ++ if (ret < 0) ++ goto out_warn_father; ++ } ++ } ++#endif ++ + /* Some init's such as busybox will set sane tty settings on stdin, + * stdout, stderr which it thinks is the console. We already set them + * the way we wanted on the real terminal, and we want init to do its + * setup on its console ie. the pty allocated in lxc_terminal_setup() so + * make sure that that pty is stdin,stdout,stderr. + */ ++#ifdef HAVE_ISULAD ++ setsid(); ++ if (!handler->disable_pty && handler->conf->console.pts >= 0) { ++ /* isulad:make the given terminal as controlling terminal to avoid warning ++ * sh: cannot set terminal process group (-1): Inappropriate ioctl for device ++ * sh: no job control in this shell */ ++ if (ioctl(handler->conf->console.pts, TIOCSCTTY, NULL) < 0) { ++ ERROR("Faild to make the given terminal the controlling terminal of the calling process"); ++ goto out_warn_father; ++ } ++ if (handler->daemonize || !handler->conf->is_execute) ++ ret = set_stdfds(handler->conf->console.pts); ++ else ++ ret = lxc_terminal_set_stdfds(handler->conf->console.pts); ++ if (ret < 0) { ++ ERROR("Failed to redirect std{in,out,err} to pty file " ++ "descriptor %d", handler->conf->console.pts); ++ goto out_warn_father; ++ } ++ } ++#else + if (handler->conf->console.pts >= 0) { + if (handler->daemonize || !handler->conf->is_execute) + ret = set_stdfds(handler->conf->console.pts); +@@ -1260,6 +1600,7 @@ static int do_start(void *data) + goto out_warn_father; + } + } ++#endif + + /* If we mounted a temporary proc, then unmount it now. */ + tmp_proc_unmount(handler->conf); +@@ -1283,6 +1624,21 @@ static int do_start(void *data) + + close_prot_errno_disarm(handler->sigfd); + ++#ifdef HAVE_ISULAD ++ if (!handler->disable_pty && handler->conf->console.pts < 0 && handler->daemonize) { ++ if (devnull_fd < 0) { ++ devnull_fd = open_devnull(); ++ if (devnull_fd < 0) ++ goto out_warn_father; ++ } ++ ++ ret = set_stdfds(devnull_fd); ++ if (ret < 0) { ++ ERROR("Failed to redirect std{in,out,err} to \"/dev/null\""); ++ goto out_warn_father; ++ } ++ } ++#else + if (handler->conf->console.pts < 0 && handler->daemonize) { + if (devnull_fd < 0) { + devnull_fd = open_devnull(); +@@ -1296,12 +1652,25 @@ static int do_start(void *data) + goto out_warn_father; + } + } ++#endif + + close_prot_errno_disarm(devnull_fd); + ++#ifndef HAVE_ISULAD + setsid(); + ++#endif + if (handler->conf->init_cwd) { ++#ifdef HAVE_ISULAD ++ /* try to craete workdir if not exist */ ++ struct stat st; ++ if (stat(handler->conf->init_cwd, &st) < 0 && mkdir_p(handler->conf->init_cwd, 0755) < 0) { ++ SYSERROR("Try to create directory \"%s\" as workdir failed", handler->conf->init_cwd); ++ lxc_write_error_message(handler->conf->errpipe[1], "%s:%d: Failed to create workdir: %s.", ++ __FILE__, __LINE__, strerror(errno)); ++ goto out_warn_father; ++ } ++#endif + ret = chdir(handler->conf->init_cwd); + if (ret < 0) { + SYSERROR("Could not change directory to \"%s\"", +@@ -1345,6 +1714,13 @@ static int do_start(void *data) + } + } + ++#ifdef HAVE_ISULAD ++ if (prctl(PR_SET_KEEPCAPS, 1) < 0) { ++ SYSERROR("Failed to keep permitted capabilities"); ++ goto out_warn_father; ++ } ++#endif ++ + /* The container has been setup. We can now switch to an unprivileged + * uid/gid. + */ +@@ -1358,6 +1734,13 @@ static int do_start(void *data) + if (new_gid == nsgid) + new_gid = LXC_INVALID_GID; + ++#ifdef HAVE_ISULAD ++ // isulad: set env home in container ++ if (lxc_setup_env_home(new_uid) < 0) { ++ goto out_warn_father; ++ } ++#endif ++ + /* Make sure that the processes STDIO is correctly owned by the user that we are switching to */ + ret = fix_stdio_permissions(new_uid); + if (ret) +@@ -1371,8 +1754,16 @@ static int do_start(void *data) + #if HAVE_LIBCAP + if (lxc_proc_cap_is_set(CAP_SETGID, CAP_EFFECTIVE)) + #endif ++#ifdef HAVE_ISULAD ++ /* isulad: set groups for init process, and before we set uid and gid */ ++ if (!lxc_setgroups(handler->conf->init_groups_len, handler->conf->init_groups)) { ++ ERROR("Can not set groups"); ++ goto out_warn_father; ++ } ++#else + if (!lxc_setgroups(0, NULL)) + goto out_warn_father; ++#endif + + if (!lxc_switch_uid_gid(new_uid, new_gid)) + goto out_warn_father; +@@ -1383,6 +1774,19 @@ static int do_start(void *data) + goto out_warn_father; + } + ++#ifdef HAVE_ISULAD ++ /* isulad: drop the cap of current process */ ++ if (prctl(PR_SET_KEEPCAPS, 0) < 0) { ++ SYSERROR("Failed to clear permitted capabilities"); ++ goto out_warn_father; ++ } ++ ++ if (lxc_drop_caps(handler->conf)) { ++ SYSERROR("Failed to drop caps"); ++ goto out_warn_father; ++ } ++#endif ++ + if (handler->conf->monitor_signal_pdeath != SIGKILL) { + ret = lxc_set_death_signal(handler->conf->monitor_signal_pdeath, + handler->monitor_pid, status_fd); +@@ -1397,7 +1801,12 @@ static int do_start(void *data) + * After this call, we are in error because this ops should not return + * as it execs. + */ ++#ifdef HAVE_ISULAD ++ close_prot_errno_disarm(status_fd); ++ handler->ops->start(handler, handler->data, handler->daemonize ? handler->conf->errpipe[1] : -1); ++#else + handler->ops->start(handler, handler->data); ++#endif + + out_warn_father: + /* +@@ -1529,6 +1938,94 @@ static inline int do_share_ns(void *arg) + return 0; + } + ++#ifdef HAVE_ISULAD ++static int lxc_write_container_info(char *filename, pid_t pid, pid_t p_pid, ++ unsigned long long start_at, unsigned long long p_start_at) ++{ ++ FILE *pid_fp = NULL; ++ int ret = 0; ++ ++ pid_fp = lxc_fopen(filename, "w"); ++ if (pid_fp == NULL) { ++ SYSERROR("Failed to create pidfile '%s'",filename); ++ ret = -1; ++ goto out; ++ } ++ ++ if (fprintf(pid_fp, "%d %llu %d %llu\n", pid, start_at, p_pid, p_start_at) < 0) { ++ SYSERROR("Failed to write '%s'", filename); ++ ret = -1; ++ goto out; ++ } ++out: ++ if (pid_fp) ++ fclose(pid_fp); ++ pid_fp = NULL; ++ return ret; ++} ++ ++static int lxc_check_container_info(char *filename, pid_t pid, pid_t p_pid, ++ unsigned long long start_at, unsigned long long p_start_at) ++{ ++ int ret = 0; ++ int num; ++ char sbuf[1024] = {0}; /* bufs for stat */ ++ int saved_pid; /* process id */ ++ int saved_ppid; /* pid of parent process */ ++ unsigned long long saved_start_time; /* start time of process -- seconds since 1-1-70 */ ++ unsigned long long saved_pstart_time; /* start time of parent process -- seconds since 1-1-70 */ ++ ++ if ((lxc_file2str(filename, sbuf, sizeof(sbuf))) == -1) { ++ SYSERROR("Failed to read pidfile %s", filename); ++ ret = -1; ++ goto out; ++ } ++ ++ num = sscanf(sbuf, "%d %Lu %d %Lu", &saved_pid, &saved_start_time, &saved_ppid, &saved_pstart_time); ++ if (num != 4) { ++ SYSERROR("Call sscanf error"); ++ ret = -1; ++ goto out; ++ } ++ ++ if (pid != saved_pid || p_pid != saved_ppid ++ || start_at != saved_start_time || p_start_at != saved_pstart_time) { ++ ERROR("Check container info failed"); ++ ret = -1; ++ goto out; ++ } ++ ++out: ++ return ret; ++} ++ ++/* isuald: save pid/ppid info */ ++static int lxc_save_container_info(char *filename, pid_t pid) ++{ ++ int ret = 0; ++ pid_t p_pid = 0; ++ unsigned long long start_at = 0; ++ unsigned long long p_start_at = 0; ++ ++ start_at = lxc_get_process_startat(pid); ++ p_pid = getpid(); ++ p_start_at = lxc_get_process_startat(p_pid); ++ ++ ret = lxc_write_container_info(filename, pid, p_pid, start_at, p_start_at); ++ if (ret != 0) { ++ goto out; ++ } ++ ++ ret = lxc_check_container_info(filename, pid, p_pid, start_at, p_start_at); ++ if (ret != 0) { ++ goto out; ++ } ++ ++out: ++ return ret; ++} ++#endif ++ + /* lxc_spawn() performs crucial setup tasks and clone()s the new process which + * exec()s the requested container binary. + * Note that lxc_spawn() runs in the parent namespaces. Any operations performed +@@ -1595,7 +2092,11 @@ static int lxc_spawn(struct lxc_handler *handler) + * it readonly. + * If the container is unprivileged then skip rootfs pinning. + */ ++#ifdef HAVE_ISULAD ++ if (!wants_to_map_ids && !handler->image_type_oci) { ++#else + if (!wants_to_map_ids) { ++#endif + handler->pinfd = pin_rootfs(conf->rootfs.path); + if (handler->pinfd == -EBADF) + INFO("Failed to pin the rootfs for container \"%s\"", handler->name); +@@ -1640,6 +2141,32 @@ static int lxc_spawn(struct lxc_handler *handler) + } + TRACE("Cloned child process %d", handler->pid); + ++#ifdef HAVE_ISULAD ++ /* isulad: close pipe after clone */ ++ if (handler->conf->console.pipes[0][0] >= 0) { ++ close(handler->conf->console.pipes[0][0]); ++ handler->conf->console.pipes[0][0] = -1; ++ } ++ ++ if (handler->conf->console.pipes[1][1] >= 0) { ++ close(handler->conf->console.pipes[1][1]); ++ handler->conf->console.pipes[1][1] = -1; ++ } ++ ++ if (handler->conf->console.pipes[2][1] >= 0) { ++ close(handler->conf->console.pipes[2][1]); ++ handler->conf->console.pipes[2][1] = -1; ++ } ++ ++ /* isulad: save pid/ppid info into file*/ ++ if (handler->conf->container_info_file) { ++ if (lxc_save_container_info(handler->conf->container_info_file, handler->pid)) { ++ ERROR("Failed to save cloned container pid"); ++ goto out_delete_net; ++ } ++ } ++#endif ++ + /* Verify that we can actually make use of pidfds. */ + if (!lxc_can_use_pidfd(handler->pidfd)) + close_prot_errno_disarm(handler->pidfd); +@@ -1652,6 +2179,13 @@ static int lxc_spawn(struct lxc_handler *handler) + if (ret < 0) + SYSERROR("Failed to set environment variable: LXC_PID=%s", pidstr); + ++#ifdef HAVE_ISULAD ++ if (handler->cgroup_ops->container_cgroup) { ++ if (setenv("LXC_CGROUP_PATH", handler->cgroup_ops->container_cgroup, 1)) ++ SYSERROR("Failed to set environment variable: LXC_CGROUP_PATH=%s.", handler->cgroup_ops->container_cgroup); ++ } ++#endif ++ + for (i = 0; i < LXC_NS_MAX; i++) + if (handler->ns_on_clone_flags & ns_info[i].clone_flag) + INFO("Cloned %s", ns_info[i].flag_name); +@@ -1765,7 +2299,11 @@ static int lxc_spawn(struct lxc_handler *handler) + goto out_delete_net; + + if (!lxc_list_empty(&conf->limits)) { ++#ifdef HAVE_ISULAD ++ ret = setup_resource_limits(&conf->limits, handler->pid, conf->errpipe[1]); ++#else + ret = setup_resource_limits(&conf->limits, handler->pid); ++#endif + if (ret < 0) { + ERROR("Failed to setup resource limits"); + goto out_delete_net; +@@ -1816,6 +2354,26 @@ static int lxc_spawn(struct lxc_handler *handler) + ERROR("Failed to run lxc.hook.start-host"); + goto out_delete_net; + } ++#ifdef HAVE_ISULAD ++ /* isulad: Run oci prestart hook at here */ ++ ret = run_oci_hooks(name, "oci-prestart", conf, lxcpath); ++ if (ret < 0) { ++ ERROR("Failed to run oci prestart hooks"); ++ goto out_delete_net; ++ } ++ ++ if (START_TIMEOUT == global_timeout_state) { ++ lxc_write_error_message(conf->errpipe[1], "Starting the container \"%s\" timeout.", name); ++ ERROR("Starting the container \"%s\" timeout.", name); ++ goto out_delete_net; ++ } ++ ++ /* Tell the child to continue its initialization. We'll get ++ * LXC_SYNC_POST_OCI_PRESTART_HOOK when it is ready for us to run oci prestart hooks. ++ */ ++ if (lxc_sync_barrier_child(handler, LXC_SYNC_POST_OCI_PRESTART_HOOK)) ++ goto out_delete_net; ++#endif + + /* Tell the child to complete its initialization and wait for it to exec + * or return an error. (The child will never return +@@ -1859,6 +2417,22 @@ static int lxc_spawn(struct lxc_handler *handler) + if (ret < 0) + goto out_abort; + ++#ifdef HAVE_ISULAD ++ /* isulad: Run oci prestart hook at here */ ++ ret = run_oci_hooks(name, "oci-poststart", conf, lxcpath); ++ if (ret < 0) { ++ ERROR("Failed to run oci poststart hooks"); ++ goto out_abort; ++ } ++ ++ if (START_TIMEOUT == global_timeout_state) { ++ lxc_write_error_message(conf->errpipe[1], "Starting the container \"%s\" timeout.", name); ++ ERROR("Starting the container \"%s\" timeout.", name); ++ goto out_abort; ++ } ++ ++#endif ++ + ret = lxc_set_state(name, handler, RUNNING); + if (ret < 0) { + ERROR("Failed to set state to \"%s\"", lxc_state2str(RUNNING)); +@@ -1883,9 +2457,83 @@ out_sync_fini: + return -1; + } + ++#ifdef HAVE_ISULAD ++/* isulad: start timeout thread function */ ++static void* wait_start_timeout(void *arg) ++{ ++ struct start_timeout_conf *conf = (struct start_timeout_conf *)arg; ++ ++ sem_post(&global_timeout_sem); ++ ++ if (!conf || conf->timeout < 1) ++ goto out; ++ ++ sleep(conf->timeout); ++ ++ global_timeout_state = START_TIMEOUT; ++ ++out: ++ free(conf); ++ return ((void *)0); ++} ++ ++/* isulad: create start timeout thread */ ++static int create_start_timeout_thread(struct lxc_conf *conf, unsigned int start_timeout) ++{ ++ int ret = 0; ++ pthread_t ptid; ++ pthread_attr_t attr; ++ struct start_timeout_conf *timeout_conf = NULL; ++ ++ if (sem_init(&global_timeout_sem, 0, 0)) { ++ ERROR("Failed to init start timeout semaphore");/*lint !e613*/ ++ ret = -1; ++ return ret; ++ } ++ ++ timeout_conf = malloc(sizeof(struct start_timeout_conf)); ++ if (timeout_conf == NULL) { ++ ERROR("Failed to malloc start timeout conf"); ++ ret = -1; ++ goto out; ++ } ++ ++ memset(timeout_conf, 0, sizeof(struct start_timeout_conf)); ++ timeout_conf->errfd = conf->errpipe[1]; ++ timeout_conf->timeout = start_timeout; ++ ++ pthread_attr_init(&attr); ++ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); ++ ret = pthread_create(&ptid, &attr, wait_start_timeout, timeout_conf); ++ pthread_attr_destroy(&attr); ++ if (ret != 0) { ++ ERROR("Create start wait timeout thread failed"); ++ free(timeout_conf); ++ goto out; ++ } ++ ++ sem_wait(&global_timeout_sem); ++out: ++ sem_destroy(&global_timeout_sem); ++ return ret; ++} ++ ++// isulad: send '128 + signal' if container is killed by signal. ++#define EXIT_SIGNAL_OFFSET 128 ++#endif ++ ++ ++#ifdef HAVE_ISULAD ++int __lxc_start(struct lxc_handler *handler, struct lxc_operations *ops, ++ void *data, const char *lxcpath, bool daemonize, int *error_num, ++ unsigned int start_timeout) ++{ ++ int exit_code; ++#else + int __lxc_start(struct lxc_handler *handler, struct lxc_operations *ops, + void *data, const char *lxcpath, bool daemonize, int *error_num) + { ++#endif + int ret, status; + const char *name = handler->name; + struct lxc_conf *conf = handler->conf; +@@ -1901,6 +2549,16 @@ int __lxc_start(struct lxc_handler *handler, struct lxc_operations *ops, + handler->daemonize = daemonize; + cgroup_ops = handler->cgroup_ops; + ++#ifdef HAVE_ISULAD ++ /* isulad: add start timeout limit */ ++ if (start_timeout > 0) { ++ ret = create_start_timeout_thread(conf, start_timeout); ++ if (ret) { ++ ERROR("Failed to create start timeout thread for container \"%s\".", name); ++ goto out_abort; ++ } ++ } ++#endif + if (!attach_block_device(handler->conf)) { + ERROR("Failed to attach block device"); + ret = -1; +@@ -1959,11 +2617,13 @@ int __lxc_start(struct lxc_handler *handler, struct lxc_operations *ops, + goto out_delete_network; + } + ++#ifndef HAVE_ISULAD + if (!handler->init_died && handler->pid > 0) { + ERROR("Child process is not killed"); + ret = -1; + goto out_delete_network; + } ++#endif + + status = lxc_wait_for_pid_status(handler->pid); + if (status < 0) +@@ -1973,6 +2633,21 @@ int __lxc_start(struct lxc_handler *handler, struct lxc_operations *ops, + * reboot. This should mean it was an lxc-execute which simply exited. + * In any case, treat it as a 'halt'. + */ ++#ifdef HAVE_ISULAD ++ // isulad: recored log for container init exit ++ if (WIFSIGNALED(status)) { ++ int signal = WTERMSIG(status); ++ signal = WTERMSIG(status); ++ exit_code = EXIT_SIGNAL_OFFSET + signal; ++ ERROR("Container \"%s\" init exited with signal %d", name, signal); ++ } else if (WIFEXITED(status)) { ++ exit_code = WEXITSTATUS(status); ++ ERROR("Container \"%s\" init exited with status %d", name, exit_code); ++ } else { ++ exit_code = -1; ++ ERROR("Container \"%s\" init exited with unknown status", name); ++ } ++#else + if (WIFSIGNALED(status)) { + switch(WTERMSIG(status)) { + case SIGINT: /* halt */ +@@ -1990,6 +2665,7 @@ int __lxc_start(struct lxc_handler *handler, struct lxc_operations *ops, + break; + } + } ++#endif + + ret = lxc_restore_phys_nics_to_netns(handler); + if (ret < 0) +@@ -1997,11 +2673,20 @@ int __lxc_start(struct lxc_handler *handler, struct lxc_operations *ops, + + close_prot_errno_disarm(handler->pinfd); + ++#ifdef HAVE_ISULAD ++ lxc_monitor_send_exit_code(name, exit_code, handler->lxcpath); ++#else + lxc_monitor_send_exit_code(name, status, handler->lxcpath); ++#endif ++ + lxc_error_set_and_log(handler->pid, status); + if (error_num) + *error_num = handler->exit_status; + ++#ifdef HAVE_ISULAD ++ handler->exit_code = exit_code; /* record exit code */ ++#endif ++ + /* These are not the droids you are looking for. */ + __private_goto1: + lxc_delete_network(handler); +@@ -2032,7 +2717,11 @@ struct start_args { + char *const *argv; + }; + ++#ifdef HAVE_ISULAD ++static int start(struct lxc_handler *handler, void* data, int fd) ++#else + static int start(struct lxc_handler *handler, void* data) ++#endif + { + struct start_args *arg = data; + +@@ -2040,6 +2729,9 @@ static int start(struct lxc_handler *handler, void* data) + + execvp(arg->argv[0], arg->argv); + SYSERROR("Failed to exec \"%s\"", arg->argv[0]); ++#ifdef HAVE_ISULAD ++ lxc_write_error_message(fd, "exec: \"%s\": %s.", arg->argv[0], strerror(errno)); ++#endif + return 0; + } + +@@ -2057,14 +2749,22 @@ static struct lxc_operations start_ops = { + }; + + int lxc_start(char *const argv[], struct lxc_handler *handler, ++#ifdef HAVE_ISULAD ++ const char *lxcpath, bool daemonize, int *error_num, unsigned int start_timeout) ++#else + const char *lxcpath, bool daemonize, int *error_num) ++#endif + { + struct start_args start_arg = { + .argv = argv, + }; + + TRACE("Doing lxc_start"); ++#ifdef HAVE_ISULAD ++ return __lxc_start(handler, &start_ops, &start_arg, lxcpath, daemonize, error_num, start_timeout); ++#else + return __lxc_start(handler, &start_ops, &start_arg, lxcpath, daemonize, error_num); ++#endif + } + + static void lxc_destroy_container_on_signal(struct lxc_handler *handler, +@@ -2136,3 +2836,261 @@ static bool do_destroy_container(struct lxc_handler *handler) + + return storage_destroy(handler->conf); + } ++ ++#ifdef HAVE_ISULAD ++/*isulad: set env for clean resources */ ++static int clean_resource_set_env(struct lxc_handler *handler) ++{ ++ const char *name = handler->name; ++ struct lxc_conf *conf = handler->conf; ++ char bufstr[PATH_MAX + 1]; ++ int i = 0; ++ int j = 0; ++ int len = 2; //set "LXC_PID" and "LXC_CGNS_AWARE" ++ ++ if (conf == NULL || conf->ocihooks == NULL || conf->ocihooks->poststop_len == 0) { ++ return 0; ++ } ++ ++ if (name) { ++ len++; ++ } ++ if (conf->rcfile) { ++ len++; ++ } ++ if (conf->rootfs.mount) { ++ len++; ++ } ++ if (conf->rootfs.path) { ++ len++; ++ } ++ if (conf->console.path) { ++ len++; ++ } ++ if (conf->console.log_path) { ++ len++; ++ } ++ if (handler->cgroup_ops->container_cgroup) { ++ len++; ++ } ++ ++ for (; i < conf->ocihooks->poststop_len; i++) { ++ size_t cap = conf->ocihooks->poststop[i]->env_len; ++ size_t newcap = cap + len + 1; ++ if (lxc_grow_array((void ***)&(conf->ocihooks->poststop[i]->env), &cap, newcap, 1) != 0) { ++ return -1; ++ } ++ j = conf->ocihooks->poststop[i]->env_len; ++ /* Start of environment variable setup for hooks. */ ++ if (name) { ++ snprintf(bufstr, PATH_MAX + 1, "LXC_NAME=%s", name); ++ conf->ocihooks->poststop[i]->env[j++] = safe_strdup(bufstr); ++ } ++ if (conf->rcfile) { ++ snprintf(bufstr, PATH_MAX + 1, "LXC_CONFIG_FILE=%s", conf->rcfile); ++ conf->ocihooks->poststop[i]->env[j++] = safe_strdup(bufstr); ++ } ++ if (conf->rootfs.mount) { ++ snprintf(bufstr, PATH_MAX + 1, "LXC_ROOTFS_MOUNT=%s", conf->rootfs.mount); ++ conf->ocihooks->poststop[i]->env[j++] = safe_strdup(bufstr); ++ } ++ if (conf->rootfs.path) { ++ snprintf(bufstr, PATH_MAX + 1, "LXC_ROOTFS_PATH=%s", conf->rootfs.path); ++ conf->ocihooks->poststop[i]->env[j++] = safe_strdup(bufstr); ++ } ++ if (conf->console.path) { ++ snprintf(bufstr, PATH_MAX + 1, "LXC_CONSOLE=%s", conf->console.path); ++ conf->ocihooks->poststop[i]->env[j++] = safe_strdup(bufstr); ++ } ++ if (conf->console.log_path) { ++ snprintf(bufstr, PATH_MAX + 1, "LXC_CONSOLE_LOGPATH=%s", conf->console.log_path); ++ conf->ocihooks->poststop[i]->env[j++] = safe_strdup(bufstr); ++ } ++ conf->ocihooks->poststop[i]->env[j++] = safe_strdup("LXC_CGNS_AWARE=1"); ++ ++ snprintf(bufstr, PATH_MAX + 1, "LXC_PID=%d", handler->pid); ++ conf->ocihooks->poststop[i]->env[j++] = safe_strdup(bufstr); ++ if (handler->cgroup_ops->container_cgroup) { ++ snprintf(bufstr, PATH_MAX + 1, "LXC_CGROUP_PATH=%s", handler->cgroup_ops->container_cgroup); ++ conf->ocihooks->poststop[i]->env[j++] = safe_strdup(bufstr); ++ } ++ conf->ocihooks->poststop[i]->env_len = j; ++ /* End of environment variable setup for hooks. */ ++ } ++ return 0; ++} ++ ++/*isulad: init handler for clean */ ++static struct lxc_handler *lxc_init_clean_handler(char *name, char *lxcpath, struct lxc_conf *conf, pid_t pid) ++{ ++ int i; ++ struct lxc_handler *handler; ++ ++ handler = malloc(sizeof(*handler)); ++ if (handler == NULL) ++ return NULL; ++ ++ memset(handler, 0, sizeof(*handler)); ++ ++ /* Note that am_guest_unpriv() checks the effective uid. We ++ * probably don't care if we are real root only if we are running ++ * as root so this should be fine. ++ */ ++ handler->am_root = !am_guest_unpriv(); ++ handler->data_sock[0] = handler->data_sock[1] = -1; ++ handler->conf = conf; ++ handler->lxcpath = lxcpath; ++ handler->pinfd = -1; ++ handler->sigfd = -EBADF; ++ handler->pidfd = -EBADF; ++ handler->init_died = false; ++ handler->monitor_status_fd = -EBADF; ++ handler->pid = pid; ++ handler->state_socket_pair[0] = handler->state_socket_pair[1] = -1; ++ if (handler->conf->reboot == REBOOT_NONE) ++ lxc_list_init(&handler->conf->state_clients); ++ ++ for (i = 0; i < LXC_NS_MAX; i++) ++ handler->nsfd[i] = -1; ++ ++ handler->name = name; ++ handler->exit_code = -1; /* isulad: record exit code of container */ ++ ++ handler->cgroup_ops = cgroup_init(conf); ++ if (!handler->cgroup_ops) { ++ ERROR("Failed to initialize cgroup driver"); ++ goto on_error; ++ } ++ ++ INFO("Container \"%s\" 's clean handler is initialized.", name); ++ ++ return handler; ++ ++on_error: ++ lxc_put_handler(handler); ++ ++ return NULL; ++} ++ ++/*isulad: init handler for clean */ ++static struct lxc_handler *lxc_init_pids_handler(char *name, char *lxcpath, struct lxc_conf *conf) ++{ ++ int i; ++ struct lxc_handler *handler; ++ ++ handler = malloc(sizeof(*handler)); ++ if (handler == NULL) ++ return NULL; ++ ++ memset(handler, 0, sizeof(*handler)); ++ ++ /* Note that am_guest_unpriv() checks the effective uid. We ++ * probably don't care if we are real root only if we are running ++ * as root so this should be fine. ++ */ ++ handler->am_root = !am_guest_unpriv(); ++ handler->data_sock[0] = handler->data_sock[1] = -1; ++ handler->conf = conf; ++ handler->lxcpath = lxcpath; ++ handler->pinfd = -1; ++ handler->sigfd = -EBADF; ++ handler->init_died = false; ++ handler->state_socket_pair[0] = handler->state_socket_pair[1] = -1; ++ handler->monitor_status_fd = -EBADF; ++ handler->pidfd = -EBADF; ++ if (handler->conf->reboot == REBOOT_NONE) ++ lxc_list_init(&handler->conf->state_clients); ++ ++ for (i = 0; i < LXC_NS_MAX; i++) ++ handler->nsfd[i] = -1; ++ ++ handler->name = name; ++ handler->exit_code = -1; /* isulad: record exit code of container */ ++ ++ handler->cgroup_ops = cgroup_init(conf); ++ if (!handler->cgroup_ops) { ++ ERROR("Failed to initialize cgroup driver"); ++ goto on_error; ++ } ++ ++ INFO("Container \"%s\" 's clean handler is initialized.", name); ++ ++ return handler; ++ ++on_error: ++ lxc_put_handler(handler); ++ ++ return NULL; ++} ++ ++/*isulad: do_lxcapi_clean_resource */ ++int do_lxcapi_clean_resource(char *name, char *lxcpath, struct lxc_conf *conf, pid_t pid) ++{ ++ int ret = 0; ++ struct lxc_handler *handler = NULL; ++ int retry_count = 0; ++ int max_retry = 10; ++ ++ handler = lxc_init_clean_handler(name, lxcpath, conf, pid); ++ if (!handler) { ++ ERROR("Failed to init container %s clean handler", name); ++ ret = -1; ++ goto out; ++ } ++ ++ if (clean_resource_set_env(handler) != 0) { ++ ERROR("Failed to set env for poststop hooks"); ++ ret = -1; ++ goto out; ++ } ++ ++ if (run_oci_hooks(handler->name, "oci-poststop", handler->conf, handler->lxcpath)) { ++ ERROR("Failed to run lxc.hook.post-stop for container \"%s\".", handler->name); ++ ret = -1; ++ } ++ ++retry: ++ if (!handler->cgroup_ops->payload_destroy(handler->cgroup_ops, handler)) { ++ TRACE("Trying to kill all subprocess"); ++ signal_all_processes(handler); ++ TRACE("Finished kill all subprocess"); ++ if (retry_count < max_retry) { ++ usleep(100 * 1000); /* 100 millisecond */ ++ retry_count++; ++ goto retry; ++ } ++ SYSERROR("Failed to destroy cgroup path for container: \"%s\"", handler->name); ++ ret = -1; ++ } ++ ++out: ++ lxc_put_handler(handler); ++ return ret; ++} ++ ++/*isulad: do_lxcapi_get_pids */ ++int do_lxcapi_get_pids(char *name, char *lxcpath, struct lxc_conf *conf, pid_t **pids,size_t *pids_len) ++{ ++ int ret = 0; ++ struct lxc_handler *handler = NULL; ++ struct cgroup_ops *cg_ops = NULL; ++ ++ handler = lxc_init_pids_handler(name, lxcpath, conf); ++ if (!handler) { ++ ERROR("Failed to init container %s clean handler", name); ++ ret = -1; ++ goto out; ++ } ++ ++ cg_ops = handler->cgroup_ops; ++ ret = get_all_pids(cg_ops, pids, pids_len); ++ if (ret < 0) { ++ WARN("failed to get all pids"); ++ } ++ ++out: ++ lxc_put_handler(handler); ++ return ret; ++} ++ ++#endif +diff --git a/src/lxc/storage/btrfs.c b/src/lxc/storage/btrfs.c +index 92a4a6d..069a9dd 100644 +--- a/src/lxc/storage/btrfs.c ++++ b/src/lxc/storage/btrfs.c +@@ -197,16 +197,27 @@ int btrfs_mount(struct lxc_storage *bdev) + const char *src; + int ret; + ++#ifdef HAVE_ISULAD ++ unsigned long pflags = 0; ++#endif ++ + if (strcmp(bdev->type, "btrfs")) + return -22; + + if (!bdev->src || !bdev->dest) + return -22; + ++#ifdef HAVE_ISULAD ++ if (parse_mntopts(bdev->mntopts, &mntflags, &pflags, &mntdata) < 0) { ++ free(mntdata); ++ return -22; ++ } ++#else + if (parse_mntopts(bdev->mntopts, &mntflags, &mntdata) < 0) { + free(mntdata); + return -22; + } ++#endif + + src = lxc_storage_get_path(bdev->src, "btrfs"); + +diff --git a/src/lxc/storage/overlay.c b/src/lxc/storage/overlay.c +index 770785c..75a81de 100644 +--- a/src/lxc/storage/overlay.c ++++ b/src/lxc/storage/overlay.c +@@ -349,6 +349,9 @@ int ovl_mount(struct lxc_storage *bdev) + char *work, *lastslash; + size_t len, len2; + int ret, ret2; ++#ifdef HAVE_ISULAD ++ unsigned long pflags = 0; ++#endif + + if (strcmp(bdev->type, "overlay") && strcmp(bdev->type, "overlayfs")) + return -22; +@@ -414,7 +417,12 @@ int ovl_mount(struct lxc_storage *bdev) + work = must_make_path(upper, LXC_OVERLAY_WORK_DIR, NULL); + upper[lastslash - upper] = '/'; + ++#ifdef HAVE_ISULAD ++ ret = parse_mntopts(bdev->mntopts, &mntflags, &pflags, &mntdata); ++#else + ret = parse_mntopts(bdev->mntopts, &mntflags, &mntdata); ++#endif ++ + if (ret < 0) { + ERROR("Failed to parse mount options"); + free(mntdata); +diff --git a/src/lxc/sync.h b/src/lxc/sync.h +index ff7a1eb..56c1dfc 100644 +--- a/src/lxc/sync.h ++++ b/src/lxc/sync.h +@@ -11,6 +11,10 @@ enum { + LXC_SYNC_POST_CONFIGURE, + LXC_SYNC_CGROUP, + LXC_SYNC_CGROUP_UNSHARE, ++#ifdef HAVE_ISULAD ++ LXC_SYNC_OCI_PRESTART_HOOK, ++ LXC_SYNC_POST_OCI_PRESTART_HOOK, ++#endif + LXC_SYNC_CGROUP_LIMITS, + LXC_SYNC_READY_START, + LXC_SYNC_RESTART, +diff --git a/src/lxc/terminal.c b/src/lxc/terminal.c +index e58db5c..0539eca 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_PTY_H + #include +@@ -183,6 +187,69 @@ static int lxc_terminal_truncate_log_file(struct lxc_terminal *terminal) + return lxc_unpriv(ftruncate(terminal->log_fd, 0)); + } + ++#ifdef HAVE_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; +@@ -196,6 +263,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); + +@@ -212,6 +288,7 @@ static int lxc_terminal_rotate_log_file(struct lxc_terminal *terminal) + return lxc_terminal_create_log_file(terminal); + } + ++#ifndef HAVE_ISULAD + static int lxc_terminal_write_log_file(struct lxc_terminal *terminal, char *buf, + int bytes_read) + { +@@ -317,7 +394,465 @@ static int lxc_terminal_write_log_file(struct lxc_terminal *terminal, char *buf, + bytes_read -= ret; + return bytes_read; + } ++#endif ++ ++#ifdef HAVE_ISULAD ++/* get time buffer */ ++static bool get_time_buffer(struct timespec *timestamp, char *timebuffer, ++ size_t maxsize) ++{ ++ struct tm tm_utc = { 0 }; ++ int32_t nanos = 0; ++ time_t seconds; ++ size_t len = 0; ++ int ret = 0; ++ ++ if (!timebuffer || !maxsize) { ++ return false; ++ } ++ ++ seconds = (time_t)timestamp->tv_sec; ++ gmtime_r(&seconds, &tm_utc); ++ strftime(timebuffer, maxsize, "%Y-%m-%dT%H:%M:%S", &tm_utc); ++ ++ nanos = (int32_t)timestamp->tv_nsec; ++ len = strlen(timebuffer); ++ ret = snprintf(timebuffer + len, (maxsize - len), ".%09dZ", nanos); ++ if (ret < 0 || ret >= (maxsize - len)) { ++ return false; ++ } ++ ++ return true; ++} ++ ++/* get now time buffer */ ++static bool get_now_time_buffer(char *timebuffer, size_t maxsize) ++{ ++ int err = 0; ++ struct timespec ts; ++ ++ err = clock_gettime(CLOCK_REALTIME, &ts); ++ if (err != 0) { ++ ERROR("failed to get time"); ++ return false; ++ } ++ ++ return get_time_buffer(&ts, timebuffer, maxsize); ++} ++ ++static int isulad_lxc_terminal_rotate_write_data(struct lxc_terminal *terminal, const char *buf, ++ int bytes_read) ++{ ++ int ret; ++ struct stat st; ++ int64_t space_left = -1; ++ ++ if (terminal->log_fd < 0) ++ return 0; ++ ++ /* A log size <= 0 means that there's no limit on the size of the log ++ * file at which point we simply ignore whether the log is supposed to ++ * be rotated or not. ++ */ ++ if (terminal->log_size <= 0) ++ return lxc_write_nointr(terminal->log_fd, buf, bytes_read); ++ ++ /* Get current size of the log file. */ ++ ret = fstat(terminal->log_fd, &st); ++ if (ret < 0) { ++ SYSERROR("Failed to stat the terminal log file descriptor"); ++ return -1; ++ } ++ ++ /* handle non-regular files */ ++ if ((st.st_mode & S_IFMT) != S_IFREG) { ++ /* This isn't a regular file. so rotating the file seems a ++ * dangerous thing to do, size limits are also very ++ * questionable. Let's not risk anything and tell the user that ++ * he's requesting us to do weird stuff. ++ */ ++ if (terminal->log_rotate > 0 || terminal->log_size > 0) ++ return -EINVAL; ++ ++ /* I mean, sure log wherever you want to. */ ++ return lxc_write_nointr(terminal->log_fd, buf, bytes_read); ++ } ++ ++ space_left = terminal->log_size - st.st_size; ++ ++ /* User doesn't want to rotate the log file and there's no more space ++ * left so simply truncate it. ++ */ ++ if (space_left <= 0 && terminal->log_rotate <= 0) { ++ ret = lxc_terminal_truncate_log_file(terminal); ++ if (ret < 0) ++ return ret; ++ ++ if (bytes_read <= terminal->log_size) ++ return lxc_write_nointr(terminal->log_fd, buf, bytes_read); ++ ++ /* Write as much as we can into the buffer and loose the rest. */ ++ return lxc_write_nointr(terminal->log_fd, buf, terminal->log_size); ++ } ++ ++ /* There's enough space left. */ ++ if (bytes_read <= space_left) ++ return lxc_write_nointr(terminal->log_fd, buf, bytes_read); ++ ++ /* There'd be more to write but we aren't instructed to rotate the log ++ * file so simply return. There's no error on our side here. ++ */ ++ if (terminal->log_rotate > 0) ++ ret = lxc_terminal_rotate_log_file(terminal); ++ else ++ ret = lxc_terminal_truncate_log_file(terminal); ++ if (ret < 0) ++ return ret; ++ ++ if (terminal->log_size < bytes_read) { ++ /* Well, this is unfortunate because it means that there is more ++ * to write than the user has granted us space. There are ++ * multiple ways to handle this but let's use the simplest one: ++ * write as much as we can, tell the user that there was more ++ * stuff to write and move on. ++ * Note that this scenario shouldn't actually happen with the ++ * standard pty-based terminal that LXC allocates since it will ++ * be switched into raw mode. In raw mode only 1 byte at a time ++ * should be read and written. ++ */ ++ WARN("Size of terminal log file is smaller than the bytes to write"); ++ ret = lxc_write_nointr(terminal->log_fd, buf, terminal->log_size); ++ if (ret < 0) ++ return -1; ++ bytes_read -= ret; ++ return bytes_read; ++ } ++ ++ /* Yay, we made it. */ ++ ret = lxc_write_nointr(terminal->log_fd, buf, bytes_read); ++ if (ret < 0) ++ return -1; ++ bytes_read -= ret; ++ return bytes_read; ++} ++ ++static ssize_t isulad_logger_json_write(struct lxc_terminal *terminal, const char *type, const char *buf, ++ int bytes_read) ++{ ++ logger_json_file *msg = NULL; ++ ssize_t ret = -1; ++ size_t len; ++ char *json = NULL; ++ char timebuffer[64] = { 0 }; ++ parser_error err = NULL; ++ struct parser_context ctx = { GEN_OPTIONS_SIMPLIFY | GEN_OPTIONS_NOT_VALIDATE_UTF8, stderr }; ++ ++ if (bytes_read < 0 || bytes_read >= INT_MAX) { ++ return -1; ++ } ++ msg = calloc(sizeof(logger_json_file), 1); ++ if (msg == NULL) { ++ return -errno; ++ } ++ msg->log = calloc(bytes_read, 1); ++ if (!msg->log) { ++ goto cleanup; ++ } ++ memcpy(msg->log, buf, bytes_read); ++ msg->log_len = bytes_read; ++ msg->stream = type ? safe_strdup(type) : safe_strdup("stdout"); ++ ++ get_now_time_buffer(timebuffer, sizeof(timebuffer)); ++ msg->time = safe_strdup(timebuffer); ++ ++ json = logger_json_file_generate_json(msg, &ctx, &err); ++ if (!json) { ++ ERROR("Failed to generate json: %s", err); ++ goto cleanup; ++ } ++ len = strlen(json); ++ json[len] = '\n'; ++ ret = isulad_lxc_terminal_rotate_write_data(terminal, json, len + 1); ++cleanup: ++ free(json); ++ free_logger_json_file(msg); ++ free(err); ++ return ret; ++} ++ ++static ssize_t isulad_logger_syslog_write(struct lxc_terminal *terminal, const char *buf) ++{ ++ syslog(LOG_INFO, "%s", buf); ++ return 0; ++} ++ ++static inline bool is_syslog(const char *driver) ++{ ++ if (driver == NULL) { ++ return false; ++ } ++ ++ return (strcmp("syslog", driver) == 0); ++} ++ ++static inline ssize_t isulad_logger_write(struct lxc_terminal *terminal, const char *type, const char *buf, ++ int bytes_read) ++{ ++ if (is_syslog(terminal->log_driver)) { ++ return isulad_logger_syslog_write(terminal, buf); ++ } ++ ++ return isulad_logger_json_write(terminal, type, buf, bytes_read); ++} ++ ++static int isulad_lxc_terminal_write_log_file(struct lxc_terminal *terminal, const char *type, char *buf, ++ int bytes_read) ++{ ++#define __BUF_CACHE_SIZE (16 * LXC_TERMINAL_BUFFER_SIZE) ++ static char cache[__BUF_CACHE_SIZE]; ++ static int size = 0; ++ int upto, index; ++ int begin = 0, buf_readed = 0, buf_left = 0; ++ int ret; ++ ++ if (buf != NULL && bytes_read > 0) { ++ /* Work out how much more data we are okay with reading this time. */ ++ upto = size + bytes_read; ++ if (upto > __BUF_CACHE_SIZE) { ++ upto = __BUF_CACHE_SIZE; ++ } ++ ++ if (upto > size) { ++ buf_readed = upto - size; ++ memcpy(cache + size, buf, buf_readed); ++ buf_left = bytes_read - buf_readed; ++ size += buf_readed; ++ } ++ } ++ ++ // If we have no data to log, and there's no more coming, we're done. ++ if (size == 0) ++ return 0; ++ ++ // Break up the data that we've buffered up into lines, and log each in turn. ++ for (index = 0; index < size; index++) { ++ if (cache[index] == '\n') { ++ ret = isulad_logger_write(terminal, type, cache + begin, index - begin + 1); ++ if (ret < 0) { ++ WARN("Failed to log msg"); ++ } ++ begin = index + 1; ++ } ++ } ++ /* If there's no more coming, or the buffer is full but ++ * has no newlines, log whatever we haven't logged yet, ++ * noting that it's a partial log line. */ ++ if (buf == NULL || (begin == 0 && size == __BUF_CACHE_SIZE)) { ++ if (begin < size) { ++ ret = isulad_logger_write(terminal, type, cache + begin, size - begin); ++ if (ret < 0) { ++ WARN("Failed to log msg"); ++ } ++ begin = 0; ++ size = 0; ++ } ++ if (buf == NULL) { ++ return 0; ++ } ++ } ++ /* Move any unlogged data to the front of the buffer in preparation for another read. */ ++ if (begin > 0) { ++ memcpy(cache, cache + begin, size - begin); ++ size -= begin; ++ } ++ /* Move left data to cache buffer */ ++ if (buf_left > 0) { ++ memcpy(cache + size, buf + buf_readed, buf_left); ++ size += buf_left; ++ } ++ return 0; ++} ++ ++/* isulad: forward data to all fifos */ ++static void lxc_forward_data_to_fifo(struct lxc_list *list, bool is_err, const char *buf, int r) ++{ ++ struct lxc_list *it = NULL; ++ struct lxc_list *next = NULL; ++ struct lxc_fifos_fd *elem = NULL; ++ ssize_t w = 0; ++ ++ lxc_list_for_each_safe(it, list, next) { ++ elem = it->elem; ++ if (is_err) { ++ if (elem->err_fd >= 0) { ++ w = lxc_write_nointr_for_fifo(elem->err_fd, buf, r); ++ if (w != r) { ++ WARN("Failed to write to fifo fd %d with error: %s", elem->err_fd, strerror(errno)); ++ } ++ } ++ } else { ++ if (elem->out_fd >= 0) { ++ w = lxc_write_nointr_for_fifo(elem->out_fd, buf, r); ++ if (w != r) { ++ WARN("Failed to write to fifo fd %d with error: %s", elem->out_fd, strerror(errno)); ++ } ++ } ++ } ++ } ++ ++ return; ++} ++ ++/* isulad: judge the fd whether is fifo */ ++static bool lxc_terminal_is_fifo(int fd, struct lxc_list *list) ++{ ++ struct lxc_list *it = NULL; ++ struct lxc_list *next = NULL; ++ struct lxc_fifos_fd *elem = NULL; ++ ++ lxc_list_for_each_safe(it, list, next) { ++ elem = it->elem; ++ if (elem->in_fd == fd) ++ return true; ++ } ++ ++ return false; ++} ++ ++/* isulad: if fd == -1, means delete all the fifos*/ ++int lxc_terminal_delete_fifo(int fd, struct lxc_list *list) ++{ ++ struct lxc_list *it = NULL; ++ struct lxc_list *next = NULL; ++ struct lxc_fifos_fd *elem = NULL; ++ ++ lxc_list_for_each_safe(it, list, next) { ++ elem = it->elem; ++ if (elem->in_fd == fd || -1 == fd) { ++ INFO("Delete fifo fd %d", fd); ++ lxc_list_del(it); ++ if (elem->in_fifo) ++ free(elem->in_fifo); ++ if (elem->out_fifo) ++ free(elem->out_fifo); ++ if (elem->err_fifo) ++ free(elem->err_fifo); ++ if (elem->in_fd >= 0) ++ close(elem->in_fd); ++ if (elem->out_fd >= 0) ++ close(elem->out_fd); ++ if (elem->err_fd >= 0) ++ close(elem->err_fd); ++ free(elem); ++ } ++ } ++ ++ return 0; ++} ++ ++int lxc_terminal_io_cb(int fd, uint32_t events, void *data, ++ struct lxc_epoll_descr *descr) ++{ ++ struct lxc_terminal *terminal = data; ++ char buf[2 * LXC_TERMINAL_BUFFER_SIZE]; ++ int r, w, w_log, w_rbuf; ++ ++ w = r = lxc_read_nointr(fd, buf, sizeof(buf)); ++ if (r <= 0) { ++ INFO("Terminal client on fd %d has exited", fd); ++ lxc_mainloop_del_handler(descr, fd); ++ ++ if (fd == terminal->ptmx) { ++ terminal->ptmx = -EBADF; ++ /* write remained buffer to terminal log */ ++ if (terminal->log_fd >= 0) { ++ w_log = isulad_lxc_terminal_write_log_file(terminal, "stdout", NULL, 0); ++ if (w_log < 0) ++ TRACE("Failed to write %d bytes to terminal log", r); ++ } ++ /* notes: do not close the ptmx fd due to if we close the fd, the process may ++ * recive SIGHUP and the exit code will be 129 (128 + 1) ++ */ ++ return LXC_MAINLOOP_CLOSE; ++ } else if (fd == terminal->peer) { ++ lxc_terminal_signal_fini(terminal); ++ terminal->peer = -EBADF; ++ close(fd); ++ return LXC_MAINLOOP_CONTINUE; /* isulad: do not close mainloop when peer close*/ ++ } else if (lxc_terminal_is_fifo(fd, &terminal->fifos)) { ++ /* isulad: delete fifos when the client close */ ++ lxc_terminal_delete_fifo(fd, &terminal->fifos); ++ return LXC_MAINLOOP_CONTINUE; ++ } else if (fd == terminal->pipes[1][0] || fd == terminal->pipes[2][0]) { ++ if (fd == terminal->pipes[1][0]) { ++ if (terminal->log_fd >= 0) { ++ w_log = isulad_lxc_terminal_write_log_file(terminal, "stdout", NULL, 0); ++ } ++ terminal->pipes[1][0] = -EBADF; ++ } else if (fd == terminal->pipes[2][0]) { ++ if (terminal->log_fd >= 0) { ++ w_log = isulad_lxc_terminal_write_log_file(terminal, "stderr", NULL, 0); ++ } ++ terminal->pipes[2][0] = -EBADF; ++ } ++ /* notes: do not close the ptmx fd due to if we close the fd, the process may ++ * recive SIGHUP and the exit code will be 141 (128 + 13) ++ */ ++ return LXC_MAINLOOP_CONTINUE; ++ } else if (fd == terminal->pipes[0][1]) { ++ TRACE("closed stdin pipe of container stdin"); ++ terminal->pipes[0][1] = -EBADF; ++ return LXC_MAINLOOP_CONTINUE; ++ } else { ++ WARN("Handler received unexpected file descriptor"); ++ } ++ close(fd); ++ return LXC_MAINLOOP_CLOSE; ++ } ++ ++ if (fd == terminal->peer || lxc_terminal_is_fifo(fd, &terminal->fifos)) { ++ if (terminal->ptmx > 0) ++ w = lxc_write_nointr(terminal->ptmx, buf, r); ++ if (terminal->pipes[0][1] > 0) ++ w = lxc_write_nointr(terminal->pipes[0][1], buf, r); ++ } ++ ++ w_rbuf = w_log = 0; ++ if (fd == terminal->ptmx || 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->ptmx || fd == terminal->pipes[1][0]) ++ w_log = isulad_lxc_terminal_write_log_file(terminal, "stdout", buf, r); ++ else if (fd == terminal->pipes[2][0]) ++ w_log = isulad_lxc_terminal_write_log_file(terminal, "stderr", buf, r); ++ } ++ } ++ ++ if (w != r) ++ WARN("Short write on terminal 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 LXC_MAINLOOP_CONTINUE; ++} ++#else + int lxc_terminal_io_cb(int fd, uint32_t events, void *data, + struct lxc_epoll_descr *descr) + { +@@ -374,6 +909,7 @@ int lxc_terminal_io_cb(int fd, uint32_t events, void *data, + + return LXC_MAINLOOP_CONTINUE; + } ++#endif + + static int lxc_terminal_mainloop_add_peer(struct lxc_terminal *terminal) + { +@@ -401,6 +937,110 @@ static int lxc_terminal_mainloop_add_peer(struct lxc_terminal *terminal) + return 0; + } + ++#ifdef HAVE_ISULAD ++/* isulad add pipes to mainloop */ ++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], ++ lxc_terminal_io_cb, terminal); ++ 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], ++ lxc_terminal_io_cb, terminal); ++ 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], ++ lxc_terminal_io_cb, terminal); ++ if (ret) { ++ ERROR("pipe fd %d not added to mainloop", terminal->pipes[2][0]); ++ return -1; ++ } ++ } ++ return ret; ++} ++ ++/* isulad add fifo to mainloop */ ++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, ++ lxc_terminal_io_cb, terminal); ++ if (ret) { ++ ERROR("console fifo %s not added to mainloop", elem->in_fifo); ++ return -1; ++ } ++ } ++ } ++ return ret; ++} ++ ++int lxc_terminal_mainloop_add(struct lxc_epoll_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; ++ } ++ ++ if (terminal->ptmx < 0) { ++ INFO("Terminal is not initialized"); ++ return 0; ++ } ++ ++ ret = lxc_mainloop_add_handler(descr, terminal->ptmx, ++ lxc_terminal_io_cb, terminal); ++ if (ret < 0) { ++ ERROR("Failed to add handler for terminal ptmx fd %d to " ++ "mainloop", terminal->ptmx); ++ return -1; ++ } ++ ++ return 0; ++} ++#else + int lxc_terminal_mainloop_add(struct lxc_epoll_descr *descr, + struct lxc_terminal *terminal) + { +@@ -426,6 +1066,7 @@ int lxc_terminal_mainloop_add(struct lxc_epoll_descr *descr, + + return lxc_terminal_mainloop_add_peer(terminal); + } ++#endif + + int lxc_setup_tios(int fd, struct termios *oldtios) + { +@@ -639,14 +1280,39 @@ void lxc_terminal_free(struct lxc_conf *conf, int fd) + + static int lxc_terminal_peer_default(struct lxc_terminal *terminal) + { ++#ifdef HAVE_ISULAD ++ struct lxc_terminal_state *ts = NULL; ++ const char *path = NULL; ++#else + struct lxc_terminal_state *ts; + const char *path; ++#endif + int ret = 0; + + 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) { +@@ -760,6 +1426,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 + } + + /** +@@ -828,6 +1523,251 @@ int lxc_terminal_create_log_file(struct lxc_terminal *terminal) + 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; ++} ++ ++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; ++} ++ ++int lxc_terminal_create(struct lxc_terminal *terminal) ++{ ++ int ret; ++ ++ if (!terminal->disable_pty) { ++ ret = openpty(&terminal->ptmx, &terminal->pts, NULL, NULL, NULL); ++ if (ret < 0) { ++ SYSERROR("Failed to open terminal"); ++ return -1; ++ } ++ ++ ret = ttyname_r(terminal->pts, terminal->name, sizeof(terminal->name)); ++ if (ret < 0) { ++ SYSERROR("Failed to retrieve name of terminal pts"); ++ goto err; ++ } ++ ++ ret = fd_cloexec(terminal->ptmx, true); ++ if (ret < 0) { ++ SYSERROR("Failed to set FD_CLOEXEC flag on terminal ptmx"); ++ goto err; ++ } ++ ++ /* isulad: make ptmx NONBLOCK */ ++ ret = fd_nonblock(terminal->ptmx); ++ if (ret < 0) { ++ SYSERROR("Failed to set O_NONBLOCK flag on terminal ptmx"); ++ goto err; ++ } ++ ++ ret = fd_cloexec(terminal->pts, true); ++ if (ret < 0) { ++ SYSERROR("Failed to set FD_CLOEXEC flag on terminal pts"); ++ goto err; ++ } ++ ++ ret = lxc_terminal_peer_default(terminal); ++ if (ret < 0) { ++ ERROR("Failed to allocate proxy terminal"); ++ goto err; ++ } ++ } else { ++ /* isulad: create 3 pipes */ ++ /* for stdin */ ++ if (pipe2(terminal->pipes[0], O_CLOEXEC)) { ++ ERROR("Failed to create stdin pipe"); ++ goto err; ++ } ++ ++ /* for stdout */ ++ if (pipe2(terminal->pipes[1], O_CLOEXEC)) { ++ ERROR("Failed to create stdout pipe"); ++ goto err; ++ } ++ /* for stderr */ ++ if (pipe2(terminal->pipes[2], O_CLOEXEC)) { ++ ERROR("Failed to create stderr pipe"); ++ goto err; ++ } ++ } ++ ++ /* isulad: open fifos */ ++ ret = lxc_terminal_fifo_default(terminal); ++ if (ret < 0) { ++ ERROR("Failed to allocate fifo terminal"); ++ goto err; ++ } ++ ++ return 0; ++ ++err: ++ lxc_terminal_delete(terminal); ++ return -ENODEV; ++} ++ ++/* 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; ++} ++ ++#else + int lxc_terminal_create(struct lxc_terminal *terminal) + { + int ret; +@@ -868,6 +1808,7 @@ err: + lxc_terminal_delete(terminal); + return -ENODEV; + } ++#endif + + int lxc_terminal_setup(struct lxc_conf *conf) + { +@@ -883,6 +1824,18 @@ int lxc_terminal_setup(struct lxc_conf *conf) + if (ret < 0) + return -1; + ++#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; +@@ -1120,9 +2073,15 @@ int lxc_terminal_prepare_login(int fd) + if (ret < 0) + return -1; + ++#ifdef HAVE_ISULAD ++ ret = set_stdfds(fd); ++ if (ret < 0) ++ return -1; ++#else + ret = lxc_terminal_set_stdfds(fd); + if (ret < 0) + return -1; ++#endif + + if (fd > STDERR_FILENO) + close(fd); +@@ -1146,6 +2105,18 @@ 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) +@@ -1155,6 +2126,15 @@ 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 + } + + int lxc_terminal_map_ids(struct lxc_conf *c, struct lxc_terminal *terminal) +@@ -1167,6 +2147,15 @@ int lxc_terminal_map_ids(struct lxc_conf *c, struct lxc_terminal *terminal) + if (strcmp(terminal->name, "") == 0) + return 0; + ++#ifdef HAVE_ISULAD ++ ret = chown_mapped_root(terminal->name, c); ++ if (ret < 0) { ++ ERROR("Failed to chown terminal \"%s\"", terminal->name); ++ return -1; ++ } ++ ++ TRACE("Chowned terminal \"%s\"", terminal->name); ++#else + ret = userns_exec_mapped_root(terminal->name, terminal->pts, c); + if (ret < 0) { + return log_error(-1, "Failed to chown terminal %d(%s)", +@@ -1174,6 +2163,7 @@ int lxc_terminal_map_ids(struct lxc_conf *c, struct lxc_terminal *terminal) + } + + TRACE("Chowned terminal %d(%s)", terminal->pts, terminal->name); ++#endif + + return 0; + } +diff --git a/src/tests/Makefile.am b/src/tests/Makefile.am +index 11bba26..03bf439 100644 +--- a/src/tests/Makefile.am ++++ b/src/tests/Makefile.am +@@ -58,6 +58,10 @@ AM_CFLAGS=-DLXCROOTFSMOUNT=\"$(LXCROOTFSMOUNT)\" \ + -I $(top_srcdir)/src/lxc/tools \ + -pthread + ++if HAVE_ISULAD ++AM_CFLAGS += -I $(top_srcdir)/src/lxc/json ++endif ++ + if ENABLE_APPARMOR + AM_CFLAGS += -DHAVE_APPARMOR + endif +diff --git a/src/tests/attach.c b/src/tests/attach.c +index 07e641d..f36caac 100644 +--- a/src/tests/attach.c ++++ b/src/tests/attach.c +@@ -29,6 +29,9 @@ + #include "lxctest.h" + #include "utils.h" + #include "lsm/lsm.h" ++#ifdef HAVE_ISULAD ++#include "config.h" ++#endif + + #include + +@@ -76,7 +79,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_process_label_get(syscall(SYS_getpid))); + return 0; +@@ -187,7 +194,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 + diff --git a/0001-iSulad-add-json-files-and-adapt-to-meson.patch b/0008-refactor-patch-code-of-json.patch similarity index 70% rename from 0001-iSulad-add-json-files-and-adapt-to-meson.patch rename to 0008-refactor-patch-code-of-json.patch index d08c5e1405fb341821920b9b2bb17fdfc673538e..217af9e97009906a30eb04a5ae76a2bfe1089856 100644 --- a/0001-iSulad-add-json-files-and-adapt-to-meson.patch +++ b/0008-refactor-patch-code-of-json.patch @@ -1,44 +1,24 @@ -From 757bc66c44a58ca2d65eb4c8199ad55cba580d00 Mon Sep 17 00:00:00 2001 -From: haozi007 -Date: Fri, 14 Jul 2023 11:21:56 +0800 -Subject: [PATCH 1/3] [iSulad] add json files and adapt to meson +From 4c68aefb92800112f48aa73a55f80b368b09c69f Mon Sep 17 00:00:00 2001 +From: zhangxiaoyu +Date: Wed, 20 Jul 2022 11:00:13 +0800 +Subject: [PATCH] refactor patch code of json -Signed-off-by: haozi007 +Signed-off-by: zhangxiaoyu --- - meson.build | 30 +- - meson_options.txt | 8 + - src/lxc/af_unix.c | 50 + - src/lxc/af_unix.h | 5 + - src/lxc/cgroups/isulad_cgfsng.c | 3229 ++++++++++++++++++++++++++++++ - src/lxc/commands.c | 179 ++ - src/lxc/commands.h | 10 + - src/lxc/commands_utils.c | 57 + - src/lxc/commands_utils.h | 7 + - src/lxc/exec_commands.c | 477 +++++ - src/lxc/exec_commands.h | 77 + - src/lxc/isulad_utils.c | 535 +++++ - src/lxc/isulad_utils.h | 102 + + src/lxc/cgroups/isulad_cgfsng.c | 3223 ++++++++++++++++++++++++++++++ src/lxc/json/defs.c | 205 ++ src/lxc/json/defs.h | 37 + src/lxc/json/json_common.c | 1153 +++++++++++ - src/lxc/json/json_common.h | 194 ++ + src/lxc/json/json_common.h | 185 ++ src/lxc/json/logger_json_file.c | 246 +++ src/lxc/json/logger_json_file.h | 45 + src/lxc/json/oci_runtime_hooks.c | 52 + src/lxc/json/oci_runtime_hooks.h | 15 + src/lxc/json/oci_runtime_spec.c | 195 ++ src/lxc/json/oci_runtime_spec.h | 37 + - src/lxc/json/read-file.c | 95 + src/lxc/json/read-file.h | 11 + - src/lxc/meson.build | 26 +- - src/lxc/path.c | 521 +++++ - src/lxc/path.h | 33 + - 28 files changed, 7629 insertions(+), 2 deletions(-) + 12 files changed, 5404 insertions(+) create mode 100644 src/lxc/cgroups/isulad_cgfsng.c - create mode 100644 src/lxc/exec_commands.c - create mode 100644 src/lxc/exec_commands.h - create mode 100644 src/lxc/isulad_utils.c - create mode 100644 src/lxc/isulad_utils.h create mode 100644 src/lxc/json/defs.c create mode 100644 src/lxc/json/defs.h create mode 100755 src/lxc/json/json_common.c @@ -49,183 +29,14 @@ Signed-off-by: haozi007 create mode 100644 src/lxc/json/oci_runtime_hooks.h create mode 100644 src/lxc/json/oci_runtime_spec.c create mode 100644 src/lxc/json/oci_runtime_spec.h - create mode 100644 src/lxc/json/read-file.c create mode 100644 src/lxc/json/read-file.h - create mode 100644 src/lxc/path.c - create mode 100644 src/lxc/path.h -diff --git a/meson.build b/meson.build -index 1b2d673..fda8045 100644 ---- a/meson.build -+++ b/meson.build -@@ -163,6 +163,8 @@ want_seccomp = get_option('seccomp') - want_thread_safety = get_option('thread-safety') - want_memfd_rexec = get_option('memfd-rexec') - want_sd_bus = get_option('sd-bus') -+want_isulad = get_option('isulad') -+want_securecomplie = get_option('securecomplie') - - srcconf.set_quoted('DEFAULT_CGROUP_PATTERN', cgrouppattern) - if coverity -@@ -228,6 +230,19 @@ possible_link_flags = [ - '-fstack-protector-strong', - ] - -+if want_isulad -+ possible_cc_flags += ['-D_FORTIFY_SOURCE=2'] -+ yajldep = dependency('yajl', version : '>=2') -+ srcconf.set('HAVE_ISULAD', yajldep.found()) -+ liblxc_dependencies += yajldep -+else -+ srcconf.set('HAVE_ISULAD', false) -+endif -+ -+if want_isulad or want_securecomplie -+ possible_link_flags += ['-Wl,-z,noexecstack'] -+endif -+ - # The gold linker fails with a bus error on sparc64 - if build_machine.cpu_family() != 'sparc64' - possible_link_flags += '-Wl,-fuse-ld=gold' -@@ -881,13 +896,24 @@ template_scripts = [] - test_programs = [] - - # Includes. -+if want_isulad - liblxc_includes = include_directories( - '.', - 'src', - 'src/include', - 'src/lxc', -+ 'src/lxc/json', - 'src/lxc/cgroups', - 'src/lxc/storage') -+else -+liblxc_includes = include_directories( -+ '.', -+ 'src', -+ 'src/include', -+ 'src/lxc', -+ 'src/lxc/cgroups', -+ 'src/lxc/storage') -+endif - - # Our static sub-project binaries don't (and in fact can't) link to our - # dependencies directly, but need access to the headers when compiling (most -@@ -942,7 +968,9 @@ subdir('doc/ja') - subdir('doc/ko') - subdir('doc/examples') - subdir('doc/rootfs') --subdir('hooks') -+if not want_isulad -+ subdir('hooks') -+endif - if want_commands - subdir('src/lxc/cmd') - endif -diff --git a/meson_options.txt b/meson_options.txt -index 9803473..7146b17 100644 ---- a/meson_options.txt -+++ b/meson_options.txt -@@ -120,3 +120,11 @@ option('memfd-rexec', type : 'boolean', value : 'true', - - option('distrosysconfdir', type : 'string', value: '', - description: 'relative path to sysconfdir for distro default configuration') -+ -+# was --{disable,enable}-isulad in autotools -+option('isulad', type: 'boolean', value: 'true', -+ description: 'enable adapt to iSulad') -+ -+# was --{disable,enable}-securecomplie in autotools -+option('securecomplie', type: 'boolean', value: 'true', -+ description: 'enable secure compile') -\ No newline at end of file -diff --git a/src/lxc/af_unix.c b/src/lxc/af_unix.c -index 6f05b70..6db1864 100644 ---- a/src/lxc/af_unix.c -+++ b/src/lxc/af_unix.c -@@ -516,7 +516,11 @@ int lxc_unix_connect_type(struct sockaddr_un *addr, int type) - ret = connect(fd, (struct sockaddr *)addr, - offsetof(struct sockaddr_un, sun_path) + len); - if (ret < 0) -+#ifdef HAVE_ISULAD -+ return syswarn("Failed to connect AF_UNIX socket"); -+#else - return syserror("Failed to connect AF_UNIX socket"); -+#endif - - return move_fd(fd); - } -@@ -545,3 +549,49 @@ int lxc_socket_set_timeout(int fd, int rcv_timeout, int snd_timeout) - - return 0; - } -+ -+#ifdef HAVE_ISULAD -+int lxc_named_unix_open(const char *path, int type, int flags) -+{ -+ __do_close int fd = -EBADF; -+ int ret; -+ ssize_t len; -+ struct sockaddr_un addr; -+ -+ fd = socket(PF_UNIX, type | SOCK_CLOEXEC, 0); -+ if (fd < 0) -+ return -1; -+ -+ if (!path) -+ return move_fd(fd); -+ -+ len = lxc_unix_sockaddr(&addr, path); -+ if (len < 0) -+ return -1; -+ -+ ret = bind(fd, (struct sockaddr *)&addr, len); -+ if (ret < 0) -+ return -1; -+ -+ if (chmod(path, 0600) < 0) -+ return -1; -+ -+ if (type == SOCK_STREAM) { -+ ret = listen(fd, 100); -+ if (ret < 0) -+ return -1; -+ } -+ -+ return move_fd(fd); -+} -+ -+int lxc_named_unix_connect(const char *path) -+{ -+ struct sockaddr_un addr; -+ -+ if (lxc_unix_sockaddr(&addr, path) < 0) -+ return -1; -+ -+ return lxc_unix_connect_type(&addr, SOCK_STREAM); -+} -+#endif -diff --git a/src/lxc/af_unix.h b/src/lxc/af_unix.h -index ba119cf..605afc2 100644 ---- a/src/lxc/af_unix.h -+++ b/src/lxc/af_unix.h -@@ -168,4 +168,9 @@ static inline void put_unix_fds(struct unix_fds *fds) - } - define_cleanup_function(struct unix_fds *, put_unix_fds); - -+#ifdef HAVE_ISULAD -+__hidden extern int lxc_named_unix_open(const char *path, int type, int flags); -+__hidden extern int lxc_named_unix_connect(const char *path); -+#endif -+ - #endif /* __LXC_AF_UNIX_H */ diff --git a/src/lxc/cgroups/isulad_cgfsng.c b/src/lxc/cgroups/isulad_cgfsng.c new file mode 100644 -index 0000000..dcaa229 +index 0000000..8a9656a --- /dev/null +++ b/src/lxc/cgroups/isulad_cgfsng.c -@@ -0,0 +1,3229 @@ +@@ -0,0 +1,3223 @@ +/****************************************************************************** + * Copyright (c) Huawei Technologies Co., Ltd. 2019. All rights reserved. + * Author: lifeng @@ -905,14 +716,15 @@ index 0000000..dcaa229 + return false; + } + ++#ifdef HAVE_ISULAD + if (ops->no_controller) { -+ DEBUG("no controller found, ignore isulad_cgfsng_payload_destroy"); ++ DEBUG("no controller found, isgnore isulad_cgfsng_payload_destroy"); + return true; + } ++#endif + + if (!ops->hierarchies) { -+ DEBUG("no hierarchies found, ignore isulad_cgfsng_payload_destroy"); -+ return true; ++ return false; + } + + if (!handler) { @@ -1166,15 +978,8 @@ index 0000000..dcaa229 + struct lxc_handler *handler) +{ + int i; -+ -+ if (!ops) -+ return ret_set_errno(false, ENOENT); -+ + char *container_cgroup = ops->container_cgroup; + -+ if (!ops->hierarchies) -+ return true; -+ +#ifdef HAVE_ISULAD + if (ops->no_controller) { + DEBUG("no controller found, isgnore isulad_cgfsng_payload_create"); @@ -2698,7 +2503,7 @@ index 0000000..dcaa229 + goto retry; + } + lxc_write_error_message(ops->errfd, -+ "%s:%d: setting cgroup config for ready process caused failed to write %s to %s: %s", ++ "%s:%d: setting cgroup config for ready process caused \"failed to write %s to %s: %s\".", + __FILE__, __LINE__, value, fullpath, strerror(errno)); + } + free(fullpath); @@ -3455,2214 +3260,1179 @@ index 0000000..dcaa229 + + return move_ptr(cgfsng_ops); +} -diff --git a/src/lxc/commands.c b/src/lxc/commands.c -index 07be1d5..2188b31 100644 ---- a/src/lxc/commands.c -+++ b/src/lxc/commands.c -@@ -90,6 +90,10 @@ static const char *lxc_cmd_str(lxc_cmd_t cmd) - [LXC_CMD_GET_CGROUP_FD] = "get_cgroup_fd", - [LXC_CMD_GET_LIMIT_CGROUP_FD] = "get_limit_cgroup_fd", - [LXC_CMD_GET_SYSTEMD_SCOPE] = "get_systemd_scope", -+#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) -@@ -223,6 +227,12 @@ static ssize_t lxc_cmd_rsp_recv(int sock, struct lxc_cmd_rr *cmd) - break; - } - -+#ifdef HAVE_ISULAD -+ /*isulad: add timeout 3s to avoid long block due to [lxc monitor] error*/ -+ if (lxc_socket_set_timeout(sock, 3, 3) != 0) { -+ return syserror_ret(-1, "Failed to set timeout"); -+ } -+#endif - /* Receive the first response including file descriptors if any. */ - bytes_recv = lxc_cmd_rsp_recv_fds(sock, fds, rsp, cur_cmdstr); - if (bytes_recv < 0) -@@ -1576,7 +1586,12 @@ 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 -+ // for check connect failed, we just log warnning -+ return log_warn_errno(-1, errno, "Failed to serve state clients"); -+#else - return log_error_errno(-1, errno, "Failed to serve state clients"); +diff --git a/src/lxc/json/defs.c b/src/lxc/json/defs.c +new file mode 100644 +index 0000000..4bf569a +--- /dev/null ++++ b/src/lxc/json/defs.c +@@ -0,0 +1,205 @@ ++// Generated from defs.json. Do not edit! ++#ifndef _GNU_SOURCE ++#define _GNU_SOURCE +#endif - - return 0; - } -@@ -1916,6 +1931,125 @@ static int lxc_cmd_rsp_send_enosys(int fd, int id) - return syserror_set(-ENOSYS, "Invalid command id %d", id); - } - -+#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; -+ bool stopped = false; -+ 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_reap(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; -+ bool stopped = false; -+ 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);; ++#include ++#include ++#include "defs.h" + -+ return lxc_cmd_rsp_send_reap(fd, &rsp); ++defs_hook *make_defs_hook(yajl_val tree, struct parser_context *ctx, parser_error *err) { ++ defs_hook *ret = NULL; ++ *err = 0; ++ if (tree == NULL) ++ return ret; ++ ret = safe_malloc(sizeof(*ret)); ++ { ++ yajl_val val = get_val(tree, "path", yajl_t_string); ++ if (val != NULL) { ++ char *str = YAJL_GET_STRING(val); ++ ret->path = safe_strdup(str ? str : ""); ++ } ++ } ++ { ++ yajl_val tmp = get_val(tree, "args", yajl_t_array); ++ if (tmp != NULL && YAJL_GET_ARRAY(tmp) != NULL && YAJL_GET_ARRAY(tmp)->len > 0) { ++ size_t i; ++ ret->args_len = YAJL_GET_ARRAY(tmp)->len; ++ if (YAJL_GET_ARRAY(tmp)->len > SIZE_MAX / sizeof(*ret->args) - 1) { ++ free_defs_hook(ret); ++ return NULL; ++ } ++ ret->args = safe_malloc((YAJL_GET_ARRAY(tmp)->len + 1) * sizeof(*ret->args)); ++ for (i = 0; i < YAJL_GET_ARRAY(tmp)->len; i++) { ++ yajl_val val = YAJL_GET_ARRAY(tmp)->values[i]; ++ if (val != NULL) { ++ char *str = YAJL_GET_STRING(val); ++ ret->args[i] = safe_strdup(str ? str : ""); ++ } ++ } ++ } ++ } ++ { ++ yajl_val tmp = get_val(tree, "env", yajl_t_array); ++ if (tmp != NULL && YAJL_GET_ARRAY(tmp) != NULL && YAJL_GET_ARRAY(tmp)->len > 0) { ++ size_t i; ++ ret->env_len = YAJL_GET_ARRAY(tmp)->len; ++ if (YAJL_GET_ARRAY(tmp)->len > SIZE_MAX / sizeof(*ret->env) - 1) { ++ free_defs_hook(ret); ++ return NULL; ++ } ++ ret->env = safe_malloc((YAJL_GET_ARRAY(tmp)->len + 1) * sizeof(*ret->env)); ++ for (i = 0; i < YAJL_GET_ARRAY(tmp)->len; i++) { ++ yajl_val val = YAJL_GET_ARRAY(tmp)->values[i]; ++ if (val != NULL) { ++ char *str = YAJL_GET_STRING(val); ++ ret->env[i] = safe_strdup(str ? str : ""); ++ } ++ } ++ } ++ } ++ { ++ yajl_val val = get_val(tree, "timeout", yajl_t_number); ++ if (val != NULL) { ++ int invalid = common_safe_int(YAJL_GET_NUMBER(val), (int *)&ret->timeout); ++ if (invalid) { ++ if (asprintf(err, "Invalid value '%s' with type 'integer' for key 'timeout': %s", YAJL_GET_NUMBER(val), strerror(-invalid)) < 0) ++ *err = safe_strdup("error allocating memory"); ++ free_defs_hook(ret); ++ return NULL; ++ } ++ } ++ } ++ if (ret->path == NULL) { ++ if (asprintf(err, "Required field '%s' not present", "path") < 0) ++ *err = safe_strdup("error allocating memory"); ++ free_defs_hook(ret); ++ return NULL; ++ } + ++ if (tree->type == yajl_t_object && (ctx->options & PARSE_OPTIONS_STRICT)) { ++ int i; ++ for (i = 0; i < tree->u.object.len; i++) ++ if (strcmp(tree->u.object.keys[i], "path") && ++ strcmp(tree->u.object.keys[i], "args") && ++ strcmp(tree->u.object.keys[i], "env") && ++ strcmp(tree->u.object.keys[i], "timeout")) { ++ if (ctx->stderr > 0) ++ fprintf(ctx->stderr, "WARNING: unknown key found: %s\n", tree->u.object.keys[i]); ++ } ++ } ++ return ret; +} -+#endif + - static int lxc_cmd_process(int fd, struct lxc_cmd_req *req, - struct lxc_handler *handler, - struct lxc_async_descr *descr) -@@ -1951,6 +2085,10 @@ static int lxc_cmd_process(int fd, struct lxc_cmd_req *req, - [LXC_CMD_GET_CGROUP_FD] = lxc_cmd_get_cgroup_fd_callback, - [LXC_CMD_GET_LIMIT_CGROUP_FD] = lxc_cmd_get_limit_cgroup_fd_callback, - [LXC_CMD_GET_SYSTEMD_SCOPE] = lxc_cmd_get_systemd_scope_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) -@@ -2104,6 +2242,46 @@ static int lxc_cmd_accept(int fd, uint32_t events, void *data, - return ret; - } - -+#ifdef HAVE_ISULAD -+// isulad required named unix socket to make safe connect, -+// so need to replace abstrace unix socket -+int lxc_server_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_server_init(const char *name, const char *lxcpath, const char *suffix) - { - __do_close int fd = -EBADF; -@@ -2128,6 +2306,7 @@ int lxc_server_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_async_descr *descr, - struct lxc_handler *handler) -diff --git a/src/lxc/commands.h b/src/lxc/commands.h -index 2a39748..d5d1a0e 100644 ---- a/src/lxc/commands.h -+++ b/src/lxc/commands.h -@@ -53,6 +53,10 @@ typedef enum { - LXC_CMD_GET_CGROUP_FD = 24, - LXC_CMD_GET_LIMIT_CGROUP_FD = 25, - LXC_CMD_GET_SYSTEMD_SCOPE = 26, -+#ifdef HAVE_ISULAD -+ LXC_CMD_SET_TERMINAL_FIFOS = 27, -+ LXC_CMD_SET_TERMINAL_WINCH = 28, -+#endif - LXC_CMD_MAX, - } lxc_cmd_t; - -@@ -179,4 +183,10 @@ __hidden extern int lxc_cmd_get_limit_cgroup_fd(const char *name, - struct cgroup_fd *ret_fd); - __hidden extern int lxc_cmd_get_devpts_fd(const char *name, const char *lxcpath); - -+#ifdef HAVE_ISULAD -+__hidden 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); -+__hidden 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/commands_utils.c b/src/lxc/commands_utils.c -index 3558ff7..33780dd 100644 ---- a/src/lxc/commands_utils.c -+++ b/src/lxc/commands_utils.c -@@ -143,12 +143,69 @@ int lxc_make_abstract_socket_name(char *path, size_t pathlen, - return 0; - } - -+#ifdef HAVE_ISULAD -+char *generate_named_unix_sock_dir(const char *name) -+{ -+ __do_free char *exec_sock_dir = NULL; -+ __do_free char *rundir = NULL; -+ -+ rundir = get_rundir(); -+ if (!rundir) -+ rundir = strdup("/var/run"); -+ -+ if (asprintf(&exec_sock_dir, "%s/lxc/%s", rundir, name) < 0) { -+ return log_error_errno(NULL, errno, "Failed to allocate memory"); -+ } -+ -+ return move_ptr(exec_sock_dir); ++void free_defs_hook(defs_hook *ptr) { ++ if (ptr == NULL) ++ return; ++ free(ptr->path); ++ ptr->path = NULL; ++ if (ptr->args != NULL) { ++ size_t i; ++ for (i = 0; i < ptr->args_len; i++) { ++ if (ptr->args[i] != NULL) { ++ free(ptr->args[i]); ++ ptr->args[i] = NULL; ++ } ++ } ++ free(ptr->args); ++ ptr->args = NULL; ++ } ++ if (ptr->env != NULL) { ++ size_t i; ++ for (i = 0; i < ptr->env_len; i++) { ++ if (ptr->env[i] != NULL) { ++ free(ptr->env[i]); ++ ptr->env[i] = NULL; ++ } ++ } ++ free(ptr->env); ++ ptr->env = NULL; ++ } ++ free(ptr); +} + -+int generate_named_unix_sock_path(const char *container_name, const char *sock_name, -+ char *out_path, size_t len) -+{ -+#define MAX_SOCK_NAME_LENGTH 12 -+ int ret; -+ __do_free char *sock_dir = NULL; -+ __do_free char *short_sock_name = NULL; -+ -+ if (container_name == NULL || sock_name == NULL) -+ return -1; -+ -+ sock_dir = generate_named_unix_sock_dir(container_name); -+ if (sock_dir == NULL) -+ return -1; -+ -+ short_sock_name = strdup(sock_name); -+ if (strlen(short_sock_name) > MAX_SOCK_NAME_LENGTH) -+ short_sock_name[MAX_SOCK_NAME_LENGTH] = '\0'; -+ -+ ret = snprintf(out_path, len, "%s/%s.sock", sock_dir, short_sock_name); -+ if (ret < 0 || (size_t)ret >= len) -+ return log_error_errno(-1, errno, "Failed to allocate memory"); -+ -+ return 0; ++yajl_gen_status gen_defs_hook(yajl_gen g, defs_hook *ptr, struct parser_context *ctx, parser_error *err) { ++ yajl_gen_status stat = yajl_gen_status_ok; ++ *err = 0; ++ stat = reformat_start_map(g); ++ if (yajl_gen_status_ok != stat) ++ GEN_SET_ERROR_AND_RETURN(stat, err); ++ if ((ctx->options & GEN_OPTIONS_ALLKEYVALUE) ||(ptr != NULL && ptr->path != NULL)) { ++ char *str = ""; ++ stat = reformat_map_key(g, "path", strlen("path")); ++ if (yajl_gen_status_ok != stat) ++ GEN_SET_ERROR_AND_RETURN(stat, err); ++ if (ptr != NULL && ptr->path != NULL) { ++ str = ptr->path; ++ } ++ stat = reformat_string(g, str, strlen(str)); ++ if (yajl_gen_status_ok != stat) ++ GEN_SET_ERROR_AND_RETURN(stat, err); ++ } ++ if ((ctx->options & GEN_OPTIONS_ALLKEYVALUE) || (ptr != NULL && ptr->args != NULL)) { ++ size_t len = 0, i; ++ stat = reformat_map_key(g, "args", strlen("args")); ++ if (yajl_gen_status_ok != stat) ++ GEN_SET_ERROR_AND_RETURN(stat, err); ++ if (ptr != NULL && ptr->args != NULL) { ++ len = ptr->args_len; ++ } ++ if (!len && !(ctx->options & GEN_OPTIONS_SIMPLIFY)) ++ yajl_gen_config(g, yajl_gen_beautify, 0); ++ stat = reformat_start_array(g); ++ if (yajl_gen_status_ok != stat) ++ GEN_SET_ERROR_AND_RETURN(stat, err); ++ for (i = 0; i < len; i++) { ++ stat = reformat_string(g, ptr->args[i], strlen(ptr->args[i])); ++ if (yajl_gen_status_ok != stat) ++ GEN_SET_ERROR_AND_RETURN(stat, err); ++ } ++ stat = reformat_end_array(g); ++ if (yajl_gen_status_ok != stat) ++ GEN_SET_ERROR_AND_RETURN(stat, err); ++ if (!len && !(ctx->options & GEN_OPTIONS_SIMPLIFY)) ++ yajl_gen_config(g, yajl_gen_beautify, 1); ++ } ++ if ((ctx->options & GEN_OPTIONS_ALLKEYVALUE) || (ptr != NULL && ptr->env != NULL)) { ++ size_t len = 0, i; ++ stat = reformat_map_key(g, "env", strlen("env")); ++ if (yajl_gen_status_ok != stat) ++ GEN_SET_ERROR_AND_RETURN(stat, err); ++ if (ptr != NULL && ptr->env != NULL) { ++ len = ptr->env_len; ++ } ++ if (!len && !(ctx->options & GEN_OPTIONS_SIMPLIFY)) ++ yajl_gen_config(g, yajl_gen_beautify, 0); ++ stat = reformat_start_array(g); ++ if (yajl_gen_status_ok != stat) ++ GEN_SET_ERROR_AND_RETURN(stat, err); ++ for (i = 0; i < len; i++) { ++ stat = reformat_string(g, ptr->env[i], strlen(ptr->env[i])); ++ if (yajl_gen_status_ok != stat) ++ GEN_SET_ERROR_AND_RETURN(stat, err); ++ } ++ stat = reformat_end_array(g); ++ if (yajl_gen_status_ok != stat) ++ GEN_SET_ERROR_AND_RETURN(stat, err); ++ if (!len && !(ctx->options & GEN_OPTIONS_SIMPLIFY)) ++ yajl_gen_config(g, yajl_gen_beautify, 1); ++ } ++ if ((ctx->options & GEN_OPTIONS_ALLKEYVALUE) ||(ptr != NULL && ptr->timeout)) { ++ long long int num = 0; ++ stat = reformat_map_key(g, "timeout", strlen("timeout")); ++ if (yajl_gen_status_ok != stat) ++ GEN_SET_ERROR_AND_RETURN(stat, err); ++ if (ptr != NULL && ptr->timeout) { ++ num = (long long int)ptr->timeout; ++ } ++ stat = reformat_int(g, num); ++ if (yajl_gen_status_ok != stat) ++ GEN_SET_ERROR_AND_RETURN(stat, err); ++ } ++ stat = reformat_end_map(g); ++ if (yajl_gen_status_ok != stat) ++ GEN_SET_ERROR_AND_RETURN(stat, err); ++ return yajl_gen_status_ok; +} -+#endif -+ - int lxc_cmd_connect(const char *name, const char *lxcpath, - const char *hashed_sock_name, const char *suffix) - { - int ret, client_fd; - char path[LXC_AUDS_ADDR_LEN] = {0}; - -+#ifdef HAVE_ISULAD -+ if (generate_named_unix_sock_path(name, suffix, path, sizeof(path)) != 0) -+ return -1; -+ -+ if (file_exists(path)) { -+ client_fd = lxc_named_unix_connect(path); -+ if (client_fd < 0) -+ return -1; -+ -+ return client_fd; -+ } -+#endif -+ - ret = lxc_make_abstract_socket_name(path, sizeof(path), name, lxcpath, - hashed_sock_name, suffix); - if (ret < 0) -diff --git a/src/lxc/commands_utils.h b/src/lxc/commands_utils.h -index 28ce490..2704ae2 100644 ---- a/src/lxc/commands_utils.h -+++ b/src/lxc/commands_utils.h -@@ -67,4 +67,11 @@ __hidden extern int lxc_cmd_connect(const char *name, const char *lxcpath, - __hidden extern void lxc_cmd_notify_state_listeners(const char *name, - const char *lxcpath, - lxc_state_t state); -+ -+#ifdef HAVE_ISULAD -+__hidden extern char *generate_named_unix_sock_dir(const char *name); -+__hidden extern int generate_named_unix_sock_path(const char *container_name, const char *sock_name, -+ char *out_path, size_t len); -+#endif /* HAVE ISULAD */ -+ - #endif /* __LXC_COMMANDS_UTILS_H */ -diff --git a/src/lxc/exec_commands.c b/src/lxc/exec_commands.c +diff --git a/src/lxc/json/defs.h b/src/lxc/json/defs.h new file mode 100644 -index 0000000..bd81d66 +index 0000000..0bbd8ac --- /dev/null -+++ b/src/lxc/exec_commands.c -@@ -0,0 +1,477 @@ -+/****************************************************************************** -+ * Copyright (c) Huawei Technologies Co., Ltd. 2019. All rights reserved. -+ * Author: lifeng -+ * Create: 2019-12-08 -+ * Description: provide container definition -+ * lxc: linux Container library -+ * This library is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU Lesser General Public -+ * License as published by the Free Software Foundation; either -+ * version 2.1 of the License, or (at your option) any later version. -+ * -+ * This library is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * Lesser General Public License for more details. -+ * -+ * You should have received a copy of the GNU Lesser General Public -+ * License along with this library; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -+ ******************************************************************************/ ++++ b/src/lxc/json/defs.h +@@ -0,0 +1,37 @@ ++// Generated from defs.json. Do not edit! ++#ifndef DEFS_SCHEMA_H ++#define DEFS_SCHEMA_H + -+#ifndef _GNU_SOURCE -+#define _GNU_SOURCE 1 ++#include ++#include ++#include "json_common.h" ++ ++#ifdef __cplusplus ++extern "C" { +#endif -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include + -+#include "af_unix.h" -+#include "cgroup.h" -+#include "exec_commands.h" -+#include "commands_utils.h" -+#include "conf.h" -+#include "config.h" -+#include "confile.h" -+#include "log.h" -+#include "lxc.h" -+#include "lxclock.h" -+#include "mainloop.h" -+#include "monitor.h" -+#include "string_utils.h" -+#include "terminal.h" -+#include "utils.h" ++typedef struct { ++ char *path; + -+lxc_log_define(commands_exec, lxc); ++ char **args; ++ size_t args_len; + -+static const char *lxc_exec_cmd_str(lxc_exec_cmd_t cmd) -+{ -+ static const char *const cmdname[LXC_EXEC_CMD_MAX] = { -+ [LXC_EXEC_CMD_SET_TERMINAL_WINCH] = "set_exec_terminal_winch", -+ }; ++ char **env; ++ size_t env_len; + -+ if (cmd >= LXC_EXEC_CMD_MAX) -+ return "Invalid request"; ++ int timeout; + -+ return cmdname[cmd]; +} ++defs_hook; + -+static int lxc_exec_cmd_rsp_recv(int sock, struct lxc_exec_cmd_rr *cmd) -+{ -+ int ret, rspfd; -+ struct lxc_exec_cmd_rsp *rsp = &cmd->rsp; -+ -+ /*isulad: add timeout 1s to avoid long block due to [lxc monitor] error*/ -+ if (lxc_socket_set_timeout(sock, 1, 1) != 0) { -+ return syserror_ret(-1, "Failed to set timeout"); -+ } -+ -+ ret = lxc_cmd_rsp_recv_fds(sock, &rspfd, 1, rsp, sizeof(*rsp)); -+ if (ret < 0) { -+ SYSERROR("Failed to receive response for command \"%s\"", -+ lxc_exec_cmd_str(cmd->req.cmd)); -+ -+ if (errno == ECONNRESET || errno == EAGAIN || errno == EWOULDBLOCK) { -+ errno = ECONNRESET; /*isulad set errno ECONNRESET when timeout */ -+ return -1; -+ } ++void free_defs_hook(defs_hook *ptr); + -+ return -1; -+ } -+ TRACE("Command \"%s\" received response", lxc_exec_cmd_str(cmd->req.cmd)); ++defs_hook *make_defs_hook(yajl_val tree, struct parser_context *ctx, parser_error *err); + -+ if (rsp->datalen == 0) { -+ DEBUG("Response data length for command \"%s\" is 0", -+ lxc_exec_cmd_str(cmd->req.cmd)); -+ return ret; -+ } ++yajl_gen_status gen_defs_hook(yajl_gen g, defs_hook *ptr, struct parser_context *ctx, parser_error *err); + -+ if (rsp->datalen > LXC_CMD_DATA_MAX) { -+ ERROR("Response data for command \"%s\" is too long: %d bytes > %d", -+ lxc_exec_cmd_str(cmd->req.cmd), rsp->datalen, LXC_CMD_DATA_MAX); -+ return -1; -+ } ++#ifdef __cplusplus ++} ++#endif + -+ rsp->data = malloc(rsp->datalen); -+ if (!rsp->data) { -+ errno = ENOMEM; -+ ERROR("Failed to allocate response buffer for command \"%s\"", -+ lxc_exec_cmd_str(cmd->req.cmd)); -+ return -1; -+ } ++#endif +diff --git a/src/lxc/json/json_common.c b/src/lxc/json/json_common.c +new file mode 100755 +index 0000000..ec20c59 +--- /dev/null ++++ b/src/lxc/json/json_common.c +@@ -0,0 +1,1153 @@ ++// Auto generated file. Do not edit! ++#define _GNU_SOURCE ++#include ++#include ++#include ++#include "json_common.h" + -+ ret = lxc_recv_nointr(sock, rsp->data, rsp->datalen, 0); -+ if (ret != rsp->datalen) { -+ SYSERROR("Failed to receive response data for command \"%s\"", -+ lxc_exec_cmd_str(cmd->req.cmd)); -+ return -1; -+ } ++#define MAX_NUM_STR_LEN 21 + -+ return ret; ++yajl_gen_status reformat_number(void *ctx, const char *str, size_t len) { ++ yajl_gen g = (yajl_gen) ctx; ++ return yajl_gen_number(g, str, len); +} + -+static int lxc_exec_cmd_rsp_send(int fd, struct lxc_exec_cmd_rsp *rsp) -+{ -+ ssize_t ret; -+ -+ errno = EMSGSIZE; -+ ret = lxc_send_nointr(fd, rsp, sizeof(*rsp), MSG_NOSIGNAL); -+ if (ret < 0 || (size_t)ret != sizeof(*rsp)) { -+ SYSERROR("Failed to send command response %zd", ret); -+ return -1; -+ } ++yajl_gen_status reformat_uint(void *ctx, long long unsigned int num) { ++ char numstr[MAX_NUM_STR_LEN]; ++ int ret; + -+ if (!rsp->data || rsp->datalen <= 0) -+ return 0; ++ ret = snprintf(numstr, MAX_NUM_STR_LEN, "%llu", num); ++ if (ret < 0 || ret >= MAX_NUM_STR_LEN) { ++ return yajl_gen_in_error_state; ++ } ++ return reformat_number(ctx, (const char *)numstr, strlen(numstr)); ++} + -+ errno = EMSGSIZE; -+ ret = lxc_send_nointr(fd, rsp->data, rsp->datalen, MSG_NOSIGNAL); -+ if (ret < 0 || ret != (ssize_t)rsp->datalen) { -+ SYSWARN("Failed to send command response data %zd", ret); -+ return -1; -+ } ++yajl_gen_status reformat_int(void *ctx, long long int num) { ++ char numstr[MAX_NUM_STR_LEN]; ++ int ret; + -+ return 0; ++ ret = snprintf(numstr, MAX_NUM_STR_LEN, "%lld", num); ++ if (ret < 0 || ret >= MAX_NUM_STR_LEN) { ++ return yajl_gen_in_error_state; ++ } ++ return reformat_number(ctx, (const char *)numstr, strlen(numstr)); +} + -+static int lxc_exec_cmd_send(const char *name, struct lxc_exec_cmd_rr *cmd, -+ const char *lxcpath, const char *hashed_sock_name, const char *suffix) -+{ -+ int client_fd, saved_errno; -+ ssize_t ret = -1; -+ -+ client_fd = lxc_cmd_connect(name, lxcpath, hashed_sock_name, suffix); -+ if (client_fd < 0) -+ return -1; ++yajl_gen_status reformat_double(void *ctx, double num) { ++ yajl_gen g = (yajl_gen) ctx; ++ return yajl_gen_double(g, num); ++} + -+ ret = lxc_abstract_unix_send_credential(client_fd, &cmd->req, -+ sizeof(cmd->req)); -+ if (ret < 0 || (size_t)ret != sizeof(cmd->req)) -+ goto on_error; ++yajl_gen_status reformat_string(void *ctx, const char *str, size_t len) { ++ yajl_gen g = (yajl_gen) ctx; ++ return yajl_gen_string(g, (const unsigned char *)str, len); ++} + -+ if (cmd->req.datalen <= 0) -+ return client_fd; ++yajl_gen_status reformat_null(void *ctx) { ++ yajl_gen g = (yajl_gen) ctx; ++ return yajl_gen_null(g); ++} + -+ errno = EMSGSIZE; -+ ret = lxc_send_nointr(client_fd, (void *)cmd->req.data, -+ cmd->req.datalen, MSG_NOSIGNAL); -+ if (ret < 0 || ret != (ssize_t)cmd->req.datalen) -+ goto on_error; ++yajl_gen_status reformat_bool(void *ctx, int boolean) { ++ yajl_gen g = (yajl_gen) ctx; ++ return yajl_gen_bool(g, boolean); ++} + -+ return client_fd; ++yajl_gen_status reformat_map_key(void *ctx, const char *str, size_t len) { ++ yajl_gen g = (yajl_gen) ctx; ++ return yajl_gen_string(g, (const unsigned char *)str, len); ++} + -+on_error: -+ saved_errno = errno; -+ close(client_fd); -+ errno = saved_errno; ++yajl_gen_status reformat_start_map(void *ctx) { ++ yajl_gen g = (yajl_gen) ctx; ++ return yajl_gen_map_open(g); ++} + -+ return -1; ++yajl_gen_status reformat_end_map(void *ctx) { ++ yajl_gen g = (yajl_gen) ctx; ++ return yajl_gen_map_close(g); +} + -+static int lxc_exec_cmd(const char *name, struct lxc_exec_cmd_rr *cmd, const char *lxcpath, const char *hashed_sock_name, const char *suffix) -+{ -+ int client_fd = -1; -+ int saved_errno; -+ int ret = -1; -+ -+ client_fd = lxc_exec_cmd_send(name, cmd, lxcpath, hashed_sock_name, suffix); -+ if (client_fd < 0) { -+ SYSTRACE("Command \"%s\" failed to connect command socket", -+ lxc_exec_cmd_str(cmd->req.cmd)); -+ return -1; -+ } -+ -+ ret = lxc_exec_cmd_rsp_recv(client_fd, cmd); -+ -+ saved_errno = errno; -+ close(client_fd); -+ errno = saved_errno; -+ return ret; ++yajl_gen_status reformat_start_array(void *ctx) { ++ yajl_gen g = (yajl_gen) ctx; ++ return yajl_gen_array_open(g); +} + -+int lxc_exec_cmd_set_terminal_winch(const char *name, const char *lxcpath, const char *suffix, unsigned int height, unsigned int width) -+{ -+ int ret = 0; -+ struct lxc_exec_cmd_set_terminal_winch_request data = { 0 }; ++yajl_gen_status reformat_end_array(void *ctx) { ++ yajl_gen g = (yajl_gen) ctx; ++ return yajl_gen_array_close(g); ++} + -+ data.height = height; -+ data.width = width; ++bool json_gen_init(yajl_gen *g, struct parser_context *ctx) { ++ *g = yajl_gen_alloc(NULL); ++ if (NULL == *g) { ++ return false; + -+ struct lxc_exec_cmd_rr cmd = { -+ .req = { -+ .cmd = LXC_EXEC_CMD_SET_TERMINAL_WINCH, -+ .datalen = sizeof(struct lxc_exec_cmd_set_terminal_winch_request), -+ .data = &data, -+ }, -+ }; ++ } ++ yajl_gen_config(*g, yajl_gen_beautify, !(ctx->options & GEN_OPTIONS_SIMPLIFY)); ++ yajl_gen_config(*g, yajl_gen_validate_utf8, !(ctx->options & GEN_OPTIONS_NOT_VALIDATE_UTF8)); ++ return true; ++} + -+ ret = lxc_exec_cmd(name, &cmd, lxcpath, NULL, suffix); -+ if (ret < 0) { -+ ERROR("Failed to send command to container"); -+ return -1; -+ } ++yajl_val get_val(yajl_val tree, const char *name, yajl_type type) { ++ const char *path[] = { name, NULL }; ++ return yajl_tree_get(tree, path, type); ++} + -+ if (cmd.rsp.ret != 0) { -+ ERROR("Command response error:%d", cmd.rsp.ret); -+ return -1; -+ } -+ return 0; ++void *safe_malloc(size_t size) { ++ void *ret = NULL; ++ if (size == 0) { ++ abort(); ++ } ++ ret = calloc(1, size); ++ if (ret == NULL) { ++ abort(); ++ } ++ return ret; +} + -+static int lxc_exec_cmd_set_terminal_winch_callback(int fd, struct lxc_exec_cmd_req *req, -+ struct lxc_exec_command_handler *handler) -+{ -+ struct lxc_exec_cmd_rsp rsp; -+ struct lxc_exec_cmd_set_terminal_winch_request *data = (struct lxc_exec_cmd_set_terminal_winch_request *)(req->data); -+ memset(&rsp, 0, sizeof(rsp)); ++int common_safe_double(const char *numstr, double *converted) { ++ char *err_str = NULL; ++ double d; + -+ rsp.ret = lxc_set_terminal_winsz(handler->terminal, data->height, data->width);; ++ if (numstr == NULL) { ++ return -EINVAL; ++ } ++ ++ errno = 0; ++ d = strtod(numstr, &err_str); ++ if (errno > 0) { ++ return -errno; ++ } + -+ return lxc_exec_cmd_rsp_send(fd, &rsp); ++ if (err_str == NULL || err_str == numstr || *err_str != '\0') { ++ return -EINVAL; ++ } + ++ *converted = d; ++ return 0; +} + -+static int lxc_exec_cmd_process(int fd, struct lxc_exec_cmd_req *req, -+ struct lxc_exec_command_handler *handler) -+{ -+ typedef int (*callback)(int, struct lxc_exec_cmd_req *, struct lxc_exec_command_handler *); ++int common_safe_uint8(const char *numstr, uint8_t *converted) { ++ char *err = NULL; ++ unsigned long int uli; + -+ callback cb[LXC_EXEC_CMD_MAX] = { -+ [LXC_EXEC_CMD_SET_TERMINAL_WINCH] = lxc_exec_cmd_set_terminal_winch_callback, -+ }; ++ if (numstr == NULL) { ++ return -EINVAL; ++ } + -+ if (req->cmd >= LXC_EXEC_CMD_MAX) { -+ ERROR("Undefined command id %d", req->cmd); -+ return -1; -+ } -+ return cb[req->cmd](fd, req, handler); -+} ++ errno = 0; ++ uli = strtoul(numstr, &err, 0); ++ if (errno > 0) { ++ return -errno; ++ } + -+static void lxc_exec_cmd_fd_cleanup(int fd, struct lxc_epoll_descr *descr) -+{ -+ lxc_mainloop_del_handler(descr, fd); -+ close(fd); -+ return; -+} ++ if (err == NULL || err == numstr || *err != '\0') { ++ return -EINVAL; ++ } + -+static int lxc_exec_cmd_handler(int fd, uint32_t events, void *data, -+ struct lxc_epoll_descr *descr) -+{ -+ int ret; -+ struct lxc_exec_cmd_req req; -+ void *reqdata = NULL; -+ struct lxc_exec_command_handler *handler = data; ++ if (uli > UINT8_MAX) { ++ return -ERANGE; ++ } + -+ ret = lxc_abstract_unix_rcv_credential(fd, &req, sizeof(req)); -+ if (ret < 0) { -+ SYSERROR("Failed to receive data on command socket for command " -+ "\"%s\"", lxc_exec_cmd_str(req.cmd)); ++ *converted = (uint8_t)uli; ++ return 0; ++} + -+ if (errno == EACCES) { -+ /* We don't care for the peer, just send and close. */ -+ struct lxc_exec_cmd_rsp rsp = {.ret = ret}; ++int common_safe_uint16(const char *numstr, uint16_t *converted) { ++ char *err = NULL; ++ unsigned long int uli; + -+ lxc_exec_cmd_rsp_send(fd, &rsp); -+ } ++ if (numstr == NULL) { ++ return -EINVAL; ++ } + -+ goto out_close; -+ } ++ errno = 0; ++ uli = strtoul(numstr, &err, 0); ++ if (errno > 0) { ++ return -errno; ++ } + -+ if (ret == 0) -+ goto out_close; ++ if (err == NULL || err == numstr || *err != '\0') { ++ return -EINVAL; ++ } + -+ if (ret != sizeof(req)) { -+ WARN("Failed to receive full command request. Ignoring request " -+ "for \"%s\"", lxc_exec_cmd_str(req.cmd)); -+ ret = -1; -+ goto out_close; -+ } ++ if (uli > UINT16_MAX) { ++ return -ERANGE; ++ } + -+ if (req.datalen > LXC_CMD_DATA_MAX) { -+ ERROR("Received command data length %d is too large for " -+ "command \"%s\"", req.datalen, lxc_exec_cmd_str(req.cmd)); -+ errno = EFBIG; -+ ret = -EFBIG; -+ goto out_close; -+ } ++ *converted = (uint16_t)uli; ++ return 0; ++} + -+ if (req.datalen > 0) { -+ reqdata = alloca(req.datalen); -+ if (!reqdata) { -+ ERROR("Failed to allocate memory for \"%s\" command", -+ lxc_exec_cmd_str(req.cmd)); -+ errno = ENOMEM; -+ ret = -ENOMEM; -+ goto out_close; -+ } ++int common_safe_uint32(const char *numstr, uint32_t *converted) { ++ char *err = NULL; ++ unsigned long long int ull; + -+ ret = lxc_recv_nointr(fd, reqdata, req.datalen, 0); -+ if (ret != req.datalen) { -+ WARN("Failed to receive full command request. Ignoring " -+ "request for \"%s\"", lxc_exec_cmd_str(req.cmd)); -+ ret = LXC_MAINLOOP_ERROR; -+ goto out_close; -+ } ++ if (numstr == NULL) { ++ return -EINVAL; ++ } + -+ req.data = reqdata; -+ } ++ errno = 0; ++ ull = strtoull(numstr, &err, 0); ++ if (errno > 0) { ++ return -errno; ++ } + -+ ret = lxc_exec_cmd_process(fd, &req, handler); -+ if (ret) { -+ /* This is not an error, but only a request to close fd. */ -+ ret = LXC_MAINLOOP_CONTINUE; -+ goto out_close; -+ } ++ if (err == NULL || err == numstr || *err != '\0') { ++ return -EINVAL; ++ } + -+out: -+ return ret; ++ if (ull > UINT32_MAX) { ++ return -ERANGE; ++ } + -+out_close: -+ lxc_exec_cmd_fd_cleanup(fd, descr); -+ goto out; ++ *converted = (uint32_t)ull; ++ return 0; +} + -+static int lxc_exec_cmd_accept(int fd, uint32_t events, void *data, -+ struct lxc_epoll_descr *descr) -+{ -+ int connection = -1; -+ int opt = 1, ret = -1; -+ -+ connection = accept(fd, NULL, 0); -+ if (connection < 0) { -+ SYSERROR("Failed to accept connection to run command"); -+ return LXC_MAINLOOP_ERROR; -+ } -+ -+ ret = fcntl(connection, F_SETFD, FD_CLOEXEC); -+ if (ret < 0) { -+ SYSERROR("Failed to set close-on-exec on incoming command connection"); -+ goto out_close; -+ } ++int common_safe_uint64(const char *numstr, uint64_t *converted) { ++ char *err = NULL; ++ unsigned long long int ull; + -+ ret = setsockopt(connection, SOL_SOCKET, SO_PASSCRED, &opt, sizeof(opt)); -+ if (ret < 0) { -+ SYSERROR("Failed to enable necessary credentials on command socket"); -+ goto out_close; -+ } ++ if (numstr == NULL) { ++ return -EINVAL; ++ } + -+ ret = lxc_mainloop_add_handler(descr, connection, lxc_exec_cmd_handler, data); -+ if (ret) { -+ ERROR("Failed to add command handler"); -+ goto out_close; -+ } ++ errno = 0; ++ ull = strtoull(numstr, &err, 0); ++ if (errno > 0) { ++ return -errno; ++ } + -+out: -+ return ret; ++ if (err == NULL || err == numstr || *err != '\0') { ++ return -EINVAL; ++ } + -+out_close: -+ close(connection); -+ goto out; ++ *converted = (uint64_t)ull; ++ return 0; +} -+#ifdef HAVE_ISULAD -+int lxc_exec_unix_sock_delete(const char *name, const char *suffix) -+{ -+ char path[LXC_AUDS_ADDR_LEN] = {0}; + -+ if (name == NULL || suffix == NULL) -+ return -1; ++int common_safe_uint(const char *numstr, unsigned int *converted) { ++ char *err = NULL; ++ unsigned long long int ull; + -+ if (generate_named_unix_sock_path(name, suffix, path, sizeof(path)) != 0) -+ return -1; ++ if (numstr == NULL) { ++ return -EINVAL; ++ } + -+ (void)unlink(path); ++ errno = 0; ++ ull = strtoull(numstr, &err, 0); ++ if (errno > 0) { ++ return -errno; ++ } + -+ return 0; -+} ++ if (err == NULL || err == numstr || *err != '\0') { ++ return -EINVAL; ++ } + -+int lxc_exec_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 *exec_sock_dir = NULL; ++ if (ull > UINT_MAX) { ++ return -ERANGE; ++ } + -+ exec_sock_dir = generate_named_unix_sock_dir(name); -+ if (exec_sock_dir == NULL) -+ return -1; ++ *converted = (unsigned int)ull; ++ return 0; ++} + -+ if (mkdir_p(exec_sock_dir, 0600) < 0) -+ return log_error_errno(-1, errno, "Failed to create exec sock directory %s", path); ++int common_safe_int8(const char *numstr, int8_t *converted) { ++ char *err = NULL; ++ long int li; + -+ if (generate_named_unix_sock_path(name, suffix, path, sizeof(path)) != 0) -+ return -1; ++ if (numstr == NULL) { ++ return -EINVAL; ++ } + -+ TRACE("Creating unix socket \"%s\"", path); ++ errno = 0; ++ li = strtol(numstr, &err, 0); ++ if (errno > 0) { ++ return -errno; ++ } + -+ fd = lxc_named_unix_open(path, SOCK_STREAM, 0); -+ if (fd < 0) { -+ if (errno == EADDRINUSE) { -+ WARN("Container \"%s\" exec unix sock is occupied", 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); -+ } -+ } ++ if (err == NULL || err == numstr || *err != '\0') { ++ return -EINVAL; ++ } + -+ 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"); ++ if (li > INT8_MAX || li < INT8_MIN) { ++ return -ERANGE; ++ } + -+ return log_trace(move_fd(fd), "Created unix socket \"%s\"", path); ++ *converted = (int8_t)li; ++ return 0; +} -+#else -+int lxc_exec_cmd_init(const char *name, const char *lxcpath, const char *suffix) -+{ -+ int fd, ret; -+ char path[LXC_AUDS_ADDR_LEN] = {0}; + -+ ret = lxc_make_abstract_socket_name(path, sizeof(path), name, lxcpath, NULL, suffix); -+ if (ret < 0) -+ return -1; -+ TRACE("Creating abstract unix socket \"%s\"", &path[1]); ++int common_safe_int16(const char *numstr, int16_t *converted) { ++ char *err = NULL; ++ long int li; + -+ fd = lxc_abstract_unix_open(path, SOCK_STREAM, 0); -+ if (fd < 0) { -+ SYSERROR("Failed to create command socket %s", &path[1]); -+ if (errno == EADDRINUSE) -+ ERROR("Container \"%s\" appears to be already running", name); ++ if (numstr == NULL) { ++ return -EINVAL; ++ } + -+ return -1; -+ } ++ errno = 0; ++ li = strtol(numstr, &err, 0); ++ if (errno > 0) { ++ return -errno; ++ } + -+ ret = fcntl(fd, F_SETFD, FD_CLOEXEC); -+ if (ret < 0) { -+ SYSERROR("Failed to set FD_CLOEXEC on command socket file descriptor"); -+ close(fd); -+ return -1; -+ } ++ if (err == NULL || err == numstr || *err != '\0') { ++ return -EINVAL; ++ } + -+ return fd; -+} -+#endif ++ if (li > INT16_MAX || li < INT16_MIN) { ++ return -ERANGE; ++ } + -+int lxc_exec_cmd_mainloop_add(struct lxc_epoll_descr *descr, struct lxc_exec_command_handler *handler) -+{ -+ int ret; -+ int fd = handler->maincmd_fd; ++ *converted = (int16_t)li; ++ return 0; ++} + -+ ret = lxc_mainloop_add_handler(descr, fd, lxc_exec_cmd_accept, handler); -+ if (ret < 0) { -+ ERROR("Failed to add handler for command socket"); -+ close(fd); -+ } -+ -+ return ret; -+} -diff --git a/src/lxc/exec_commands.h b/src/lxc/exec_commands.h -new file mode 100644 -index 0000000..3ec2a22 ---- /dev/null -+++ b/src/lxc/exec_commands.h -@@ -0,0 +1,77 @@ -+/****************************************************************************** -+ * Copyright (c) Huawei Technologies Co., Ltd. 2019. All rights reserved. -+ * Author: lifeng -+ * Create: 2019-12-08 -+ * Description: provide container definition -+ * lxc: linux Container library -+ * This library is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU Lesser General Public -+ * License as published by the Free Software Foundation; either -+ * version 2.1 of the License, or (at your option) any later version. -+ * -+ * This library is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * Lesser General Public License for more details. -+ * -+ * You should have received a copy of the GNU Lesser General Public -+ * License along with this library; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -+ ******************************************************************************/ -+ -+#ifndef __LXC_EXEC_COMMANDS_H -+#define __LXC_EXEC_COMMANDS_H -+ -+#include -+#include -+#include -+ -+#include "lxccontainer.h" -+#include "macro.h" -+#include "state.h" -+#include "terminal.h" -+ -+struct lxc_exec_command_handler { -+ int maincmd_fd; -+ struct lxc_terminal *terminal; -+}; -+ -+typedef enum { -+ LXC_EXEC_CMD_SET_TERMINAL_WINCH, -+ LXC_EXEC_CMD_MAX, -+} lxc_exec_cmd_t; -+ -+struct lxc_exec_cmd_req { -+ lxc_exec_cmd_t cmd; -+ int datalen; -+ const void *data; -+}; -+ -+struct lxc_exec_cmd_rsp { -+ int ret; /* 0 on success, -errno on failure */ -+ int datalen; -+ void *data; -+}; -+ -+struct lxc_exec_cmd_rr { -+ struct lxc_exec_cmd_req req; -+ struct lxc_exec_cmd_rsp rsp; -+}; -+ -+struct lxc_exec_cmd_set_terminal_winch_request { -+ unsigned int height; -+ unsigned int width; -+}; -+ -+struct lxc_epoll_descr; -+struct lxc_handler; -+ -+extern int lxc_exec_cmd_init(const char *name, const char *lxcpath, const char *suffix); -+extern int lxc_exec_cmd_mainloop_add(struct lxc_epoll_descr *descr, struct lxc_exec_command_handler *handler); -+extern int lxc_exec_cmd_set_terminal_winch(const char *name, const char *lxcpath, const char *suffix, unsigned int height, unsigned int width); -+ -+#ifdef HAVE_ISULAD -+extern int lxc_exec_unix_sock_delete(const char *name, const char *suffix); -+#endif -+ -+#endif /* __exec_commands_h */ -diff --git a/src/lxc/isulad_utils.c b/src/lxc/isulad_utils.c -new file mode 100644 -index 0000000..ee39302 ---- /dev/null -+++ b/src/lxc/isulad_utils.c -@@ -0,0 +1,535 @@ -+/* 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 _GNU_SOURCE -+#define _GNU_SOURCE 1 -+#endif -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#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 "" */ -+ if (!tmp) -+ return NULL; -+ *tmp = '\0'; /* replace trailing ')' with NUL */ ++int common_safe_int32(const char *numstr, int32_t *converted) { ++ char *err = NULL; ++ long long int lli; + -+ 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 "(". */ -+ /* https://www.openwall.com/lists/musl/2013/11/15/5: musl's sscanf("%15c",cmd) -+ requires exactly 15 characters; anything shorter is a matching failure. */ -+#ifdef __MUSL__ -+ num = sscanf(S, "%d (%15s", &P->pid, P->cmd); /* comm[16] in kernel */ -+#else -+ num = sscanf(S, "%d (%15c", &P->pid, P->cmd); /* comm[16] in kernel */ -+#endif -+ 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 (numstr == NULL) { ++ return -EINVAL; + } -+ 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; ++ errno = 0; ++ lli = strtol(numstr, &err, 0); ++ if (errno > 0) { ++ return -errno; + } + -+ if ((lxc_file2str(filename, sbuf, sizeof(sbuf))) == -1) { -+ SYSERROR("Failed to read pidfile %s", filename); -+ goto out; ++ if (err == NULL || err == numstr || *err != '\0') { ++ return -EINVAL; + } + -+ pid_info = lxc_stat2proc(sbuf); -+ if (!pid_info) { -+ ERROR("Failed to get proc stat info"); -+ goto out; ++ if (lli > INT32_MAX || lli < INT32_MIN) { ++ return -ERANGE; + } + -+ 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) -+{ -+#define __PASSWD_FILE__ "/etc/passwd" -+ char *homedir = "/"; // default home dir is / -+ FILE *stream = NULL; -+ struct passwd pw, *pwbufp = NULL; -+ char buf[BUFSIZ]; -+ const char *curr_home = NULL; -+ -+ curr_home = getenv("HOME"); -+ // if user set or image set, just use it. -+ if (curr_home != NULL && strcmp(curr_home, "") != 0) { -+ return 0; -+ } -+ -+ stream = fopen_cloexec(__PASSWD_FILE__, "r"); -+ if (stream == NULL) { -+ SYSWARN("Failed to open %s", __PASSWD_FILE__); -+ goto set_env; -+ } -+ -+#if IS_BIONIC -+ while (util_getpwent_r(stream, &pw, buf, sizeof(buf), &pwbufp) == 0 && pwbufp != NULL) { -+#else -+ while (fgetpwent_r(stream, &pw, buf, sizeof(buf), &pwbufp) == 0 && pwbufp != NULL) { -+#endif -+ if (pwbufp->pw_uid == uid) { -+ homedir = pwbufp->pw_dir; -+ goto set_env; -+ } -+ } -+ WARN("User invalid, can not find user '%u'", uid); -+ -+set_env: -+ if (stream) -+ fclose(stream); -+ -+ // if we didn't configure HOME, set it based on uid; -+ // override it if reach here. -+ if (setenv("HOME", homedir, 1) < 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; ++ *converted = (int32_t)lli; ++ return 0; +} + -+static int hold_int(const char delim, bool required, char **src, unsigned int *dst) -+{ -+ unsigned long long int res = 0; -+ char *err_str = NULL; ++int common_safe_int64(const char *numstr, int64_t *converted) { ++ char *err = NULL; ++ long long int lli; + -+ // ensure *src not a empty string -+ if (**src == '\0') { -+ ERROR("Empty subject on given entrie is not allowed."); -+ return -1; ++ if (numstr == NULL) { ++ return -EINVAL; + } + + errno = 0; -+ // covert string to long long -+ res = strtoull(*src, &err_str, 0); -+ if (errno != 0 && errno != ERANGE) { -+ ERROR("Parse int from string failed."); -+ return -1; -+ } -+ -+ // **src is not a digit -+ if (err_str == *src) { -+ if (!required) { -+ ERROR("Integer part is missing."); -+ return -1; -+ } -+ // if required, just set 0 -+ *dst = 0; -+ } else { -+ if (sizeof(void *) > 4 && res > UINT_MAX) { // make sure 64-bit platform behave same as 32-bit -+ res = UINT_MAX; -+ } -+ res = res & UINT_MAX; -+ *dst = (uint32_t)res; ++ lli = strtoll(numstr, &err, 0); ++ if (errno > 0) { ++ return -errno; + } + -+ // normal case -+ if (*err_str == delim) { -+ err_str++; -+ } else if (*err_str != '\0') { -+ ERROR("Invalid digit string."); -+ return -1; ++ if (err == NULL || err == numstr || *err != '\0') { ++ return -EINVAL; + } + -+ *src = err_str; // update src to next valid context in line. ++ *converted = (int64_t)lli; + return 0; +} + -+static void hold_string(const char delim, char **src, char **dst) -+{ -+ for (*dst = *src; **src != delim; ++(*src)) { -+ if (**src == '\0') { -+ break; -+ } -+ } ++int common_safe_int(const char *numstr, int *converted) { ++ char *err = NULL; ++ long long int lli; + -+ if (**src == delim) { -+ **src = '\0'; -+ ++(*src); ++ if (numstr == NULL) { ++ return -EINVAL; + } -+} -+ -+static int parse_line_pw(const char delim, char *line, struct passwd *result) -+{ -+ int ret = 0; -+ bool required = false; -+ char *walker = NULL; + -+ walker = strpbrk(line, "\n"); -+ if (walker != NULL) { -+ // clear newline char -+ *walker = '\0'; ++ errno = 0; ++ lli = strtol(numstr, &err, 0); ++ if (errno > 0) { ++ return -errno; + } + -+ hold_string(delim, &line, &result->pw_name); -+ -+ required = (result->pw_name[0] == '+' || result->pw_name[0] == '-') ? true : false; -+ -+ hold_string(delim, &line, &result->pw_passwd); -+ -+ ret = hold_int(delim, required, &line, &result->pw_uid); -+ if (ret != 0) { -+ // a legitimate line must have uid -+ ERROR("Parse uid error."); -+ return ret; ++ if (err == NULL || err == numstr || *err != '\0') { ++ return -EINVAL; + } + -+ ret = hold_int(delim, required, &line, &result->pw_gid); -+ if (ret != 0) { -+ // it's ok to not provide gid -+ ERROR("Parse gid error."); -+ return ret; ++ if (lli > INT_MAX || lli < INT_MIN) { ++ return -ERANGE; + } + -+ hold_string(delim, &line, &result->pw_gecos); -+ -+ hold_string(delim, &line, &result->pw_dir); -+ -+ result->pw_shell = line; ++ *converted = (int)lli; + return 0; +} + -+char *util_left_trim_space(char *str) -+{ -+ char *begin = str; -+ char *tmp = str; -+ while (isspace(*begin)) { -+ begin++; ++yajl_gen_status gen_json_map_int_int(void *ctx, json_map_int_int *map, struct parser_context *ptx, parser_error *err) { ++ yajl_gen_status stat = yajl_gen_status_ok; ++ yajl_gen g = (yajl_gen) ctx; ++ size_t len = 0, i = 0; ++ if (map != NULL) { ++ len = map->len; + } -+ while ((*tmp++ = *begin++)) { ++ if (!len && !(ptx->options & GEN_OPTIONS_SIMPLIFY)) { ++ yajl_gen_config(g, yajl_gen_beautify, 0); + } -+ return str; -+} ++ stat = reformat_start_map(g); ++ if (yajl_gen_status_ok != stat) { ++ GEN_SET_ERROR_AND_RETURN(stat, err); + -+int util_getpwent_r(FILE *stream, struct passwd *resbuf, char *buffer, size_t buflen, struct passwd **result) -+{ -+ const char delim = ':'; -+ char *buff_end = NULL; -+ char *walker = NULL; -+ bool got = false; -+ int ret = 0; -+ -+ if (stream == NULL || resbuf == NULL || buffer == NULL || result == NULL) { -+ ERROR("Password obj, params is NULL."); -+ return -1; + } -+ -+ if (buflen <= 1) { -+ ERROR("Inadequate buffer length was given."); -+ return -1; -+ } -+ -+ buff_end = buffer + buflen - 1; -+ flockfile(stream); -+ -+ while (1) { -+ *buff_end = '\xff'; -+ walker = fgets_unlocked(buffer, buflen, stream); -+ // if get NULL string -+ if (walker == NULL) { -+ *result = NULL; -+ // reach end of file, return error -+ if (feof(stream)) { -+ ret = ENOENT; -+ goto out; ++ for (i = 0; i < len; i++) { ++ char numstr[MAX_NUM_STR_LEN]; ++ int nret; ++ nret = snprintf(numstr, MAX_NUM_STR_LEN, "%lld", (long long int)map->keys[i]); ++ if (nret < 0 || nret >= MAX_NUM_STR_LEN) { ++ if (!*err && asprintf(err, "Error to print string") < 0) { ++ *(err) = safe_strdup("error allocating memory"); + } -+ // overflow buffer -+ ret = ERANGE; -+ goto out; ++ return yajl_gen_in_error_state; + } -+ // just overflow last char in buffer -+ if (*buff_end != '\xff') { -+ *result = NULL; -+ ret = ERANGE; -+ goto out; ++ stat = reformat_string(g, numstr, strlen(numstr)); ++ if (yajl_gen_status_ok != stat) { ++ GEN_SET_ERROR_AND_RETURN(stat, err); + } -+ -+ (void)util_left_trim_space(buffer); -+ // skip comment line and empty line -+ if (walker[0] == '#' || walker[0] == '\0') { -+ continue; ++ stat = reformat_int(g, map->values[i]); ++ if (yajl_gen_status_ok != stat) { ++ GEN_SET_ERROR_AND_RETURN(stat, err); + } ++ } + -+ if (parse_line_pw(delim, walker, resbuf) == 0) { -+ got = true; -+ break; -+ } ++ stat = reformat_end_map(g); ++ if (yajl_gen_status_ok != stat) { ++ GEN_SET_ERROR_AND_RETURN(stat, err); + } -+ if (!got) { -+ *result = NULL; -+ ret = ERANGE; -+ goto out; ++ if (!len && !(ptx->options & GEN_OPTIONS_SIMPLIFY)) { ++ yajl_gen_config(g, yajl_gen_beautify, 1); + } -+ -+ *result = resbuf; -+ ret = 0; -+out: -+ funlockfile(stream); -+ return ret; ++ return yajl_gen_status_ok; +} -diff --git a/src/lxc/isulad_utils.h b/src/lxc/isulad_utils.h -new file mode 100644 -index 0000000..7a5eb89 ---- /dev/null -+++ b/src/lxc/isulad_utils.h -@@ -0,0 +1,102 @@ -+/* 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 -+#include -+#include -+ -+/* 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); -+ -+int util_getpwent_r(FILE *stream, struct passwd *resbuf, char *buffer, size_t buflen, struct passwd **result); -+ -+#endif -diff --git a/src/lxc/json/defs.c b/src/lxc/json/defs.c -new file mode 100644 -index 0000000..4bf569a ---- /dev/null -+++ b/src/lxc/json/defs.c -@@ -0,0 +1,205 @@ -+// Generated from defs.json. Do not edit! -+#ifndef _GNU_SOURCE -+#define _GNU_SOURCE -+#endif -+#include -+#include -+#include "defs.h" + -+defs_hook *make_defs_hook(yajl_val tree, struct parser_context *ctx, parser_error *err) { -+ defs_hook *ret = NULL; -+ *err = 0; -+ if (tree == NULL) -+ return ret; -+ ret = safe_malloc(sizeof(*ret)); -+ { -+ yajl_val val = get_val(tree, "path", yajl_t_string); -+ if (val != NULL) { -+ char *str = YAJL_GET_STRING(val); -+ ret->path = safe_strdup(str ? str : ""); ++void free_json_map_int_int(json_map_int_int *map) { ++ if (map != NULL) { ++ size_t i; ++ for (i = 0; i < map->len; i++) { ++ // No need to free key for type int ++ // No need to free value for type int + } ++ free(map->keys); ++ map->keys = NULL; ++ free(map->values); ++ map->values = NULL; ++ free(map); + } -+ { -+ yajl_val tmp = get_val(tree, "args", yajl_t_array); -+ if (tmp != NULL && YAJL_GET_ARRAY(tmp) != NULL && YAJL_GET_ARRAY(tmp)->len > 0) { -+ size_t i; -+ ret->args_len = YAJL_GET_ARRAY(tmp)->len; -+ if (YAJL_GET_ARRAY(tmp)->len > SIZE_MAX / sizeof(*ret->args) - 1) { -+ free_defs_hook(ret); -+ return NULL; -+ } -+ ret->args = safe_malloc((YAJL_GET_ARRAY(tmp)->len + 1) * sizeof(*ret->args)); -+ for (i = 0; i < YAJL_GET_ARRAY(tmp)->len; i++) { -+ yajl_val val = YAJL_GET_ARRAY(tmp)->values[i]; -+ if (val != NULL) { -+ char *str = YAJL_GET_STRING(val); -+ ret->args[i] = safe_strdup(str ? str : ""); -+ } -+ } ++} ++json_map_int_int *make_json_map_int_int(yajl_val src, struct parser_context *ctx, parser_error *err) { ++ json_map_int_int *ret = NULL; ++ if (src != NULL && YAJL_GET_OBJECT(src) != NULL) { ++ size_t i; ++ size_t len = YAJL_GET_OBJECT(src)->len; ++ if (len > SIZE_MAX / sizeof(int) - 1) { ++ return NULL; + } -+ } -+ { -+ yajl_val tmp = get_val(tree, "env", yajl_t_array); -+ if (tmp != NULL && YAJL_GET_ARRAY(tmp) != NULL && YAJL_GET_ARRAY(tmp)->len > 0) { -+ size_t i; -+ ret->env_len = YAJL_GET_ARRAY(tmp)->len; -+ if (YAJL_GET_ARRAY(tmp)->len > SIZE_MAX / sizeof(*ret->env) - 1) { -+ free_defs_hook(ret); -+ return NULL; -+ } -+ ret->env = safe_malloc((YAJL_GET_ARRAY(tmp)->len + 1) * sizeof(*ret->env)); -+ for (i = 0; i < YAJL_GET_ARRAY(tmp)->len; i++) { -+ yajl_val val = YAJL_GET_ARRAY(tmp)->values[i]; -+ if (val != NULL) { -+ char *str = YAJL_GET_STRING(val); -+ ret->env[i] = safe_strdup(str ? str : ""); ++ ret = safe_malloc(sizeof(*ret)); ++ ret->len = len; ++ ret->keys = safe_malloc((len + 1) * sizeof(int)); ++ ret->values = safe_malloc((len + 1) * sizeof(int)); ++ for (i = 0; i < len; i++) { ++ const char *srckey = YAJL_GET_OBJECT(src)->keys[i]; ++ yajl_val srcval = YAJL_GET_OBJECT(src)->values[i]; ++ ++ if (srckey != NULL) { ++ int invalid; ++ invalid = common_safe_int(srckey, &(ret->keys[i])); ++ if (invalid) { ++ if (*err == NULL && asprintf(err, "Invalid key '%s' with type 'int': %s", srckey, strerror(-invalid)) < 0) { ++ *(err) = safe_strdup("error allocating memory"); ++ } ++ free_json_map_int_int(ret); ++ return NULL; + } + } -+ } -+ } -+ { -+ yajl_val val = get_val(tree, "timeout", yajl_t_number); -+ if (val != NULL) { -+ int invalid = common_safe_int(YAJL_GET_NUMBER(val), (int *)&ret->timeout); -+ if (invalid) { -+ if (asprintf(err, "Invalid value '%s' with type 'integer' for key 'timeout': %s", YAJL_GET_NUMBER(val), strerror(-invalid)) < 0) -+ *err = safe_strdup("error allocating memory"); -+ free_defs_hook(ret); -+ return NULL; -+ } -+ } -+ } -+ if (ret->path == NULL) { -+ if (asprintf(err, "Required field '%s' not present", "path") < 0) -+ *err = safe_strdup("error allocating memory"); -+ free_defs_hook(ret); -+ return NULL; -+ } + -+ if (tree->type == yajl_t_object && (ctx->options & PARSE_OPTIONS_STRICT)) { -+ int i; -+ for (i = 0; i < tree->u.object.len; i++) -+ if (strcmp(tree->u.object.keys[i], "path") && -+ strcmp(tree->u.object.keys[i], "args") && -+ strcmp(tree->u.object.keys[i], "env") && -+ strcmp(tree->u.object.keys[i], "timeout")) { -+ if (ctx->stderr > 0) -+ fprintf(ctx->stderr, "WARNING: unknown key found: %s\n", tree->u.object.keys[i]); ++ if (srcval != NULL) { ++ int invalid; ++ if (!YAJL_IS_NUMBER(srcval)) { ++ if (*err == NULL && asprintf(err, "Invalid value with type 'int' for key '%s'", srckey) < 0) { ++ *(err) = safe_strdup("error allocating memory"); ++ } ++ free_json_map_int_int(ret); ++ return NULL; ++ } ++ invalid = common_safe_int(YAJL_GET_NUMBER(srcval), &(ret->values[i])); ++ if (invalid) { ++ if (*err == NULL && asprintf(err, "Invalid value with type 'int' for key '%s': %s", srckey, strerror(-invalid)) < 0) { ++ *(err) = safe_strdup("error allocating memory"); ++ } ++ free_json_map_int_int(ret); ++ return NULL; ++ } + } + } ++ } + return ret; +} ++int append_json_map_int_int(json_map_int_int *map, int key, int val) { ++ size_t len; ++ int *keys = NULL; ++ int *vals = NULL; + -+void free_defs_hook(defs_hook *ptr) { -+ if (ptr == NULL) -+ return; -+ free(ptr->path); -+ ptr->path = NULL; -+ if (ptr->args != NULL) { -+ size_t i; -+ for (i = 0; i < ptr->args_len; i++) { -+ if (ptr->args[i] != NULL) { -+ free(ptr->args[i]); -+ ptr->args[i] = NULL; -+ } -+ } -+ free(ptr->args); -+ ptr->args = NULL; ++ if (map == NULL) { ++ return -1; + } -+ if (ptr->env != NULL) { -+ size_t i; -+ for (i = 0; i < ptr->env_len; i++) { -+ if (ptr->env[i] != NULL) { -+ free(ptr->env[i]); -+ ptr->env[i] = NULL; -+ } -+ } -+ free(ptr->env); -+ ptr->env = NULL; ++ ++ if ((SIZE_MAX / sizeof(int) - 1) < map->len) { ++ return -1; + } -+ free(ptr); ++ ++ len = map->len + 1; ++ keys = safe_malloc(len * sizeof(int)); ++ vals = safe_malloc(len * sizeof(int)); ++ ++ if (map->len) { ++ (void)memcpy(keys, map->keys, map->len * sizeof(int)); ++ (void)memcpy(vals, map->values, map->len * sizeof(int)); ++ } ++ free(map->keys); ++ map->keys = keys; ++ free(map->values); ++ map->values = vals; ++ map->keys[map->len] = key; ++ map->values[map->len] = val; ++ ++ map->len++; ++ return 0; +} + -+yajl_gen_status gen_defs_hook(yajl_gen g, defs_hook *ptr, struct parser_context *ctx, parser_error *err) { ++yajl_gen_status gen_json_map_int_bool(void *ctx, json_map_int_bool *map, struct parser_context *ptx, parser_error *err) { + yajl_gen_status stat = yajl_gen_status_ok; -+ *err = 0; ++ yajl_gen g = (yajl_gen) ctx; ++ size_t len = 0, i = 0; ++ if (map != NULL) { ++ len = map->len; ++ } ++ if (!len && !(ptx->options & GEN_OPTIONS_SIMPLIFY)) { ++ yajl_gen_config(g, yajl_gen_beautify, 0); ++ } + stat = reformat_start_map(g); -+ if (yajl_gen_status_ok != stat) ++ if (yajl_gen_status_ok != stat) { + GEN_SET_ERROR_AND_RETURN(stat, err); -+ if ((ctx->options & GEN_OPTIONS_ALLKEYVALUE) ||(ptr != NULL && ptr->path != NULL)) { -+ char *str = ""; -+ stat = reformat_map_key(g, "path", strlen("path")); -+ if (yajl_gen_status_ok != stat) -+ GEN_SET_ERROR_AND_RETURN(stat, err); -+ if (ptr != NULL && ptr->path != NULL) { -+ str = ptr->path; -+ } -+ stat = reformat_string(g, str, strlen(str)); -+ if (yajl_gen_status_ok != stat) -+ GEN_SET_ERROR_AND_RETURN(stat, err); -+ } -+ if ((ctx->options & GEN_OPTIONS_ALLKEYVALUE) || (ptr != NULL && ptr->args != NULL)) { -+ size_t len = 0, i; -+ stat = reformat_map_key(g, "args", strlen("args")); -+ if (yajl_gen_status_ok != stat) -+ GEN_SET_ERROR_AND_RETURN(stat, err); -+ if (ptr != NULL && ptr->args != NULL) { -+ len = ptr->args_len; -+ } -+ if (!len && !(ctx->options & GEN_OPTIONS_SIMPLIFY)) -+ yajl_gen_config(g, yajl_gen_beautify, 0); -+ stat = reformat_start_array(g); -+ if (yajl_gen_status_ok != stat) -+ GEN_SET_ERROR_AND_RETURN(stat, err); -+ for (i = 0; i < len; i++) { -+ stat = reformat_string(g, ptr->args[i], strlen(ptr->args[i])); -+ if (yajl_gen_status_ok != stat) -+ GEN_SET_ERROR_AND_RETURN(stat, err); -+ } -+ stat = reformat_end_array(g); -+ if (yajl_gen_status_ok != stat) -+ GEN_SET_ERROR_AND_RETURN(stat, err); -+ if (!len && !(ctx->options & GEN_OPTIONS_SIMPLIFY)) -+ yajl_gen_config(g, yajl_gen_beautify, 1); ++ + } -+ if ((ctx->options & GEN_OPTIONS_ALLKEYVALUE) || (ptr != NULL && ptr->env != NULL)) { -+ size_t len = 0, i; -+ stat = reformat_map_key(g, "env", strlen("env")); -+ if (yajl_gen_status_ok != stat) -+ GEN_SET_ERROR_AND_RETURN(stat, err); -+ if (ptr != NULL && ptr->env != NULL) { -+ len = ptr->env_len; ++ for (i = 0; i < len; i++) { ++ char numstr[MAX_NUM_STR_LEN]; ++ int nret; ++ nret = snprintf(numstr, MAX_NUM_STR_LEN, "%lld", (long long int)map->keys[i]); ++ if (nret < 0 || nret >= MAX_NUM_STR_LEN) { ++ if (!*err && asprintf(err, "Error to print string") < 0) { ++ *(err) = safe_strdup("error allocating memory"); ++ } ++ return yajl_gen_in_error_state; + } -+ if (!len && !(ctx->options & GEN_OPTIONS_SIMPLIFY)) -+ yajl_gen_config(g, yajl_gen_beautify, 0); -+ stat = reformat_start_array(g); -+ if (yajl_gen_status_ok != stat) ++ stat = reformat_string(g, numstr, strlen(numstr)); ++ if (yajl_gen_status_ok != stat) { + GEN_SET_ERROR_AND_RETURN(stat, err); -+ for (i = 0; i < len; i++) { -+ stat = reformat_string(g, ptr->env[i], strlen(ptr->env[i])); -+ if (yajl_gen_status_ok != stat) -+ GEN_SET_ERROR_AND_RETURN(stat, err); + } -+ stat = reformat_end_array(g); -+ if (yajl_gen_status_ok != stat) -+ GEN_SET_ERROR_AND_RETURN(stat, err); -+ if (!len && !(ctx->options & GEN_OPTIONS_SIMPLIFY)) -+ yajl_gen_config(g, yajl_gen_beautify, 1); -+ } -+ if ((ctx->options & GEN_OPTIONS_ALLKEYVALUE) ||(ptr != NULL && ptr->timeout)) { -+ long long int num = 0; -+ stat = reformat_map_key(g, "timeout", strlen("timeout")); -+ if (yajl_gen_status_ok != stat) ++ stat = reformat_bool(g, map->values[i]); ++ if (yajl_gen_status_ok != stat) { + GEN_SET_ERROR_AND_RETURN(stat, err); -+ if (ptr != NULL && ptr->timeout) { -+ num = (long long int)ptr->timeout; + } -+ stat = reformat_int(g, num); -+ if (yajl_gen_status_ok != stat) -+ GEN_SET_ERROR_AND_RETURN(stat, err); + } ++ + stat = reformat_end_map(g); -+ if (yajl_gen_status_ok != stat) ++ if (yajl_gen_status_ok != stat) { + GEN_SET_ERROR_AND_RETURN(stat, err); ++ } ++ if (!len && !(ptx->options & GEN_OPTIONS_SIMPLIFY)) { ++ yajl_gen_config(g, yajl_gen_beautify, 1); ++ } + return yajl_gen_status_ok; +} -diff --git a/src/lxc/json/defs.h b/src/lxc/json/defs.h -new file mode 100644 -index 0000000..0bbd8ac ---- /dev/null -+++ b/src/lxc/json/defs.h -@@ -0,0 +1,37 @@ -+// Generated from defs.json. Do not edit! -+#ifndef DEFS_SCHEMA_H -+#define DEFS_SCHEMA_H -+ -+#include -+#include -+#include "json_common.h" -+ -+#ifdef __cplusplus -+extern "C" { -+#endif -+ -+typedef struct { -+ char *path; -+ -+ char **args; -+ size_t args_len; -+ -+ char **env; -+ size_t env_len; -+ -+ int timeout; -+ -+} -+defs_hook; -+ -+void free_defs_hook(defs_hook *ptr); -+ -+defs_hook *make_defs_hook(yajl_val tree, struct parser_context *ctx, parser_error *err); -+ -+yajl_gen_status gen_defs_hook(yajl_gen g, defs_hook *ptr, struct parser_context *ctx, parser_error *err); -+ -+#ifdef __cplusplus -+} -+#endif -+ -+#endif -diff --git a/src/lxc/json/json_common.c b/src/lxc/json/json_common.c -new file mode 100755 -index 0000000..ec20c59 ---- /dev/null -+++ b/src/lxc/json/json_common.c -@@ -0,0 +1,1153 @@ -+// Auto generated file. Do not edit! -+#define _GNU_SOURCE -+#include -+#include -+#include -+#include "json_common.h" -+ -+#define MAX_NUM_STR_LEN 21 + -+yajl_gen_status reformat_number(void *ctx, const char *str, size_t len) { -+ yajl_gen g = (yajl_gen) ctx; -+ return yajl_gen_number(g, str, len); ++void free_json_map_int_bool(json_map_int_bool *map) { ++ if (map != NULL) { ++ free(map->keys); ++ map->keys = NULL; ++ free(map->values); ++ map->values = NULL; ++ free(map); ++ } +} ++json_map_int_bool *make_json_map_int_bool(yajl_val src, struct parser_context *ctx, parser_error *err) { ++ json_map_int_bool *ret = NULL; ++ if (src != NULL && YAJL_GET_OBJECT(src) != NULL) { ++ size_t i; ++ size_t len = YAJL_GET_OBJECT(src)->len; ++ if (len > SIZE_MAX / sizeof(int) - 1) { ++ return NULL; ++ } ++ ret = safe_malloc(sizeof(*ret)); ++ ret->len = len; ++ ret->keys = safe_malloc((len + 1) * sizeof(int)); ++ ret->values = safe_malloc((len + 1) * sizeof(bool)); ++ for (i = 0; i < len; i++) { ++ const char *srckey = YAJL_GET_OBJECT(src)->keys[i]; ++ yajl_val srcval = YAJL_GET_OBJECT(src)->values[i]; + -+yajl_gen_status reformat_uint(void *ctx, long long unsigned int num) { -+ char numstr[MAX_NUM_STR_LEN]; -+ int ret; ++ if (srckey != NULL) { ++ int invalid; ++ invalid = common_safe_int(srckey, &(ret->keys[i])); ++ if (invalid) { ++ if (*err == NULL && asprintf(err, "Invalid key '%s' with type 'int': %s", srckey, strerror(-invalid)) < 0) { ++ *(err) = safe_strdup("error allocating memory"); ++ } ++ free_json_map_int_bool(ret); ++ return NULL; ++ } ++ } + -+ ret = snprintf(numstr, MAX_NUM_STR_LEN, "%llu", num); -+ if (ret < 0 || ret >= MAX_NUM_STR_LEN) { -+ return yajl_gen_in_error_state; ++ if (srcval != NULL) { ++ if (YAJL_IS_TRUE(srcval)) { ++ ret->values[i] = true; ++ } else if (YAJL_IS_FALSE(srcval)) { ++ ret->values[i] = false; ++ } else { ++ if (*err == NULL && asprintf(err, "Invalid value with type 'bool' for key '%s'", srckey) < 0) { ++ *(err) = safe_strdup("error allocating memory"); ++ } ++ free_json_map_int_bool(ret); ++ return NULL; ++ } ++ } ++ } + } -+ return reformat_number(ctx, (const char *)numstr, strlen(numstr)); ++ return ret; +} ++int append_json_map_int_bool(json_map_int_bool *map, int key, bool val) { ++ size_t len; ++ int *keys = NULL; ++ bool *vals = NULL; + -+yajl_gen_status reformat_int(void *ctx, long long int num) { -+ char numstr[MAX_NUM_STR_LEN]; -+ int ret; ++ if (map == NULL) { ++ return -1; ++ } + -+ ret = snprintf(numstr, MAX_NUM_STR_LEN, "%lld", num); -+ if (ret < 0 || ret >= MAX_NUM_STR_LEN) { -+ return yajl_gen_in_error_state; ++ if ((SIZE_MAX / sizeof(int) - 1) < map->len || (SIZE_MAX / sizeof(bool) - 1) < map->len) { ++ return -1; + } -+ return reformat_number(ctx, (const char *)numstr, strlen(numstr)); -+} + -+yajl_gen_status reformat_double(void *ctx, double num) { -+ yajl_gen g = (yajl_gen) ctx; -+ return yajl_gen_double(g, num); -+} ++ len = map->len + 1; ++ keys = safe_malloc(len * sizeof(int)); ++ vals = safe_malloc(len * sizeof(bool)); + -+yajl_gen_status reformat_string(void *ctx, const char *str, size_t len) { -+ yajl_gen g = (yajl_gen) ctx; -+ return yajl_gen_string(g, (const unsigned char *)str, len); -+} ++ if (map->len) { ++ (void)memcpy(keys, map->keys, map->len * sizeof(int)); ++ (void)memcpy(vals, map->values, map->len * sizeof(bool)); ++ } ++ free(map->keys); ++ map->keys = keys; ++ free(map->values); ++ map->values = vals; ++ map->keys[map->len] = key; ++ map->values[map->len] = val; + -+yajl_gen_status reformat_null(void *ctx) { -+ yajl_gen g = (yajl_gen) ctx; -+ return yajl_gen_null(g); ++ map->len++; ++ return 0; +} + -+yajl_gen_status reformat_bool(void *ctx, int boolean) { ++yajl_gen_status gen_json_map_int_string(void *ctx, json_map_int_string *map, struct parser_context *ptx, parser_error *err) { ++ yajl_gen_status stat = yajl_gen_status_ok; + yajl_gen g = (yajl_gen) ctx; -+ return yajl_gen_bool(g, boolean); -+} -+ -+yajl_gen_status reformat_map_key(void *ctx, const char *str, size_t len) { -+ yajl_gen g = (yajl_gen) ctx; -+ return yajl_gen_string(g, (const unsigned char *)str, len); -+} -+ -+yajl_gen_status reformat_start_map(void *ctx) { -+ yajl_gen g = (yajl_gen) ctx; -+ return yajl_gen_map_open(g); -+} -+ -+yajl_gen_status reformat_end_map(void *ctx) { -+ yajl_gen g = (yajl_gen) ctx; -+ return yajl_gen_map_close(g); -+} -+ -+yajl_gen_status reformat_start_array(void *ctx) { -+ yajl_gen g = (yajl_gen) ctx; -+ return yajl_gen_array_open(g); -+} -+ -+yajl_gen_status reformat_end_array(void *ctx) { -+ yajl_gen g = (yajl_gen) ctx; -+ return yajl_gen_array_close(g); -+} -+ -+bool json_gen_init(yajl_gen *g, struct parser_context *ctx) { -+ *g = yajl_gen_alloc(NULL); -+ if (NULL == *g) { -+ return false; ++ size_t len = 0, i = 0; ++ if (map != NULL) { ++ len = map->len; ++ } ++ if (!len && !(ptx->options & GEN_OPTIONS_SIMPLIFY)) { ++ yajl_gen_config(g, yajl_gen_beautify, 0); ++ } ++ stat = reformat_start_map(g); ++ if (yajl_gen_status_ok != stat) { ++ GEN_SET_ERROR_AND_RETURN(stat, err); + + } -+ yajl_gen_config(*g, yajl_gen_beautify, !(ctx->options & GEN_OPTIONS_SIMPLIFY)); -+ yajl_gen_config(*g, yajl_gen_validate_utf8, !(ctx->options & GEN_OPTIONS_NOT_VALIDATE_UTF8)); -+ return true; -+} -+ -+yajl_val get_val(yajl_val tree, const char *name, yajl_type type) { -+ const char *path[] = { name, NULL }; -+ return yajl_tree_get(tree, path, type); -+} ++ for (i = 0; i < len; i++) { ++ char numstr[MAX_NUM_STR_LEN]; ++ int nret; ++ nret = snprintf(numstr, MAX_NUM_STR_LEN, "%lld", (long long int)map->keys[i]); ++ if (nret < 0 || nret >= MAX_NUM_STR_LEN) { ++ if (!*err && asprintf(err, "Error to print string") < 0) { ++ *(err) = safe_strdup("error allocating memory"); ++ } ++ return yajl_gen_in_error_state; ++ } ++ stat = reformat_string(g, numstr, strlen(numstr)); ++ if (yajl_gen_status_ok != stat) { ++ GEN_SET_ERROR_AND_RETURN(stat, err); ++ } ++ stat = reformat_string(g, map->values[i], strlen(map->values[i]));; ++ if (yajl_gen_status_ok != stat) { ++ GEN_SET_ERROR_AND_RETURN(stat, err); ++ } ++ } + -+void *safe_malloc(size_t size) { -+ void *ret = NULL; -+ if (size == 0) { -+ abort(); ++ stat = reformat_end_map(g); ++ if (yajl_gen_status_ok != stat) { ++ GEN_SET_ERROR_AND_RETURN(stat, err); + } -+ ret = calloc(1, size); -+ if (ret == NULL) { -+ abort(); ++ if (!len && !(ptx->options & GEN_OPTIONS_SIMPLIFY)) { ++ yajl_gen_config(g, yajl_gen_beautify, 1); + } -+ return ret; ++ return yajl_gen_status_ok; +} + -+int common_safe_double(const char *numstr, double *converted) { -+ char *err_str = NULL; -+ double d; -+ -+ if (numstr == NULL) { -+ return -EINVAL; ++void free_json_map_int_string(json_map_int_string *map) { ++ if (map != NULL) { ++ size_t i; ++ for (i = 0; i < map->len; i++) { ++ // No need to free key for type int ++ free(map->values[i]); ++ map->values[i] = NULL; ++ } ++ free(map->keys); ++ map->keys = NULL; ++ free(map->values); ++ map->values = NULL; ++ free(map); + } ++} ++json_map_int_string *make_json_map_int_string(yajl_val src, struct parser_context *ctx, parser_error *err) { ++ json_map_int_string *ret = NULL; ++ if (src != NULL && YAJL_GET_OBJECT(src) != NULL) { ++ size_t i; ++ size_t len = YAJL_GET_OBJECT(src)->len; ++ if (len > SIZE_MAX / sizeof(char *) - 1) { ++ return NULL; ++ } ++ ret = safe_malloc(sizeof(*ret)); ++ ret->len = len; ++ ret->keys = safe_malloc((len + 1) * sizeof(int)); ++ ret->values = safe_malloc((len + 1) * sizeof(char *)); ++ for (i = 0; i < len; i++) { ++ const char *srckey = YAJL_GET_OBJECT(src)->keys[i]; ++ yajl_val srcval = YAJL_GET_OBJECT(src)->values[i]; + -+ errno = 0; -+ d = strtod(numstr, &err_str); -+ if (errno > 0) { -+ return -errno; -+ } ++ if (srckey != NULL) { ++ int invalid; ++ invalid = common_safe_int(srckey, &(ret->keys[i])); ++ if (invalid) { ++ if (*err == NULL && asprintf(err, "Invalid key '%s' with type 'int': %s", srckey, strerror(-invalid)) < 0) { ++ *(err) = safe_strdup("error allocating memory"); ++ } ++ free_json_map_int_string(ret); ++ return NULL; ++ } ++ } + -+ if (err_str == NULL || err_str == numstr || *err_str != '\0') { -+ return -EINVAL; ++ if (srcval != NULL) { ++ if (!YAJL_IS_STRING(srcval)) { ++ if (*err == NULL && asprintf(err, "Invalid value with type 'string' for key '%s'", srckey) < 0) { ++ *(err) = safe_strdup("error allocating memory"); ++ } ++ free_json_map_int_string(ret); ++ return NULL; ++ } ++ char *str = YAJL_GET_STRING(srcval); ++ ret->values[i] = safe_strdup(str ? str : ""); ++ } ++ } + } -+ -+ *converted = d; -+ return 0; ++ return ret; +} ++int append_json_map_int_string(json_map_int_string *map, int key, const char *val) { ++ size_t len; ++ int *keys = NULL; ++ char **vals = NULL; + -+int common_safe_uint8(const char *numstr, uint8_t *converted) { -+ char *err = NULL; -+ unsigned long int uli; -+ -+ if (numstr == NULL) { -+ return -EINVAL; ++ if (map == NULL) { ++ return -1; + } + -+ errno = 0; -+ uli = strtoul(numstr, &err, 0); -+ if (errno > 0) { -+ return -errno; ++ if ((SIZE_MAX / sizeof(int) - 1) < map->len || (SIZE_MAX / sizeof(char *) - 1) < map->len) { ++ return -1; + } + -+ if (err == NULL || err == numstr || *err != '\0') { -+ return -EINVAL; -+ } ++ len = map->len + 1; ++ keys = safe_malloc(len * sizeof(int)); ++ vals = safe_malloc(len * sizeof(char *)); + -+ if (uli > UINT8_MAX) { -+ return -ERANGE; ++ if (map->len) { ++ (void)memcpy(keys, map->keys, map->len * sizeof(int)); ++ (void)memcpy(vals, map->values, map->len * sizeof(char *)); + } ++ free(map->keys); ++ map->keys = keys; ++ free(map->values); ++ map->values = vals; ++ map->keys[map->len] = key; ++ map->values[map->len] = safe_strdup(val ? val : ""); + -+ *converted = (uint8_t)uli; ++ map->len++; + return 0; +} + -+int common_safe_uint16(const char *numstr, uint16_t *converted) { -+ char *err = NULL; -+ unsigned long int uli; -+ -+ if (numstr == NULL) { -+ return -EINVAL; -+ } -+ -+ errno = 0; -+ uli = strtoul(numstr, &err, 0); -+ if (errno > 0) { -+ return -errno; ++yajl_gen_status gen_json_map_string_int(void *ctx, json_map_string_int *map, struct parser_context *ptx, parser_error *err) { ++ yajl_gen_status stat = yajl_gen_status_ok; ++ yajl_gen g = (yajl_gen) ctx; ++ size_t len = 0, i = 0; ++ if (map != NULL) { ++ len = map->len; + } -+ -+ if (err == NULL || err == numstr || *err != '\0') { -+ return -EINVAL; ++ if (!len && !(ptx->options & GEN_OPTIONS_SIMPLIFY)) { ++ yajl_gen_config(g, yajl_gen_beautify, 0); + } ++ stat = reformat_start_map(g); ++ if (yajl_gen_status_ok != stat) { ++ GEN_SET_ERROR_AND_RETURN(stat, err); + -+ if (uli > UINT16_MAX) { -+ return -ERANGE; + } -+ -+ *converted = (uint16_t)uli; -+ return 0; -+} -+ -+int common_safe_uint32(const char *numstr, uint32_t *converted) { -+ char *err = NULL; -+ unsigned long long int ull; -+ -+ if (numstr == NULL) { -+ return -EINVAL; ++ for (i = 0; i < len; i++) { ++ stat = reformat_string(g, map->keys[i], strlen(map->keys[i])); ++ if (yajl_gen_status_ok != stat) { ++ GEN_SET_ERROR_AND_RETURN(stat, err); ++ } ++ stat = reformat_int(g, map->values[i]); ++ if (yajl_gen_status_ok != stat) { ++ GEN_SET_ERROR_AND_RETURN(stat, err); ++ } + } + -+ errno = 0; -+ ull = strtoull(numstr, &err, 0); -+ if (errno > 0) { -+ return -errno; ++ stat = reformat_end_map(g); ++ if (yajl_gen_status_ok != stat) { ++ GEN_SET_ERROR_AND_RETURN(stat, err); + } -+ -+ if (err == NULL || err == numstr || *err != '\0') { -+ return -EINVAL; ++ if (!len && !(ptx->options & GEN_OPTIONS_SIMPLIFY)) { ++ yajl_gen_config(g, yajl_gen_beautify, 1); + } ++ return yajl_gen_status_ok; ++} + -+ if (ull > UINT32_MAX) { -+ return -ERANGE; ++void free_json_map_string_int(json_map_string_int *map) { ++ if (map != NULL) { ++ size_t i; ++ for (i = 0; i < map->len; i++) { ++ free(map->keys[i]); ++ map->keys[i] = NULL; ++ // No need to free value for type int ++ } ++ free(map->keys); ++ map->keys = NULL; ++ free(map->values); ++ map->values = NULL; ++ free(map); + } -+ -+ *converted = (uint32_t)ull; -+ return 0; +} ++json_map_string_int *make_json_map_string_int(yajl_val src, struct parser_context *ctx, parser_error *err) { ++ json_map_string_int *ret = NULL; ++ if (src != NULL && YAJL_GET_OBJECT(src) != NULL) { ++ size_t i; ++ size_t len = YAJL_GET_OBJECT(src)->len; ++ if (len > SIZE_MAX / sizeof(char *) - 1) { ++ return NULL; ++ } ++ ret = safe_malloc(sizeof(*ret)); ++ ret->len = len; ++ ret->keys = safe_malloc((len + 1) * sizeof(char *)); ++ ret->values = safe_malloc((len + 1) * sizeof(int)); ++ for (i = 0; i < len; i++) { ++ const char *srckey = YAJL_GET_OBJECT(src)->keys[i]; ++ yajl_val srcval = YAJL_GET_OBJECT(src)->values[i]; ++ ret->keys[i] = safe_strdup(srckey ? srckey : ""); + -+int common_safe_uint64(const char *numstr, uint64_t *converted) { -+ char *err = NULL; -+ unsigned long long int ull; -+ -+ if (numstr == NULL) { -+ return -EINVAL; -+ } -+ -+ errno = 0; -+ ull = strtoull(numstr, &err, 0); -+ if (errno > 0) { -+ return -errno; -+ } -+ -+ if (err == NULL || err == numstr || *err != '\0') { -+ return -EINVAL; -+ } -+ -+ *converted = (uint64_t)ull; -+ return 0; -+} -+ -+int common_safe_uint(const char *numstr, unsigned int *converted) { -+ char *err = NULL; -+ unsigned long long int ull; -+ -+ if (numstr == NULL) { -+ return -EINVAL; -+ } -+ -+ errno = 0; -+ ull = strtoull(numstr, &err, 0); -+ if (errno > 0) { -+ return -errno; -+ } -+ -+ if (err == NULL || err == numstr || *err != '\0') { -+ return -EINVAL; -+ } -+ -+ if (ull > UINT_MAX) { -+ return -ERANGE; -+ } -+ -+ *converted = (unsigned int)ull; -+ return 0; -+} -+ -+int common_safe_int8(const char *numstr, int8_t *converted) { -+ char *err = NULL; -+ long int li; -+ -+ if (numstr == NULL) { -+ return -EINVAL; -+ } -+ -+ errno = 0; -+ li = strtol(numstr, &err, 0); -+ if (errno > 0) { -+ return -errno; -+ } -+ -+ if (err == NULL || err == numstr || *err != '\0') { -+ return -EINVAL; -+ } -+ -+ if (li > INT8_MAX || li < INT8_MIN) { -+ return -ERANGE; -+ } -+ -+ *converted = (int8_t)li; -+ return 0; -+} -+ -+int common_safe_int16(const char *numstr, int16_t *converted) { -+ char *err = NULL; -+ long int li; -+ -+ if (numstr == NULL) { -+ return -EINVAL; -+ } -+ -+ errno = 0; -+ li = strtol(numstr, &err, 0); -+ if (errno > 0) { -+ return -errno; -+ } -+ -+ if (err == NULL || err == numstr || *err != '\0') { -+ return -EINVAL; -+ } -+ -+ if (li > INT16_MAX || li < INT16_MIN) { -+ return -ERANGE; -+ } -+ -+ *converted = (int16_t)li; -+ return 0; -+} -+ -+int common_safe_int32(const char *numstr, int32_t *converted) { -+ char *err = NULL; -+ long long int lli; -+ -+ if (numstr == NULL) { -+ return -EINVAL; -+ } -+ -+ errno = 0; -+ lli = strtol(numstr, &err, 0); -+ if (errno > 0) { -+ return -errno; -+ } -+ -+ if (err == NULL || err == numstr || *err != '\0') { -+ return -EINVAL; -+ } -+ -+ if (lli > INT32_MAX || lli < INT32_MIN) { -+ return -ERANGE; -+ } -+ -+ *converted = (int32_t)lli; -+ return 0; -+} -+ -+int common_safe_int64(const char *numstr, int64_t *converted) { -+ char *err = NULL; -+ long long int lli; -+ -+ if (numstr == NULL) { -+ return -EINVAL; -+ } -+ -+ errno = 0; -+ lli = strtoll(numstr, &err, 0); -+ if (errno > 0) { -+ return -errno; -+ } -+ -+ if (err == NULL || err == numstr || *err != '\0') { -+ return -EINVAL; ++ if (srcval != NULL) { ++ int invalid; ++ if (!YAJL_IS_NUMBER(srcval)) { ++ if (*err == NULL && asprintf(err, "Invalid value with type 'int' for key '%s'", srckey) < 0) { ++ *(err) = safe_strdup("error allocating memory"); ++ } ++ free_json_map_string_int(ret); ++ return NULL; ++ } ++ invalid = common_safe_int(YAJL_GET_NUMBER(srcval), &(ret->values[i])); ++ if (invalid) { ++ if (*err == NULL && asprintf(err, "Invalid value with type 'int' for key '%s': %s", srckey, strerror(-invalid)) < 0) { ++ *(err) = safe_strdup("error allocating memory"); ++ } ++ free_json_map_string_int(ret); ++ return NULL; ++ } ++ } ++ } + } -+ -+ *converted = (int64_t)lli; -+ return 0; ++ return ret; +} ++int append_json_map_string_int(json_map_string_int *map, const char *key, int val) { ++ size_t len; ++ char **keys = NULL; ++ int *vals = NULL; + -+int common_safe_int(const char *numstr, int *converted) { -+ char *err = NULL; -+ long long int lli; -+ -+ if (numstr == NULL) { -+ return -EINVAL; ++ if (map == NULL) { ++ return -1; + } + -+ errno = 0; -+ lli = strtol(numstr, &err, 0); -+ if (errno > 0) { -+ return -errno; ++ if ((SIZE_MAX / sizeof(char *) - 1) < map->len || (SIZE_MAX / sizeof(int) - 1) < map->len) { ++ return -1; + } + -+ if (err == NULL || err == numstr || *err != '\0') { -+ return -EINVAL; -+ } ++ len = map->len + 1; ++ keys = safe_malloc(len * sizeof(char *)); ++ vals = safe_malloc(len * sizeof(int)); + -+ if (lli > INT_MAX || lli < INT_MIN) { -+ return -ERANGE; ++ if (map->len) { ++ (void)memcpy(keys, map->keys, map->len * sizeof(char *)); ++ (void)memcpy(vals, map->values, map->len * sizeof(int)); + } ++ free(map->keys); ++ map->keys = keys; ++ free(map->values); ++ map->values = vals; ++ map->keys[map->len] = safe_strdup(key ? key : ""); ++ map->values[map->len] = val; + -+ *converted = (int)lli; ++ map->len++; + return 0; +} + -+yajl_gen_status gen_json_map_int_int(void *ctx, json_map_int_int *map, struct parser_context *ptx, parser_error *err) { ++yajl_gen_status gen_json_map_string_bool(void *ctx, json_map_string_bool *map, struct parser_context *ptx, parser_error *err) { + yajl_gen_status stat = yajl_gen_status_ok; + yajl_gen g = (yajl_gen) ctx; + size_t len = 0, i = 0; @@ -5678,20 +4448,11 @@ index 0000000..ec20c59 + + } + for (i = 0; i < len; i++) { -+ char numstr[MAX_NUM_STR_LEN]; -+ int nret; -+ nret = snprintf(numstr, MAX_NUM_STR_LEN, "%lld", (long long int)map->keys[i]); -+ if (nret < 0 || nret >= MAX_NUM_STR_LEN) { -+ if (!*err && asprintf(err, "Error to print string") < 0) { -+ *(err) = safe_strdup("error allocating memory"); -+ } -+ return yajl_gen_in_error_state; -+ } -+ stat = reformat_string(g, numstr, strlen(numstr)); ++ stat = reformat_string(g, map->keys[i], strlen(map->keys[i])); + if (yajl_gen_status_ok != stat) { + GEN_SET_ERROR_AND_RETURN(stat, err); + } -+ stat = reformat_int(g, map->values[i]); ++ stat = reformat_bool(g, map->values[i]); + if (yajl_gen_status_ok != stat) { + GEN_SET_ERROR_AND_RETURN(stat, err); + } @@ -5707,12 +4468,13 @@ index 0000000..ec20c59 + return yajl_gen_status_ok; +} + -+void free_json_map_int_int(json_map_int_int *map) { ++void free_json_map_string_bool(json_map_string_bool *map) { + if (map != NULL) { + size_t i; + for (i = 0; i < map->len; i++) { -+ // No need to free key for type int -+ // No need to free value for type int ++ free(map->keys[i]); ++ map->keys[i] = NULL; ++ // No need to free value for type bool + } + free(map->keys); + map->keys = NULL; @@ -5721,169 +4483,22 @@ index 0000000..ec20c59 + free(map); + } +} -+json_map_int_int *make_json_map_int_int(yajl_val src, struct parser_context *ctx, parser_error *err) { -+ json_map_int_int *ret = NULL; ++json_map_string_bool *make_json_map_string_bool(yajl_val src, struct parser_context *ctx, parser_error *err) { ++ json_map_string_bool *ret = NULL; + if (src != NULL && YAJL_GET_OBJECT(src) != NULL) { + size_t i; + size_t len = YAJL_GET_OBJECT(src)->len; -+ if (len > SIZE_MAX / sizeof(int) - 1) { ++ if (len > SIZE_MAX / sizeof(char *) - 1) { + return NULL; + } + ret = safe_malloc(sizeof(*ret)); + ret->len = len; -+ ret->keys = safe_malloc((len + 1) * sizeof(int)); -+ ret->values = safe_malloc((len + 1) * sizeof(int)); ++ ret->keys = safe_malloc((len + 1) * sizeof(char *)); ++ ret->values = safe_malloc((len + 1) * sizeof(bool)); + for (i = 0; i < len; i++) { + const char *srckey = YAJL_GET_OBJECT(src)->keys[i]; + yajl_val srcval = YAJL_GET_OBJECT(src)->values[i]; -+ -+ if (srckey != NULL) { -+ int invalid; -+ invalid = common_safe_int(srckey, &(ret->keys[i])); -+ if (invalid) { -+ if (*err == NULL && asprintf(err, "Invalid key '%s' with type 'int': %s", srckey, strerror(-invalid)) < 0) { -+ *(err) = safe_strdup("error allocating memory"); -+ } -+ free_json_map_int_int(ret); -+ return NULL; -+ } -+ } -+ -+ if (srcval != NULL) { -+ int invalid; -+ if (!YAJL_IS_NUMBER(srcval)) { -+ if (*err == NULL && asprintf(err, "Invalid value with type 'int' for key '%s'", srckey) < 0) { -+ *(err) = safe_strdup("error allocating memory"); -+ } -+ free_json_map_int_int(ret); -+ return NULL; -+ } -+ invalid = common_safe_int(YAJL_GET_NUMBER(srcval), &(ret->values[i])); -+ if (invalid) { -+ if (*err == NULL && asprintf(err, "Invalid value with type 'int' for key '%s': %s", srckey, strerror(-invalid)) < 0) { -+ *(err) = safe_strdup("error allocating memory"); -+ } -+ free_json_map_int_int(ret); -+ return NULL; -+ } -+ } -+ } -+ } -+ return ret; -+} -+int append_json_map_int_int(json_map_int_int *map, int key, int val) { -+ size_t len; -+ int *keys = NULL; -+ int *vals = NULL; -+ -+ if (map == NULL) { -+ return -1; -+ } -+ -+ if ((SIZE_MAX / sizeof(int) - 1) < map->len) { -+ return -1; -+ } -+ -+ len = map->len + 1; -+ keys = safe_malloc(len * sizeof(int)); -+ vals = safe_malloc(len * sizeof(int)); -+ -+ if (map->len) { -+ (void)memcpy(keys, map->keys, map->len * sizeof(int)); -+ (void)memcpy(vals, map->values, map->len * sizeof(int)); -+ } -+ free(map->keys); -+ map->keys = keys; -+ free(map->values); -+ map->values = vals; -+ map->keys[map->len] = key; -+ map->values[map->len] = val; -+ -+ map->len++; -+ return 0; -+} -+ -+yajl_gen_status gen_json_map_int_bool(void *ctx, json_map_int_bool *map, struct parser_context *ptx, parser_error *err) { -+ yajl_gen_status stat = yajl_gen_status_ok; -+ yajl_gen g = (yajl_gen) ctx; -+ size_t len = 0, i = 0; -+ if (map != NULL) { -+ len = map->len; -+ } -+ if (!len && !(ptx->options & GEN_OPTIONS_SIMPLIFY)) { -+ yajl_gen_config(g, yajl_gen_beautify, 0); -+ } -+ stat = reformat_start_map(g); -+ if (yajl_gen_status_ok != stat) { -+ GEN_SET_ERROR_AND_RETURN(stat, err); -+ -+ } -+ for (i = 0; i < len; i++) { -+ char numstr[MAX_NUM_STR_LEN]; -+ int nret; -+ nret = snprintf(numstr, MAX_NUM_STR_LEN, "%lld", (long long int)map->keys[i]); -+ if (nret < 0 || nret >= MAX_NUM_STR_LEN) { -+ if (!*err && asprintf(err, "Error to print string") < 0) { -+ *(err) = safe_strdup("error allocating memory"); -+ } -+ return yajl_gen_in_error_state; -+ } -+ stat = reformat_string(g, numstr, strlen(numstr)); -+ if (yajl_gen_status_ok != stat) { -+ GEN_SET_ERROR_AND_RETURN(stat, err); -+ } -+ stat = reformat_bool(g, map->values[i]); -+ if (yajl_gen_status_ok != stat) { -+ GEN_SET_ERROR_AND_RETURN(stat, err); -+ } -+ } -+ -+ stat = reformat_end_map(g); -+ if (yajl_gen_status_ok != stat) { -+ GEN_SET_ERROR_AND_RETURN(stat, err); -+ } -+ if (!len && !(ptx->options & GEN_OPTIONS_SIMPLIFY)) { -+ yajl_gen_config(g, yajl_gen_beautify, 1); -+ } -+ return yajl_gen_status_ok; -+} -+ -+void free_json_map_int_bool(json_map_int_bool *map) { -+ if (map != NULL) { -+ free(map->keys); -+ map->keys = NULL; -+ free(map->values); -+ map->values = NULL; -+ free(map); -+ } -+} -+json_map_int_bool *make_json_map_int_bool(yajl_val src, struct parser_context *ctx, parser_error *err) { -+ json_map_int_bool *ret = NULL; -+ if (src != NULL && YAJL_GET_OBJECT(src) != NULL) { -+ size_t i; -+ size_t len = YAJL_GET_OBJECT(src)->len; -+ if (len > SIZE_MAX / sizeof(int) - 1) { -+ return NULL; -+ } -+ ret = safe_malloc(sizeof(*ret)); -+ ret->len = len; -+ ret->keys = safe_malloc((len + 1) * sizeof(int)); -+ ret->values = safe_malloc((len + 1) * sizeof(bool)); -+ for (i = 0; i < len; i++) { -+ const char *srckey = YAJL_GET_OBJECT(src)->keys[i]; -+ yajl_val srcval = YAJL_GET_OBJECT(src)->values[i]; -+ -+ if (srckey != NULL) { -+ int invalid; -+ invalid = common_safe_int(srckey, &(ret->keys[i])); -+ if (invalid) { -+ if (*err == NULL && asprintf(err, "Invalid key '%s' with type 'int': %s", srckey, strerror(-invalid)) < 0) { -+ *(err) = safe_strdup("error allocating memory"); -+ } -+ free_json_map_int_bool(ret); -+ return NULL; -+ } -+ } ++ ret->keys[i] = safe_strdup(srckey ? srckey : ""); + + if (srcval != NULL) { + if (YAJL_IS_TRUE(srcval)) { @@ -5894,7 +4509,7 @@ index 0000000..ec20c59 + if (*err == NULL && asprintf(err, "Invalid value with type 'bool' for key '%s'", srckey) < 0) { + *(err) = safe_strdup("error allocating memory"); + } -+ free_json_map_int_bool(ret); ++ free_json_map_string_bool(ret); + return NULL; + } + } @@ -5902,39 +4517,40 @@ index 0000000..ec20c59 + } + return ret; +} -+int append_json_map_int_bool(json_map_int_bool *map, int key, bool val) { ++ ++int append_json_map_string_bool(json_map_string_bool *map, const char *key, bool val) { + size_t len; -+ int *keys = NULL; ++ char **keys = NULL; + bool *vals = NULL; + + if (map == NULL) { + return -1; + } + -+ if ((SIZE_MAX / sizeof(int) - 1) < map->len || (SIZE_MAX / sizeof(bool) - 1) < map->len) { ++ if ((SIZE_MAX / sizeof(char *) - 1) < map->len || (SIZE_MAX / sizeof(bool) - 1) < map->len) { + return -1; + } + + len = map->len + 1; -+ keys = safe_malloc(len * sizeof(int)); ++ keys = safe_malloc(len * sizeof(char *)); + vals = safe_malloc(len * sizeof(bool)); + + if (map->len) { -+ (void)memcpy(keys, map->keys, map->len * sizeof(int)); ++ (void)memcpy(keys, map->keys, map->len * sizeof(char *)); + (void)memcpy(vals, map->values, map->len * sizeof(bool)); + } + free(map->keys); + map->keys = keys; + free(map->values); + map->values = vals; -+ map->keys[map->len] = key; ++ map->keys[map->len] = safe_strdup(key ? key : ""); + map->values[map->len] = val; + + map->len++; + return 0; +} + -+yajl_gen_status gen_json_map_int_string(void *ctx, json_map_int_string *map, struct parser_context *ptx, parser_error *err) { ++yajl_gen_status gen_json_map_string_string(void *ctx, json_map_string_string *map, struct parser_context *ptx, parser_error *err) { + yajl_gen_status stat = yajl_gen_status_ok; + yajl_gen g = (yajl_gen) ctx; + size_t len = 0, i = 0; @@ -5950,16 +4566,7 @@ index 0000000..ec20c59 + + } + for (i = 0; i < len; i++) { -+ char numstr[MAX_NUM_STR_LEN]; -+ int nret; -+ nret = snprintf(numstr, MAX_NUM_STR_LEN, "%lld", (long long int)map->keys[i]); -+ if (nret < 0 || nret >= MAX_NUM_STR_LEN) { -+ if (!*err && asprintf(err, "Error to print string") < 0) { -+ *(err) = safe_strdup("error allocating memory"); -+ } -+ return yajl_gen_in_error_state; -+ } -+ stat = reformat_string(g, numstr, strlen(numstr)); ++ stat = reformat_string(g, map->keys[i], strlen(map->keys[i])); + if (yajl_gen_status_ok != stat) { + GEN_SET_ERROR_AND_RETURN(stat, err); + } @@ -5979,11 +4586,12 @@ index 0000000..ec20c59 + return yajl_gen_status_ok; +} + -+void free_json_map_int_string(json_map_int_string *map) { ++void free_json_map_string_string(json_map_string_string *map) { + if (map != NULL) { + size_t i; + for (i = 0; i < map->len; i++) { -+ // No need to free key for type int ++ free(map->keys[i]); ++ map->keys[i] = NULL; + free(map->values[i]); + map->values[i] = NULL; + } @@ -5994,8 +4602,8 @@ index 0000000..ec20c59 + free(map); + } +} -+json_map_int_string *make_json_map_int_string(yajl_val src, struct parser_context *ctx, parser_error *err) { -+ json_map_int_string *ret = NULL; ++json_map_string_string *make_json_map_string_string(yajl_val src, struct parser_context *ctx, parser_error *err) { ++ json_map_string_string *ret = NULL; + if (src != NULL && YAJL_GET_OBJECT(src) != NULL) { + size_t i; + size_t len = YAJL_GET_OBJECT(src)->len; @@ -6004,30 +4612,19 @@ index 0000000..ec20c59 + } + ret = safe_malloc(sizeof(*ret)); + ret->len = len; -+ ret->keys = safe_malloc((len + 1) * sizeof(int)); ++ ret->keys = safe_malloc((len + 1) * sizeof(char *)); + ret->values = safe_malloc((len + 1) * sizeof(char *)); + for (i = 0; i < len; i++) { + const char *srckey = YAJL_GET_OBJECT(src)->keys[i]; + yajl_val srcval = YAJL_GET_OBJECT(src)->values[i]; -+ -+ if (srckey != NULL) { -+ int invalid; -+ invalid = common_safe_int(srckey, &(ret->keys[i])); -+ if (invalid) { -+ if (*err == NULL && asprintf(err, "Invalid key '%s' with type 'int': %s", srckey, strerror(-invalid)) < 0) { -+ *(err) = safe_strdup("error allocating memory"); -+ } -+ free_json_map_int_string(ret); -+ return NULL; -+ } -+ } ++ ret->keys[i] = safe_strdup(srckey ? srckey : ""); + + if (srcval != NULL) { + if (!YAJL_IS_STRING(srcval)) { + if (*err == NULL && asprintf(err, "Invalid value with type 'string' for key '%s'", srckey) < 0) { + *(err) = safe_strdup("error allocating memory"); + } -+ free_json_map_int_string(ret); ++ free_json_map_string_string(ret); + return NULL; + } + char *str = YAJL_GET_STRING(srcval); @@ -6037,489 +4634,124 @@ index 0000000..ec20c59 + } + return ret; +} -+int append_json_map_int_string(json_map_int_string *map, int key, const char *val) { -+ size_t len; -+ int *keys = NULL; ++int append_json_map_string_string(json_map_string_string *map, const char *key, const char *val) { ++ size_t len, i; ++ char **keys = NULL; + char **vals = NULL; + + if (map == NULL) { + return -1; + } + -+ if ((SIZE_MAX / sizeof(int) - 1) < map->len || (SIZE_MAX / sizeof(char *) - 1) < map->len) { ++ for (i = 0; i < map->len; i++) { ++ if (strcmp(map->keys[i], key) == 0) { ++ free(map->values[i]); ++ map->values[i] = safe_strdup(val ? val : ""); ++ return 0; ++ } ++ } ++ ++ if ((SIZE_MAX / sizeof(char *) - 1) < map->len) { + return -1; + } + + len = map->len + 1; -+ keys = safe_malloc(len * sizeof(int)); ++ keys = safe_malloc(len * sizeof(char *)); + vals = safe_malloc(len * sizeof(char *)); + + if (map->len) { -+ (void)memcpy(keys, map->keys, map->len * sizeof(int)); ++ (void)memcpy(keys, map->keys, map->len * sizeof(char *)); + (void)memcpy(vals, map->values, map->len * sizeof(char *)); + } + free(map->keys); + map->keys = keys; + free(map->values); + map->values = vals; -+ map->keys[map->len] = key; ++ map->keys[map->len] = safe_strdup(key ? key : ""); + map->values[map->len] = safe_strdup(val ? val : ""); + + map->len++; + return 0; +} +diff --git a/src/lxc/json/json_common.h b/src/lxc/json/json_common.h +new file mode 100755 +index 0000000..60aa5fd +--- /dev/null ++++ b/src/lxc/json/json_common.h +@@ -0,0 +1,185 @@ ++// Auto generated file. Do not edit! ++#ifndef _JSON_COMMON_H ++#define _JSON_COMMON_H + -+yajl_gen_status gen_json_map_string_int(void *ctx, json_map_string_int *map, struct parser_context *ptx, parser_error *err) { -+ yajl_gen_status stat = yajl_gen_status_ok; -+ yajl_gen g = (yajl_gen) ctx; -+ size_t len = 0, i = 0; -+ if (map != NULL) { -+ len = map->len; -+ } -+ if (!len && !(ptx->options & GEN_OPTIONS_SIMPLIFY)) { -+ yajl_gen_config(g, yajl_gen_beautify, 0); -+ } -+ stat = reformat_start_map(g); -+ if (yajl_gen_status_ok != stat) { -+ GEN_SET_ERROR_AND_RETURN(stat, err); ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "utils.h" + -+ } -+ for (i = 0; i < len; i++) { -+ stat = reformat_string(g, map->keys[i], strlen(map->keys[i])); -+ if (yajl_gen_status_ok != stat) { -+ GEN_SET_ERROR_AND_RETURN(stat, err); -+ } -+ stat = reformat_int(g, map->values[i]); -+ if (yajl_gen_status_ok != stat) { -+ GEN_SET_ERROR_AND_RETURN(stat, err); -+ } -+ } ++#ifdef __cplusplus ++extern "C" { ++#endif + -+ stat = reformat_end_map(g); -+ if (yajl_gen_status_ok != stat) { -+ GEN_SET_ERROR_AND_RETURN(stat, err); -+ } -+ if (!len && !(ptx->options & GEN_OPTIONS_SIMPLIFY)) { -+ yajl_gen_config(g, yajl_gen_beautify, 1); -+ } -+ return yajl_gen_status_ok; -+} ++# undef linux + -+void free_json_map_string_int(json_map_string_int *map) { -+ if (map != NULL) { -+ size_t i; -+ for (i = 0; i < map->len; i++) { -+ free(map->keys[i]); -+ map->keys[i] = NULL; -+ // No need to free value for type int -+ } -+ free(map->keys); -+ map->keys = NULL; -+ free(map->values); -+ map->values = NULL; -+ free(map); -+ } -+} -+json_map_string_int *make_json_map_string_int(yajl_val src, struct parser_context *ctx, parser_error *err) { -+ json_map_string_int *ret = NULL; -+ if (src != NULL && YAJL_GET_OBJECT(src) != NULL) { -+ size_t i; -+ size_t len = YAJL_GET_OBJECT(src)->len; -+ if (len > SIZE_MAX / sizeof(char *) - 1) { -+ return NULL; -+ } -+ ret = safe_malloc(sizeof(*ret)); -+ ret->len = len; -+ ret->keys = safe_malloc((len + 1) * sizeof(char *)); -+ ret->values = safe_malloc((len + 1) * sizeof(int)); -+ for (i = 0; i < len; i++) { -+ const char *srckey = YAJL_GET_OBJECT(src)->keys[i]; -+ yajl_val srcval = YAJL_GET_OBJECT(src)->values[i]; -+ ret->keys[i] = safe_strdup(srckey ? srckey : ""); ++//options to report error if there is unknown key found in json ++# define PARSE_OPTIONS_STRICT 0x01 ++//options to generate all key and value ++# define GEN_OPTIONS_ALLKEYVALUE 0x02 ++//options to generate simplify(no indent) json string ++# define GEN_OPTIONS_SIMPLIFY 0x04 ++//options not to validate utf8 data ++# define GEN_OPTIONS_NOT_VALIDATE_UTF8 0x08 + -+ if (srcval != NULL) { -+ int invalid; -+ if (!YAJL_IS_NUMBER(srcval)) { -+ if (*err == NULL && asprintf(err, "Invalid value with type 'int' for key '%s'", srckey) < 0) { -+ *(err) = safe_strdup("error allocating memory"); -+ } -+ free_json_map_string_int(ret); -+ return NULL; -+ } -+ invalid = common_safe_int(YAJL_GET_NUMBER(srcval), &(ret->values[i])); -+ if (invalid) { -+ if (*err == NULL && asprintf(err, "Invalid value with type 'int' for key '%s': %s", srckey, strerror(-invalid)) < 0) { -+ *(err) = safe_strdup("error allocating memory"); -+ } -+ free_json_map_string_int(ret); -+ return NULL; -+ } -+ } -+ } ++#define GEN_SET_ERROR_AND_RETURN(stat, err) { \ ++ if (*(err) == NULL) {\ ++ if (asprintf(err, "%s: %s: %d: error generating json, errcode: %d", __FILE__, __func__, __LINE__, stat) < 0) { \ ++ *(err) = safe_strdup("error allocating memory"); \ ++ } \ ++ }\ ++ return stat; \ + } -+ return ret; -+} -+int append_json_map_string_int(json_map_string_int *map, const char *key, int val) { -+ size_t len; -+ char **keys = NULL; -+ int *vals = NULL; + -+ if (map == NULL) { -+ return -1; -+ } ++typedef char *parser_error; + -+ if ((SIZE_MAX / sizeof(char *) - 1) < map->len || (SIZE_MAX / sizeof(int) - 1) < map->len) { -+ return -1; -+ } ++struct parser_context { ++ unsigned int options; ++ FILE *stderr; ++}; + -+ len = map->len + 1; -+ keys = safe_malloc(len * sizeof(char *)); -+ vals = safe_malloc(len * sizeof(int)); ++yajl_gen_status reformat_number(void *ctx, const char *str, size_t len); + -+ if (map->len) { -+ (void)memcpy(keys, map->keys, map->len * sizeof(char *)); -+ (void)memcpy(vals, map->values, map->len * sizeof(int)); -+ } -+ free(map->keys); -+ map->keys = keys; -+ free(map->values); -+ map->values = vals; -+ map->keys[map->len] = safe_strdup(key ? key : ""); -+ map->values[map->len] = val; ++yajl_gen_status reformat_uint(void *ctx, long long unsigned int num); + -+ map->len++; -+ return 0; -+} ++yajl_gen_status reformat_int(void *ctx, long long int num); + -+yajl_gen_status gen_json_map_string_bool(void *ctx, json_map_string_bool *map, struct parser_context *ptx, parser_error *err) { -+ yajl_gen_status stat = yajl_gen_status_ok; -+ yajl_gen g = (yajl_gen) ctx; -+ size_t len = 0, i = 0; -+ if (map != NULL) { -+ len = map->len; -+ } -+ if (!len && !(ptx->options & GEN_OPTIONS_SIMPLIFY)) { -+ yajl_gen_config(g, yajl_gen_beautify, 0); -+ } -+ stat = reformat_start_map(g); -+ if (yajl_gen_status_ok != stat) { -+ GEN_SET_ERROR_AND_RETURN(stat, err); ++yajl_gen_status reformat_double(void *ctx, double num); + -+ } -+ for (i = 0; i < len; i++) { -+ stat = reformat_string(g, map->keys[i], strlen(map->keys[i])); -+ if (yajl_gen_status_ok != stat) { -+ GEN_SET_ERROR_AND_RETURN(stat, err); -+ } -+ stat = reformat_bool(g, map->values[i]); -+ if (yajl_gen_status_ok != stat) { -+ GEN_SET_ERROR_AND_RETURN(stat, err); -+ } -+ } ++yajl_gen_status reformat_string(void *ctx, const char *str, size_t len); + -+ stat = reformat_end_map(g); -+ if (yajl_gen_status_ok != stat) { -+ GEN_SET_ERROR_AND_RETURN(stat, err); -+ } -+ if (!len && !(ptx->options & GEN_OPTIONS_SIMPLIFY)) { -+ yajl_gen_config(g, yajl_gen_beautify, 1); -+ } -+ return yajl_gen_status_ok; -+} ++yajl_gen_status reformat_null(void *ctx); + -+void free_json_map_string_bool(json_map_string_bool *map) { -+ if (map != NULL) { -+ size_t i; -+ for (i = 0; i < map->len; i++) { -+ free(map->keys[i]); -+ map->keys[i] = NULL; -+ // No need to free value for type bool -+ } -+ free(map->keys); -+ map->keys = NULL; -+ free(map->values); -+ map->values = NULL; -+ free(map); -+ } -+} -+json_map_string_bool *make_json_map_string_bool(yajl_val src, struct parser_context *ctx, parser_error *err) { -+ json_map_string_bool *ret = NULL; -+ if (src != NULL && YAJL_GET_OBJECT(src) != NULL) { -+ size_t i; -+ size_t len = YAJL_GET_OBJECT(src)->len; -+ if (len > SIZE_MAX / sizeof(char *) - 1) { -+ return NULL; -+ } -+ ret = safe_malloc(sizeof(*ret)); -+ ret->len = len; -+ ret->keys = safe_malloc((len + 1) * sizeof(char *)); -+ ret->values = safe_malloc((len + 1) * sizeof(bool)); -+ for (i = 0; i < len; i++) { -+ const char *srckey = YAJL_GET_OBJECT(src)->keys[i]; -+ yajl_val srcval = YAJL_GET_OBJECT(src)->values[i]; -+ ret->keys[i] = safe_strdup(srckey ? srckey : ""); ++yajl_gen_status reformat_bool(void *ctx, int boolean); + -+ if (srcval != NULL) { -+ if (YAJL_IS_TRUE(srcval)) { -+ ret->values[i] = true; -+ } else if (YAJL_IS_FALSE(srcval)) { -+ ret->values[i] = false; -+ } else { -+ if (*err == NULL && asprintf(err, "Invalid value with type 'bool' for key '%s'", srckey) < 0) { -+ *(err) = safe_strdup("error allocating memory"); -+ } -+ free_json_map_string_bool(ret); -+ return NULL; -+ } -+ } -+ } -+ } -+ return ret; -+} ++yajl_gen_status reformat_map_key(void *ctx, const char *str, size_t len); + -+int append_json_map_string_bool(json_map_string_bool *map, const char *key, bool val) { -+ size_t len; -+ char **keys = NULL; -+ bool *vals = NULL; ++yajl_gen_status reformat_start_map(void *ctx); + -+ if (map == NULL) { -+ return -1; -+ } ++yajl_gen_status reformat_end_map(void *ctx); + -+ if ((SIZE_MAX / sizeof(char *) - 1) < map->len || (SIZE_MAX / sizeof(bool) - 1) < map->len) { -+ return -1; -+ } ++yajl_gen_status reformat_start_array(void *ctx); + -+ len = map->len + 1; -+ keys = safe_malloc(len * sizeof(char *)); -+ vals = safe_malloc(len * sizeof(bool)); ++yajl_gen_status reformat_end_array(void *ctx); + -+ if (map->len) { -+ (void)memcpy(keys, map->keys, map->len * sizeof(char *)); -+ (void)memcpy(vals, map->values, map->len * sizeof(bool)); -+ } -+ free(map->keys); -+ map->keys = keys; -+ free(map->values); -+ map->values = vals; -+ map->keys[map->len] = safe_strdup(key ? key : ""); -+ map->values[map->len] = val; ++bool json_gen_init(yajl_gen *g, struct parser_context *ctx); + -+ map->len++; -+ return 0; -+} ++yajl_val get_val(yajl_val tree, const char *name, yajl_type type); + -+yajl_gen_status gen_json_map_string_string(void *ctx, json_map_string_string *map, struct parser_context *ptx, parser_error *err) { -+ yajl_gen_status stat = yajl_gen_status_ok; -+ yajl_gen g = (yajl_gen) ctx; -+ size_t len = 0, i = 0; -+ if (map != NULL) { -+ len = map->len; -+ } -+ if (!len && !(ptx->options & GEN_OPTIONS_SIMPLIFY)) { -+ yajl_gen_config(g, yajl_gen_beautify, 0); -+ } -+ stat = reformat_start_map(g); -+ if (yajl_gen_status_ok != stat) { -+ GEN_SET_ERROR_AND_RETURN(stat, err); -+ -+ } -+ for (i = 0; i < len; i++) { -+ stat = reformat_string(g, map->keys[i], strlen(map->keys[i])); -+ if (yajl_gen_status_ok != stat) { -+ GEN_SET_ERROR_AND_RETURN(stat, err); -+ } -+ stat = reformat_string(g, map->values[i], strlen(map->values[i]));; -+ if (yajl_gen_status_ok != stat) { -+ GEN_SET_ERROR_AND_RETURN(stat, err); -+ } -+ } -+ -+ stat = reformat_end_map(g); -+ if (yajl_gen_status_ok != stat) { -+ GEN_SET_ERROR_AND_RETURN(stat, err); -+ } -+ if (!len && !(ptx->options & GEN_OPTIONS_SIMPLIFY)) { -+ yajl_gen_config(g, yajl_gen_beautify, 1); -+ } -+ return yajl_gen_status_ok; -+} -+ -+void free_json_map_string_string(json_map_string_string *map) { -+ if (map != NULL) { -+ size_t i; -+ for (i = 0; i < map->len; i++) { -+ free(map->keys[i]); -+ map->keys[i] = NULL; -+ free(map->values[i]); -+ map->values[i] = NULL; -+ } -+ free(map->keys); -+ map->keys = NULL; -+ free(map->values); -+ map->values = NULL; -+ free(map); -+ } -+} -+json_map_string_string *make_json_map_string_string(yajl_val src, struct parser_context *ctx, parser_error *err) { -+ json_map_string_string *ret = NULL; -+ if (src != NULL && YAJL_GET_OBJECT(src) != NULL) { -+ size_t i; -+ size_t len = YAJL_GET_OBJECT(src)->len; -+ if (len > SIZE_MAX / sizeof(char *) - 1) { -+ return NULL; -+ } -+ ret = safe_malloc(sizeof(*ret)); -+ ret->len = len; -+ ret->keys = safe_malloc((len + 1) * sizeof(char *)); -+ ret->values = safe_malloc((len + 1) * sizeof(char *)); -+ for (i = 0; i < len; i++) { -+ const char *srckey = YAJL_GET_OBJECT(src)->keys[i]; -+ yajl_val srcval = YAJL_GET_OBJECT(src)->values[i]; -+ ret->keys[i] = safe_strdup(srckey ? srckey : ""); -+ -+ if (srcval != NULL) { -+ if (!YAJL_IS_STRING(srcval)) { -+ if (*err == NULL && asprintf(err, "Invalid value with type 'string' for key '%s'", srckey) < 0) { -+ *(err) = safe_strdup("error allocating memory"); -+ } -+ free_json_map_string_string(ret); -+ return NULL; -+ } -+ char *str = YAJL_GET_STRING(srcval); -+ ret->values[i] = safe_strdup(str ? str : ""); -+ } -+ } -+ } -+ return ret; -+} -+int append_json_map_string_string(json_map_string_string *map, const char *key, const char *val) { -+ size_t len, i; -+ char **keys = NULL; -+ char **vals = NULL; -+ -+ if (map == NULL) { -+ return -1; -+ } -+ -+ for (i = 0; i < map->len; i++) { -+ if (strcmp(map->keys[i], key) == 0) { -+ free(map->values[i]); -+ map->values[i] = safe_strdup(val ? val : ""); -+ return 0; -+ } -+ } -+ -+ if ((SIZE_MAX / sizeof(char *) - 1) < map->len) { -+ return -1; -+ } -+ -+ len = map->len + 1; -+ keys = safe_malloc(len * sizeof(char *)); -+ vals = safe_malloc(len * sizeof(char *)); -+ -+ if (map->len) { -+ (void)memcpy(keys, map->keys, map->len * sizeof(char *)); -+ (void)memcpy(vals, map->values, map->len * sizeof(char *)); -+ } -+ free(map->keys); -+ map->keys = keys; -+ free(map->values); -+ map->values = vals; -+ map->keys[map->len] = safe_strdup(key ? key : ""); -+ map->values[map->len] = safe_strdup(val ? val : ""); -+ -+ map->len++; -+ return 0; -+} -diff --git a/src/lxc/json/json_common.h b/src/lxc/json/json_common.h -new file mode 100755 -index 0000000..bcac13e ---- /dev/null -+++ b/src/lxc/json/json_common.h -@@ -0,0 +1,194 @@ -+// Auto generated file. Do not edit! -+#ifndef _JSON_COMMON_H -+#define _JSON_COMMON_H -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include "isulad_utils.h" -+ -+#ifdef __cplusplus -+extern "C" { -+#endif -+ -+# undef linux -+ -+#ifdef __MUSL__ -+#undef stdin -+#undef stdout -+#undef stderr -+#define stdin stdin -+#define stdout stdout -+#define stderr stderr -+#endif -+ -+//options to report error if there is unknown key found in json -+# define PARSE_OPTIONS_STRICT 0x01 -+//options to generate all key and value -+# define GEN_OPTIONS_ALLKEYVALUE 0x02 -+//options to generate simplify(no indent) json string -+# define GEN_OPTIONS_SIMPLIFY 0x04 -+//options not to validate utf8 data -+# define GEN_OPTIONS_NOT_VALIDATE_UTF8 0x08 -+ -+#define GEN_SET_ERROR_AND_RETURN(stat, err) { \ -+ if (*(err) == NULL) {\ -+ if (asprintf(err, "%s: %s: %d: error generating json, errcode: %d", __FILE__, __func__, __LINE__, stat) < 0) { \ -+ *(err) = safe_strdup("error allocating memory"); \ -+ } \ -+ }\ -+ return stat; \ -+ } -+ -+typedef char *parser_error; -+ -+struct parser_context { -+ unsigned int options; -+ FILE *stderr; -+}; -+ -+yajl_gen_status reformat_number(void *ctx, const char *str, size_t len); -+ -+yajl_gen_status reformat_uint(void *ctx, long long unsigned int num); -+ -+yajl_gen_status reformat_int(void *ctx, long long int num); -+ -+yajl_gen_status reformat_double(void *ctx, double num); -+ -+yajl_gen_status reformat_string(void *ctx, const char *str, size_t len); -+ -+yajl_gen_status reformat_null(void *ctx); -+ -+yajl_gen_status reformat_bool(void *ctx, int boolean); -+ -+yajl_gen_status reformat_map_key(void *ctx, const char *str, size_t len); -+ -+yajl_gen_status reformat_start_map(void *ctx); -+ -+yajl_gen_status reformat_end_map(void *ctx); -+ -+yajl_gen_status reformat_start_array(void *ctx); -+ -+yajl_gen_status reformat_end_array(void *ctx); -+ -+bool json_gen_init(yajl_gen *g, struct parser_context *ctx); -+ -+yajl_val get_val(yajl_val tree, const char *name, yajl_type type); -+ -+void *safe_malloc(size_t size); ++void *safe_malloc(size_t size); + +int common_safe_double(const char *numstr, double *converted); + @@ -6619,1372 +4851,661 @@ index 0000000..bcac13e + size_t len; +} json_map_string_string; + -+void free_json_map_string_string(json_map_string_string *map); -+ -+json_map_string_string *make_json_map_string_string(yajl_val src, struct parser_context *ctx, parser_error *err); -+ -+yajl_gen_status gen_json_map_string_string(void *ctx, json_map_string_string *map, struct parser_context *ptx, parser_error *err); -+ -+int append_json_map_string_string(json_map_string_string *map, const char *key, const char *val); -+ -+#ifdef __cplusplus -+} -+#endif -+ -+#endif -\ No newline at end of file -diff --git a/src/lxc/json/logger_json_file.c b/src/lxc/json/logger_json_file.c -new file mode 100644 -index 0000000..6abeef4 ---- /dev/null -+++ b/src/lxc/json/logger_json_file.c -@@ -0,0 +1,246 @@ -+// Generated from json-file.json. Do not edit! -+#ifndef _GNU_SOURCE -+#define _GNU_SOURCE -+#endif -+#include -+#include -+#include "logger_json_file.h" -+ -+logger_json_file *make_logger_json_file(yajl_val tree, struct parser_context *ctx, parser_error *err) { -+ logger_json_file *ret = NULL; -+ *err = 0; -+ if (tree == NULL) -+ return ret; -+ ret = safe_malloc(sizeof(*ret)); -+ { -+ yajl_val tmp = get_val(tree, "log", yajl_t_string); -+ if (tmp != NULL) { -+ char *str = YAJL_GET_STRING(tmp); -+ ret->log = (uint8_t *)safe_strdup(str ? str : ""); -+ ret->log_len = str != NULL ? strlen(str) : 0; -+ } -+ } -+ { -+ yajl_val val = get_val(tree, "stream", yajl_t_string); -+ if (val != NULL) { -+ char *str = YAJL_GET_STRING(val); -+ ret->stream = safe_strdup(str ? str : ""); -+ } -+ } -+ { -+ yajl_val val = get_val(tree, "time", yajl_t_string); -+ if (val != NULL) { -+ char *str = YAJL_GET_STRING(val); -+ ret->time = safe_strdup(str ? str : ""); -+ } -+ } -+ { -+ yajl_val tmp = get_val(tree, "attrs", yajl_t_string); -+ if (tmp != NULL) { -+ char *str = YAJL_GET_STRING(tmp); -+ ret->attrs = (uint8_t *)safe_strdup(str ? str : ""); -+ ret->attrs_len = str != NULL ? strlen(str) : 0; -+ } -+ } -+ -+ if (tree->type == yajl_t_object && (ctx->options & PARSE_OPTIONS_STRICT)) { -+ int i; -+ for (i = 0; i < tree->u.object.len; i++) -+ if (strcmp(tree->u.object.keys[i], "log") && -+ strcmp(tree->u.object.keys[i], "stream") && -+ strcmp(tree->u.object.keys[i], "time") && -+ strcmp(tree->u.object.keys[i], "attrs")) { -+ if (ctx->stderr > 0) -+ fprintf(ctx->stderr, "WARNING: unknown key found: %s\n", tree->u.object.keys[i]); -+ } -+ } -+ return ret; -+} -+ -+void free_logger_json_file(logger_json_file *ptr) { -+ if (ptr == NULL) -+ return; -+ free(ptr->log); -+ ptr->log = NULL; -+ free(ptr->stream); -+ ptr->stream = NULL; -+ free(ptr->time); -+ ptr->time = NULL; -+ free(ptr->attrs); -+ ptr->attrs = NULL; -+ free(ptr); -+} -+ -+yajl_gen_status gen_logger_json_file(yajl_gen g, logger_json_file *ptr, struct parser_context *ctx, parser_error *err) { -+ yajl_gen_status stat = yajl_gen_status_ok; -+ *err = 0; -+ stat = reformat_start_map(g); -+ if (yajl_gen_status_ok != stat) -+ GEN_SET_ERROR_AND_RETURN(stat, err); -+ if ((ctx->options & GEN_OPTIONS_ALLKEYVALUE) || (ptr != NULL && ptr->log != NULL && ptr->log_len)) { -+ const char *str = ""; -+ size_t len = 0; -+ stat = reformat_map_key(g, "log", strlen("log")); -+ if (yajl_gen_status_ok != stat) -+ GEN_SET_ERROR_AND_RETURN(stat, err); -+ if (ptr != NULL && ptr->log != NULL) { -+ str = (const char *)ptr->log; -+ len = ptr->log_len; -+ } -+ stat = reformat_string(g, str, len); -+ if (yajl_gen_status_ok != stat) -+ GEN_SET_ERROR_AND_RETURN(stat, err); -+ } -+ if ((ctx->options & GEN_OPTIONS_ALLKEYVALUE) ||(ptr != NULL && ptr->stream != NULL)) { -+ char *str = ""; -+ stat = reformat_map_key(g, "stream", strlen("stream")); -+ if (yajl_gen_status_ok != stat) -+ GEN_SET_ERROR_AND_RETURN(stat, err); -+ if (ptr != NULL && ptr->stream != NULL) { -+ str = ptr->stream; -+ } -+ stat = reformat_string(g, str, strlen(str)); -+ if (yajl_gen_status_ok != stat) -+ GEN_SET_ERROR_AND_RETURN(stat, err); -+ } -+ if ((ctx->options & GEN_OPTIONS_ALLKEYVALUE) ||(ptr != NULL && ptr->time != NULL)) { -+ char *str = ""; -+ stat = reformat_map_key(g, "time", strlen("time")); -+ if (yajl_gen_status_ok != stat) -+ GEN_SET_ERROR_AND_RETURN(stat, err); -+ if (ptr != NULL && ptr->time != NULL) { -+ str = ptr->time; -+ } -+ stat = reformat_string(g, str, strlen(str)); -+ if (yajl_gen_status_ok != stat) -+ GEN_SET_ERROR_AND_RETURN(stat, err); -+ } -+ if ((ctx->options & GEN_OPTIONS_ALLKEYVALUE) || (ptr != NULL && ptr->attrs != NULL && ptr->attrs_len)) { -+ const char *str = ""; -+ size_t len = 0; -+ stat = reformat_map_key(g, "attrs", strlen("attrs")); -+ if (yajl_gen_status_ok != stat) -+ GEN_SET_ERROR_AND_RETURN(stat, err); -+ if (ptr != NULL && ptr->attrs != NULL) { -+ str = (const char *)ptr->attrs; -+ len = ptr->attrs_len; -+ } -+ stat = reformat_string(g, str, len); -+ if (yajl_gen_status_ok != stat) -+ GEN_SET_ERROR_AND_RETURN(stat, err); -+ } -+ stat = reformat_end_map(g); -+ if (yajl_gen_status_ok != stat) -+ GEN_SET_ERROR_AND_RETURN(stat, err); -+ return yajl_gen_status_ok; -+} -+ -+ -+logger_json_file *logger_json_file_parse_file(const char *filename, struct parser_context *ctx, parser_error *err) { -+ logger_json_file *ptr = NULL; -+ size_t filesize; -+ char *content = NULL; -+ -+ if (filename == NULL || err == NULL) -+ return NULL; -+ -+ *err = NULL; -+ content = read_file(filename, &filesize); -+ if (content == NULL) { -+ if (asprintf(err, "cannot read the file: %s", filename) < 0) -+ *err = safe_strdup("error allocating memory"); -+ return NULL; -+ } -+ ptr = logger_json_file_parse_data(content, ctx, err); -+ free(content); -+ return ptr; -+} -+ -+logger_json_file *logger_json_file_parse_file_stream(FILE *stream, struct parser_context *ctx, parser_error *err) { -+ logger_json_file *ptr = NULL; -+ size_t filesize; -+ char *content = NULL ; -+ -+ if (stream == NULL || err == NULL) -+ return NULL; -+ -+ *err = NULL; -+ content = fread_file(stream, &filesize); -+ if (content == NULL) { -+ *err = safe_strdup("cannot read the file"); -+ return NULL; -+ } -+ ptr = logger_json_file_parse_data(content, ctx, err); -+ free(content); -+ return ptr; -+} -+ -+logger_json_file *logger_json_file_parse_data(const char *jsondata, struct parser_context *ctx, parser_error *err) { -+ logger_json_file *ptr = NULL; -+ yajl_val tree; -+ char errbuf[1024]; -+ struct parser_context tmp_ctx; -+ -+ if (jsondata == NULL || err == NULL) -+ return NULL; -+ -+ *err = NULL; -+ if (ctx == NULL) { -+ ctx = &tmp_ctx; -+ memset(&tmp_ctx, 0, sizeof(tmp_ctx)); -+ } -+ tree = yajl_tree_parse(jsondata, errbuf, sizeof(errbuf)); -+ if (tree == NULL) { -+ if (asprintf(err, "cannot parse the data: %s", errbuf) < 0) -+ *err = safe_strdup("error allocating memory"); -+ return NULL; -+ } -+ ptr = make_logger_json_file(tree, ctx, err); -+ yajl_tree_free(tree); -+ return ptr; -+} -+char *logger_json_file_generate_json(logger_json_file *ptr, struct parser_context *ctx, parser_error *err) { -+ yajl_gen g = NULL; -+ struct parser_context tmp_ctx; -+ const unsigned char *gen_buf = NULL; -+ char *json_buf = NULL; -+ size_t gen_len = 0; -+ -+ if (ptr == NULL || err == NULL) -+ return NULL; -+ -+ *err = NULL; -+ if (ctx == NULL) { -+ ctx = &tmp_ctx; -+ memset(&tmp_ctx, 0, sizeof(tmp_ctx)); -+ } -+ -+ if (!json_gen_init(&g, ctx)) { -+ *err = safe_strdup("Json_gen init failed"); -+ goto out; -+ } -+ if (yajl_gen_status_ok != gen_logger_json_file(g, ptr, ctx, err)) { -+ if (*err == NULL) -+ *err = safe_strdup("Failed to generate json"); -+ goto free_out; -+ } -+ yajl_gen_get_buf(g, &gen_buf, &gen_len); -+ if (gen_buf == NULL) { -+ *err = safe_strdup("Error to get generated json"); -+ goto free_out; -+ } -+ -+ if (gen_len == SIZE_MAX) { -+ *err = safe_strdup("Invalid buffer length"); -+ goto free_out; -+ } -+ json_buf = safe_malloc(gen_len + 1); -+ (void)memcpy(json_buf, gen_buf, gen_len); -+ json_buf[gen_len] = '\0'; -+ -+free_out: -+ yajl_gen_clear(g); -+ yajl_gen_free(g); -+out: -+ return json_buf; -+} -diff --git a/src/lxc/json/logger_json_file.h b/src/lxc/json/logger_json_file.h -new file mode 100644 -index 0000000..ad5af7b ---- /dev/null -+++ b/src/lxc/json/logger_json_file.h -@@ -0,0 +1,45 @@ -+// Generated from json-file.json. Do not edit! -+#ifndef LOGGER_JSON_FILE_SCHEMA_H -+#define LOGGER_JSON_FILE_SCHEMA_H -+ -+#include -+#include -+#include "json_common.h" -+ -+#ifdef __cplusplus -+extern "C" { -+#endif -+ -+typedef struct { -+ uint8_t *log; -+ size_t log_len; -+ -+ char *stream; -+ -+ char *time; -+ -+ uint8_t *attrs; -+ size_t attrs_len; -+ -+} -+logger_json_file; -+ -+void free_logger_json_file(logger_json_file *ptr); -+ -+logger_json_file *make_logger_json_file(yajl_val tree, struct parser_context *ctx, parser_error *err); -+ -+yajl_gen_status gen_logger_json_file(yajl_gen g, logger_json_file *ptr, struct parser_context *ctx, parser_error *err); -+ -+logger_json_file *logger_json_file_parse_file(const char *filename, struct parser_context *ctx, parser_error *err); -+ -+logger_json_file *logger_json_file_parse_file_stream(FILE *stream, struct parser_context *ctx, parser_error *err); -+ -+logger_json_file *logger_json_file_parse_data(const char *jsondata, struct parser_context *ctx, parser_error *err); -+ -+char *logger_json_file_generate_json(logger_json_file *ptr, struct parser_context *ctx, parser_error *err); -+ -+#ifdef __cplusplus -+} -+#endif -+ -+#endif -diff --git a/src/lxc/json/oci_runtime_hooks.c b/src/lxc/json/oci_runtime_hooks.c -new file mode 100644 -index 0000000..41ddb67 ---- /dev/null -+++ b/src/lxc/json/oci_runtime_hooks.c -@@ -0,0 +1,52 @@ -+/****************************************************************************** -+ * Copyright (C), 1988-1999, Huawei Tech. Co., Ltd. -+ * FileName: oci_runtime_hooks.c -+ * Author: maoweiyong Version: 0.1 Date: 2018-11-07 -+ * Explanation: provide oci runtime hooks functions -+ ******************************************************************************/ -+#ifndef _GNU_SOURCE -+#define _GNU_SOURCE -+#endif -+#include -+#include "oci_runtime_hooks.h" -+ -+#include "log.h" -+#include "utils.h" -+ -+#define PARSE_ERR_BUFFER_SIZE 1024 -+ -+oci_runtime_spec_hooks *oci_runtime_spec_hooks_parse_file(const char *filename, -+ struct parser_context *ctx, parser_error *err) -+{ -+ yajl_val tree; -+ size_t filesize; -+ -+ if (!filename || !err) { -+ return NULL; -+ } -+ *err = NULL; -+ struct parser_context tmp_ctx; -+ if (!ctx) { -+ ctx = &tmp_ctx; -+ memset(&tmp_ctx, 0, sizeof(tmp_ctx)); -+ } -+ char *content = read_file(filename, &filesize); -+ char errbuf[PARSE_ERR_BUFFER_SIZE]; -+ if (content == NULL) { -+ if (asprintf(err, "cannot read the file: %s", filename) < 0) { -+ *err = safe_strdup("error allocating memory"); -+ } -+ return NULL; -+ } -+ tree = yajl_tree_parse(content, errbuf, sizeof(errbuf)); -+ free(content); -+ if (tree == NULL) { -+ if (asprintf(err, "cannot parse the file: %s", errbuf) < 0) { -+ *err = safe_strdup("error allocating memory"); -+ } -+ return NULL; -+ } -+ oci_runtime_spec_hooks *ptr = make_oci_runtime_spec_hooks(tree, ctx, err); -+ yajl_tree_free(tree); -+ return ptr; -+} -diff --git a/src/lxc/json/oci_runtime_hooks.h b/src/lxc/json/oci_runtime_hooks.h -new file mode 100644 -index 0000000..bf570c9 ---- /dev/null -+++ b/src/lxc/json/oci_runtime_hooks.h -@@ -0,0 +1,15 @@ -+/****************************************************************************** -+ * Copyright (C), 1988-1999, Huawei Tech. Co., Ltd. -+ * FileName: oci_runtime_hooks.h -+ * Author: tanyifeng Version: 0.1 Date: 2018-11-08 -+ * Explanation: provide container oci runtime hooks function definition -+ ******************************************************************************/ -+#ifndef _CONTAINER_HOOKS_H -+# define _CONTAINER_HOOKS_H -+ -+# include "oci_runtime_spec.h" -+ -+oci_runtime_spec_hooks *oci_runtime_spec_hooks_parse_file(const char *filename, -+ struct parser_context *ctx, parser_error *err); -+ -+#endif -diff --git a/src/lxc/json/oci_runtime_spec.c b/src/lxc/json/oci_runtime_spec.c -new file mode 100644 -index 0000000..fd342de ---- /dev/null -+++ b/src/lxc/json/oci_runtime_spec.c -@@ -0,0 +1,195 @@ -+// Generated from spec.json. Do not edit! -+#ifndef _GNU_SOURCE -+#define _GNU_SOURCE -+#endif -+#include -+#include -+#include "oci_runtime_spec.h" -+ -+oci_runtime_spec_hooks *make_oci_runtime_spec_hooks(yajl_val tree, struct parser_context *ctx, parser_error *err) { -+ oci_runtime_spec_hooks *ret = NULL; -+ *err = 0; -+ if (tree == NULL) -+ return ret; -+ ret = safe_malloc(sizeof(*ret)); -+ { -+ yajl_val tmp = get_val(tree, "prestart", yajl_t_array); -+ if (tmp != NULL && YAJL_GET_ARRAY(tmp) != NULL && YAJL_GET_ARRAY(tmp)->len > 0) { -+ size_t i; -+ ret->prestart_len = YAJL_GET_ARRAY(tmp)->len; -+ ret->prestart = safe_malloc((YAJL_GET_ARRAY(tmp)->len + 1) * sizeof(*ret->prestart)); -+ for (i = 0; i < YAJL_GET_ARRAY(tmp)->len; i++) { -+ yajl_val val = YAJL_GET_ARRAY(tmp)->values[i]; -+ ret->prestart[i] = make_defs_hook(val, ctx, err); -+ if (ret->prestart[i] == NULL) { -+ free_oci_runtime_spec_hooks(ret); -+ return NULL; -+ } -+ } -+ } -+ } -+ { -+ yajl_val tmp = get_val(tree, "poststart", yajl_t_array); -+ if (tmp != NULL && YAJL_GET_ARRAY(tmp) != NULL && YAJL_GET_ARRAY(tmp)->len > 0) { -+ size_t i; -+ ret->poststart_len = YAJL_GET_ARRAY(tmp)->len; -+ ret->poststart = safe_malloc((YAJL_GET_ARRAY(tmp)->len + 1) * sizeof(*ret->poststart)); -+ for (i = 0; i < YAJL_GET_ARRAY(tmp)->len; i++) { -+ yajl_val val = YAJL_GET_ARRAY(tmp)->values[i]; -+ ret->poststart[i] = make_defs_hook(val, ctx, err); -+ if (ret->poststart[i] == NULL) { -+ free_oci_runtime_spec_hooks(ret); -+ return NULL; -+ } -+ } -+ } -+ } -+ { -+ yajl_val tmp = get_val(tree, "poststop", yajl_t_array); -+ if (tmp != NULL && YAJL_GET_ARRAY(tmp) != NULL && YAJL_GET_ARRAY(tmp)->len > 0) { -+ size_t i; -+ ret->poststop_len = YAJL_GET_ARRAY(tmp)->len; -+ ret->poststop = safe_malloc((YAJL_GET_ARRAY(tmp)->len + 1) * sizeof(*ret->poststop)); -+ for (i = 0; i < YAJL_GET_ARRAY(tmp)->len; i++) { -+ yajl_val val = YAJL_GET_ARRAY(tmp)->values[i]; -+ ret->poststop[i] = make_defs_hook(val, ctx, err); -+ if (ret->poststop[i] == NULL) { -+ free_oci_runtime_spec_hooks(ret); -+ return NULL; -+ } -+ } -+ } -+ } -+ -+ if (tree->type == yajl_t_object && (ctx->options & PARSE_OPTIONS_STRICT)) { -+ int i; -+ for (i = 0; i < tree->u.object.len; i++) -+ if (strcmp(tree->u.object.keys[i], "prestart") && -+ strcmp(tree->u.object.keys[i], "poststart") && -+ strcmp(tree->u.object.keys[i], "poststop")) { -+ if (ctx->stderr > 0) -+ fprintf(ctx->stderr, "WARNING: unknown key found: %s\n", tree->u.object.keys[i]); -+ } -+ } -+ return ret; -+} -+ -+void free_oci_runtime_spec_hooks(oci_runtime_spec_hooks *ptr) { -+ if (ptr == NULL) -+ return; -+ if (ptr->prestart != NULL) { -+ size_t i; -+ for (i = 0; i < ptr->prestart_len; i++) -+ if (ptr->prestart[i] != NULL) { -+ free_defs_hook(ptr->prestart[i]); -+ ptr->prestart[i] = NULL; -+ } -+ free(ptr->prestart); -+ ptr->prestart = NULL; -+ } -+ if (ptr->poststart != NULL) { -+ size_t i; -+ for (i = 0; i < ptr->poststart_len; i++) -+ if (ptr->poststart[i] != NULL) { -+ free_defs_hook(ptr->poststart[i]); -+ ptr->poststart[i] = NULL; -+ } -+ free(ptr->poststart); -+ ptr->poststart = NULL; -+ } -+ if (ptr->poststop != NULL) { -+ size_t i; -+ for (i = 0; i < ptr->poststop_len; i++) -+ if (ptr->poststop[i] != NULL) { -+ free_defs_hook(ptr->poststop[i]); -+ ptr->poststop[i] = NULL; -+ } -+ free(ptr->poststop); -+ ptr->poststop = NULL; -+ } -+ free(ptr); -+} -+ -+yajl_gen_status gen_oci_runtime_spec_hooks(yajl_gen g, oci_runtime_spec_hooks *ptr, struct parser_context *ctx, parser_error *err) { -+ yajl_gen_status stat = yajl_gen_status_ok; -+ *err = 0; -+ stat = reformat_start_map(g); -+ if (yajl_gen_status_ok != stat) -+ GEN_SET_ERROR_AND_RETURN(stat, err); -+ if ((ctx->options & GEN_OPTIONS_ALLKEYVALUE) ||(ptr != NULL && ptr->prestart != NULL)) { -+ size_t len = 0, i; -+ stat = reformat_map_key(g, "prestart", strlen("prestart")); -+ if (yajl_gen_status_ok != stat) -+ GEN_SET_ERROR_AND_RETURN(stat, err); -+ if (ptr != NULL && ptr->prestart != NULL) { -+ len = ptr->prestart_len; -+ } -+ if (!len && !(ctx->options & GEN_OPTIONS_SIMPLIFY)) -+ yajl_gen_config(g, yajl_gen_beautify, 0); -+ stat = reformat_start_array(g); -+ if (yajl_gen_status_ok != stat) -+ GEN_SET_ERROR_AND_RETURN(stat, err); -+ for (i = 0; i < len; i++) { -+ stat = gen_defs_hook(g, ptr->prestart[i], ctx, err); -+ if (yajl_gen_status_ok != stat) -+ GEN_SET_ERROR_AND_RETURN(stat, err); -+ } -+ stat = reformat_end_array(g); -+ if (!len && !(ctx->options & GEN_OPTIONS_SIMPLIFY)) -+ yajl_gen_config(g, yajl_gen_beautify, 1); -+ if (yajl_gen_status_ok != stat) -+ GEN_SET_ERROR_AND_RETURN(stat, err); -+ } -+ if ((ctx->options & GEN_OPTIONS_ALLKEYVALUE) ||(ptr != NULL && ptr->poststart != NULL)) { -+ size_t len = 0, i; -+ stat = reformat_map_key(g, "poststart", strlen("poststart")); -+ if (yajl_gen_status_ok != stat) -+ GEN_SET_ERROR_AND_RETURN(stat, err); -+ if (ptr != NULL && ptr->poststart != NULL) { -+ len = ptr->poststart_len; -+ } -+ if (!len && !(ctx->options & GEN_OPTIONS_SIMPLIFY)) -+ yajl_gen_config(g, yajl_gen_beautify, 0); -+ stat = reformat_start_array(g); -+ if (yajl_gen_status_ok != stat) -+ GEN_SET_ERROR_AND_RETURN(stat, err); -+ for (i = 0; i < len; i++) { -+ stat = gen_defs_hook(g, ptr->poststart[i], ctx, err); -+ if (yajl_gen_status_ok != stat) -+ GEN_SET_ERROR_AND_RETURN(stat, err); -+ } -+ stat = reformat_end_array(g); -+ if (!len && !(ctx->options & GEN_OPTIONS_SIMPLIFY)) -+ yajl_gen_config(g, yajl_gen_beautify, 1); -+ if (yajl_gen_status_ok != stat) -+ GEN_SET_ERROR_AND_RETURN(stat, err); -+ } -+ if ((ctx->options & GEN_OPTIONS_ALLKEYVALUE) ||(ptr != NULL && ptr->poststop != NULL)) { -+ size_t len = 0, i; -+ stat = reformat_map_key(g, "poststop", strlen("poststop")); -+ if (yajl_gen_status_ok != stat) -+ GEN_SET_ERROR_AND_RETURN(stat, err); -+ if (ptr != NULL && ptr->poststop != NULL) { -+ len = ptr->poststop_len; -+ } -+ if (!len && !(ctx->options & GEN_OPTIONS_SIMPLIFY)) -+ yajl_gen_config(g, yajl_gen_beautify, 0); -+ stat = reformat_start_array(g); -+ if (yajl_gen_status_ok != stat) -+ GEN_SET_ERROR_AND_RETURN(stat, err); -+ for (i = 0; i < len; i++) { -+ stat = gen_defs_hook(g, ptr->poststop[i], ctx, err); -+ if (yajl_gen_status_ok != stat) -+ GEN_SET_ERROR_AND_RETURN(stat, err); -+ } -+ stat = reformat_end_array(g); -+ if (!len && !(ctx->options & GEN_OPTIONS_SIMPLIFY)) -+ yajl_gen_config(g, yajl_gen_beautify, 1); -+ if (yajl_gen_status_ok != stat) -+ GEN_SET_ERROR_AND_RETURN(stat, err); -+ } -+ stat = reformat_end_map(g); -+ if (yajl_gen_status_ok != stat) -+ GEN_SET_ERROR_AND_RETURN(stat, err); -+ return yajl_gen_status_ok; -+} -diff --git a/src/lxc/json/oci_runtime_spec.h b/src/lxc/json/oci_runtime_spec.h -new file mode 100644 -index 0000000..ef3f161 ---- /dev/null -+++ b/src/lxc/json/oci_runtime_spec.h -@@ -0,0 +1,37 @@ -+// Generated from spec.json. Do not edit! -+#ifndef OCI_RUNTIME_SPEC_SCHEMA_H -+#define OCI_RUNTIME_SPEC_SCHEMA_H -+ -+#include -+#include -+#include "json_common.h" -+#include "defs.h" -+ -+#ifdef __cplusplus -+extern "C" { -+#endif -+ -+typedef struct { -+ defs_hook **prestart; -+ size_t prestart_len; -+ -+ defs_hook **poststart; -+ size_t poststart_len; -+ -+ defs_hook **poststop; -+ size_t poststop_len; -+ -+} -+oci_runtime_spec_hooks; -+ -+void free_oci_runtime_spec_hooks(oci_runtime_spec_hooks *ptr); ++void free_json_map_string_string(json_map_string_string *map); + -+oci_runtime_spec_hooks *make_oci_runtime_spec_hooks(yajl_val tree, struct parser_context *ctx, parser_error *err); ++json_map_string_string *make_json_map_string_string(yajl_val src, struct parser_context *ctx, parser_error *err); + -+yajl_gen_status gen_oci_runtime_spec_hooks(yajl_gen g, oci_runtime_spec_hooks *ptr, struct parser_context *ctx, parser_error *err); ++yajl_gen_status gen_json_map_string_string(void *ctx, json_map_string_string *map, struct parser_context *ptx, parser_error *err); ++ ++int append_json_map_string_string(json_map_string_string *map, const char *key, const char *val); + +#ifdef __cplusplus +} +#endif + +#endif -diff --git a/src/lxc/json/read-file.c b/src/lxc/json/read-file.c +\ No newline at end of file +diff --git a/src/lxc/json/logger_json_file.c b/src/lxc/json/logger_json_file.c new file mode 100644 -index 0000000..34ebeed +index 0000000..6abeef4 --- /dev/null -+++ b/src/lxc/json/read-file.c -@@ -0,0 +1,95 @@ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include "read-file.h" -+ -+#ifndef O_CLOEXEC -+#define O_CLOEXEC 02000000 ++++ b/src/lxc/json/logger_json_file.c +@@ -0,0 +1,246 @@ ++// Generated from json-file.json. Do not edit! ++#ifndef _GNU_SOURCE ++#define _GNU_SOURCE +#endif ++#include ++#include ++#include "logger_json_file.h" + -+char *fread_file(FILE *stream, size_t *length) -+{ -+ char *buf = NULL, *tmpbuf = NULL; -+ size_t off = 0; -+ -+ while (1) { -+ size_t ret, newsize; -+ -+ newsize = off + BUFSIZ + 1; -+ tmpbuf = (char *)calloc(1, newsize); -+ if (tmpbuf == NULL) { -+ goto out; -+ } -+ -+ if (buf) { -+ memcpy(tmpbuf, buf, off); -+ -+ memset(buf, 0, off); -+ -+ free(buf); -+ } -+ -+ buf = tmpbuf; -+ ret = fread(buf + off, 1, BUFSIZ, stream); -+ if (!ret && ferror(stream)) { -+ tmpbuf = NULL; -+ goto out; ++logger_json_file *make_logger_json_file(yajl_val tree, struct parser_context *ctx, parser_error *err) { ++ logger_json_file *ret = NULL; ++ *err = 0; ++ if (tree == NULL) ++ return ret; ++ ret = safe_malloc(sizeof(*ret)); ++ { ++ yajl_val tmp = get_val(tree, "log", yajl_t_string); ++ if (tmp != NULL) { ++ char *str = YAJL_GET_STRING(tmp); ++ ret->log = (uint8_t *)safe_strdup(str ? str : ""); ++ ret->log_len = str != NULL ? strlen(str) : 0; + } -+ if (ret < BUFSIZ || feof(stream)) { -+ *length = off + ret + 1; -+ buf[*length - 1] = '\0'; -+ return buf; ++ } ++ { ++ yajl_val val = get_val(tree, "stream", yajl_t_string); ++ if (val != NULL) { ++ char *str = YAJL_GET_STRING(val); ++ ret->stream = safe_strdup(str ? str : ""); + } -+ off += BUFSIZ; + } -+out: -+ if (buf) { -+ free(buf); ++ { ++ yajl_val val = get_val(tree, "time", yajl_t_string); ++ if (val != NULL) { ++ char *str = YAJL_GET_STRING(val); ++ ret->time = safe_strdup(str ? str : ""); ++ } + } -+ if (tmpbuf) { -+ free(tmpbuf); ++ { ++ yajl_val tmp = get_val(tree, "attrs", yajl_t_string); ++ if (tmp != NULL) { ++ char *str = YAJL_GET_STRING(tmp); ++ ret->attrs = (uint8_t *)safe_strdup(str ? str : ""); ++ ret->attrs_len = str != NULL ? strlen(str) : 0; ++ } + } -+ return NULL; + ++ if (tree->type == yajl_t_object && (ctx->options & PARSE_OPTIONS_STRICT)) { ++ int i; ++ for (i = 0; i < tree->u.object.len; i++) ++ if (strcmp(tree->u.object.keys[i], "log") && ++ strcmp(tree->u.object.keys[i], "stream") && ++ strcmp(tree->u.object.keys[i], "time") && ++ strcmp(tree->u.object.keys[i], "attrs")) { ++ if (ctx->stderr > 0) ++ fprintf(ctx->stderr, "WARNING: unknown key found: %s\n", tree->u.object.keys[i]); ++ } ++ } ++ return ret; +} + -+char *read_file(const char *path, size_t *length) -+{ -+ char *buf = NULL; -+ char rpath[PATH_MAX + 1] = {0}; -+ int fd = -1; -+ int tmperrno; -+ FILE *fp = NULL; ++void free_logger_json_file(logger_json_file *ptr) { ++ if (ptr == NULL) ++ return; ++ free(ptr->log); ++ ptr->log = NULL; ++ free(ptr->stream); ++ ptr->stream = NULL; ++ free(ptr->time); ++ ptr->time = NULL; ++ free(ptr->attrs); ++ ptr->attrs = NULL; ++ free(ptr); ++} + -+ if (!path || !length) { -+ return NULL; ++yajl_gen_status gen_logger_json_file(yajl_gen g, logger_json_file *ptr, struct parser_context *ctx, parser_error *err) { ++ yajl_gen_status stat = yajl_gen_status_ok; ++ *err = 0; ++ stat = reformat_start_map(g); ++ if (yajl_gen_status_ok != stat) ++ GEN_SET_ERROR_AND_RETURN(stat, err); ++ if ((ctx->options & GEN_OPTIONS_ALLKEYVALUE) || (ptr != NULL && ptr->log != NULL && ptr->log_len)) { ++ const char *str = ""; ++ size_t len = 0; ++ stat = reformat_map_key(g, "log", strlen("log")); ++ if (yajl_gen_status_ok != stat) ++ GEN_SET_ERROR_AND_RETURN(stat, err); ++ if (ptr != NULL && ptr->log != NULL) { ++ str = (const char *)ptr->log; ++ len = ptr->log_len; ++ } ++ stat = reformat_string(g, str, len); ++ if (yajl_gen_status_ok != stat) ++ GEN_SET_ERROR_AND_RETURN(stat, err); + } -+ -+ if (strlen(path) > PATH_MAX || NULL == realpath(path, rpath)) { -+ return NULL; ++ if ((ctx->options & GEN_OPTIONS_ALLKEYVALUE) ||(ptr != NULL && ptr->stream != NULL)) { ++ char *str = ""; ++ stat = reformat_map_key(g, "stream", strlen("stream")); ++ if (yajl_gen_status_ok != stat) ++ GEN_SET_ERROR_AND_RETURN(stat, err); ++ if (ptr != NULL && ptr->stream != NULL) { ++ str = ptr->stream; ++ } ++ stat = reformat_string(g, str, strlen(str)); ++ if (yajl_gen_status_ok != stat) ++ GEN_SET_ERROR_AND_RETURN(stat, err); + } -+ -+ fd = open(rpath, O_RDONLY | O_CLOEXEC); -+ if (fd < 0) { -+ return NULL; ++ if ((ctx->options & GEN_OPTIONS_ALLKEYVALUE) ||(ptr != NULL && ptr->time != NULL)) { ++ char *str = ""; ++ stat = reformat_map_key(g, "time", strlen("time")); ++ if (yajl_gen_status_ok != stat) ++ GEN_SET_ERROR_AND_RETURN(stat, err); ++ if (ptr != NULL && ptr->time != NULL) { ++ str = ptr->time; ++ } ++ stat = reformat_string(g, str, strlen(str)); ++ if (yajl_gen_status_ok != stat) ++ GEN_SET_ERROR_AND_RETURN(stat, err); + } -+ -+ fp = fdopen(fd, "r"); -+ tmperrno = errno; -+ if (!fp) { -+ close(fd); -+ errno = tmperrno; -+ return NULL; ++ if ((ctx->options & GEN_OPTIONS_ALLKEYVALUE) || (ptr != NULL && ptr->attrs != NULL && ptr->attrs_len)) { ++ const char *str = ""; ++ size_t len = 0; ++ stat = reformat_map_key(g, "attrs", strlen("attrs")); ++ if (yajl_gen_status_ok != stat) ++ GEN_SET_ERROR_AND_RETURN(stat, err); ++ if (ptr != NULL && ptr->attrs != NULL) { ++ str = (const char *)ptr->attrs; ++ len = ptr->attrs_len; ++ } ++ stat = reformat_string(g, str, len); ++ if (yajl_gen_status_ok != stat) ++ GEN_SET_ERROR_AND_RETURN(stat, err); + } -+ -+ buf = fread_file(fp, length); -+ fclose(fp); -+ return buf; ++ stat = reformat_end_map(g); ++ if (yajl_gen_status_ok != stat) ++ GEN_SET_ERROR_AND_RETURN(stat, err); ++ return yajl_gen_status_ok; +} -diff --git a/src/lxc/json/read-file.h b/src/lxc/json/read-file.h -new file mode 100644 -index 0000000..5d6e0eb ---- /dev/null -+++ b/src/lxc/json/read-file.h -@@ -0,0 +1,11 @@ -+#ifndef READ_FILE_H -+#define READ_FILE_H -+ -+#include -+#include -+ -+extern char *fread_file(FILE *stream, size_t *length); -+ -+extern char *read_file(const char *path, size_t *length); -+ -+#endif -diff --git a/src/lxc/meson.build b/src/lxc/meson.build -index f33257c..3166401 100644 ---- a/src/lxc/meson.build -+++ b/src/lxc/meson.build -@@ -25,7 +25,6 @@ liblxcfs_version_file = configure_file( - ) - - liblxc_sources = files( -- 'cgroups/cgfsng.c', - 'cgroups/cgroup.c', - 'cgroups/cgroup.h', - 'cgroups/cgroup2_devices.c', -@@ -139,6 +138,31 @@ liblxc_sources = files( - 'uuid.c', - 'uuid.h') - -+if want_isulad -+ liblxc_sources += files( -+ 'cgroups/isulad_cgfsng.c', -+ 'exec_commands.c', -+ 'exec_commands.h', -+ 'isulad_utils.c', -+ 'isulad_utils.h', -+ 'path.c', -+ 'path.h', -+ 'json/defs.c', -+ 'json/defs.h', -+ 'json/json_common.c', -+ 'json/json_common.h', -+ 'json/logger_json_file.c', -+ 'json/logger_json_file.h', -+ 'json/oci_runtime_hooks.c', -+ 'json/oci_runtime_hooks.h', -+ 'json/oci_runtime_spec.c', -+ 'json/oci_runtime_spec.h', -+ 'json/read-file.c', -+ 'json/read-file.h') -+else -+ liblxc_sources += files('cgroups/cgfsng.c') -+endif -+ - if want_apparmor and libapparmor.found() - liblxc_sources += files('lsm/apparmor.c') - endif -diff --git a/src/lxc/path.c b/src/lxc/path.c -new file mode 100644 -index 0000000..3881058 ---- /dev/null -+++ b/src/lxc/path.c -@@ -0,0 +1,521 @@ -+/* 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 -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include + -+#include "path.h" -+#include "log.h" -+#include "isulad_utils.h" + -+lxc_log_define(lxc_path_ui, lxc); ++logger_json_file *logger_json_file_parse_file(const char *filename, struct parser_context *ctx, parser_error *err) { ++ logger_json_file *ptr = NULL; ++ size_t filesize; ++ char *content = NULL; + -+#define ISSLASH(C) ((C) == '/') -+#define IS_ABSOLUTE_FILE_NAME(F) (ISSLASH ((F)[0])) ++ if (filename == NULL || err == NULL) ++ return NULL; + -+static bool do_clean_path_continue(const char *endpos, const char *stpos, const char *respath, char **dst) -+{ -+ if (endpos - stpos == 1 && stpos[0] == '.') { -+ return true; -+ } else if (endpos - stpos == 2 && stpos[0] == '.' && stpos[1] == '.') { -+ char *dest = *dst; -+ if (dest <= respath + 1) { -+ return true; -+ } -+ for (--dest; dest > respath && !ISSLASH(dest[-1]); --dest) { -+ *dst = dest; -+ return true; -+ } -+ *dst = dest; -+ return true; ++ *err = NULL; ++ content = read_file(filename, &filesize); ++ if (content == NULL) { ++ if (asprintf(err, "cannot read the file: %s", filename) < 0) ++ *err = safe_strdup("error allocating memory"); ++ return NULL; + } -+ return false; ++ ptr = logger_json_file_parse_data(content, ctx, err); ++ free(content); ++ return ptr; +} + -+int do_clean_path(const char *respath, const char *limit_respath, -+ const char *stpos, char **dst) -+{ -+ char *dest = *dst; -+ const char *endpos = NULL; -+ -+ for (endpos = stpos; *stpos; stpos = endpos) { -+ while (ISSLASH(*stpos)) { -+ ++stpos; -+ } -+ -+ for (endpos = stpos; *endpos && !ISSLASH(*endpos); ++endpos) { -+ } -+ -+ if (endpos - stpos == 0) { -+ break; -+ } else if (do_clean_path_continue(endpos, stpos, respath, &dest)) { -+ continue; -+ } -+ -+ if (!ISSLASH(dest[-1])) { -+ *dest++ = '/'; -+ } ++logger_json_file *logger_json_file_parse_file_stream(FILE *stream, struct parser_context *ctx, parser_error *err) { ++ logger_json_file *ptr = NULL; ++ size_t filesize; ++ char *content = NULL ; + -+ if (dest + (endpos - stpos) >= limit_respath) { -+ ERROR("Path is too long"); -+ if (dest > respath + 1) { -+ dest--; -+ } -+ *dest = '\0'; -+ return -1; -+ } ++ if (stream == NULL || err == NULL) ++ return NULL; + -+ memcpy(dest, stpos, (size_t)(endpos - stpos)); -+ dest += endpos - stpos; -+ *dest = '\0'; ++ *err = NULL; ++ content = fread_file(stream, &filesize); ++ if (content == NULL) { ++ *err = safe_strdup("cannot read the file"); ++ return NULL; + } -+ *dst = dest; -+ return 0; ++ ptr = logger_json_file_parse_data(content, ctx, err); ++ free(content); ++ return ptr; +} + -+char *cleanpath(const char *path, char *realpath, size_t realpath_len) -+{ -+ char *respath = NULL; -+ char *dest = NULL; -+ const char *stpos = NULL; -+ const char *limit_respath = NULL; ++logger_json_file *logger_json_file_parse_data(const char *jsondata, struct parser_context *ctx, parser_error *err) { ++ logger_json_file *ptr = NULL; ++ yajl_val tree; ++ char errbuf[1024]; ++ struct parser_context tmp_ctx; ++ ++ if (jsondata == NULL || err == NULL) ++ return NULL; + -+ if (path == NULL || path[0] == '\0' || \ -+ realpath == NULL || (realpath_len < PATH_MAX)) { ++ *err = NULL; ++ if (ctx == NULL) { ++ ctx = &tmp_ctx; ++ memset(&tmp_ctx, 0, sizeof(tmp_ctx)); ++ } ++ tree = yajl_tree_parse(jsondata, errbuf, sizeof(errbuf)); ++ if (tree == NULL) { ++ if (asprintf(err, "cannot parse the data: %s", errbuf) < 0) ++ *err = safe_strdup("error allocating memory"); + return NULL; + } ++ ptr = make_logger_json_file(tree, ctx, err); ++ yajl_tree_free(tree); ++ return ptr; ++} ++char *logger_json_file_generate_json(logger_json_file *ptr, struct parser_context *ctx, parser_error *err) { ++ yajl_gen g = NULL; ++ struct parser_context tmp_ctx; ++ const unsigned char *gen_buf = NULL; ++ char *json_buf = NULL; ++ size_t gen_len = 0; + -+ respath = realpath; -+ -+ memset(respath, 0, realpath_len); -+ limit_respath = respath + PATH_MAX; ++ if (ptr == NULL || err == NULL) ++ return NULL; + -+ if (!IS_ABSOLUTE_FILE_NAME(path)) { -+ if (!getcwd(respath, PATH_MAX)) { -+ ERROR("Failed to getcwd"); -+ respath[0] = '\0'; -+ goto error; -+ } -+ dest = strchr(respath, '\0'); -+ if (dest == NULL) { -+ ERROR("Failed to get the end of respath"); -+ goto error; -+ } -+ if (strlen(path) > (PATH_MAX - strlen(respath) - 1)) { -+ ERROR("Path is too long"); -+ goto error; -+ } -+ strcat(respath, path); -+ stpos = path; -+ } else { -+ dest = respath; -+ *dest++ = '/'; -+ stpos = path; ++ *err = NULL; ++ if (ctx == NULL) { ++ ctx = &tmp_ctx; ++ memset(&tmp_ctx, 0, sizeof(tmp_ctx)); + } + -+ if (do_clean_path(respath, limit_respath, stpos, &dest)) { -+ goto error; ++ if (!json_gen_init(&g, ctx)) { ++ *err = safe_strdup("Json_gen init failed"); ++ goto out; + } -+ -+ if (dest > respath + 1 && ISSLASH(dest[-1])) { -+ --dest; ++ if (yajl_gen_status_ok != gen_logger_json_file(g, ptr, ctx, err)) { ++ if (*err == NULL) ++ *err = safe_strdup("Failed to generate json"); ++ goto free_out; ++ } ++ yajl_gen_get_buf(g, &gen_buf, &gen_len); ++ if (gen_buf == NULL) { ++ *err = safe_strdup("Error to get generated json"); ++ goto free_out; + } -+ *dest = '\0'; + -+ return respath; ++ if (gen_len == SIZE_MAX) { ++ *err = safe_strdup("Invalid buffer length"); ++ goto free_out; ++ } ++ json_buf = safe_malloc(gen_len + 1); ++ (void)memcpy(json_buf, gen_buf, gen_len); ++ json_buf[gen_len] = '\0'; + -+error: -+ return NULL; ++free_out: ++ yajl_gen_clear(g); ++ yajl_gen_free(g); ++out: ++ return json_buf; +} +diff --git a/src/lxc/json/logger_json_file.h b/src/lxc/json/logger_json_file.h +new file mode 100644 +index 0000000..ad5af7b +--- /dev/null ++++ b/src/lxc/json/logger_json_file.h +@@ -0,0 +1,45 @@ ++// Generated from json-file.json. Do not edit! ++#ifndef LOGGER_JSON_FILE_SCHEMA_H ++#define LOGGER_JSON_FILE_SCHEMA_H + -+static int do_path_realloc(const char *start, const char *end, -+ char **rpath, char **dest, const char **rpath_limit) -+{ -+ long long dest_offset = *dest - *rpath; -+ char *new_rpath = NULL; -+ size_t new_size; -+ int nret = 0; -+ size_t gap = 0; ++#include ++#include ++#include "json_common.h" + -+ if (*dest + (end - start) < *rpath_limit) { -+ return 0; -+ } ++#ifdef __cplusplus ++extern "C" { ++#endif + -+ gap = (size_t)(end - start) + 1; -+ new_size = (size_t)(*rpath_limit - *rpath); -+ if (new_size > SIZE_MAX - gap) { -+ ERROR("Out of range!"); -+ return -1; -+ } ++typedef struct { ++ uint8_t *log; ++ size_t log_len; + -+ if (gap > PATH_MAX) { -+ new_size += gap; -+ } else { -+ new_size += PATH_MAX; -+ } -+ nret = lxc_mem_realloc((void **)&new_rpath, new_size, *rpath, PATH_MAX); -+ if (nret) { -+ ERROR("Failed to realloc memory for files limit variables"); -+ return -1; -+ } -+ *rpath = new_rpath; -+ *rpath_limit = *rpath + new_size; ++ char *stream; + -+ *dest = *rpath + dest_offset; ++ char *time; + -+ return 0; -+} ++ uint8_t *attrs; ++ size_t attrs_len; + -+static int do_get_symlinks_copy_buf(const char *buf, const char *prefix, size_t prefix_len, -+ char **rpath, char **dest) -+{ -+ if (IS_ABSOLUTE_FILE_NAME(buf)) { -+ if (prefix_len) { -+ memcpy(*rpath, prefix, prefix_len); -+ } -+ *dest = *rpath + prefix_len; -+ *(*dest)++ = '/'; -+ } else { -+ if (*dest > *rpath + prefix_len + 1) { -+ for (--(*dest); *dest > *rpath && !ISSLASH((*dest)[-1]); --(*dest)) { -+ continue; -+ } -+ } -+ } -+ return 0; +} ++logger_json_file; + -+static int do_get_symlinks(const char **fullpath, const char *prefix, size_t prefix_len, -+ char **rpath, char **dest, const char **end, -+ int *num_links, char **extra_buf) -+{ -+ char *buf = NULL; -+ size_t len; -+ ssize_t n; -+ int ret = -1; -+ -+ if (++(*num_links) > MAXSYMLINKS) { -+ ERROR("Too many links in '%s'", *fullpath); -+ goto out; -+ } -+ -+ buf = lxc_common_calloc_s(PATH_MAX); -+ if (buf == NULL) { -+ ERROR("Out of memory"); -+ goto out; -+ } ++void free_logger_json_file(logger_json_file *ptr); + -+ n = readlink(*rpath, buf, PATH_MAX - 1); -+ if (n < 0) { -+ goto out; -+ } -+ buf[n] = '\0'; ++logger_json_file *make_logger_json_file(yajl_val tree, struct parser_context *ctx, parser_error *err); + -+ if (*extra_buf == NULL) { -+ *extra_buf = lxc_common_calloc_s(PATH_MAX); -+ if (*extra_buf == NULL) { -+ ERROR("Out of memory"); -+ goto out; -+ } -+ } ++yajl_gen_status gen_logger_json_file(yajl_gen g, logger_json_file *ptr, struct parser_context *ctx, parser_error *err); + -+ len = strlen(*end); -+ if (len >= (size_t)(PATH_MAX - n)) { -+ ERROR("Path is too long"); -+ goto out; -+ } ++logger_json_file *logger_json_file_parse_file(const char *filename, struct parser_context *ctx, parser_error *err); + -+ memmove(&(*extra_buf)[n], *end, len + 1); -+ memcpy(*extra_buf, buf, (size_t)n); ++logger_json_file *logger_json_file_parse_file_stream(FILE *stream, struct parser_context *ctx, parser_error *err); + -+ *fullpath = *end = *extra_buf; ++logger_json_file *logger_json_file_parse_data(const char *jsondata, struct parser_context *ctx, parser_error *err); + -+ if (do_get_symlinks_copy_buf(buf, prefix, prefix_len, rpath, dest) != 0) { -+ goto out; -+ } ++char *logger_json_file_generate_json(logger_json_file *ptr, struct parser_context *ctx, parser_error *err); + -+ ret = 0; -+out: -+ free(buf); -+ return ret; ++#ifdef __cplusplus +} ++#endif + -+static bool do_eval_symlinks_in_scope_is_symlink(const char *path) -+{ -+ struct stat st; ++#endif +diff --git a/src/lxc/json/oci_runtime_hooks.c b/src/lxc/json/oci_runtime_hooks.c +new file mode 100644 +index 0000000..41ddb67 +--- /dev/null ++++ b/src/lxc/json/oci_runtime_hooks.c +@@ -0,0 +1,52 @@ ++/****************************************************************************** ++ * Copyright (C), 1988-1999, Huawei Tech. Co., Ltd. ++ * FileName: oci_runtime_hooks.c ++ * Author: maoweiyong Version: 0.1 Date: 2018-11-07 ++ * Explanation: provide oci runtime hooks functions ++ ******************************************************************************/ ++#ifndef _GNU_SOURCE ++#define _GNU_SOURCE ++#endif ++#include ++#include "oci_runtime_hooks.h" + -+ if (lstat(path, &st) < 0) { -+ return true; -+ } ++#include "log.h" ++#include "utils.h" + -+ if (!S_ISLNK(st.st_mode)) { -+ return true; -+ } -+ return false; -+} ++#define PARSE_ERR_BUFFER_SIZE 1024 + -+static void do_eval_symlinks_skip_slash(const char **start, const char **end) ++oci_runtime_spec_hooks *oci_runtime_spec_hooks_parse_file(const char *filename, ++ struct parser_context *ctx, parser_error *err) +{ -+ while (ISSLASH(**start)) { -+ ++(*start); -+ } ++ yajl_val tree; ++ size_t filesize; + -+ for (*end = *start; **end && !ISSLASH(**end); ++(*end)) { -+ } ++ if (!filename || !err) { ++ return NULL; ++ } ++ *err = NULL; ++ struct parser_context tmp_ctx; ++ if (!ctx) { ++ ctx = &tmp_ctx; ++ memset(&tmp_ctx, 0, sizeof(tmp_ctx)); ++ } ++ char *content = read_file(filename, &filesize); ++ char errbuf[PARSE_ERR_BUFFER_SIZE]; ++ if (content == NULL) { ++ if (asprintf(err, "cannot read the file: %s", filename) < 0) { ++ *err = safe_strdup("error allocating memory"); ++ } ++ return NULL; ++ } ++ tree = yajl_tree_parse(content, errbuf, sizeof(errbuf)); ++ free(content); ++ if (tree == NULL) { ++ if (asprintf(err, "cannot parse the file: %s", errbuf) < 0) { ++ *err = safe_strdup("error allocating memory"); ++ } ++ return NULL; ++ } ++ oci_runtime_spec_hooks *ptr = make_oci_runtime_spec_hooks(tree, ctx, err); ++ yajl_tree_free(tree); ++ return ptr; +} +diff --git a/src/lxc/json/oci_runtime_hooks.h b/src/lxc/json/oci_runtime_hooks.h +new file mode 100644 +index 0000000..bf570c9 +--- /dev/null ++++ b/src/lxc/json/oci_runtime_hooks.h +@@ -0,0 +1,15 @@ ++/****************************************************************************** ++ * Copyright (C), 1988-1999, Huawei Tech. Co., Ltd. ++ * FileName: oci_runtime_hooks.h ++ * Author: tanyifeng Version: 0.1 Date: 2018-11-08 ++ * Explanation: provide container oci runtime hooks function definition ++ ******************************************************************************/ ++#ifndef _CONTAINER_HOOKS_H ++# define _CONTAINER_HOOKS_H + -+static inline void skip_dest_traling_slash(char **dest, char **rpath, size_t prefix_len) -+{ -+ if (*dest > *rpath + prefix_len + 1) { -+ for (--(*dest); *dest > *rpath && !ISSLASH((*dest)[-1]); --(*dest)) { -+ continue; -+ } -+ } -+} ++# include "oci_runtime_spec.h" + -+static inline bool is_current_char(const char c) -+{ -+ return c == '.'; -+} ++oci_runtime_spec_hooks *oci_runtime_spec_hooks_parse_file(const char *filename, ++ struct parser_context *ctx, parser_error *err); ++ ++#endif +diff --git a/src/lxc/json/oci_runtime_spec.c b/src/lxc/json/oci_runtime_spec.c +new file mode 100644 +index 0000000..fd342de +--- /dev/null ++++ b/src/lxc/json/oci_runtime_spec.c +@@ -0,0 +1,195 @@ ++// Generated from spec.json. Do not edit! ++#ifndef _GNU_SOURCE ++#define _GNU_SOURCE ++#endif ++#include ++#include ++#include "oci_runtime_spec.h" ++ ++oci_runtime_spec_hooks *make_oci_runtime_spec_hooks(yajl_val tree, struct parser_context *ctx, parser_error *err) { ++ oci_runtime_spec_hooks *ret = NULL; ++ *err = 0; ++ if (tree == NULL) ++ return ret; ++ ret = safe_malloc(sizeof(*ret)); ++ { ++ yajl_val tmp = get_val(tree, "prestart", yajl_t_array); ++ if (tmp != NULL && YAJL_GET_ARRAY(tmp) != NULL && YAJL_GET_ARRAY(tmp)->len > 0) { ++ size_t i; ++ ret->prestart_len = YAJL_GET_ARRAY(tmp)->len; ++ ret->prestart = safe_malloc((YAJL_GET_ARRAY(tmp)->len + 1) * sizeof(*ret->prestart)); ++ for (i = 0; i < YAJL_GET_ARRAY(tmp)->len; i++) { ++ yajl_val val = YAJL_GET_ARRAY(tmp)->values[i]; ++ ret->prestart[i] = make_defs_hook(val, ctx, err); ++ if (ret->prestart[i] == NULL) { ++ free_oci_runtime_spec_hooks(ret); ++ return NULL; ++ } ++ } ++ } ++ } ++ { ++ yajl_val tmp = get_val(tree, "poststart", yajl_t_array); ++ if (tmp != NULL && YAJL_GET_ARRAY(tmp) != NULL && YAJL_GET_ARRAY(tmp)->len > 0) { ++ size_t i; ++ ret->poststart_len = YAJL_GET_ARRAY(tmp)->len; ++ ret->poststart = safe_malloc((YAJL_GET_ARRAY(tmp)->len + 1) * sizeof(*ret->poststart)); ++ for (i = 0; i < YAJL_GET_ARRAY(tmp)->len; i++) { ++ yajl_val val = YAJL_GET_ARRAY(tmp)->values[i]; ++ ret->poststart[i] = make_defs_hook(val, ctx, err); ++ if (ret->poststart[i] == NULL) { ++ free_oci_runtime_spec_hooks(ret); ++ return NULL; ++ } ++ } ++ } ++ } ++ { ++ yajl_val tmp = get_val(tree, "poststop", yajl_t_array); ++ if (tmp != NULL && YAJL_GET_ARRAY(tmp) != NULL && YAJL_GET_ARRAY(tmp)->len > 0) { ++ size_t i; ++ ret->poststop_len = YAJL_GET_ARRAY(tmp)->len; ++ ret->poststop = safe_malloc((YAJL_GET_ARRAY(tmp)->len + 1) * sizeof(*ret->poststop)); ++ for (i = 0; i < YAJL_GET_ARRAY(tmp)->len; i++) { ++ yajl_val val = YAJL_GET_ARRAY(tmp)->values[i]; ++ ret->poststop[i] = make_defs_hook(val, ctx, err); ++ if (ret->poststop[i] == NULL) { ++ free_oci_runtime_spec_hooks(ret); ++ return NULL; ++ } ++ } ++ } ++ } + -+static inline bool is_specify_current(const char *end, const char *start) -+{ -+ return (end - start == 1) && is_current_char(start[0]); ++ if (tree->type == yajl_t_object && (ctx->options & PARSE_OPTIONS_STRICT)) { ++ int i; ++ for (i = 0; i < tree->u.object.len; i++) ++ if (strcmp(tree->u.object.keys[i], "prestart") && ++ strcmp(tree->u.object.keys[i], "poststart") && ++ strcmp(tree->u.object.keys[i], "poststop")) { ++ if (ctx->stderr > 0) ++ fprintf(ctx->stderr, "WARNING: unknown key found: %s\n", tree->u.object.keys[i]); ++ } ++ } ++ return ret; +} + -+static inline bool is_specify_parent(const char *end, const char *start) -+{ -+ return (end - start == 2) && is_current_char(start[0]) && is_current_char(start[1]); ++void free_oci_runtime_spec_hooks(oci_runtime_spec_hooks *ptr) { ++ if (ptr == NULL) ++ return; ++ if (ptr->prestart != NULL) { ++ size_t i; ++ for (i = 0; i < ptr->prestart_len; i++) ++ if (ptr->prestart[i] != NULL) { ++ free_defs_hook(ptr->prestart[i]); ++ ptr->prestart[i] = NULL; ++ } ++ free(ptr->prestart); ++ ptr->prestart = NULL; ++ } ++ if (ptr->poststart != NULL) { ++ size_t i; ++ for (i = 0; i < ptr->poststart_len; i++) ++ if (ptr->poststart[i] != NULL) { ++ free_defs_hook(ptr->poststart[i]); ++ ptr->poststart[i] = NULL; ++ } ++ free(ptr->poststart); ++ ptr->poststart = NULL; ++ } ++ if (ptr->poststop != NULL) { ++ size_t i; ++ for (i = 0; i < ptr->poststop_len; i++) ++ if (ptr->poststop[i] != NULL) { ++ free_defs_hook(ptr->poststop[i]); ++ ptr->poststop[i] = NULL; ++ } ++ free(ptr->poststop); ++ ptr->poststop = NULL; ++ } ++ free(ptr); +} + -+static int do_eval_symlinks_in_scope(const char *fullpath, const char *prefix, -+ size_t prefix_len, -+ char **rpath, char **dest, const char *rpath_limit) -+{ -+ const char *start = NULL; -+ const char *end = NULL; -+ char *extra_buf = NULL; -+ int nret = 0; -+ int num_links = 0; -+ -+ start = fullpath + prefix_len; -+ for (end = start; *start; start = end) { -+ do_eval_symlinks_skip_slash(&start, &end); -+ if (end - start == 0) { -+ break; -+ } else if (is_specify_current(end, start)) { -+ ; -+ } else if (is_specify_parent(end, start)) { -+ skip_dest_traling_slash(dest, rpath, prefix_len); -+ } else { -+ if (!ISSLASH((*dest)[-1])) { -+ *(*dest)++ = '/'; -+ } -+ -+ nret = do_path_realloc(start, end, rpath, dest, &rpath_limit); -+ if (nret != 0) { -+ nret = -1; -+ goto out; -+ } -+ -+ memcpy(*dest, start, (size_t)(end - start)); -+ *dest += end - start; -+ **dest = '\0'; -+ -+ if (do_eval_symlinks_in_scope_is_symlink(*rpath)) { -+ continue; -+ } -+ -+ nret = do_get_symlinks(&fullpath, prefix, prefix_len, rpath, dest, &end, &num_links, &extra_buf); -+ if (nret != 0) { -+ nret = -1; -+ goto out; -+ } -+ } -+ } -+out: -+ free(extra_buf); -+ return nret; ++yajl_gen_status gen_oci_runtime_spec_hooks(yajl_gen g, oci_runtime_spec_hooks *ptr, struct parser_context *ctx, parser_error *err) { ++ yajl_gen_status stat = yajl_gen_status_ok; ++ *err = 0; ++ stat = reformat_start_map(g); ++ if (yajl_gen_status_ok != stat) ++ GEN_SET_ERROR_AND_RETURN(stat, err); ++ if ((ctx->options & GEN_OPTIONS_ALLKEYVALUE) ||(ptr != NULL && ptr->prestart != NULL)) { ++ size_t len = 0, i; ++ stat = reformat_map_key(g, "prestart", strlen("prestart")); ++ if (yajl_gen_status_ok != stat) ++ GEN_SET_ERROR_AND_RETURN(stat, err); ++ if (ptr != NULL && ptr->prestart != NULL) { ++ len = ptr->prestart_len; ++ } ++ if (!len && !(ctx->options & GEN_OPTIONS_SIMPLIFY)) ++ yajl_gen_config(g, yajl_gen_beautify, 0); ++ stat = reformat_start_array(g); ++ if (yajl_gen_status_ok != stat) ++ GEN_SET_ERROR_AND_RETURN(stat, err); ++ for (i = 0; i < len; i++) { ++ stat = gen_defs_hook(g, ptr->prestart[i], ctx, err); ++ if (yajl_gen_status_ok != stat) ++ GEN_SET_ERROR_AND_RETURN(stat, err); ++ } ++ stat = reformat_end_array(g); ++ if (!len && !(ctx->options & GEN_OPTIONS_SIMPLIFY)) ++ yajl_gen_config(g, yajl_gen_beautify, 1); ++ if (yajl_gen_status_ok != stat) ++ GEN_SET_ERROR_AND_RETURN(stat, err); ++ } ++ if ((ctx->options & GEN_OPTIONS_ALLKEYVALUE) ||(ptr != NULL && ptr->poststart != NULL)) { ++ size_t len = 0, i; ++ stat = reformat_map_key(g, "poststart", strlen("poststart")); ++ if (yajl_gen_status_ok != stat) ++ GEN_SET_ERROR_AND_RETURN(stat, err); ++ if (ptr != NULL && ptr->poststart != NULL) { ++ len = ptr->poststart_len; ++ } ++ if (!len && !(ctx->options & GEN_OPTIONS_SIMPLIFY)) ++ yajl_gen_config(g, yajl_gen_beautify, 0); ++ stat = reformat_start_array(g); ++ if (yajl_gen_status_ok != stat) ++ GEN_SET_ERROR_AND_RETURN(stat, err); ++ for (i = 0; i < len; i++) { ++ stat = gen_defs_hook(g, ptr->poststart[i], ctx, err); ++ if (yajl_gen_status_ok != stat) ++ GEN_SET_ERROR_AND_RETURN(stat, err); ++ } ++ stat = reformat_end_array(g); ++ if (!len && !(ctx->options & GEN_OPTIONS_SIMPLIFY)) ++ yajl_gen_config(g, yajl_gen_beautify, 1); ++ if (yajl_gen_status_ok != stat) ++ GEN_SET_ERROR_AND_RETURN(stat, err); ++ } ++ if ((ctx->options & GEN_OPTIONS_ALLKEYVALUE) ||(ptr != NULL && ptr->poststop != NULL)) { ++ size_t len = 0, i; ++ stat = reformat_map_key(g, "poststop", strlen("poststop")); ++ if (yajl_gen_status_ok != stat) ++ GEN_SET_ERROR_AND_RETURN(stat, err); ++ if (ptr != NULL && ptr->poststop != NULL) { ++ len = ptr->poststop_len; ++ } ++ if (!len && !(ctx->options & GEN_OPTIONS_SIMPLIFY)) ++ yajl_gen_config(g, yajl_gen_beautify, 0); ++ stat = reformat_start_array(g); ++ if (yajl_gen_status_ok != stat) ++ GEN_SET_ERROR_AND_RETURN(stat, err); ++ for (i = 0; i < len; i++) { ++ stat = gen_defs_hook(g, ptr->poststop[i], ctx, err); ++ if (yajl_gen_status_ok != stat) ++ GEN_SET_ERROR_AND_RETURN(stat, err); ++ } ++ stat = reformat_end_array(g); ++ if (!len && !(ctx->options & GEN_OPTIONS_SIMPLIFY)) ++ yajl_gen_config(g, yajl_gen_beautify, 1); ++ if (yajl_gen_status_ok != stat) ++ GEN_SET_ERROR_AND_RETURN(stat, err); ++ } ++ stat = reformat_end_map(g); ++ if (yajl_gen_status_ok != stat) ++ GEN_SET_ERROR_AND_RETURN(stat, err); ++ return yajl_gen_status_ok; +} +diff --git a/src/lxc/json/oci_runtime_spec.h b/src/lxc/json/oci_runtime_spec.h +new file mode 100644 +index 0000000..ef3f161 +--- /dev/null ++++ b/src/lxc/json/oci_runtime_spec.h +@@ -0,0 +1,37 @@ ++// Generated from spec.json. Do not edit! ++#ifndef OCI_RUNTIME_SPEC_SCHEMA_H ++#define OCI_RUNTIME_SPEC_SCHEMA_H + -+static char *eval_symlinks_in_scope(const char *fullpath, const char *rootpath) -+{ -+ char resroot[PATH_MAX] = {0}; -+ char *root = NULL; -+ char *rpath = NULL; -+ char *dest = NULL; -+ char *prefix = NULL; -+ const char *rpath_limit = NULL; -+ size_t prefix_len; -+ -+ if (fullpath == NULL || rootpath == NULL) { -+ return NULL; -+ } -+ -+ root = cleanpath(rootpath, resroot, sizeof(resroot)); -+ if (root == NULL) { -+ ERROR("Failed to get cleaned path"); -+ return NULL; -+ } -+ -+ if (!strcmp(fullpath, root)) { -+ return safe_strdup(fullpath); -+ } -+ -+ if (strstr(fullpath, root) == NULL) { -+ ERROR("Path '%s' is not in '%s'", fullpath, root); -+ return NULL; -+ } -+ -+ rpath = lxc_common_calloc_s(PATH_MAX); -+ if (rpath == NULL) { -+ ERROR("Out of memory"); -+ goto out; -+ } -+ rpath_limit = rpath + PATH_MAX; ++#include ++#include ++#include "json_common.h" ++#include "defs.h" + -+ prefix = root; -+ prefix_len = (size_t)strlen(prefix); -+ if (!strcmp(prefix, "/")) { -+ prefix_len = 0; -+ } ++#ifdef __cplusplus ++extern "C" { ++#endif + -+ dest = rpath; -+ if (prefix_len) { -+ memcpy(rpath, prefix, prefix_len); -+ dest += prefix_len; -+ } -+ *dest++ = '/'; ++typedef struct { ++ defs_hook **prestart; ++ size_t prestart_len; + -+ if (do_eval_symlinks_in_scope(fullpath, prefix, prefix_len, &rpath, &dest, -+ rpath_limit)) { -+ goto out; -+ } ++ defs_hook **poststart; ++ size_t poststart_len; + -+ if (dest > rpath + prefix_len + 1 && ISSLASH(dest[-1])) { -+ --dest; -+ } -+ *dest = '\0'; -+ return rpath; ++ defs_hook **poststop; ++ size_t poststop_len; + -+out: -+ free(rpath); -+ return NULL; +} ++oci_runtime_spec_hooks; + -+// FollowSymlinkInScope is a wrapper around evalSymlinksInScope that returns an -+// absolute path. This function handles paths in a platform-agnostic manner. -+char *follow_symlink_in_scope(const char *fullpath, const char *rootpath) -+{ -+ char resfull[PATH_MAX] = {0}, *full = NULL; -+ char resroot[PATH_MAX] = {0}, *root = NULL; ++void free_oci_runtime_spec_hooks(oci_runtime_spec_hooks *ptr); + -+ full = cleanpath(fullpath, resfull, PATH_MAX); -+ if (!full) { -+ ERROR("Failed to get cleaned path"); -+ return NULL; -+ } ++oci_runtime_spec_hooks *make_oci_runtime_spec_hooks(yajl_val tree, struct parser_context *ctx, parser_error *err); + -+ root = cleanpath(rootpath, resroot, PATH_MAX); -+ if (!root) { -+ ERROR("Failed to get cleaned path"); -+ return NULL; -+ } ++yajl_gen_status gen_oci_runtime_spec_hooks(yajl_gen g, oci_runtime_spec_hooks *ptr, struct parser_context *ctx, parser_error *err); + -+ return eval_symlinks_in_scope(full, root); ++#ifdef __cplusplus +} ++#endif + -+// Rel returns a relative path that is lexically equivalent to targpath when -+// joined to basepath with an intervening separator. That is, -+// Join(basepath, Rel(basepath, targpath)) is equivalent to targpath itself. -+// On success, the returned path will always be relative to basepath, -+// even if basepath and targpath share no elements. -+// An error is returned if targpath can't be made relative to basepath or if -+// knowing the current working directory would be necessary to compute it. -+// Rel calls Clean on the result. -+char *path_relative(const char *basepath, const char *targpath) -+{ -+ char resbase[PATH_MAX] = {0}, *base = NULL; -+ char restarg[PATH_MAX] = {0}, *targ = NULL; -+ size_t bl = 0, tl = 0, b0 = 0, bi = 0, t0 = 0, ti = 0; -+ -+ base = cleanpath(basepath, resbase, PATH_MAX); -+ if (!base) { -+ ERROR("Failed to get cleaned path"); -+ return NULL; -+ } -+ -+ targ = cleanpath(targpath, restarg, PATH_MAX); -+ if (!targ) { -+ ERROR("Failed to get cleaned path"); -+ return NULL; -+ } -+ -+ if (strcmp(base, targ) == 0) -+ return safe_strdup("."); -+ -+ bl = strlen(base); -+ tl = strlen(targ); -+ while(true) { -+ while(bi < bl && !ISSLASH(base[bi])) -+ bi++; -+ while(ti < tl && !ISSLASH(targ[ti])) -+ ti++; -+ //not the same string -+ if (((bi - b0) != (ti - t0)) || strncmp(base + b0, targ + t0, bi - b0)) -+ break; -+ if (bi < bl) -+ bi++; -+ if (ti < tl) -+ ti++; -+ b0 = bi; -+ t0 = ti; -+ } -+ -+ if (b0 != bl) { -+ // Base elements left. Must go up before going down. -+ size_t seps = 0, i; -+ size_t ncopyed = 0, seps_size; -+ char *buf = NULL; -+ -+ for (bi = b0; bi < bl; bi++) { -+ if (ISSLASH(base[bi])) -+ seps++; -+ } -+ //strlen(..) + strlen(/..) + '\0' -+ seps_size = 2 + seps * 3 + 1; -+ if (t0 != tl) -+ seps_size += 1 + tl - t0; -+ -+ buf = calloc(seps_size, 1); -+ if (!buf) { -+ ERROR("Out of memory"); -+ return NULL; -+ } -+ buf[ncopyed++] = '.'; -+ buf[ncopyed++] = '.'; -+ for (i = 0; i < seps; i++) { -+ buf[ncopyed++] = '/'; -+ buf[ncopyed++] = '.'; -+ buf[ncopyed++] = '.'; -+ } -+ if (t0 != tl) { -+ buf[ncopyed++] = '/'; -+ memcpy(buf + ncopyed, targ + t0, tl - t0 + 1); -+ } -+ return buf; -+ } -+ -+ return safe_strdup(targ + t0); -+} -diff --git a/src/lxc/path.h b/src/lxc/path.h ++#endif +diff --git a/src/lxc/json/read-file.h b/src/lxc/json/read-file.h new file mode 100644 -index 0000000..59bbc59 +index 0000000..5d6e0eb --- /dev/null -+++ b/src/lxc/path.h -@@ -0,0 +1,33 @@ -+/* 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_PATH_H_ -+#define __ISULAD_PATH_H_ ++++ b/src/lxc/json/read-file.h +@@ -0,0 +1,11 @@ ++#ifndef READ_FILE_H ++#define READ_FILE_H + -+#include ++#include ++#include + -+/* -+ * cleanpath is similar to realpath of glibc, but not expands symbolic links, -+ * and not check the existence of components of the path. -+ */ -+char *cleanpath(const char *path, char *realpath, size_t realpath_len); -+ -+// FollowSymlinkInScope is a wrapper around evalSymlinksInScope that returns an -+// absolute path. This function handles paths in a platform-agnostic manner. -+char *follow_symlink_in_scope(const char *fullpath, const char *rootpath); -+ -+// Rel returns a relative path that is lexically equivalent to targpath when -+// joined to basepath with an intervening separator. That is, -+// Join(basepath, Rel(basepath, targpath)) is equivalent to targpath itself. -+// On success, the returned path will always be relative to basepath, -+// even if basepath and targpath share no elements. -+// An error is returned if targpath can't be made relative to basepath or if -+// knowing the current working directory would be necessary to compute it. -+// Rel calls Clean on the result. -+char *path_relative(const char *basepath, const char *targpath); ++extern char *fread_file(FILE *stream, size_t *length); ++ ++extern char *read_file(const char *path, size_t *length); + +#endif -- diff --git a/0009-fix-HOME-env-of-container-unset-error.patch b/0009-fix-HOME-env-of-container-unset-error.patch new file mode 100644 index 0000000000000000000000000000000000000000..799a7e71c85942f07524a88a0f116f16ec6b663f --- /dev/null +++ b/0009-fix-HOME-env-of-container-unset-error.patch @@ -0,0 +1,316 @@ +From 043b2483585a2d8168e0fde8b37054733a31f263 Mon Sep 17 00:00:00 2001 +From: haozi007 +Date: Mon, 25 Jul 2022 15:36:23 +0800 +Subject: [PATCH] fix HOME env of container unset error + +Signed-off-by: haozi007 +--- + src/lxc/isulad_utils.c | 210 ++++++++++++++++++++++++++++++++++++++++- + src/lxc/isulad_utils.h | 3 + + src/lxc/start.c | 14 +-- + 3 files changed, 216 insertions(+), 11 deletions(-) + +diff --git a/src/lxc/isulad_utils.c b/src/lxc/isulad_utils.c +index 15d9323..cd7fca8 100644 +--- a/src/lxc/isulad_utils.c ++++ b/src/lxc/isulad_utils.c +@@ -6,6 +6,10 @@ + * Create: 2020-04-11 + ******************************************************************************/ + ++#ifndef _GNU_SOURCE ++#define _GNU_SOURCE 1 ++#endif ++ + #include + #include + #include +@@ -13,6 +17,10 @@ + #include + #include + #include ++#include ++#include ++#include ++#include + + #include "isulad_utils.h" + #include "log.h" +@@ -244,20 +252,34 @@ out: + // isulad: set env home in container + int lxc_setup_env_home(uid_t uid) + { ++#define __PASSWD_FILE__ "/etc/passwd" + char *homedir = "/"; // default home dir is / ++ FILE *stream = NULL; + 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; ++ stream = fopen_cloexec(__PASSWD_FILE__, "r"); ++ if (stream == NULL) { ++ SYSWARN("Failed to open %s", __PASSWD_FILE__); + goto set_env; + } + ++#if IS_BIONIC ++ while (util_getpwent_r(stream, &pw, buf, sizeof(buf), &pwbufp) == 0 && pwbufp != NULL) { ++#else ++ while (fgetpwent_r(stream, &pw, buf, sizeof(buf), &pwbufp) == 0 && pwbufp != NULL) { ++#endif ++ if (pwbufp->pw_uid == uid) { ++ homedir = pwbufp->pw_dir; ++ goto set_env; ++ } ++ } + WARN("User invalid, can not find user '%u'", uid); + + set_env: ++ if (stream) ++ fclose(stream); ++ + // if we didn't configure HOME, set it based on uid + if (setenv("HOME", homedir, 0) < 0) { + SYSERROR("Unable to set env 'HOME'"); +@@ -317,3 +339,183 @@ bool is_non_negative_num(const char *s) + } + return true; + } ++ ++static int hold_int(const char delim, bool required, char **src, unsigned int *dst) ++{ ++ unsigned long long int res = 0; ++ char *err_str = NULL; ++ ++ // ensure *src not a empty string ++ if (**src == '\0') { ++ ERROR("Empty subject on given entrie is not allowed."); ++ return -1; ++ } ++ ++ errno = 0; ++ // covert string to long long ++ res = strtoull(*src, &err_str, 0); ++ if (errno != 0 && errno != ERANGE) { ++ ERROR("Parse int from string failed."); ++ return -1; ++ } ++ ++ // **src is not a digit ++ if (err_str == *src) { ++ if (!required) { ++ ERROR("Integer part is missing."); ++ return -1; ++ } ++ // if required, just set 0 ++ *dst = 0; ++ } else { ++ if (sizeof(void *) > 4 && res > UINT_MAX) { // make sure 64-bit platform behave same as 32-bit ++ res = UINT_MAX; ++ } ++ res = res & UINT_MAX; ++ *dst = (uint32_t)res; ++ } ++ ++ // normal case ++ if (*err_str == delim) { ++ err_str++; ++ } else if (*err_str != '\0') { ++ ERROR("Invalid digit string."); ++ return -1; ++ } ++ ++ *src = err_str; // update src to next valid context in line. ++ return 0; ++} ++ ++static void hold_string(const char delim, char **src, char **dst) ++{ ++ for (*dst = *src; **src != delim; ++(*src)) { ++ if (**src == '\0') { ++ break; ++ } ++ } ++ ++ if (**src == delim) { ++ **src = '\0'; ++ ++(*src); ++ } ++} ++ ++static int parse_line_pw(const char delim, char *line, struct passwd *result) ++{ ++ int ret = 0; ++ bool required = false; ++ char *walker = NULL; ++ ++ walker = strpbrk(line, "\n"); ++ if (walker != NULL) { ++ // clear newline char ++ *walker = '\0'; ++ } ++ ++ hold_string(delim, &line, &result->pw_name); ++ ++ required = (result->pw_name[0] == '+' || result->pw_name[0] == '-') ? true : false; ++ ++ hold_string(delim, &line, &result->pw_passwd); ++ ++ ret = hold_int(delim, required, &line, &result->pw_uid); ++ if (ret != 0) { ++ // a legitimate line must have uid ++ ERROR("Parse uid error."); ++ return ret; ++ } ++ ++ ret = hold_int(delim, required, &line, &result->pw_gid); ++ if (ret != 0) { ++ // it's ok to not provide gid ++ ERROR("Parse gid error."); ++ return ret; ++ } ++ ++ hold_string(delim, &line, &result->pw_gecos); ++ ++ hold_string(delim, &line, &result->pw_dir); ++ ++ result->pw_shell = line; ++ return 0; ++} ++ ++char *util_left_trim_space(char *str) ++{ ++ char *begin = str; ++ char *tmp = str; ++ while (isspace(*begin)) { ++ begin++; ++ } ++ while ((*tmp++ = *begin++)) { ++ } ++ return str; ++} ++ ++int util_getpwent_r(FILE *stream, struct passwd *resbuf, char *buffer, size_t buflen, struct passwd **result) ++{ ++ const char delim = ':'; ++ char *buff_end = NULL; ++ char *walker = NULL; ++ bool got = false; ++ int ret = 0; ++ ++ if (stream == NULL || resbuf == NULL || buffer == NULL || result == NULL) { ++ ERROR("Password obj, params is NULL."); ++ return -1; ++ } ++ ++ if (buflen <= 1) { ++ ERROR("Inadequate buffer length was given."); ++ return -1; ++ } ++ ++ buff_end = buffer + buflen - 1; ++ flockfile(stream); ++ ++ while (1) { ++ *buff_end = '\xff'; ++ walker = fgets_unlocked(buffer, buflen, stream); ++ // if get NULL string ++ if (walker == NULL) { ++ *result = NULL; ++ // reach end of file, return error ++ if (feof(stream)) { ++ ret = ENOENT; ++ goto out; ++ } ++ // overflow buffer ++ ret = ERANGE; ++ goto out; ++ } ++ // just overflow last char in buffer ++ if (*buff_end != '\xff') { ++ *result = NULL; ++ ret = ERANGE; ++ goto out; ++ } ++ ++ (void)util_left_trim_space(buffer); ++ // skip comment line and empty line ++ if (walker[0] == '#' || walker[0] == '\0') { ++ continue; ++ } ++ ++ if (parse_line_pw(delim, walker, resbuf) == 0) { ++ got = true; ++ break; ++ } ++ } ++ if (!got) { ++ *result = NULL; ++ ret = ERANGE; ++ goto out; ++ } ++ ++ *result = resbuf; ++ ret = 0; ++out: ++ funlockfile(stream); ++ return ret; ++} +\ No newline at end of file +diff --git a/src/lxc/isulad_utils.h b/src/lxc/isulad_utils.h +index 345f511..7a5eb89 100644 +--- a/src/lxc/isulad_utils.h ++++ b/src/lxc/isulad_utils.h +@@ -10,6 +10,7 @@ + + #include + #include ++#include + + /* isulad: replace space with SPACE_MAGIC_STR */ + #define SPACE_MAGIC_STR "[#)" +@@ -96,4 +97,6 @@ extern bool lxc_process_alive(pid_t pid, unsigned long long start_time); + + extern bool is_non_negative_num(const char *s); + ++int util_getpwent_r(FILE *stream, struct passwd *resbuf, char *buffer, size_t buflen, struct passwd **result); ++ + #endif +diff --git a/src/lxc/start.c b/src/lxc/start.c +index f82df34..6fe1203 100644 +--- a/src/lxc/start.c ++++ b/src/lxc/start.c +@@ -1727,6 +1727,13 @@ static int do_start(void *data) + new_uid = handler->conf->init_uid; + new_gid = handler->conf->init_gid; + ++#ifdef HAVE_ISULAD ++ // isulad: set env home in container, must before "Avoid unnecessary syscalls." ++ if (lxc_setup_env_home(new_uid) < 0) { ++ goto out_warn_father; ++ } ++#endif ++ + /* Avoid unnecessary syscalls. */ + if (new_uid == nsuid) + new_uid = LXC_INVALID_UID; +@@ -1734,13 +1741,6 @@ static int do_start(void *data) + if (new_gid == nsgid) + new_gid = LXC_INVALID_GID; + +-#ifdef HAVE_ISULAD +- // isulad: set env home in container +- if (lxc_setup_env_home(new_uid) < 0) { +- goto out_warn_father; +- } +-#endif +- + /* Make sure that the processes STDIO is correctly owned by the user that we are switching to */ + ret = fix_stdio_permissions(new_uid); + if (ret) +-- +2.25.1 + diff --git a/0010-check-yajl-only-when-have-isulad.patch b/0010-check-yajl-only-when-have-isulad.patch new file mode 100644 index 0000000000000000000000000000000000000000..e4ea3c1b4d729db4c1b99deff3f814c84756499c --- /dev/null +++ b/0010-check-yajl-only-when-have-isulad.patch @@ -0,0 +1,70 @@ +From d4cb8f6a8f46a3f5d72f22d7f79df83ad82215e0 Mon Sep 17 00:00:00 2001 +From: zhangxiaoyu +Date: Mon, 25 Jul 2022 16:42:03 +0800 +Subject: [PATCH] check yajl only when have isulad + +Signed-off-by: zhangxiaoyu +--- + configure.ac | 6 +++--- + src/lxc/Makefile.am | 7 +++++-- + src/lxc/af_unix.c | 2 +- + 3 files changed, 9 insertions(+), 6 deletions(-) + +diff --git a/configure.ac b/configure.ac +index ce8854e..2180586 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -120,9 +120,6 @@ AM_CONDITIONAL([DISTRO_UBUNTU], [test "x$with_distro" = "xubuntu"]) + + AC_CONFIG_LINKS([config/etc/default.conf:config/etc/${distroconf}]) + +-# Check yajl +-PKG_CHECK_MODULES([YAJL], [yajl >= 2],[],[AC_MSG_ERROR([You must install yajl >= 2])]) +- + # Check for init system type + AC_MSG_CHECKING([for init system type]) + AC_ARG_WITH([init-script], +@@ -839,6 +836,9 @@ AM_CONDITIONAL([HAVE_ISULAD], [test "x$adapt_isulad" = "xyes"]) + if test "x$adapt_isulad" = "xyes"; then + AC_DEFINE([HAVE_ISULAD], 1, [adapt to iSulad]) + AC_MSG_RESULT([yes]) ++ ++ # Check yajl ++ PKG_CHECK_MODULES([YAJL], [yajl >= 2],[],[AC_MSG_ERROR([You must install yajl >= 2])]) + else + AC_MSG_RESULT([no]) + fi +diff --git a/src/lxc/Makefile.am b/src/lxc/Makefile.am +index b9a8750..61a229f 100644 +--- a/src/lxc/Makefile.am ++++ b/src/lxc/Makefile.am +@@ -360,8 +360,11 @@ LDADD = liblxc.la \ + @OPENSSL_LIBS@ \ + @SECCOMP_LIBS@ \ + @SELINUX_LIBS@ \ +- @DLOG_LIBS@ \ +- @YAJL_LIBS@ ++ @DLOG_LIBS@ ++ ++if HAVE_ISULAD ++ LDADD += @YAJL_LIBS@ ++endif + + if ENABLE_TOOLS + lxc_attach_SOURCES = tools/lxc_attach.c \ +diff --git a/src/lxc/af_unix.c b/src/lxc/af_unix.c +index cb4233e..0be9368 100644 +--- a/src/lxc/af_unix.c ++++ b/src/lxc/af_unix.c +@@ -382,7 +382,7 @@ int lxc_unix_connect_type(struct sockaddr_un *addr, int type) + offsetof(struct sockaddr_un, sun_path) + len); + if (ret < 0) + #ifdef HAVE_ISULAD +- return log_error_errno(-1, errno, ++ return log_warn_errno(-1, errno, + "Failed to connect new AF_UNIX socket"); + #else + return log_error_errno(-1, errno, +-- +2.25.1 + diff --git a/0011-drop-security_context_t.patch b/0011-drop-security_context_t.patch new file mode 100644 index 0000000000000000000000000000000000000000..b935b8b57148eb395cc132c0dc44919f74a9a485 --- /dev/null +++ b/0011-drop-security_context_t.patch @@ -0,0 +1,29 @@ +From bcc3084c9230486c3a7d40cff633d581f6a1a990 Mon Sep 17 00:00:00 2001 +From: zhangxiaoyu +Date: Tue, 26 Jul 2022 14:27:11 +0800 +Subject: [PATCH] drop security_context_t + +Signed-off-by: zhangxiaoyu +--- + src/lxc/lsm/selinux.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/src/lxc/lsm/selinux.c b/src/lxc/lsm/selinux.c +index bd4f449..c24d238 100644 +--- a/src/lxc/lsm/selinux.c ++++ b/src/lxc/lsm/selinux.c +@@ -36,7 +36,11 @@ lxc_log_define(selinux, lsm); + */ + static char *selinux_process_label_get(pid_t pid) + { ++#ifdef HAVE_ISULAD ++ char *ctx; ++#else + security_context_t ctx; ++#endif + char *label; + + if (getpidcon_raw(pid, &ctx) < 0) { +-- +2.25.1 + diff --git a/0012-only-set-user-or-image-set-non-empty-HOME.patch b/0012-only-set-user-or-image-set-non-empty-HOME.patch new file mode 100644 index 0000000000000000000000000000000000000000..61686e0a99317d98af66e89ca9e5ab46faaf61c8 --- /dev/null +++ b/0012-only-set-user-or-image-set-non-empty-HOME.patch @@ -0,0 +1,50 @@ +From 7273c6631f692872384cce83cc04b4084ee98f73 Mon Sep 17 00:00:00 2001 +From: haozi007 +Date: Tue, 9 Aug 2022 17:30:59 +0800 +Subject: [PATCH] only set user or image set non-empty HOME + +Signed-off-by: haozi007 +--- + src/lxc/isulad_utils.c | 14 +++++++++++--- + 1 file changed, 11 insertions(+), 3 deletions(-) + +diff --git a/src/lxc/isulad_utils.c b/src/lxc/isulad_utils.c +index cd7fca8..067e1c9 100644 +--- a/src/lxc/isulad_utils.c ++++ b/src/lxc/isulad_utils.c +@@ -257,6 +257,13 @@ int lxc_setup_env_home(uid_t uid) + FILE *stream = NULL; + struct passwd pw, *pwbufp = NULL; + char buf[BUFSIZ]; ++ const char *curr_home = NULL; ++ ++ curr_home = getenv("HOME"); ++ // if user set or image set, just use it. ++ if (curr_home != NULL && strcmp(curr_home, "") != 0) { ++ return 0; ++ } + + stream = fopen_cloexec(__PASSWD_FILE__, "r"); + if (stream == NULL) { +@@ -280,8 +287,9 @@ set_env: + if (stream) + fclose(stream); + +- // if we didn't configure HOME, set it based on uid +- if (setenv("HOME", homedir, 0) < 0) { ++ // if we didn't configure HOME, set it based on uid; ++ // override it if reach here. ++ if (setenv("HOME", homedir, 1) < 0) { + SYSERROR("Unable to set env 'HOME'"); + return -1; + } +@@ -518,4 +526,4 @@ int util_getpwent_r(FILE *stream, struct passwd *resbuf, char *buffer, size_t bu + out: + funlockfile(stream); + return ret; +-} +\ No newline at end of file ++} +-- +2.25.1 + diff --git a/0013-return-fail-if-no-args-or-no-rootfs-path-found.patch b/0013-return-fail-if-no-args-or-no-rootfs-path-found.patch new file mode 100644 index 0000000000000000000000000000000000000000..41a72e1d9e657b30a2fb2f81a27aa6215afd449f --- /dev/null +++ b/0013-return-fail-if-no-args-or-no-rootfs-path-found.patch @@ -0,0 +1,38 @@ +From a2aff3425a6f35bdb9f83880a1545b89606bf7c9 Mon Sep 17 00:00:00 2001 +From: WangFengTu +Date: Fri, 19 Aug 2022 14:32:22 +0800 +Subject: [PATCH] return fail if no args or no rootfs path found + +Signed-off-by: WangFengTu +--- + src/lxc/lxccontainer.c | 14 ++++++++++++++ + 1 file changed, 14 insertions(+) + +diff --git a/src/lxc/lxccontainer.c b/src/lxc/lxccontainer.c +index 3f75184..4b669bb 100644 +--- a/src/lxc/lxccontainer.c ++++ b/src/lxc/lxccontainer.c +@@ -1030,6 +1030,20 @@ static bool do_lxcapi_start(struct lxc_container *c, int useinit, char * const a + argv = init_cmd = use_init_args(conf->init_argv, conf->init_argc); + } + ++ // do not allow using default rootfs path when isulad ++ if (conf->rootfs.mount == NULL) { ++ ERROR("Empty rootfs path detected"); ++ lxc_put_handler(handler); ++ return false; ++ } ++ ++ // do not allow using default args when isulad ++ if (!argv) { ++ ERROR("Empty args detected"); ++ lxc_put_handler(handler); ++ return false; ++ } ++ + if (c->image_type_oci) { + handler->image_type_oci = true; + } +-- +2.25.1 + diff --git a/0014-fix-tools-using-option-give-error-message.patch b/0014-fix-tools-using-option-give-error-message.patch new file mode 100644 index 0000000000000000000000000000000000000000..2c79051b612e82449381157eab3153800d9c17e1 --- /dev/null +++ b/0014-fix-tools-using-option-give-error-message.patch @@ -0,0 +1,25 @@ +From cce266a71a8998e17abada2a7e716298c2169208 Mon Sep 17 00:00:00 2001 +From: Neil.wrz +Date: Thu, 1 Sep 2022 05:04:56 -0700 +Subject: [PATCH] fix tools using '-?' option give error message + +Signed-off-by: Neil.wrz +--- + src/lxc/tools/arguments.h | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/src/lxc/tools/arguments.h b/src/lxc/tools/arguments.h +index c16d99f..80c2083 100644 +--- a/src/lxc/tools/arguments.h ++++ b/src/lxc/tools/arguments.h +@@ -145,6 +145,7 @@ struct lxc_arguments { + #define LXC_COMMON_OPTIONS \ + { "name", required_argument, 0, 'n' }, \ + { "help", no_argument, 0, 'h' }, \ ++ { "help", no_argument, 0, '?' }, \ + { "usage", no_argument, 0, OPT_USAGE }, \ + { "version", no_argument, 0, OPT_VERSION }, \ + { "quiet", no_argument, 0, 'q' }, \ +-- +2.25.1 + diff --git a/0015-fix-do-mask-pathes-after-parent-mounted.patch b/0015-fix-do-mask-pathes-after-parent-mounted.patch new file mode 100644 index 0000000000000000000000000000000000000000..9243c493eb915ffadbaf429fcb8e33f821678848 --- /dev/null +++ b/0015-fix-do-mask-pathes-after-parent-mounted.patch @@ -0,0 +1,44 @@ +From 96a35e077d21a1abf1cc3819fb842b8089ee268d Mon Sep 17 00:00:00 2001 +From: isuladci +Date: Tue, 20 Sep 2022 01:40:18 -0700 +Subject: [PATCH] fix do mask pathes after parent mounted + +Signed-off-by: isuladci +--- + src/lxc/conf.c | 14 +++++++------- + 1 file changed, 7 insertions(+), 7 deletions(-) + +diff --git a/src/lxc/conf.c b/src/lxc/conf.c +index 378cf9f..439601a 100644 +--- a/src/lxc/conf.c ++++ b/src/lxc/conf.c +@@ -3975,19 +3975,19 @@ int lxc_setup(struct lxc_handler *handler) + } + + #ifdef HAVE_ISULAD +- // isulad: setup rootfs masked paths +- if (!lxc_list_empty(&lxc_conf->rootfs.maskedpaths)) { +- if (setup_rootfs_maskedpaths(&lxc_conf->rootfs.maskedpaths)) { +- return log_error(-1, "failed to setup maskedpaths"); +- } +- } +- + // isulad: setup rootfs ro paths + if (!lxc_list_empty(&lxc_conf->rootfs.ropaths)) { + if (setup_rootfs_ropaths(&lxc_conf->rootfs.ropaths)) { + return log_error(-1, "failed to setup readonlypaths"); + } + } ++ ++ // isulad: setup rootfs masked paths ++ if (!lxc_list_empty(&lxc_conf->rootfs.maskedpaths)) { ++ if (setup_rootfs_maskedpaths(&lxc_conf->rootfs.maskedpaths)) { ++ return log_error(-1, "failed to setup maskedpaths"); ++ } ++ } + + //isulad: system container, remount /proc/sys/xxx by mount_list + if (lxc_conf->systemd != NULL && strcmp(lxc_conf->systemd, "true") == 0) { +-- +2.25.1 + diff --git a/0016-skip-kill-cgroup-processes-if-no-hierarchies.patch b/0016-skip-kill-cgroup-processes-if-no-hierarchies.patch new file mode 100644 index 0000000000000000000000000000000000000000..9538da7781bdaa78d96f32346fd75c754ec3a8de --- /dev/null +++ b/0016-skip-kill-cgroup-processes-if-no-hierarchies.patch @@ -0,0 +1,36 @@ +From 2aa9204b74c96413944a715408cfd5d2f3a34d66 Mon Sep 17 00:00:00 2001 +From: isuladci +Date: Thu, 22 Sep 2022 10:44:26 +0800 +Subject: [PATCH] skip kill cgroup processes if no hierarchies + +Signed-off-by: isuladci +--- + src/lxc/cgroups/isulad_cgfsng.c | 7 +++---- + 1 file changed, 3 insertions(+), 4 deletions(-) + +diff --git a/src/lxc/cgroups/isulad_cgfsng.c b/src/lxc/cgroups/isulad_cgfsng.c +index 8a9656a..f5cf81c 100644 +--- a/src/lxc/cgroups/isulad_cgfsng.c ++++ b/src/lxc/cgroups/isulad_cgfsng.c +@@ -677,15 +677,14 @@ __cgfsng_ops static bool isulad_cgfsng_payload_destroy(struct cgroup_ops *ops, + return false; + } + +-#ifdef HAVE_ISULAD + if (ops->no_controller) { +- DEBUG("no controller found, isgnore isulad_cgfsng_payload_destroy"); ++ DEBUG("no controller found, ignore isulad_cgfsng_payload_destroy"); + return true; + } +-#endif + + if (!ops->hierarchies) { +- return false; ++ DEBUG("no hierarchies found, ignore isulad_cgfsng_payload_destroy"); ++ return true; + } + + if (!handler) { +-- +2.25.1 + diff --git a/0017-lxc-Add-sw64-architecture.patch b/0017-lxc-Add-sw64-architecture.patch new file mode 100644 index 0000000000000000000000000000000000000000..b8b0696cdf7a23486f3957d2141369d0aafbdfc6 --- /dev/null +++ b/0017-lxc-Add-sw64-architecture.patch @@ -0,0 +1,26 @@ +From 10ce28085f6d425aae21e043a45c6ef02fdd1e44 Mon Sep 17 00:00:00 2001 +From: rpm-build +Date: Mon, 24 Oct 2022 11:03:11 +0800 +Subject: [PATCH] Add sw64 architecture + +Signed-off-by: rpm-build +--- + src/lxc/syscall_numbers.h | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/src/lxc/syscall_numbers.h b/src/lxc/syscall_numbers.h +index bfd0e57..803eab7 100644 +--- a/src/lxc/syscall_numbers.h ++++ b/src/lxc/syscall_numbers.h +@@ -377,6 +377,8 @@ + #ifndef __NR_pidfd_send_signal + #if defined __alpha__ + #define __NR_pidfd_send_signal 534 ++ #elif defined __sw_64__ ++ #define __NR_pidfd_send_signal 271 + #elif defined _MIPS_SIM + #if _MIPS_SIM == _MIPS_SIM_ABI32 /* o32 */ + #define __NR_pidfd_send_signal 4424 +-- +2.33.0 + diff --git a/0018-add-macro-to-adapt-musl-libc.patch b/0018-add-macro-to-adapt-musl-libc.patch new file mode 100644 index 0000000000000000000000000000000000000000..5247304fa62c6e01d5c4166f40fb9b3201010a89 --- /dev/null +++ b/0018-add-macro-to-adapt-musl-libc.patch @@ -0,0 +1,33 @@ +From 62f36cfa7abafa213b7a0ba26136b409d241b019 Mon Sep 17 00:00:00 2001 +From: isuladci +Date: Thu, 24 Nov 2022 17:05:44 +0800 +Subject: [PATCH] add macro to adapt musl libc + +Signed-off-by: isuladci +--- + src/lxc/json/json_common.h | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/src/lxc/json/json_common.h b/src/lxc/json/json_common.h +index 60aa5fd..67c2df8 100755 +--- a/src/lxc/json/json_common.h ++++ b/src/lxc/json/json_common.h +@@ -17,6 +17,15 @@ extern "C" { + + # undef linux + ++#ifdef __MUSL__ ++#undef stdin ++#undef stdout ++#undef stderr ++#define stdin stdin ++#define stdout stdout ++#define stderr stderr ++#endif ++ + //options to report error if there is unknown key found in json + # define PARSE_OPTIONS_STRICT 0x01 + //options to generate all key and value +-- +2.25.1 + diff --git a/0019-add-lxc-attach-add-gids-option.patch b/0019-add-lxc-attach-add-gids-option.patch new file mode 100644 index 0000000000000000000000000000000000000000..77f75711bbd2e4f9db0c96f705ca6abfd0734c50 --- /dev/null +++ b/0019-add-lxc-attach-add-gids-option.patch @@ -0,0 +1,178 @@ +From 90512fd67873600a490d2432e6c9429771f719be Mon Sep 17 00:00:00 2001 +From: isuladci +Date: Fri, 2 Dec 2022 18:52:39 +0800 +Subject: [PATCH] add lxc-attach add-gids option + +Signed-off-by: isuladci +--- + src/lxc/attach.c | 13 ++++++-- + src/lxc/attach_options.h | 2 ++ + src/lxc/tools/arguments.h | 3 ++ + src/lxc/tools/lxc_attach.c | 65 ++++++++++++++++++++++++++++++++++++++ + 4 files changed, 80 insertions(+), 3 deletions(-) + +diff --git a/src/lxc/attach.c b/src/lxc/attach.c +index 8a2c52a..24d020d 100644 +--- a/src/lxc/attach.c ++++ b/src/lxc/attach.c +@@ -1019,9 +1019,16 @@ static int attach_child_main(struct attach_clone_payload *payload) + goto on_error; + } + +- if (!lxc_setgroups(init_ctx->container->lxc_conf->init_groups_len, +- init_ctx->container->lxc_conf->init_groups)) +- goto on_error; ++ if (options->add_gids != NULL && options->add_gids_len != 0) { ++ if (!lxc_setgroups(options->add_gids_len, options->add_gids)) { ++ goto on_error; ++ } ++ } else { ++ if (!lxc_setgroups(init_ctx->container->lxc_conf->init_groups_len, ++ init_ctx->container->lxc_conf->init_groups)) { ++ goto on_error; ++ } ++ } + #endif + + /* Make sure that the processes STDIO is correctly owned by the user that we are switching to */ +diff --git a/src/lxc/attach_options.h b/src/lxc/attach_options.h +index 16b4e21..4591d65 100644 +--- a/src/lxc/attach_options.h ++++ b/src/lxc/attach_options.h +@@ -124,6 +124,8 @@ typedef struct lxc_attach_options_t { + const char *suffix; + bool disable_pty; + bool open_stdin; ++ gid_t *add_gids; /* attach user additional gids */ ++ size_t add_gids_len; + #endif + } lxc_attach_options_t; + +diff --git a/src/lxc/tools/arguments.h b/src/lxc/tools/arguments.h +index 80c2083..583390a 100644 +--- a/src/lxc/tools/arguments.h ++++ b/src/lxc/tools/arguments.h +@@ -50,6 +50,8 @@ struct lxc_arguments { + int open_stdin; + unsigned int start_timeout; /* isulad: Seconds for waiting on a container to start before it is killed*/ + int64_t attach_timeout; /* for lxc-attach */ ++ gid_t *add_gids; ++ size_t add_gids_len; + #endif + + /* for lxc-console */ +@@ -175,6 +177,7 @@ struct lxc_arguments { + #define OPT_OPEN_STDIN OPT_USAGE - 14 + #define OPT_ATTACH_TIMEOUT OPT_USAGE - 15 + #define OPT_ATTACH_SUFFIX OPT_USAGE - 16 ++#define OPT_ADDITIONAL_GIDS OPT_USAGE - 17 + #endif + + extern int lxc_arguments_parse(struct lxc_arguments *args, int argc, +diff --git a/src/lxc/tools/lxc_attach.c b/src/lxc/tools/lxc_attach.c +index 1a5a241..f6ddf2d 100644 +--- a/src/lxc/tools/lxc_attach.c ++++ b/src/lxc/tools/lxc_attach.c +@@ -78,6 +78,7 @@ static const struct option my_longopts[] = { + #else + {"workdir", required_argument, 0, 'w'}, + {"user", required_argument, 0, 'u'}, ++ {"add-gids", required_argument, 0, OPT_ADDITIONAL_GIDS}, + {"in-fifo", required_argument, 0, OPT_INPUT_FIFO}, /* isulad add terminal fifos*/ + {"out-fifo", required_argument, 0, OPT_OUTPUT_FIFO}, + {"err-fifo", required_argument, 0, OPT_STDERR_FIFO}, +@@ -146,6 +147,7 @@ Options :\n\ + "\ + -w, --workdir Working directory inside the container.\n\ + -u, --user User ID (format: UID[:GID])\n\ ++ --add-gids Additional gids (format: GID[,GID])\n\ + --in-fifo Stdin fifo path\n\ + --out-fifo Stdout fifo path\n\ + --err-fifo Stderr fifo path\n\ +@@ -228,6 +230,58 @@ static int get_attach_uid_gid(const char *username, uid_t *user_id, gid_t *group + free(tmp); + return 0; + } ++ ++static int get_attach_add_gids(const char *add_gids, gid_t **gids, size_t *gids_len) ++{ ++ long long int readvalue; ++ size_t i, len; ++ const size_t max_gids = 100; ++ gid_t *g = NULL; ++ __do_free_string_list char **gids_str = NULL; ++ ++ if (add_gids == NULL || strlen(add_gids) == 0) { ++ ERROR("None additional gids"); ++ return -1; ++ } ++ ++ gids_str = lxc_string_split(add_gids, ','); ++ if (gids_str == NULL) { ++ ERROR("Failed to split additional gids"); ++ return -1; ++ } ++ ++ len = lxc_array_len((void **)gids_str); ++ if (len > max_gids) { ++ ERROR("Too many gids"); ++ return -1; ++ } ++ ++ g = calloc(len, sizeof(gid_t)); ++ if (g == NULL) { ++ ERROR("Out of memory"); ++ return -1; ++ } ++ ++ for (i = 0; i < len; i++) { ++ if (lxc_safe_long_long(gids_str[i], &readvalue) != 0) { ++ SYSERROR("Invalid gid value %s", gids_str[i]); ++ goto err_out; ++ } ++ if (readvalue < 0) { ++ ERROR("Invalid gid value: %lld", readvalue); ++ goto err_out; ++ } ++ g[i] = (unsigned int)readvalue; ++ } ++ ++ *gids = g; ++ *gids_len = len; ++ return 0; ++ ++err_out: ++ free(g); ++ return -1; ++} + #endif + + static int my_parser(struct lxc_arguments *args, int c, char *arg) +@@ -331,6 +385,12 @@ static int my_parser(struct lxc_arguments *args, int c, char *arg) + case OPT_OPEN_STDIN: + args->open_stdin = 1; + break; ++ case OPT_ADDITIONAL_GIDS: ++ if (get_attach_add_gids(arg, &args->add_gids, &args->add_gids_len) != 0) { ++ ERROR("Failed to get attach additional gids"); ++ return -1; ++ } ++ break; + #endif + } + +@@ -655,6 +715,11 @@ int main(int argc, char *argv[]) + attach_options.initial_cwd = my_args.workdir; + } + ++ if (my_args.add_gids) { ++ attach_options.add_gids = my_args.add_gids; ++ attach_options.add_gids_len = my_args.add_gids_len; ++ } ++ + /* isulad: add do attach background */ + if (attach_options.attach_flags & LXC_ATTACH_TERMINAL) + wexit = do_attach_foreground(c, &command, &attach_options, &errmsg); +-- +2.25.1 + diff --git a/0020-add-sscanf-adapation-code-for-musl.patch b/0020-add-sscanf-adapation-code-for-musl.patch new file mode 100644 index 0000000000000000000000000000000000000000..a9d54706bedb2281c8deaa788e725b4bc6bff3c0 --- /dev/null +++ b/0020-add-sscanf-adapation-code-for-musl.patch @@ -0,0 +1,31 @@ +From 3cefa43ec2f5f0366c470290d48bdcd88690cf90 Mon Sep 17 00:00:00 2001 +From: isuladci +Date: Thu, 8 Dec 2022 09:48:29 +0800 +Subject: [PATCH] add sscanf adapation code for musl + +Signed-off-by: isuladci +--- + src/lxc/isulad_utils.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/src/lxc/isulad_utils.c b/src/lxc/isulad_utils.c +index 067e1c9..ee39302 100644 +--- a/src/lxc/isulad_utils.c ++++ b/src/lxc/isulad_utils.c +@@ -173,7 +173,13 @@ static proc_t *lxc_stat2proc(const char *S) + (void)memset(P, 0x00, sizeof(proc_t)); + + /* parse these two strings separately, skipping the leading "(". */ ++ /* https://www.openwall.com/lists/musl/2013/11/15/5: musl's sscanf("%15c",cmd) ++ requires exactly 15 characters; anything shorter is a matching failure. */ ++#ifdef __MUSL__ ++ num = sscanf(S, "%d (%15s", &P->pid, P->cmd); /* comm[16] in kernel */ ++#else + num = sscanf(S, "%d (%15c", &P->pid, P->cmd); /* comm[16] in kernel */ ++#endif + if (num != 2) { + ERROR("Call sscanf error: %s", errno ? strerror(errno) : ""); + free(P); +-- +2.25.1 + diff --git a/0021-change-the-suffi-parameter-in-lxc-attach-help-output.patch b/0021-change-the-suffi-parameter-in-lxc-attach-help-output.patch new file mode 100644 index 0000000000000000000000000000000000000000..6fe236a675f429295df2b04367b4f1cfd12274e6 --- /dev/null +++ b/0021-change-the-suffi-parameter-in-lxc-attach-help-output.patch @@ -0,0 +1,26 @@ +From 026fea0b424c20c867be1577f5d98bc7bf97ba5a Mon Sep 17 00:00:00 2001 +From: isuladci +Date: Fri, 16 Dec 2022 19:17:11 +0800 +Subject: [PATCH] change the --suffi parameter in lxc-attach --help output + +Signed-off-by: isuladci +--- + src/lxc/tools/lxc_attach.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/lxc/tools/lxc_attach.c b/src/lxc/tools/lxc_attach.c +index f6ddf2d..fc0529a 100644 +--- a/src/lxc/tools/lxc_attach.c ++++ b/src/lxc/tools/lxc_attach.c +@@ -151,7 +151,7 @@ Options :\n\ + --in-fifo Stdin fifo path\n\ + --out-fifo Stdout fifo path\n\ + --err-fifo Stderr fifo path\n\ +- --suffi ID for mutli-attach on one container\n\ ++ --suffix ID for mutli-attach on one container\n\ + --timeout Timeout in seconds (default: 0)\n\ + --disable-pty Disable pty for attach\n\ + --open-stdin Open stdin for attach\n\ +-- +2.25.1 + diff --git a/0022-fix-cve-CVE-2022-47952-log-leaks-root-information.patch b/0022-fix-cve-CVE-2022-47952-log-leaks-root-information.patch new file mode 100644 index 0000000000000000000000000000000000000000..e524ed9631f9729b0d10bd76648ca95190878279 --- /dev/null +++ b/0022-fix-cve-CVE-2022-47952-log-leaks-root-information.patch @@ -0,0 +1,51 @@ +From 2b4d27ef9b5d9f38654277f021fabdda2d5f8e36 Mon Sep 17 00:00:00 2001 +From: isuladci +Date: Thu, 12 Jan 2023 19:20:43 -0800 +Subject: [PATCH] fix cve CVE-2022-47952: log leaks root information + +Signed-off-by: isuladci +--- + src/lxc/cmd/lxc_user_nic.c | 14 +++++--------- + 1 file changed, 5 insertions(+), 9 deletions(-) + +diff --git a/src/lxc/cmd/lxc_user_nic.c b/src/lxc/cmd/lxc_user_nic.c +index 4160565..5b848da 100644 +--- a/src/lxc/cmd/lxc_user_nic.c ++++ b/src/lxc/cmd/lxc_user_nic.c +@@ -1087,20 +1087,16 @@ int main(int argc, char *argv[]) + } else if (request == LXC_USERNIC_DELETE) { + char opath[LXC_PROC_PID_FD_LEN]; + +- /* Open the path with O_PATH which will not trigger an actual +- * open(). Don't report an errno to the caller to not leak +- * information whether the path exists or not. +- * When stracing setuid is stripped so this is not a concern +- * either. +- */ ++ // Keep in mind CVE-2022-47952: It's crucial not to leak any ++ // information whether open() succeeded or failed. + netns_fd = open(args.pid, O_PATH | O_CLOEXEC); + if (netns_fd < 0) { +- usernic_error("Failed to open \"%s\"\n", args.pid); ++ usernic_error("Failed while opening netns file for \"%s\"\n", args.pid); + _exit(EXIT_FAILURE); + } + + if (!fhas_fs_type(netns_fd, NSFS_MAGIC)) { +- usernic_error("Path \"%s\" does not refer to a network namespace path\n", args.pid); ++ usernic_error("Failed while opening netns file for \"%s\"\n", args.pid); + close(netns_fd); + _exit(EXIT_FAILURE); + } +@@ -1114,7 +1110,7 @@ int main(int argc, char *argv[]) + /* Now get an fd that we can use in setns() calls. */ + ret = open(opath, O_RDONLY | O_CLOEXEC); + if (ret < 0) { +- CMD_SYSERROR("Failed to open \"%s\"\n", args.pid); ++ CMD_SYSERROR("Failed while opening netns file for \"%s\"\n", args.pid); + close(netns_fd); + _exit(EXIT_FAILURE); + } +-- +2.25.1 + diff --git a/0023-fix-lxc-write-error-message.patch b/0023-fix-lxc-write-error-message.patch new file mode 100644 index 0000000000000000000000000000000000000000..91d30a7dd9706192b6cbdd1c1191f28dd1375cc9 --- /dev/null +++ b/0023-fix-lxc-write-error-message.patch @@ -0,0 +1,26 @@ +From 45948760921dbaa1c030b6848168b89428ca1434 Mon Sep 17 00:00:00 2001 +From: songbuhuang <544824346@qq.com> +Date: Wed, 8 Feb 2023 14:46:44 +0800 +Subject: [PATCH] fix lxc write error message + +Signed-off-by: songbuhuang <544824346@qq.com> +--- + src/lxc/cgroups/isulad_cgfsng.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/lxc/cgroups/isulad_cgfsng.c b/src/lxc/cgroups/isulad_cgfsng.c +index f5cf81c..6ccff63 100644 +--- a/src/lxc/cgroups/isulad_cgfsng.c ++++ b/src/lxc/cgroups/isulad_cgfsng.c +@@ -2463,7 +2463,7 @@ retry: + goto retry; + } + lxc_write_error_message(ops->errfd, +- "%s:%d: setting cgroup config for ready process caused \"failed to write %s to %s: %s\".", ++ "%s:%d: setting cgroup config for ready process caused failed to write %s to %s: %s", + __FILE__, __LINE__, value, fullpath, strerror(errno)); + } + free(fullpath); +-- +2.25.1 + diff --git a/0024-remove-process-inheritable-capability.patch b/0024-remove-process-inheritable-capability.patch new file mode 100644 index 0000000000000000000000000000000000000000..f8b7984d39e38485ab4571c954265e825fb9bce6 --- /dev/null +++ b/0024-remove-process-inheritable-capability.patch @@ -0,0 +1,27 @@ +From d232c098c9a75fce2b7e6da55faa89cd546d3dc9 Mon Sep 17 00:00:00 2001 +From: isuladci +Date: Tue, 31 Jan 2023 19:14:57 +0800 +Subject: [PATCH] remove process inheritable capability + +Signed-off-by: zhangxiaoyu +--- + src/lxc/conf.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/src/lxc/conf.c b/src/lxc/conf.c +index 439601a..c478bf2 100644 +--- a/src/lxc/conf.c ++++ b/src/lxc/conf.c +@@ -5528,7 +5528,8 @@ int lxc_drop_caps(struct lxc_conf *conf) + if (caplist[i]) { + cap_data[CAP_TO_INDEX(i)].effective = cap_data[CAP_TO_INDEX(i)].effective | (i > 31 ? __DEF_CAP_TO_MASK(i % 32) : __DEF_CAP_TO_MASK(i)); + cap_data[CAP_TO_INDEX(i)].permitted = cap_data[CAP_TO_INDEX(i)].permitted | (i > 31 ? __DEF_CAP_TO_MASK(i % 32) : __DEF_CAP_TO_MASK(i)); +- cap_data[CAP_TO_INDEX(i)].inheritable = cap_data[CAP_TO_INDEX(i)].inheritable | (i > 31 ? __DEF_CAP_TO_MASK(i % 32) : __DEF_CAP_TO_MASK(i)); ++ // fix CVE-2022-24769 ++ // inheritable capability should be empty + } + } + +-- +2.25.1 + diff --git a/0025-fix-ops-hierarchies-cause-coredump.patch b/0025-fix-ops-hierarchies-cause-coredump.patch new file mode 100644 index 0000000000000000000000000000000000000000..e162e3b8135ef8bbb060a0b0c55cec35b0b00739 --- /dev/null +++ b/0025-fix-ops-hierarchies-cause-coredump.patch @@ -0,0 +1,32 @@ +From 636f30e34dd33a0b888faa9675fe33fb5aa0ad7a Mon Sep 17 00:00:00 2001 +From: "Neil.wrz" +Date: Tue, 21 Feb 2023 22:48:44 -0800 +Subject: [PATCH] may cause coredump + +--- + src/lxc/cgroups/isulad_cgfsng.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/src/lxc/cgroups/isulad_cgfsng.c b/src/lxc/cgroups/isulad_cgfsng.c +index 6ccff63..dcaa229 100644 +--- a/src/lxc/cgroups/isulad_cgfsng.c ++++ b/src/lxc/cgroups/isulad_cgfsng.c +@@ -938,8 +938,15 @@ __cgfsng_ops static inline bool isulad_cgfsng_payload_create(struct cgroup_ops * + struct lxc_handler *handler) + { + int i; ++ ++ if (!ops) ++ return ret_set_errno(false, ENOENT); ++ + char *container_cgroup = ops->container_cgroup; + ++ if (!ops->hierarchies) ++ return true; ++ + #ifdef HAVE_ISULAD + if (ops->no_controller) { + DEBUG("no controller found, isgnore isulad_cgfsng_payload_create"); +-- +2.25.1 + diff --git a/0026-meminfo-cri-1.25.patch b/0026-meminfo-cri-1.25.patch new file mode 100644 index 0000000000000000000000000000000000000000..b21789a4eac5b656c2a10c99fd91615f2fe1c116 --- /dev/null +++ b/0026-meminfo-cri-1.25.patch @@ -0,0 +1,55 @@ +From d8bf23cac765af4bededef26e56f7cde7bafd4fe Mon Sep 17 00:00:00 2001 +From: "ilya.kuksenok" +Date: Mon, 27 Feb 2023 14:39:39 +0300 +Subject: [PATCH] Add metrics + +Signed-off-by: ilya.kuksenok +--- + src/lxc/lxccontainer.c | 14 ++++++++++++++ + src/lxc/lxccontainer.h | 5 +++++ + 2 files changed, 19 insertions(+) + +diff --git a/src/lxc/lxccontainer.c b/src/lxc/lxccontainer.c +index 4b669bb..afbeb3c 100644 +--- a/src/lxc/lxccontainer.c ++++ b/src/lxc/lxccontainer.c +@@ -6053,6 +6053,20 @@ static bool do_lxcapi_get_container_metrics(struct lxc_container *c, struct lxc + metrics->cpu_use_nanos = metrics_get_ull(c, cgroup_ops, "cpuacct.usage"); + metrics->pids_current = metrics_get_ull(c, cgroup_ops, "pids.current"); + ++ uint64_t usage_bytes; ++ uint64_t workingset; ++ usage_bytes = metrics_match_get_ull(c,cgroup_ops, "memory.stat", "rss", 1) + ++ metrics_match_get_ull(c, cgroup_ops, "memory.stat", "cache", 1) + ++ metrics_match_get_ull(c, cgroup_ops, "memory.stat", "swap", 1); ++ // workingset = usage - inactive_file ++ workingset = usage_bytes - metrics_match_get_ull(c, cgroup_ops, "memory.stat", "total_inactive_file", 1); ++ // Avaliable bytes = limit - workingset ++ metrics->avaliable_bytes = metrics_get_ull(c, cgroup_ops, "memory.limit_in_bytes") - workingset; ++ metrics->usage_bytes = usage_bytes; ++ metrics->rss_bytes = metrics_match_get_ull(c,cgroup_ops, "memory.stat", "rss", 1); ++ metrics->page_faults = metrics_match_get_ull(c,cgroup_ops, "memory.stat", "pgfault", 1); ++ metrics->major_page_faults = metrics_match_get_ull(c,cgroup_ops, "memory.stat", "pgmajfault", 1); ++ + metrics->cpu_use_user = metrics_match_get_ull(c, cgroup_ops, "cpuacct.stat", "user", 1); + metrics->cpu_use_sys = metrics_match_get_ull(c, cgroup_ops, "cpuacct.stat", "system", 1); + +diff --git a/src/lxc/lxccontainer.h b/src/lxc/lxccontainer.h +index 3680ade..68dfec9 100644 +--- a/src/lxc/lxccontainer.h ++++ b/src/lxc/lxccontainer.h +@@ -68,6 +68,11 @@ struct lxc_container_metrics { + /* Memory usage */ + uint64_t mem_used; + uint64_t mem_limit; ++ uint64_t avaliable_bytes; ++ uint64_t usage_bytes; ++ uint64_t rss_bytes; ++ uint64_t page_faults; ++ uint64_t major_page_faults; + /* Kernel Memory usage */ + uint64_t kmem_used; + uint64_t kmem_limit; +-- +2.34.1 + diff --git a/0027-add-loongarch64-support-for-lxc.patch b/0027-add-loongarch64-support-for-lxc.patch new file mode 100644 index 0000000000000000000000000000000000000000..7f68cf1fbb7dc11ba76e9c60b6015370bbeccad7 --- /dev/null +++ b/0027-add-loongarch64-support-for-lxc.patch @@ -0,0 +1,238 @@ +From 477ecc390bf4d62e8e02b98699b377b848b043de Mon Sep 17 00:00:00 2001 +From: Wenlong Zhang +Date: Thu, 9 Feb 2023 08:18:35 +0000 +Subject: [PATCH] add loongarch64 support for lxc + +--- + src/lxc/seccomp.c | 51 +++++++++++++++++++++++++++++++++++++++ + src/lxc/syscall_numbers.h | 26 ++++++++++++++++++++ + 2 files changed, 77 insertions(+) + +diff --git a/src/lxc/seccomp.c b/src/lxc/seccomp.c +index ebbba80..94dc23a 100644 +--- a/src/lxc/seccomp.c ++++ b/src/lxc/seccomp.c +@@ -310,6 +310,7 @@ enum lxc_hostarch_t { + lxc_seccomp_arch_ppc64, + lxc_seccomp_arch_ppc64le, + lxc_seccomp_arch_ppc, ++ lxc_seccomp_arch_loongarch64, + lxc_seccomp_arch_mips, + lxc_seccomp_arch_mips64, + lxc_seccomp_arch_mips64n32, +@@ -344,6 +345,8 @@ int get_hostarch(void) + return lxc_seccomp_arch_ppc64; + else if (strncmp(uts.machine, "ppc", 3) == 0) + return lxc_seccomp_arch_ppc; ++ else if (strncmp(uts.machine, "loongarch64", 11) == 0) ++ return lxc_seccomp_arch_loongarch64; + else if (strncmp(uts.machine, "mips64", 6) == 0) + return MIPS_ARCH_N64; + else if (strncmp(uts.machine, "mips", 4) == 0) +@@ -400,6 +403,11 @@ scmp_filter_ctx get_new_ctx(enum lxc_hostarch_t n_arch, + arch = SCMP_ARCH_PPC; + break; + #endif ++#ifdef SCMP_ARCH_LOONGARCH64 ++ case lxc_seccomp_arch_loongarch64: ++ arch = SCMP_ARCH_LOONGARCH64; ++ break; ++#endif + #ifdef SCMP_ARCH_MIPS + case lxc_seccomp_arch_mips: + arch = SCMP_ARCH_MIPS; +@@ -738,6 +746,16 @@ static int parse_config_v2(FILE *f, char *line, size_t *line_bufsz, struct lxc_c + goto bad; + #endif + #endif ++#ifdef SCMP_ARCH_LOONGARCH64 ++ } else if (native_arch == lxc_seccomp_arch_loongarch64) { ++ cur_rule_arch = lxc_seccomp_arch_all; ++ ++ ctx.lxc_arch[0] = lxc_seccomp_arch_loongarch64; ++ ctx.contexts[0] = get_new_ctx(lxc_seccomp_arch_loongarch64, ++ default_policy_action, &ctx.architectures[0]); ++ if (!ctx.contexts[0]) ++ goto bad; ++#endif + #ifdef SCMP_ARCH_MIPS + } else if (native_arch == lxc_seccomp_arch_mips64) { + cur_rule_arch = lxc_seccomp_arch_all; +@@ -906,6 +924,17 @@ static int parse_config_v2(FILE *f, char *line, size_t *line_bufsz, struct lxc_c + cur_rule_arch = lxc_seccomp_arch_ppc; + } + #endif ++#ifdef SCMP_ARCH_LOONGARCH64 ++ else if (strcmp(line, "[loongarch64]") == 0 || ++ strcmp(line, "[LOONGARCH64]") == 0) { ++ if (native_arch != lxc_seccomp_arch_loongarch64) { ++ cur_rule_arch = lxc_seccomp_arch_unknown; ++ continue; ++ } ++ ++ cur_rule_arch = lxc_seccomp_arch_loongarch64; ++ } ++#endif + #ifdef SCMP_ARCH_MIPS + else if (strcmp(line, "[mips64]") == 0 || + strcmp(line, "[MIPS64]") == 0) { +@@ -1263,6 +1292,17 @@ static int parse_config_v2(FILE *f, char *line, size_t *line_bufsz, struct lxc_c + goto bad; + #endif + #endif ++#ifdef SCMP_ARCH_LOONGARCH64 ++ } else if (native_arch == lxc_seccomp_arch_loongarch64) { ++ cur_rule_arch = lxc_seccomp_arch_all; ++ ++ ctx.architectures[0] = SCMP_ARCH_LOONGARCH64; ++ ctx.contexts[0] = get_new_ctx(lxc_seccomp_arch_loongarch64, ++ default_policy_action, ++ &ctx.needs_merge[0]); ++ if (!ctx.contexts[0]) ++ goto bad; ++#endif + #ifdef SCMP_ARCH_MIPS + } else if (native_arch == lxc_seccomp_arch_mips64) { + cur_rule_arch = lxc_seccomp_arch_all; +@@ -1434,6 +1474,17 @@ static int parse_config_v2(FILE *f, char *line, size_t *line_bufsz, struct lxc_c + cur_rule_arch = lxc_seccomp_arch_ppc; + } + #endif ++#ifdef SCMP_ARCH_LOONGRCH64 ++ else if (strcmp(line, "[loongarch64]") == 0 || ++ strcmp(line, "[LOONGARCH64]") == 0) { ++ if (native_arch != lxc_seccomp_arch_loongarch64) { ++ cur_rule_arch = lxc_seccomp_arch_unknown; ++ continue; ++ } ++ ++ cur_rule_arch = lxc_seccomp_arch_loongarch64; ++ } ++#endif + #ifdef SCMP_ARCH_MIPS + else if (strcmp(line, "[mips64]") == 0 || + strcmp(line, "[MIPS64]") == 0) { +diff --git a/src/lxc/syscall_numbers.h b/src/lxc/syscall_numbers.h +index c68cf24..01aa68d 100644 +--- a/src/lxc/syscall_numbers.h ++++ b/src/lxc/syscall_numbers.h +@@ -49,6 +49,8 @@ + #if _MIPS_SIM == _MIPS_SIM_ABI64 /* n64 */ + #define __NR_keyctl 5241 + #endif ++ #elif defined __loongarch64 ++ #define __NR_keyctl 219 + #else + #define -1 + #warning "__NR_keyctl not defined for your architecture" +@@ -84,6 +86,8 @@ + #if _MIPS_SIM == _MIPS_SIM_ABI64 + #define __NR_memfd_create 5314 + #endif ++ #elif defined __loongarch64 ++ #define __NR_memfd_create 279 + #else + #define -1 + #warning "__NR_memfd_create not defined for your architecture" +@@ -117,6 +121,8 @@ + #if _MIPS_SIM == _MIPS_SIM_ABI64 /* n64 */ + #define __NR_pivot_root 5151 + #endif ++ #elif defined __loongarch64 ++ #define __NR_pivot_root 41 + #else + #define -1 + #warning "__NR_pivot_root not defined for your architecture" +@@ -150,6 +156,8 @@ + #if _MIPS_SIM == _MIPS_SIM_ABI64 /* n64 */ + #define __NR_setns 5303 + #endif ++ #elif defined __loongarch64 ++ #define __NR_setns 268 + #else + #define -1 + #warning "__NR_setns not defined for your architecture" +@@ -183,6 +191,8 @@ + #if _MIPS_SIM == _MIPS_SIM_ABI64 /* n64 */ + #define __NR_sethostname 5165 + #endif ++ #elif defined __loongarch64 ++ #define __NR_sethostname 161 + #else + #define -1 + #warning "__NR_sethostname not defined for your architecture" +@@ -216,6 +226,8 @@ + #if _MIPS_SIM == _MIPS_SIM_ABI64 /* n64 */ + #define __NR_signalfd 5276 + #endif ++ #elif defined __loongarch64 ++ #define __NR_signalfd -1 /* doesn't exist in loongarch64 */ + #else + #define -1 + #warning "__NR_signalfd not defined for your architecture" +@@ -249,6 +261,8 @@ + #if _MIPS_SIM == _MIPS_SIM_ABI64 /* n64 */ + #define __NR_signalfd4 5283 + #endif ++ #elif defined __loongarch64 ++ #define __NR_signalfd4 74 + #else + #define -1 + #warning "__NR_signalfd4 not defined for your architecture" +@@ -282,6 +296,8 @@ + #if _MIPS_SIM == _MIPS_SIM_ABI64 /* n64 */ + #define __NR_unshare 5262 + #endif ++ #elif defined __loongarch64 ++ #define __NR_unshare 97 + #else + #define -1 + #warning "__NR_unshare not defined for your architecture" +@@ -315,6 +331,8 @@ + #if _MIPS_SIM == _MIPS_SIM_ABI64 /* n64 */ + #define __NR_bpf 5315 + #endif ++ #elif defined __loongarch64 ++ #define __NR_bpf 280 + #else + #define -1 + #warning "__NR_bpf not defined for your architecture" +@@ -348,6 +366,8 @@ + #if _MIPS_SIM == _MIPS_SIM_ABI64 /* n64 */ + #define __NR_faccessat 5259 + #endif ++ #elif defined __loongarch64 ++ #define __NR_faccessat 48 + #else + #define -1 + #warning "__NR_faccessat not defined for your architecture" +@@ -401,6 +421,8 @@ + #if _MIPS_SIM == _MIPS_SIM_ABI64 /* n64 */ + #define __NR_seccomp 5312 + #endif ++ #elif defined __loongarch64 ++ #define __NR_seccomp 277 + #else + #define -1 + #warning "__NR_seccomp not defined for your architecture" +@@ -434,6 +456,8 @@ + #if _MIPS_SIM == _MIPS_SIM_ABI64 /* n64 */ + #define __NR_gettid 5178 + #endif ++ #elif defined __loongarch64 ++ #define __NR_gettid 178 + #else + #define -1 + #warning "__NR_gettid not defined for your architecture" +@@ -471,6 +495,8 @@ + #if _MIPS_SIM == _MIPS_SIM_ABI64 /* n64 */ + #define __NR_execveat 5316 + #endif ++ #elif defined __loongarch64 ++ #define __NR_execveat 281 + #else + #define -1 + #warning "__NR_execveat not defined for your architecture" +-- +2.33.0 + diff --git a/0028-use-ocihooks-env-after-getenv.patch b/0028-use-ocihooks-env-after-getenv.patch new file mode 100644 index 0000000000000000000000000000000000000000..9f7a775acc5d47b6f14c4a14e030035fcf1c3dde --- /dev/null +++ b/0028-use-ocihooks-env-after-getenv.patch @@ -0,0 +1,51 @@ +From 9c82e7c0d345eba3cc0514a536eb8438f328164e Mon Sep 17 00:00:00 2001 +From: zhangxiaoyu +Date: Thu, 30 Mar 2023 11:38:45 +0800 +Subject: [PATCH] use ocihooks env after getenv + +Signed-off-by: zhangxiaoyu +--- + src/lxc/conf.c | 13 +++++++------ + 1 file changed, 7 insertions(+), 6 deletions(-) + +diff --git a/src/lxc/conf.c b/src/lxc/conf.c +index c478bf2..3335b0d 100644 +--- a/src/lxc/conf.c ++++ b/src/lxc/conf.c +@@ -6224,7 +6224,8 @@ static char **merge_ocihook_env(char **oldenvs, size_t env_len, size_t *merge_en + { + char **result = NULL; + size_t result_len = env_len; +- size_t i, j; ++ size_t i = 0; ++ size_t j, k; + char *tmpenv = NULL; + char *lxc_envs[] = {"LD_LIBRARY_PATH", "PATH", "LXC_CGNS_AWARE", "LXC_PID", "LXC_ROOTFS_MOUNT", + "LXC_CONFIG_FILE", "LXC_CGROUP_PATH", "LXC_ROOTFS_PATH", "LXC_NAME" +@@ -6239,11 +6240,6 @@ static char **merge_ocihook_env(char **oldenvs, size_t env_len, size_t *merge_en + return NULL; + memset(result, 0, sizeof(char *) * result_len); + +- for(i = 0; i < env_len; i++) { +- if (oldenvs[i]) +- result[i] = safe_strdup(oldenvs[i]); +- } +- + for(j = 0; j < (sizeof(lxc_envs) / sizeof(char *)); j++) { + size_t env_buf_len = 0; + tmpenv = getenv(lxc_envs[j]); +@@ -6267,6 +6263,11 @@ static char **merge_ocihook_env(char **oldenvs, size_t env_len, size_t *merge_en + } + } + ++ for(k = 0; k < env_len; k++) { ++ if (oldenvs[k] && i < (result_len - 1)) ++ result[i++] = safe_strdup(oldenvs[k]); ++ } ++ + *merge_env_len = i; + return result; + } +-- +2.25.1 + diff --git a/0029-fix-mixed-use-of-signed-and-unsigned-type.patch b/0029-fix-mixed-use-of-signed-and-unsigned-type.patch new file mode 100644 index 0000000000000000000000000000000000000000..697e039eb426a4e011169a4f2c6ca007160e89fb --- /dev/null +++ b/0029-fix-mixed-use-of-signed-and-unsigned-type.patch @@ -0,0 +1,51 @@ +From 573aae0ba3b76067e76206b78c8243b34e3f40e3 Mon Sep 17 00:00:00 2001 +From: "Neil.wrz" +Date: Tue, 18 Apr 2023 00:05:27 -0700 +Subject: [PATCH] fix mixed use of signed and unsigned type + +Signed-off-by: Neil.wrz +--- + src/lxc/path.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/src/lxc/path.c b/src/lxc/path.c +index 46256cb..c0529b7 100644 +--- a/src/lxc/path.c ++++ b/src/lxc/path.c +@@ -101,7 +101,7 @@ bool filepath_split(const char *path, char **dir, char **base) + ERROR("Invalid path"); + return false; + } +- i = len - 1; ++ i = (ssize_t)(len - 1); + while (i >= 0 && path[i] != '/') + i--; + +@@ -326,7 +326,7 @@ static int do_get_symlinks(const char **fullpath, const char *prefix, size_t pre + } + + len = strlen(*end); +- if (len >= PATH_MAX - n) { ++ if (len >= (size_t)(PATH_MAX - n)) { + ERROR("Path is too long"); + goto out; + } +@@ -619,7 +619,7 @@ char *path_relative(const char *basepath, const char *targpath) + + if (b0 != bl) { + // Base elements left. Must go up before going down. +- int seps = 0, i; ++ size_t seps = 0, i; + size_t ncopyed = 0, seps_size; + char *buf = NULL; + +@@ -652,4 +652,4 @@ char *path_relative(const char *basepath, const char *targpath) + } + + return safe_strdup(targ + t0); +-} +\ No newline at end of file ++} +-- +2.25.1 + diff --git a/0030-remove-unused-meminfo-stats.patch b/0030-remove-unused-meminfo-stats.patch new file mode 100644 index 0000000000000000000000000000000000000000..5113f37f51b71d158e402ad4583f62ace6ddea3f --- /dev/null +++ b/0030-remove-unused-meminfo-stats.patch @@ -0,0 +1,48 @@ +From 4daa1572b9f129ba46cefb13683de90b49404872 Mon Sep 17 00:00:00 2001 +From: zhangxiaoyu +Date: Tue, 18 Apr 2023 15:22:21 +0800 +Subject: [PATCH] remove unused meminfo stats + +Signed-off-by: zhangxiaoyu +--- + src/lxc/lxccontainer.c | 10 ---------- + src/lxc/lxccontainer.h | 2 -- + 2 files changed, 12 deletions(-) + +diff --git a/src/lxc/lxccontainer.c b/src/lxc/lxccontainer.c +index afbeb3c..cc6c5cd 100644 +--- a/src/lxc/lxccontainer.c ++++ b/src/lxc/lxccontainer.c +@@ -6053,16 +6053,6 @@ static bool do_lxcapi_get_container_metrics(struct lxc_container *c, struct lxc + metrics->cpu_use_nanos = metrics_get_ull(c, cgroup_ops, "cpuacct.usage"); + metrics->pids_current = metrics_get_ull(c, cgroup_ops, "pids.current"); + +- uint64_t usage_bytes; +- uint64_t workingset; +- usage_bytes = metrics_match_get_ull(c,cgroup_ops, "memory.stat", "rss", 1) + +- metrics_match_get_ull(c, cgroup_ops, "memory.stat", "cache", 1) + +- metrics_match_get_ull(c, cgroup_ops, "memory.stat", "swap", 1); +- // workingset = usage - inactive_file +- workingset = usage_bytes - metrics_match_get_ull(c, cgroup_ops, "memory.stat", "total_inactive_file", 1); +- // Avaliable bytes = limit - workingset +- metrics->avaliable_bytes = metrics_get_ull(c, cgroup_ops, "memory.limit_in_bytes") - workingset; +- metrics->usage_bytes = usage_bytes; + metrics->rss_bytes = metrics_match_get_ull(c,cgroup_ops, "memory.stat", "rss", 1); + metrics->page_faults = metrics_match_get_ull(c,cgroup_ops, "memory.stat", "pgfault", 1); + metrics->major_page_faults = metrics_match_get_ull(c,cgroup_ops, "memory.stat", "pgmajfault", 1); +diff --git a/src/lxc/lxccontainer.h b/src/lxc/lxccontainer.h +index 68dfec9..96db5e6 100644 +--- a/src/lxc/lxccontainer.h ++++ b/src/lxc/lxccontainer.h +@@ -68,8 +68,6 @@ struct lxc_container_metrics { + /* Memory usage */ + uint64_t mem_used; + uint64_t mem_limit; +- uint64_t avaliable_bytes; +- uint64_t usage_bytes; + uint64_t rss_bytes; + uint64_t page_faults; + uint64_t major_page_faults; +-- +2.25.1 + diff --git a/0031-lxc-attach-Fix-lost-return-codes-of-spawned-processe.patch b/0031-lxc-attach-Fix-lost-return-codes-of-spawned-processe.patch new file mode 100644 index 0000000000000000000000000000000000000000..cef5a250f30175b8a451a451b7c1e3852819111f --- /dev/null +++ b/0031-lxc-attach-Fix-lost-return-codes-of-spawned-processe.patch @@ -0,0 +1,39 @@ +From 4ebca5a005afbc19c08f663e24d3e76518d12fa8 Mon Sep 17 00:00:00 2001 +From: Mohammed Ajmal Siddiqui +Date: Wed, 5 Oct 2022 12:20:58 +0530 +Subject: [PATCH] lxc-attach: Fix lost return codes of spawned processes that + are killed + +lxc-attach swallows the return codes of processes that are terminated +via a signal, and by default exits with a return code of 0 (i.e. +indicating success) even if the command it tried to execute was +terminated. + +This patch fixes it by explicitly checking if the process was terminated +via a signal, and returning an appropriate exit code. + +Note that we add 128 to the signal value to generate the exit code +because by convention the exit code is 128 + signal number. e.g. if a +process is killed via signal 9, then the error code is 9 + 128 = 137. + +Signed-off-by: Mohammed Ajmal Siddiqui +--- + src/lxc/tools/lxc_attach.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/src/lxc/tools/lxc_attach.c b/src/lxc/tools/lxc_attach.c +index fa303c7b4..6482b0aee 100644 +--- a/src/lxc/tools/lxc_attach.c ++++ b/src/lxc/tools/lxc_attach.c +@@ -399,6 +399,8 @@ int lxc_attach_main(int argc, char *argv[]) + } + if (WIFEXITED(ret)) + wexit = WEXITSTATUS(ret); ++ else if (WIFSIGNALED(ret)) ++ wexit = WTERMSIG(ret) + 128; + + out: + lxc_container_put(c); +-- +2.33.0 + diff --git a/0032-fix-load-bpf-failed.patch b/0032-fix-load-bpf-failed.patch new file mode 100644 index 0000000000000000000000000000000000000000..b8289070c5cac7be61722f5653dd07731a09503c --- /dev/null +++ b/0032-fix-load-bpf-failed.patch @@ -0,0 +1,30 @@ +From ea611fd8e2c04e65c9239a9236376b2686b16832 Mon Sep 17 00:00:00 2001 +From: zhangxiaoyu +Date: Sat, 6 May 2023 17:25:41 +0800 +Subject: [PATCH] fix load bpf failed + +Signed-off-by: zhangxiaoyu +--- + src/lxc/cgroups/cgroup2_devices.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/src/lxc/cgroups/cgroup2_devices.c b/src/lxc/cgroups/cgroup2_devices.c +index 04ba7b3..690e0b3 100644 +--- a/src/lxc/cgroups/cgroup2_devices.c ++++ b/src/lxc/cgroups/cgroup2_devices.c +@@ -237,6 +237,12 @@ int bpf_program_append_device(struct bpf_program *prog, struct device_item *devi + if (device->minor != -1) + jump_nr++; + ++#ifdef HAVE_ISULAD ++ // add a check, if no jump should do, just return. ++ if (jump_nr == 1) ++ return 0; ++#endif ++ + if (device_type > 0) { + struct bpf_insn ins[] = { + BPF_JMP_IMM(BPF_JNE, BPF_REG_2, device_type, jump_nr--), +-- +2.25.1 + diff --git a/0033-fix-mount-device-path-incorrect.patch b/0033-fix-mount-device-path-incorrect.patch new file mode 100644 index 0000000000000000000000000000000000000000..6c0bc4ca8df35efcf2d984f9efb46a7c26144e34 --- /dev/null +++ b/0033-fix-mount-device-path-incorrect.patch @@ -0,0 +1,27 @@ +From f7da4786892ab6b4bbe1cfedad24127a7d059f3d Mon Sep 17 00:00:00 2001 +From: zhangxiaoyu +Date: Fri, 16 Jun 2023 12:02:38 +0800 +Subject: [PATCH] fix mount device path incorrect + +Signed-off-by: zhangxiaoyu +--- + src/lxc/conf.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/src/lxc/conf.c b/src/lxc/conf.c +index 3335b0d..a5573ac 100644 +--- a/src/lxc/conf.c ++++ b/src/lxc/conf.c +@@ -6064,7 +6064,8 @@ static int setup_populate_devs(const struct lxc_rootfs *rootfs, struct lxc_list + + // Unprivileged containers cannot create devices, so + // try to bind mount the device from the host +- ret = snprintf(hostpath, MAXPATHLEN, "/dev/%s", dev_elem->name); ++ // dev_elem name is the device path ++ ret = snprintf(hostpath, MAXPATHLEN, "%s", dev_elem->name); + if (ret < 0 || ret >= MAXPATHLEN) { + ret = -1; + goto reset_umask; +-- +2.25.1 + diff --git a/0034-add-secure-compile-macro.patch b/0034-add-secure-compile-macro.patch new file mode 100644 index 0000000000000000000000000000000000000000..f6a2ed21437bb388e6efdf5682693f8feeafa855 --- /dev/null +++ b/0034-add-secure-compile-macro.patch @@ -0,0 +1,65 @@ +From 728d921b36f07833470a284a55cbfea4baaab268 Mon Sep 17 00:00:00 2001 +From: mzzhou <1362843687@qq.com> +Date: Mon, 10 Jul 2023 21:28:10 +0800 +Subject: [PATCH] add secure compile marco + +--- + configure.ac | 20 ++++++++++++++++++++ + src/lxc/Makefile.am | 6 +++++- + 2 files changed, 25 insertions(+), 1 deletion(-) + +diff --git a/configure.ac b/configure.ac +index 2180586..e66bdf1 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -837,10 +837,30 @@ if test "x$adapt_isulad" = "xyes"; then + AC_DEFINE([HAVE_ISULAD], 1, [adapt to iSulad]) + AC_MSG_RESULT([yes]) + ++ AC_MSG_CHECKING([Whether enable secure compile]) ++ AC_ARG_ENABLE([secure-compile], ++ [AC_HELP_STRING([--enable-secure-compile], [enable secure compile [default=no]])], ++ [secure_compile=$enableval], [secure_compile=yes]) ++ AM_CONDITIONAL([HAVE_SECURE_COMPILE], [test "x$secure_compile" = "xyes"]) ++ AC_DEFINE([HAVE_SECURE_COMPILE], 1, [enable secure compile]) ++ AC_MSG_RESULT([yes]) ++ + # Check yajl + PKG_CHECK_MODULES([YAJL], [yajl >= 2],[],[AC_MSG_ERROR([You must install yajl >= 2])]) + else + AC_MSG_RESULT([no]) ++ ++ AC_MSG_CHECKING([Whether enable secure compile]) ++ AC_ARG_ENABLE([secure-compile], ++ [AC_HELP_STRING([--enable-secure-compile], [enable secure compile [default=no]])], ++ [secure_compile=$enableval], [secure_compile=yes]) ++ AM_CONDITIONAL([HAVE_SECURE_COMPILE], [test "x$secure_compile" = "xyes"]) ++ if test "x$secure_compile" = "xyes"; then ++ AC_DEFINE([HAVE_SECURE_COMPILE], 1, [enable secure compile]) ++ AC_MSG_RESULT([yes]) ++ else ++ AC_MSG_RESULT([no]) ++ fi + fi + + # Files requiring some variable expansion +diff --git a/src/lxc/Makefile.am b/src/lxc/Makefile.am +index 61a229f..c1d20f6 100644 +--- a/src/lxc/Makefile.am ++++ b/src/lxc/Makefile.am +@@ -292,7 +292,11 @@ liblxc_la_LDFLAGS = -pthread \ + -version-info @LXC_ABI_MAJOR@ + + if HAVE_ISULAD +-liblxc_la_LDFLAGS += @YAJL_LIBS@ -Wl,-z,relro \ ++liblxc_la_LDFLAGS += @YAJL_LIBS@ ++endif ++ ++if HAVE_SECURE_COMPILE ++liblxc_la_LDFLAGS += -Wl,-z,relro \ + -Wl,-z,now \ + -Wl,-z,noexecstack + endif +-- +2.41.0.windows.2 + diff --git a/0035-codecheck-fix.patch b/0035-codecheck-fix.patch new file mode 100644 index 0000000000000000000000000000000000000000..ac498e59f198cf7fd1a857e064ca7edd03ebcf4c --- /dev/null +++ b/0035-codecheck-fix.patch @@ -0,0 +1,650 @@ +From 103aff2c11b16a2b53b0339b0033a77b3348fec3 Mon Sep 17 00:00:00 2001 +From: zhangxiaoyu +Date: Wed, 6 Sep 2023 15:14:06 +0800 +Subject: [PATCH] codecheck fix + +Signed-off-by: zhangxiaoyu +--- + src/lxc/af_unix.c | 4 +-- + src/lxc/attach.c | 2 +- + src/lxc/commands.c | 27 +++++++++++++---- + src/lxc/conf.c | 46 +++++++++++++++++++++++++++-- + src/lxc/exec_commands.c | 2 +- + src/lxc/file_utils.c | 2 +- + src/lxc/isulad_utils.c | 23 ++++++++++----- + src/lxc/json/json_common.c | 4 +-- + src/lxc/path.c | 32 ++++++++++++++++++-- + src/lxc/start.c | 60 +++++++++++++++++++++++++++++++------- + src/lxc/terminal.c | 24 ++++++++++++--- + 11 files changed, 186 insertions(+), 40 deletions(-) + +diff --git a/src/lxc/af_unix.c b/src/lxc/af_unix.c +index 0be9368..d98a1f9 100644 +--- a/src/lxc/af_unix.c ++++ b/src/lxc/af_unix.c +@@ -170,10 +170,10 @@ int lxc_unix_send_fds(int fd, int *sendfds, int num_sendfds, void *data, + #ifdef HAVE_ISULAD + static int lxc_abstract_unix_recv_fds_iov(int fd, int *recvfds, int num_recvfds, + struct iovec *iov, size_t iovlen, unsigned int timeout) +-#else ++#else + static int lxc_abstract_unix_recv_fds_iov(int fd, int *recvfds, int num_recvfds, + struct iovec *iov, size_t iovlen) +-#endif ++#endif + { + __do_free char *cmsgbuf = NULL; + int ret; +diff --git a/src/lxc/attach.c b/src/lxc/attach.c +index 24d020d..0ac37cc 100644 +--- a/src/lxc/attach.c ++++ b/src/lxc/attach.c +@@ -735,7 +735,7 @@ static int attach_child_main(struct attach_clone_payload *payload) + ret = sigfillset(&mask); + if (ret < 0) { + SYSERROR("Failed to fill signal mask"); +- goto on_error;; ++ goto on_error; + } + ret = sigprocmask(SIG_UNBLOCK, &mask, NULL); + if (ret < 0) { +diff --git a/src/lxc/commands.c b/src/lxc/commands.c +index c2a5665..d6b9939 100644 +--- a/src/lxc/commands.c ++++ b/src/lxc/commands.c +@@ -1504,17 +1504,32 @@ int lxc_cmd_set_terminal_fifos(const char *name, const char *lxcpath, const char + const char *out_fifo, const char *err_fifo) + { + int ret = 0, stopped = 0; +- int len = 0; ++ size_t 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) ++ if (name == NULL) { + return -1; +- len += strlen(cmd_in_fifo) + strlen(split) + strlen(cmd_out_fifo) + strlen(split) + strlen(cmd_err_fifo) + 1; ++ } ++ ++ // format: cmd_in_fifo + split + cmd_out_fifo + split + cmd_err_fifo + '\0' ++ if (strlen(cmd_in_fifo) > SIZE_MAX - strlen(split) - strlen(split) - 1) { ++ return -1; ++ } ++ len += strlen(cmd_in_fifo) + strlen(split) + strlen(split) + 1; ++ ++ if (strlen(cmd_out_fifo) > SIZE_MAX - len) { ++ return -1; ++ } ++ len += strlen(cmd_out_fifo); ++ ++ if (strlen(cmd_err_fifo) > SIZE_MAX - len) { ++ return -1; ++ } ++ len += strlen(cmd_err_fifo); + tmp = malloc(len); + if (tmp == NULL) + return -1; +@@ -1556,7 +1571,7 @@ static int lxc_cmd_set_terminal_fifos_callback(int fd, struct lxc_cmd_req *req, + struct lxc_cmd_rsp rsp; + memset(&rsp, 0, sizeof(rsp)); + +- rsp.ret = lxc_terminal_add_fifos(handler->conf, req->data);; ++ rsp.ret = lxc_terminal_add_fifos(handler->conf, req->data); + + return lxc_cmd_rsp_send(fd, &rsp); + } +@@ -1602,7 +1617,7 @@ static int lxc_cmd_set_terminal_winch_callback(int fd, struct lxc_cmd_req *req, + 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);; ++ rsp.ret = lxc_set_terminal_winsz(&handler->conf->console, data->height, data->width); + + return lxc_cmd_rsp_send(fd, &rsp); + +diff --git a/src/lxc/conf.c b/src/lxc/conf.c +index a5573ac..3e31691 100644 +--- a/src/lxc/conf.c ++++ b/src/lxc/conf.c +@@ -4640,7 +4640,11 @@ static struct lxc_list *get_minimal_idmap(const struct lxc_conf *conf, + int userns_exec_1(const struct lxc_conf *conf, int (*fn)(void *), void *data, + const char *fn_name) + { ++#ifdef HAVE_ISULAD ++ struct lxc_list *idmap = NULL; ++#else + call_cleaner(lxc_free_idmap) struct lxc_list *idmap = NULL; ++#endif + int ret = -1, status = -1; + char c = '1'; + struct userns_fn_data d = { +@@ -4659,8 +4663,16 @@ int userns_exec_1(const struct lxc_conf *conf, int (*fn)(void *), void *data, + return ret_errno(ENOENT); + + ret = pipe2(pipe_fds, O_CLOEXEC); ++#ifdef HAVE_ISULAD ++ if (ret < 0) { ++ lxc_free_idmap(idmap); ++ free(idmap); ++ return -errno; ++ } ++#else + if (ret < 0) + return -errno; ++#endif + + d.p[0] = pipe_fds[0]; + d.p[1] = pipe_fds[1]; +@@ -4710,6 +4722,11 @@ on_error: + if (status < 0) + ret = -1; + ++#ifdef HAVE_ISULAD ++ lxc_free_idmap(idmap); ++ free(idmap); ++#endif ++ + return ret; + } + +@@ -4717,7 +4734,11 @@ int userns_exec_minimal(const struct lxc_conf *conf, + int (*fn_parent)(void *), void *fn_parent_data, + int (*fn_child)(void *), void *fn_child_data) + { ++#ifdef HAVE_ISULAD ++ struct lxc_list *idmap = NULL; ++#else + call_cleaner(lxc_free_idmap) struct lxc_list *idmap = NULL; ++#endif + uid_t resuid = LXC_INVALID_UID; + gid_t resgid = LXC_INVALID_GID; + char c = '1'; +@@ -4733,8 +4754,16 @@ int userns_exec_minimal(const struct lxc_conf *conf, + return ret_errno(ENOENT); + + ret = socketpair(PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0, sock_fds); ++#ifdef HAVE_ISULAD ++ if (ret < 0) { ++ lxc_free_idmap(idmap); ++ free(idmap); ++ return -errno; ++ } ++#else + if (ret < 0) + return -errno; ++#endif + + pid = fork(); + if (pid < 0) { +@@ -4830,6 +4859,11 @@ on_error: + close_prot_errno_disarm(sock_fds[0]); + close_prot_errno_disarm(sock_fds[1]); + ++#ifdef HAVE_ISULAD ++ lxc_free_idmap(idmap); ++ free(idmap); ++#endif ++ + /* Wait for child to finish. */ + if (pid < 0) + return -1; +@@ -5468,6 +5502,10 @@ int lxc_drop_caps(struct lxc_conf *conf) + struct lxc_list *caps = NULL; + int *caplist = NULL; + ++ if (conf == NULL) { ++ return -1; ++ } ++ + if (lxc_list_empty(&conf->keepcaps)) + return 0; + +@@ -5654,7 +5692,7 @@ static int mount_entry_with_loop_dev(const char *src, const char *dest, const ch + if (srcfd < 0) + return srcfd; + ret = snprintf(srcbuf, sizeof(srcbuf), "/proc/self/fd/%d", srcfd); +- if (ret < 0 || ret > sizeof(srcbuf)) { ++ if (ret < 0 || (size_t)ret >= sizeof(srcbuf)) { + close(srcfd); + ERROR("Failed to print string"); + return -EINVAL; +@@ -5673,7 +5711,7 @@ static int mount_entry_with_loop_dev(const char *src, const char *dest, const ch + } + + ret = snprintf(destbuf, sizeof(destbuf), "/proc/self/fd/%d", destfd); +- if (ret < 0 || ret > sizeof(destbuf)) { ++ if (ret < 0 || (size_t)ret >= sizeof(destbuf)) { + if (srcfd != -1) + close(srcfd); + close(destfd); +@@ -6245,6 +6283,7 @@ static char **merge_ocihook_env(char **oldenvs, size_t env_len, size_t *merge_en + size_t env_buf_len = 0; + tmpenv = getenv(lxc_envs[j]); + if (tmpenv && i < (result_len - 1)) { ++ int nret = 0; + if (strlen(tmpenv) > (SIZE_MAX - 1 - 1 - strlen(lxc_envs[j]))) { + lxc_free_array((void **)result, free); + return NULL; +@@ -6255,7 +6294,8 @@ static char **merge_ocihook_env(char **oldenvs, size_t env_len, size_t *merge_en + lxc_free_array((void **)result, free); + return NULL; + } +- if (snprintf(lxcenv_buf, env_buf_len, "%s=%s", lxc_envs[j], tmpenv) < 0) { ++ nret = snprintf(lxcenv_buf, env_buf_len, "%s=%s", lxc_envs[j], tmpenv); ++ if (nret < 0 || nret >= env_buf_len) { + free(lxcenv_buf); + continue; + } +diff --git a/src/lxc/exec_commands.c b/src/lxc/exec_commands.c +index 50246fa..52067e1 100644 +--- a/src/lxc/exec_commands.c ++++ b/src/lxc/exec_commands.c +@@ -228,7 +228,7 @@ static int lxc_exec_cmd_set_terminal_winch_callback(int fd, struct lxc_exec_cmd_ + struct lxc_exec_cmd_set_terminal_winch_request *data = (struct lxc_exec_cmd_set_terminal_winch_request *)(req->data); + memset(&rsp, 0, sizeof(rsp)); + +- rsp.ret = lxc_set_terminal_winsz(handler->terminal, data->height, data->width);; ++ rsp.ret = lxc_set_terminal_winsz(handler->terminal, data->height, data->width); + + return lxc_exec_cmd_rsp_send(fd, &rsp); + +diff --git a/src/lxc/file_utils.c b/src/lxc/file_utils.c +index 681207b..1c18769 100644 +--- a/src/lxc/file_utils.c ++++ b/src/lxc/file_utils.c +@@ -128,7 +128,7 @@ ssize_t lxc_write_nointr_for_fifo(int fd, const char *buf, size_t count) + ssize_t nret = 0; + ssize_t nwritten; + +- if (buf == NULL) { ++ if (fd < 0 || buf == NULL) { + return -1; + } + +diff --git a/src/lxc/isulad_utils.c b/src/lxc/isulad_utils.c +index ee39302..c71bb5b 100644 +--- a/src/lxc/isulad_utils.c ++++ b/src/lxc/isulad_utils.c +@@ -42,14 +42,14 @@ int lxc_mem_realloc(void **newptr, size_t newsize, void *oldptr, size_t oldsize) + { + void *tmp = NULL; + +- if (newsize == 0) { +- goto err_out; ++ if (newptr == NULL || newsize == 0) { ++ return -1; + } + + tmp = lxc_common_calloc_s(newsize); + if (tmp == NULL) { + ERROR("Failed to malloc memory"); +- goto err_out; ++ return -1; + } + + if (oldptr != NULL) { +@@ -62,9 +62,6 @@ int lxc_mem_realloc(void **newptr, size_t newsize, void *oldptr, size_t oldsize) + + *newptr = tmp; + return 0; +- +-err_out: +- return -1; + } + + char *safe_strdup(const char *src) +@@ -87,6 +84,10 @@ int lxc_open(const char *filename, int flags, mode_t mode) + { + char rpath[PATH_MAX] = {0x00}; + ++ if (filename == NULL) { ++ return -1; ++ } ++ + if (cleanpath(filename, rpath, sizeof(rpath)) == NULL) { + return -1; + } +@@ -101,6 +102,10 @@ FILE *lxc_fopen(const char *filename, const char *mode) + { + char rpath[PATH_MAX] = {0x00}; + ++ if (filename == NULL || mode == NULL || strlen(mode) == 0) { ++ return NULL; ++ } ++ + if (cleanpath(filename, rpath, sizeof(rpath)) == NULL) { + return NULL; + } +@@ -137,6 +142,10 @@ int lxc_file2str(const char *filename, char ret[], int cap) + { + int fd, num_read; + ++ if (filename == NULL || ret == NULL || cap == 0) { ++ return -1; ++ } ++ + if ((fd = lxc_open(filename, O_RDONLY | O_CLOEXEC, 0)) == -1) + return -1; + if ((num_read = read(fd, ret, cap - 1)) <= 0) +@@ -455,7 +464,7 @@ static int parse_line_pw(const char delim, char *line, struct passwd *result) + return 0; + } + +-char *util_left_trim_space(char *str) ++static char *util_left_trim_space(char *str) + { + char *begin = str; + char *tmp = str; +diff --git a/src/lxc/json/json_common.c b/src/lxc/json/json_common.c +index ec20c59..dd4dfcd 100755 +--- a/src/lxc/json/json_common.c ++++ b/src/lxc/json/json_common.c +@@ -682,7 +682,7 @@ yajl_gen_status gen_json_map_int_string(void *ctx, json_map_int_string *map, str + if (yajl_gen_status_ok != stat) { + GEN_SET_ERROR_AND_RETURN(stat, err); + } +- stat = reformat_string(g, map->values[i], strlen(map->values[i]));; ++ stat = reformat_string(g, map->values[i], strlen(map->values[i])); + if (yajl_gen_status_ok != stat) { + GEN_SET_ERROR_AND_RETURN(stat, err); + } +@@ -1048,7 +1048,7 @@ yajl_gen_status gen_json_map_string_string(void *ctx, json_map_string_string *ma + if (yajl_gen_status_ok != stat) { + GEN_SET_ERROR_AND_RETURN(stat, err); + } +- stat = reformat_string(g, map->values[i], strlen(map->values[i]));; ++ stat = reformat_string(g, map->values[i], strlen(map->values[i])); + if (yajl_gen_status_ok != stat) { + GEN_SET_ERROR_AND_RETURN(stat, err); + } +diff --git a/src/lxc/path.c b/src/lxc/path.c +index c0529b7..25dd68d 100644 +--- a/src/lxc/path.c ++++ b/src/lxc/path.c +@@ -30,6 +30,10 @@ bool specify_current_dir(const char *path) + char *basec = NULL, *bname = NULL; + bool res = false; + ++ if (path == NULL) { ++ return false; ++ } ++ + basec = safe_strdup(path); + + bname = basename(basec); +@@ -59,6 +63,10 @@ char *preserve_trailing_dot_or_separator(const char *cleanedpath, + char *respath = NULL; + size_t len; + ++ if (cleanedpath == NULL || originalpath == NULL) { ++ return NULL; ++ } ++ + if (strlen(cleanedpath) > (SIZE_MAX - 3)) { + return NULL; + } +@@ -96,6 +104,10 @@ bool filepath_split(const char *path, char **dir, char **base) + ssize_t i; + size_t len; + ++ if (path == NULL || dir == NULL || base == NULL) { ++ return false; ++ } ++ + len = strlen(path); + if (len >= PATH_MAX) { + ERROR("Invalid path"); +@@ -138,7 +150,7 @@ static bool do_clean_path_continue(const char *endpos, const char *stpos, const + return false; + } + +-int do_clean_path(const char *respath, const char *limit_respath, ++static int do_clean_path(const char *respath, const char *limit_respath, + const char *stpos, char **dst) + { + char *dest = *dst; +@@ -515,6 +527,11 @@ char *follow_symlink_in_scope(const char *fullpath, const char *rootpath) + char resfull[PATH_MAX] = {0}, *full = NULL; + char resroot[PATH_MAX] = {0}, *root = NULL; + ++ if (fullpath == NULL || rootpath == NULL) { ++ ERROR("Invalid arguments"); ++ return NULL; ++ } ++ + full = cleanpath(fullpath, resfull, PATH_MAX); + if (!full) { + ERROR("Failed to get cleaned path"); +@@ -544,6 +561,7 @@ int get_resource_path(const char *rootpath, const char *path, + char resolved[PATH_MAX] = {0}, *cleanedpath = NULL; + char *fullpath = NULL; + size_t len; ++ int nret = 0; + + if (!rootpath || !path || !scopepath) + return -1; +@@ -562,7 +580,12 @@ int get_resource_path(const char *rootpath, const char *path, + ERROR("Out of memory"); + return -1; + } +- snprintf(fullpath, len, "%s%s", rootpath, cleanedpath); ++ nret = snprintf(fullpath, len, "%s%s", rootpath, cleanedpath); ++ if (nret < 0 || nret >= len) { ++ ERROR("Failed to snprintf"); ++ free(fullpath); ++ return -1; ++ } + + *scopepath = follow_symlink_in_scope(fullpath, rootpath); + +@@ -584,6 +607,11 @@ char *path_relative(const char *basepath, const char *targpath) + char restarg[PATH_MAX] = {0}, *targ = NULL; + size_t bl = 0, tl = 0, b0 = 0, bi = 0, t0 = 0, ti = 0; + ++ if (basepath == NULL || targpath == NULL) { ++ ERROR("Invalid arguments"); ++ return NULL; ++ } ++ + base = cleanpath(basepath, resbase, PATH_MAX); + if (!base) { + ERROR("Failed to get cleaned path"); +diff --git a/src/lxc/start.c b/src/lxc/start.c +index 6fe1203..5de444d 100644 +--- a/src/lxc/start.c ++++ b/src/lxc/start.c +@@ -906,7 +906,7 @@ struct start_timeout_conf { + int errfd; + }; + +-void trim_line(char *s) ++static void trim_line(char *s) + { + size_t len; + +@@ -1005,7 +1005,7 @@ static int _recursive_read_cgroup_procs(const char *dirpath, pid_t **pids, size_ + return failed ? -1 : 0; + } + +-int get_all_pids(struct cgroup_ops *cg_ops, pid_t **pids, size_t *len) ++static int get_all_pids(struct cgroup_ops *cg_ops, pid_t **pids, size_t *len) + { + const char *devices_path = NULL; + +@@ -2875,6 +2875,7 @@ static int clean_resource_set_env(struct lxc_handler *handler) + } + + for (; i < conf->ocihooks->poststop_len; i++) { ++ int nret = 0; + size_t cap = conf->ocihooks->poststop[i]->env_len; + size_t newcap = cap + len + 1; + if (lxc_grow_array((void ***)&(conf->ocihooks->poststop[i]->env), &cap, newcap, 1) != 0) { +@@ -2883,38 +2884,70 @@ static int clean_resource_set_env(struct lxc_handler *handler) + j = conf->ocihooks->poststop[i]->env_len; + /* Start of environment variable setup for hooks. */ + if (name) { +- snprintf(bufstr, PATH_MAX + 1, "LXC_NAME=%s", name); ++ nret = snprintf(bufstr, PATH_MAX + 1, "LXC_NAME=%s", name); ++ if (nret < 0 || nret > PATH_MAX) { ++ return -1; ++ } + conf->ocihooks->poststop[i]->env[j++] = safe_strdup(bufstr); ++ conf->ocihooks->poststop[i]->env_len++; + } + if (conf->rcfile) { +- snprintf(bufstr, PATH_MAX + 1, "LXC_CONFIG_FILE=%s", conf->rcfile); ++ nret = snprintf(bufstr, PATH_MAX + 1, "LXC_CONFIG_FILE=%s", conf->rcfile); ++ if (nret < 0 || nret > PATH_MAX) { ++ return -1; ++ } + conf->ocihooks->poststop[i]->env[j++] = safe_strdup(bufstr); ++ conf->ocihooks->poststop[i]->env_len++; + } + if (conf->rootfs.mount) { +- snprintf(bufstr, PATH_MAX + 1, "LXC_ROOTFS_MOUNT=%s", conf->rootfs.mount); ++ nret = snprintf(bufstr, PATH_MAX + 1, "LXC_ROOTFS_MOUNT=%s", conf->rootfs.mount); ++ if (nret < 0 || nret > PATH_MAX) { ++ return -1; ++ } + conf->ocihooks->poststop[i]->env[j++] = safe_strdup(bufstr); ++ conf->ocihooks->poststop[i]->env_len++; + } + if (conf->rootfs.path) { +- snprintf(bufstr, PATH_MAX + 1, "LXC_ROOTFS_PATH=%s", conf->rootfs.path); ++ nret = snprintf(bufstr, PATH_MAX + 1, "LXC_ROOTFS_PATH=%s", conf->rootfs.path); ++ if (nret < 0 || nret > PATH_MAX) { ++ return -1; ++ } + conf->ocihooks->poststop[i]->env[j++] = safe_strdup(bufstr); ++ conf->ocihooks->poststop[i]->env_len++; + } + if (conf->console.path) { +- snprintf(bufstr, PATH_MAX + 1, "LXC_CONSOLE=%s", conf->console.path); ++ nret = snprintf(bufstr, PATH_MAX + 1, "LXC_CONSOLE=%s", conf->console.path); ++ if (nret < 0 || nret > PATH_MAX) { ++ return -1; ++ } + conf->ocihooks->poststop[i]->env[j++] = safe_strdup(bufstr); ++ conf->ocihooks->poststop[i]->env_len++; + } + if (conf->console.log_path) { +- snprintf(bufstr, PATH_MAX + 1, "LXC_CONSOLE_LOGPATH=%s", conf->console.log_path); ++ nret = snprintf(bufstr, PATH_MAX + 1, "LXC_CONSOLE_LOGPATH=%s", conf->console.log_path); ++ if (nret < 0 || nret > PATH_MAX) { ++ return -1; ++ } + conf->ocihooks->poststop[i]->env[j++] = safe_strdup(bufstr); ++ conf->ocihooks->poststop[i]->env_len++; + } + conf->ocihooks->poststop[i]->env[j++] = safe_strdup("LXC_CGNS_AWARE=1"); ++ conf->ocihooks->poststop[i]->env_len++; + +- snprintf(bufstr, PATH_MAX + 1, "LXC_PID=%d", handler->pid); ++ nret = snprintf(bufstr, PATH_MAX + 1, "LXC_PID=%d", handler->pid); ++ if (nret < 0 || nret > PATH_MAX) { ++ return -1; ++ } + conf->ocihooks->poststop[i]->env[j++] = safe_strdup(bufstr); ++ conf->ocihooks->poststop[i]->env_len++; + if (handler->cgroup_ops->container_cgroup) { +- snprintf(bufstr, PATH_MAX + 1, "LXC_CGROUP_PATH=%s", handler->cgroup_ops->container_cgroup); ++ nret = snprintf(bufstr, PATH_MAX + 1, "LXC_CGROUP_PATH=%s", handler->cgroup_ops->container_cgroup); ++ if (nret < 0 || nret > PATH_MAX) { ++ return -1; ++ } + conf->ocihooks->poststop[i]->env[j++] = safe_strdup(bufstr); ++ conf->ocihooks->poststop[i]->env_len++; + } +- conf->ocihooks->poststop[i]->env_len = j; + /* End of environment variable setup for hooks. */ + } + return 0; +@@ -3075,6 +3108,11 @@ int do_lxcapi_get_pids(char *name, char *lxcpath, struct lxc_conf *conf, pid_t * + struct lxc_handler *handler = NULL; + struct cgroup_ops *cg_ops = NULL; + ++ if (conf == NULL || pids == NULL || pids_len == NULL) { ++ ERROR("Invalid arguments"); ++ return -1; ++ } ++ + handler = lxc_init_pids_handler(name, lxcpath, conf); + if (!handler) { + ERROR("Failed to init container %s clean handler", name); +diff --git a/src/lxc/terminal.c b/src/lxc/terminal.c +index 0539eca..88d4d94 100644 +--- a/src/lxc/terminal.c ++++ b/src/lxc/terminal.c +@@ -194,6 +194,11 @@ int lxc_set_terminal_winsz(struct lxc_terminal *terminal, unsigned int height, u + int ret = 0; + struct winsize wsz; + ++ if (terminal == NULL) { ++ ERROR("Invalid arguments"); ++ return -1; ++ } ++ + if (terminal->ptmx < 0) { + return 0; + } +@@ -225,6 +230,10 @@ static int lxc_terminal_rename_old_log_file(struct lxc_terminal *terminal) + char tmp[PATH_MAX] = {0}; + char *rename_fname = NULL; + ++ if (terminal->log_rotate == 0) { ++ return 0; ++ } ++ + 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) { +@@ -413,10 +422,12 @@ static bool get_time_buffer(struct timespec *timestamp, char *timebuffer, + + seconds = (time_t)timestamp->tv_sec; + gmtime_r(&seconds, &tm_utc); +- strftime(timebuffer, maxsize, "%Y-%m-%dT%H:%M:%S", &tm_utc); ++ len = strftime(timebuffer, maxsize, "%Y-%m-%dT%H:%M:%S", &tm_utc); ++ if (len == 0) { ++ return false; ++ } + + nanos = (int32_t)timestamp->tv_nsec; +- len = strlen(timebuffer); + ret = snprintf(timebuffer + len, (maxsize - len), ".%09dZ", nanos); + if (ret < 0 || ret >= (maxsize - len)) { + return false; +@@ -1548,7 +1559,7 @@ static int terminal_fifo_open(const char *fifo_path, int flags) + return fd; + } + +-bool fifo_exists(const char *path) ++static bool fifo_exists(const char *path) + { + struct stat sb; + int ret; +@@ -1715,11 +1726,16 @@ err: + int lxc_terminal_add_fifos(struct lxc_conf *conf, const char *fifonames) + { + int ret = 0; +- struct lxc_terminal *terminal = &conf->console; ++ struct lxc_terminal *terminal = NULL; + int fifofd_in = -1; + char *tmp = NULL, *saveptr = NULL, *in = NULL, *out = NULL, *err = NULL; + const char *none_fifo_name = "none"; + ++ if (conf == NULL || fifonames == NULL) { ++ return -1; ++ } ++ ++ terminal = &conf->console; + tmp = safe_strdup(fifonames); + + in = strtok_r(tmp, "&&&&", &saveptr); +-- +2.25.1 + diff --git a/apply-patches b/apply-patches index bf6f8d430250df681060dd79553840f24c10d1c9..136ca222f7342c0bd70378f07514f68b0261a7f1 100755 --- a/apply-patches +++ b/apply-patches @@ -27,12 +27,6 @@ tar -xzvf $dir_name.tar.gz cwd=$PWD cd $cwd/$dir_name -git init . -git add . -git config --local user.name "isuladci" -git config --local user.email "isulad@ci.com" -git commit -m "init repo for lxc-$dir_name" - grep -E "Patch[0-9]{4}:\s*[0-9]{4}-.*\.patch" $cwd/lxc.spec | awk '{print $2}' | while read line do if [[ $line == '' || $line =~ ^\s*# ]]; then @@ -42,9 +36,11 @@ do patch -p1 -F1 -s < $cwd/$line done +git init . git add . -git commit -m "change for iSulad" - +git config --local user.name "isuladci" +git config --local user.email "isulad@ci.com" +git commit -m "init repo" git config --local --unset user.name git config --local --unset user.email diff --git a/lxc-4.0.3.tar.gz b/lxc-4.0.3.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..88376b2b8687616c874225ca8c983b2a78993ba0 Binary files /dev/null and b/lxc-4.0.3.tar.gz differ diff --git a/lxc-5.0.2.tar.gz b/lxc-5.0.2.tar.gz deleted file mode 100644 index 846afc3f95d128cb5ea4d57b1d2b34b8e10f5640..0000000000000000000000000000000000000000 Binary files a/lxc-5.0.2.tar.gz and /dev/null differ diff --git a/lxc.spec b/lxc.spec index a1284b2ab2755180162cc82c66f68282090c6ce7..92f98da0f331715c2c6538769ec197e566f0e0d9 100644 --- a/lxc.spec +++ b/lxc.spec @@ -1,29 +1,58 @@ -%global _release 3 -%global enable_isulad 0 +%global _release 2022102422 Name: lxc -Version: 5.0.2 +Version: 4.0.3 Release: %{_release} Summary: Linux Containers userspace tools License: LGPLv2+ and GPLv2 and GPLv3 URL: https://github.com/lxc/lxc -Source0: https://linuxcontainers.org/downloads/lxc/lxc-5.0.2.tar.gz - -Patch0001: 0001-iSulad-add-json-files-and-adapt-to-meson.patch -Patch0002: 0002-iSulad-adapt-security-conf-attach-cgroup-and-start.patch -Patch0003: 0003-iSulad-adapt-conf-network-storage-and-termianl.patch -Patch0004: 0004-iSulad-adapt-confile-lxccontainer-and-start.patch -Patch0005: 0005-fix-compile-error.patch +Source0: https://linuxcontainers.org/downloads/lxc/lxc-4.0.3.tar.gz + +Patch0001: 0001-refactor-patch-code-of-utils-commands-and-so-on.patch +Patch0002: 0002-refactor-patch-code-of-isulad-for-conf-exec-attach.patch +Patch0003: 0003-refactor-patch-code-of-isulad-for-selinux-attach.patch +Patch0004: 0004-refactor-patch-code-of-lxccontianer-and-so-on.patch +Patch0005: 0005-refactor-patch-code-of-attach-and-seccomp.patch +Patch0006: 0006-refactor-patch-about-namespace-log-terminal.patch +Patch0007: 0007-refactor-patches-on-terminal.c-start.c-and-so-on.patch +Patch0008: 0008-refactor-patch-code-of-json.patch +Patch0009: 0009-fix-HOME-env-of-container-unset-error.patch +Patch0010: 0010-check-yajl-only-when-have-isulad.patch +Patch0011: 0011-drop-security_context_t.patch +Patch0012: 0012-only-set-user-or-image-set-non-empty-HOME.patch +Patch0013: 0013-return-fail-if-no-args-or-no-rootfs-path-found.patch +Patch0014: 0014-fix-tools-using-option-give-error-message.patch +Patch0015: 0015-fix-do-mask-pathes-after-parent-mounted.patch +Patch0016: 0016-skip-kill-cgroup-processes-if-no-hierarchies.patch +Patch0017: 0017-lxc-Add-sw64-architecture.patch +Patch0018: 0018-add-macro-to-adapt-musl-libc.patch +Patch0019: 0019-add-lxc-attach-add-gids-option.patch +Patch0020: 0020-add-sscanf-adapation-code-for-musl.patch +Patch0021: 0021-change-the-suffi-parameter-in-lxc-attach-help-output.patch +Patch0022: 0022-fix-cve-CVE-2022-47952-log-leaks-root-information.patch +Patch0023: 0023-fix-lxc-write-error-message.patch +Patch0024: 0024-remove-process-inheritable-capability.patch +Patch0025: 0025-fix-ops-hierarchies-cause-coredump.patch +Patch0026: 0026-meminfo-cri-1.25.patch +Patch0027: 0027-add-loongarch64-support-for-lxc.patch +Patch0028: 0028-use-ocihooks-env-after-getenv.patch +Patch0029: 0029-fix-mixed-use-of-signed-and-unsigned-type.patch +Patch0030: 0030-remove-unused-meminfo-stats.patch +Patch0031: 0031-lxc-attach-Fix-lost-return-codes-of-spawned-processe.patch +Patch0032: 0032-fix-load-bpf-failed.patch +Patch0033: 0033-fix-mount-device-path-incorrect.patch +Patch0034: 0034-add-secure-compile-macro.patch +Patch0035: 0035-codecheck-fix.patch BuildRequires: systemd-units git libtool graphviz docbook2X doxygen chrpath BuildRequires: pkgconfig(libseccomp) BuildRequires: libcap libcap-devel libselinux-devel yajl yajl-devel -BuildRequires: pkgconfig(bash-completion) meson +BuildRequires: pkgconfig(bash-completion) %ifarch riscv64 BuildRequires: libatomic_ops %endif -Requires: lxc-libs = 5.0.2-%{release} +Requires: lxc-libs = 4.0.3-%{release} %package libs Summary: Runtime library files for %{name} @@ -41,7 +70,7 @@ overhead of full virtualization. The %{name}-libs package contains libraries for running %{name} applications. -%{!?_pkgdocdir: %global _pkgdocdir %{_docdir}/lxc-5.0.2} +%{!?_pkgdocdir: %global _pkgdocdir %{_docdir}/lxc-4.0.3} %description Containers are insulated areas inside a system, which have their own namespace @@ -55,7 +84,7 @@ boot an entire "containerized" system, and to manage and debug your containers. %package devel Summary: Development files for lxc -Requires: lxc = 5.0.2-%{release} +Requires: lxc = 4.0.3-%{release} Requires: pkgconfig %description devel @@ -71,18 +100,19 @@ BuildArch: noarch This package contains documentation for lxc for creating containers. %prep -%autosetup -n lxc-5.0.2 -Sgit -p1 +%autosetup -n lxc-4.0.3 -Sgit -p1 %build %ifarch riscv64 export LDFLAGS="%{build_ldflags} -latomic -pthread" %endif -%if 0%{?enable_isulad} -meson setup -Disulad=true -Dtests=true -Dprefix=/usr build -%else -meson setup -Disulad=false -Dtests=true -Dprefix=/usr build -%endif -meson compile -C build +%configure --enable-doc --enable-api-docs \ + --disable-silent-rules --docdir=%{_pkgdocdir} --disable-rpath \ + --disable-static --disable-apparmor --enable-selinux \ + --enable-seccomp \ + --with-init-script=systemd --disable-werror + +%{make_build} %install %{make_install} @@ -113,9 +143,11 @@ chrpath -d %{buildroot}/usr/lib64/liblxc.so chmod +x %{buildroot}/usr/lib64/liblxc.so %endif # docs +mkdir -p %{buildroot}%{_pkgdocdir}/api %ifarch sw_64 %else -cp -a AUTHORS %{buildroot}%{_pkgdocdir} +cp -a AUTHORS README %{buildroot}%{_pkgdocdir} +cp -a doc/api/html/* %{buildroot}%{_pkgdocdir}/api/ %endif # cache dir @@ -132,7 +164,7 @@ rm -rf %{buildroot}%{_libdir}/liblxc.la rm -rf %{buildroot}%{_sbindir}/init.%{name}.static rm -rf %{buildroot}%{_sysconfdir}/default/%{name} %check -meson test -C build +%make_build check %post @@ -146,8 +178,7 @@ meson test -C build %{_datadir}/%{name}/%{name}.functions %dir %{_datadir}/bash-completion %dir %{_datadir}/bash-completion/completions -%{_datadir}/bash-completion/completions/* - +%{_datadir}/bash-completion/completions/lxc %files libs %defattr(-,root,root) %{_libdir}/liblxc.so @@ -157,6 +188,7 @@ meson test -C build %{_sbindir}/init.%{name} %{_sharedstatedir}/%{name} %dir %{_sysconfdir}/%{name} +%config(noreplace) %{_sysconfdir}/%{name}/default.conf %config(noreplace) %{_sysconfdir}/lxc/* %config(noreplace) %{_sysconfdir}/sysconfig/* @@ -165,15 +197,14 @@ meson test -C build %{_unitdir}/%{name}.service %{_unitdir}/%{name}@.service %{_unitdir}/%{name}-net.service -%{_unitdir}/%{name}-monitord.service %dir %{_localstatedir}/cache/%{name} %files devel %defattr(-,root,root) -%{_libdir}/liblxc.a %{_includedir}/%{name}/* %{_libdir}/pkgconfig/%{name}.pc %dir %{_datadir}/%{name} +%{_datadir}/%{name}/hooks %{_datadir}/%{name}/lxc-patch.py* %{_datadir}/%{name}/selinux %dir %{_datadir}/%{name}/templates @@ -182,9 +213,6 @@ meson test -C build %{_datadir}/%{name}/config/* %dir %{_datadir}/%{name}/__pycache__ %{_datadir}/%{name}/__pycache__/* -%if !0%{?enable_isulad} -%{_datadir}/%{name}/hooks -%endif %files help @@ -201,20 +229,509 @@ meson test -C build %endif %changelog -* Fri Aug 04 2023 zhangxiaoyu - 5.0.2-3 +* Mon Sep 11 2023 zhangxiaoyu - 4.0.3-2022102422 +- Type:bugfix +- ID:NA +- SUG:NA +- DESC: rollback to 4.0.3 + +* Mon Jul 10 2023 mzzhou<1362843687@qq.com> - 4.0.3-2022102421 +- Type:enhancement +- ID:NA +- SUG:NA +- DESC: add secure compile macro + +* Fri Jun 16 2023 zhangxiaoyu - 4.0.3-2022102420 +- Type:bugfix +- ID:NA +- SUG:NA +- DESC: fix mount device path incorrect + +* Sat May 06 2023 zhangxiaoyu - 4.0.3-2022102419 +- Type:bugfix +- ID:NA +- SUG:NA +- DESC: fix load bpf failed + +* Thu May 04 2023 Jian Zhang - 4.0.3-2022102418 +- Type:bugfix +- ID:NA +- SUG:NA +- DESC: fix lost return codes of spawned processe + +* Fri Apr 21 2023 zhangxiaoyu - 4.0.3-2022102417 +- Type:bugfix +- ID:NA +- SUG:NA +- DESC: remove unused meminfo stats + +* Mon Apr 17 2023 wangrunze - 4.0.3-2022102416 +- Type:bugfix +- ID:NA +- SUG:NA +- DESC: fix mixed use of signed and unsigned type + +* Thu Mar 30 2023 zhangxiaoyu - 4.0.3-2022102415 +- Type:bugfix +- ID:NA +- SUG:NA +- DESC: use ocihooks env after getenv + +* Sat Mar 04 2023 Wenlong Zhang - 4.0.3-2022102414 +- Type:enhancement +- ID:NA +- SUG:NA +- DESC: add loongarch64 support for lxc + +* Mon Feb 27 2023 Ilya.kuksenok - 4.0.3-2022102413 +- Type:enhancement +- ID:NA +- SUG:NA +- DESC: Add meminfo required for CRI-1.25 + +* Wed Feb 22 2023 wangrunze - 4.0.3-2022102412 +- Type:bugfix +- ID:NA +- SUG:NA +- DESC: fix ops hierarchies cause coredump + +* Wed Feb 22 2023 misaka00251 - 4.0.3-2022102411 +- Type:enhancement +- ID:NA +- SUG:NA +- DESC: fix RISC-V build errors + +* Fri Feb 17 2023 zhangxiaoyu - 4.0.3-2022102410 +- Type:bugfix +- ID:NA +- SUG:NA +- DESC: remove process inheritable capabilities + +* Mon Feb 13 2023 jiangxinyu - 4.0.3-2022102409 +- Type:enhancement +- ID:NA +- SUG:NA +- DESC:optimize test command + +* Wed Feb 08 2023 huangsong - 4.0.3-2022102408 +- Type:bugfix +- ID:NA +- SUG:NA +- DESC: fix lxc write error message + +* Fri Jan 13 2023 wangrunze - 4.0.3-2022102407 +- Type:bugfix +- ID:NA +- SUG:NA +- DESC: fix cve CVE-2022-47952 log leaks root information + +* Fri Dec 16 2022 huangsong - 4.0.3-2022102406 +- Type:bugfix +- ID:NA +- SUG:NA +- DESC: change the suffi parameter in lxc attach --help output + +* Thu Dec 08 2022 zhongtao - 4.0.3-2022102405 +- Type:bugfix +- ID:NA +- SUG:NA +- DESC: add sscanf adapation code for musl + +* Fri Dec 02 2022 zhangxiaoyu - 4.0.3-2022102404 +- Type:bugfix +- ID:NA +- SUG:NA +- DESC: add lxc-attach add-gids option + +* Thu Nov 24 2022 zhangxiaoyu - 4.0.3-2022102403 +- Type:bugfix +- ID:NA +- SUG:NA +- DESC: add macro to adapt musl libc + +* Wed Nov 9 2022 hejunjie - 4.0.3-2022102402 +- Type:bugfix +- ID:NA +- SUG:NA +- DESC: remove duplicated README and AUTHORS cross lxc-lib and lxc-help + +* Mon Oct 24 2022 wuzx - 4.0.3-2022102401 +- Type:feature +- CVE:NA +- SUG:NA +- DESC:Add sw64 architecture + +* Mon Oct 17 2022 zhangxiaoyu - 4.0.3-2022101701 +- Type:bugfix +- ID:NA +- SUG:NA +- DESC: update version to 4.0.3-2022101701 + +* Thu Sep 22 2022 zhangxiaoyu - 4.0.3-2022092201 +- Type:bugfix +- ID:NA +- SUG:NA +- DESC: skip kill cgroup processes if no hierarchies + +* Tue Sep 20 2022 Neil.wrz - 4.0.3-2022092001 +- Type:bugfix +- ID:NA +- SUG:NA +- DESC: do mask pathes after parent mounted + +* Fri Sep 2 2022 Neil.wrz - 4.0.3-2022090201 +- Type:bugfix +- ID:NA +- SUG:NA +- DESC: fix tools using -? option give error + +* Thu Sep 1 2022 zhongtao - 4.0.3-2022090101 +- Type:bugfix +- ID:NA +- SUG:NA +- DESC: add git config in apply-patches + +* Sat Aug 20 2022 wangfengtu - 4.0.3-2022082001 +- Type:bugfix +- ID:NA +- SUG:NA +- DESC: do not check rootfs.path, it may be null if rootfs is "/" + +* Fri Aug 19 2022 wangfengtu - 4.0.3-2022081901 +- Type:bugfix +- ID:NA +- SUG:NA +- DESC: return fail if no args or no rootfs path found + +* Tue Aug 9 2022 haozi007 - 4.0.3-2022080901 +- Type:bugfix +- ID:NA +- SUG:NA +- DESC: only set user or image set non empty HOME + +* Tue Jul 26 2022 zhangxiaoyu - 4.0.3-2022072601 +- Type:bugfix +- ID:NA +- SUG:NA +- DESC: drop security_context_t + +* Mon Jul 25 2022 zhangxiaoyu - 4.0.3-2022072502 +- Type:bugfix +- ID:NA +- SUG:NA +- DESC: check yajl only when have isulad + +* Mon Jul 25 2022 haozi007 - 4.0.3-2022072501 +- Type:bugfix +- ID:NA +- SUG:NA +- DESC: fix HOME env unset error + +* Thu Jul 21 2022 zhangxiaoyu - 4.0.3-2022072104 +- Type:bugfix +- ID:NA +- SUG:NA +- DESC: add header to fix compile error with have isulad + +* Thu Jul 21 2022 zhangxiaoyu - 4.0.3-2022072103 +- Type:bugfix +- ID:NA +- SUG:NA +- DESC: fix compile error + +* Thu Jul 21 2022 chengzeruizhi - 4.0.3-2022072102 +- Type:bugfix +- ID:NA +- SUG:NA +- DESC: refactor patch code of json + +* Thu Jul 21 2022 chengzeruizhi - 4.0.3-2022072101 +- Type:bugfix +- ID:NA +- SUG:NA +- DESC: refactor patches on terminal.c, start.c and others + +* Tue Jul 19 2022 wangrunze - 4.0.3-2022071904 +- Type:bugfix +- ID:NA +- SUG:NA +- DESC: refactor namespace terminal log + +* Tue Jul 19 2022 zhangxiaoyu - 4.0.3-2022071903 +- Type:bugfix +- ID:NA +- SUG:NA +- DESC: refactor patch code of attach and seccomp + +* Tue Jul 19 2022 wangfengtu - 4.0.3-2022071902 +- Type:bugfix +- ID:NA +- SUG:NA +- DESC: refactor patch code of lxccontainer and so on + +* Tue Jul 19 2022 haozi007 - 4.0.3-2022071901 +- Type:bugfix +- ID:NA +- SUG:NA +- DESC: refactor patch code of isulad for selinux/attach + +* Mon Jul 18 2022 haozi007 - 4.0.3-2022071801 +- Type:bugfix +- ID:NA +- SUG:NA +- DESC: refactor patch code of isulad for conf/exec/attach and so on + +* Fri Jul 15 2022 zhangxiaoyu - 4.0.3-2022071501 +- Type:bugfix +- ID:NA +- SUG:NA +- DESC: refactor patch code of utils commands and so on + +* Wed May 25 2022 hejunjie - 4.0.3-2022052501 +- Type:bugfix +- ID:NA +- SUG:NA +- DESC: correct license info + +* Mon May 23 2022 wangfengtu - 4.0.3-2022052301 +- Type:bugfix +- ID:NA +- SUG:NA +- DESC: do not operate playload and attach cgroup if no controller found + +* Sat May 21 2022 wangfengtu - 4.0.3-2022052101 +- Type:bugfix +- ID:NA +- SUG:NA +- DESC: add x permission when create directory + +* Fri Apr 15 2022 wujing - 4.0.3-2022041501 +- Type:refactor +- ID:NA +- SUG:NA +- DESC: refactor the way to convert selinux label to shared mode + +* Sat Apr 09 2022 wujing - 4.0.3-2022040901 +- Type:bugfix +- ID:NA +- SUG:NA +- DESC: fix bug of memory free + +* Thu Mar 17 2022 haozi007 - 4.0.3-2022031701 +- Type:improve +- ID:NA +- SUG:NA +- DESC: fix unnecessary print error message + +* Mon Feb 21 2022 chegJH - 4.0.3-2022022101 +- Type:improve +- ID:NA +- SUG:NA +- DESC: fix alwasy print and len + +* Tue Feb 15 2022 chegJH - 4.0.3-2022021501 +- Type:improve +- ID:NA +- SUG:NA +- DESC:changes for compile in android env + +* Mon Dec 27 2021 haozi007 - 4.0.3-2021122701 +- Type:improve +- ID:NA +- SUG:NA +- DESC:adapt upstream compiler settings + +* Thu Nov 25 2021 wangfengtu - 4.0.3-2021112501 +- Type:bugfix +- ID:NA +- SUG:NA +- DESC:fix cgroup attach cgroup creation + +* Fri Nov 19 2021 wangfengtu - 4.0.3-2021111901 +- Type:bugfix +- ID:NA +- SUG:NA +- DESC:ensure that the idmap pointer itself is freed + +* Thu Oct 21 2021 gaohuatao - 4.0.3-2021102101 +- Type:bugfix +- ID:NA +- SUG:NA +- DESC:disable lxc_keep + +* Sun Sep 26 2021 chengzeruizhi - 4.0.3-2021092601 +- Type:bugfix +- ID:NA +- SUG:NA +- DESC:add dependencies under require field + +* Fri Sep 17 2021 zhangxiaoyu - 4.0.3-2021091703 +- Type:bugfix +- ID:NA +- SUG:NA +- DESC:fix conf memory leak + +* Fri Sep 17 2021 haozi007 - 4.0.3-2021091702 +- Type:bugfix +- ID:NA +- SUG:NA +- DESC:just use origin loop if do not have io + +* Fri Sep 17 2021 zhangxiaoyu - 4.0.3-2021091701 +- Type:bugfix +- ID:NA +- SUG:NA +- DESC:seccomp init and destroy notifier.cookie + +* Thu Aug 26 2021 haozi007 - 4.0.3-2021082601 +- Type:bugfix +- ID:NA +- SUG:NA +- DESC:add help info for new arguments + +* Sat Jun 12 2021 lifeng - 4.0.3-2021061201 +- Type:bugfix +- ID:NA +- SUG:NA +- DESC:fix coredump + +* Tue Jun 01 2021 zhangxiaoyu - 4.0.3-2021060101 +- Type:bugfix +- ID:NA +- SUG:NA +- DESC:adjust log level + +* Thu May 13 2021 lifeng - 4.0.3-2021051301 +- Type:bugfix +- ID:NA +- SUG:NA +- DESC:adjust log level + +* Sat May 08 2021 haozi007 - 4.0.3-2021050802 +- Type:bugfix +- ID:NA +- SUG:NA +- DESC:support long syslog tag + +* Sat May 08 2021 wangfengtu - 4.0.3-2021050801 +- Type:bugfix +- ID:NA +- SUG:NA +- DESC:print error message if process workdir failed + +* Wed Apr 07 2021 wangfengtu - 4.0.3-2021040701 +- Type:bugfix +- ID:NA +- SUG:NA +- DESC:some patches missing in series.conf + +* Wed Mar 31 2021 wangfengtu - 4.0.3-2021033101 +- Type:enhancement +- ID:NA +- SUG:NA +- DESC: support cgroup v2 + +* Thu Mar 11 2021 wangfengtu - 4.0.3-2021031102 +- Type:enhancement +- ID:NA +- SUG:NA +- DESC: support isula exec --workdir + +* Thu Jan 28 2021 lifeng - 4.0.3-2021012801 +- Type:enhancement +- ID:NA +- SUG:NA +- DESC: add inactive file total metrics + +* Thu Jan 21 2021 lifeng - 4.0.3-2021012001 +- Type:enhancement +- ID:NA +- SUG:NA +- DESC: fix io data miss when exec with pipes + +* Tue Jan 05 2021 wujing - 4.0.3-2021010501 +- Type:enhancement +- ID:NA +- SUG:NA +- DESC: fix compilation errors without libcap + +* Thu Dec 24 2020 wujing - 4.0.3-2020122401 +- Type:enhancement +- ID:NA +- SUG:NA +- DESC: Streaming IO solution optimization and enhancement + +* Tue Dec 15 2020 lifeng - 4.0.3-2020121501 +- Type:enhancement +- ID:NA +- SUG:NA +- DESC: add get container metrics api to get the stat + +* Mon Dec 07 2020 wujing - 4.0.3-2020120701 +- Type:enhancement +- ID:NA +- SUG:NA +- DESC: use path based unix domain sockets instead of abstract namespace sockets + +* Fri Nov 27 2020 lifeng - 4.0.3-2020112701 +- Type:enhancement +- ID:NA +- SUG:NA +- DESC: mount: make possible to bind mount /proc and /sys/fs. +- 1. add check whether have /proc mounts entry, if has, skip the auto +- 2. mount cgroup before do mount entrys +- 3. pass if the mount on top of /proc and the source of the mount is a proc filesystem + +* Fri Nov 13 2020 lifeng - 4.0.3-2020111701 +- Type:enhancement +- ID:NA +- SUG:NA +- DESC: add make private for root.path parent + +* Fri Nov 13 2020 lifeng - 4.0.3-2020111301 +- Type:enhancement +- ID:NA +- SUG:NA +- DESC: adjust log level from error to warn + +* Tue Nov 3 2020 lifeng - 4.0.3-2020110301 +- Type:enhancement +- ID:NA +- SUG:NA +- DESC: 1. fix hook root dir error and refact cgroup + +* Sat Oct 10 2020 openEuler Buildteam - 4.0.3-2020101001 +- Type:enhancement +- ID:NA +- SUG:NA +- DESC: add patchs to series.conf + +* Fri Sep 25 2020 openEuler Buildteam - 4.0.3-2020092501 +- Type:enhancement +- ID:NA +- SUG:NA +- DESC: Code optimization + +* Fri Sep 11 2020 openEuler Buildteam - 4.0.3-2020091101 +- Type:enhancement +- ID:NA +- SUG:NA +- DESC: modify source0 address + +* Wed Sep 02 2020 openEuler Buildteam - 4.0.3-2020090101 - Type:enhancement - ID:NA - SUG:NA -- DESC: disable isulad option +- DESC: modify source0 address -* Tue Aug 01 2023 zhangxiaoyu - 5.0.2-2 +* Mon Aug 03 2020 openEuler Buildteam - 4.0.3-2020080301 - Type:enhancement - ID:NA - SUG:NA -- DESC: add isulad code and fix compile error +- DESC: add debug packages -* Thu Jul 13 2023 haozi007 - 5.0.2-1 +* Mon Apr 20 2020 openEuler Buildteam - 4.0.3-2020071501 - Type:enhancement - ID:NA - SUG:NA -- DESC: update to 5.0.2 +- DESC: update lxc to 4.0.3