diff --git a/0008-refactor-patch-code-of-json.patch b/0001-iSulad-add-json-files-and-adapt-to-meson.patch similarity index 70% rename from 0008-refactor-patch-code-of-json.patch rename to 0001-iSulad-add-json-files-and-adapt-to-meson.patch index 217af9e97009906a30eb04a5ae76a2bfe1089856..f93d498d9f7c6b9850e7575fc06e740f3ad98d02 100644 --- a/0008-refactor-patch-code-of-json.patch +++ b/0001-iSulad-add-json-files-and-adapt-to-meson.patch @@ -1,24 +1,44 @@ -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 +From 757bc66c44a58ca2d65eb4c8199ad55cba580d00 Mon Sep 17 00:00:00 2001 +From: haozi007 +Date: Fri, 14 Jul 2023 11:21:56 +0800 +Subject: [PATCH 1/2] [iSulad] add json files and adapt to meson -Signed-off-by: zhangxiaoyu +Signed-off-by: haozi007 --- - src/lxc/cgroups/isulad_cgfsng.c | 3223 ++++++++++++++++++++++++++++++ + 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/json/defs.c | 205 ++ src/lxc/json/defs.h | 37 + src/lxc/json/json_common.c | 1153 +++++++++++ - src/lxc/json/json_common.h | 185 ++ + src/lxc/json/json_common.h | 194 ++ 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 + - 12 files changed, 5404 insertions(+) + src/lxc/meson.build | 26 +- + src/lxc/path.c | 521 +++++ + src/lxc/path.h | 33 + + 28 files changed, 7629 insertions(+), 2 deletions(-) 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 @@ -29,14 +49,183 @@ Signed-off-by: zhangxiaoyu 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..8a9656a +index 0000000..dcaa229 --- /dev/null +++ b/src/lxc/cgroups/isulad_cgfsng.c -@@ -0,0 +1,3223 @@ +@@ -0,0 +1,3229 @@ +/****************************************************************************** + * Copyright (c) Huawei Technologies Co., Ltd. 2019. All rights reserved. + * Author: lifeng @@ -716,15 +905,14 @@ index 0000000..8a9656a + 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) { @@ -978,8 +1166,15 @@ index 0000000..8a9656a + 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"); @@ -2503,7 +2698,7 @@ index 0000000..8a9656a + 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); @@ -3260,2252 +3455,4536 @@ index 0000000..8a9656a + + return move_ptr(cgfsng_ops); +} -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 +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 -+#include -+#include -+#include "defs.h" + }; + + 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"); ++#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; ++ } + -+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; -+ } ++ struct lxc_cmd_rr cmd = { ++ .req = { ++ .cmd = LXC_CMD_SET_TERMINAL_FIFOS, ++ .datalen = strlen(tmp)+1, ++ .data = tmp, ++ }, ++ }; + -+ 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; ++ 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; +} + -+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); ++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); +} + -+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; -+} -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 ++struct lxc_cmd_set_terminal_winch_request { ++ unsigned int height; ++ unsigned int width; ++}; + -+typedef struct { -+ char *path; ++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 }; + -+ char **args; -+ size_t args_len; ++ data.height = height; ++ data.width = width; + -+ char **env; -+ size_t env_len; ++ struct lxc_cmd_rr cmd = { ++ .req = { ++ .cmd = LXC_CMD_SET_TERMINAL_WINCH, ++ .datalen = sizeof(struct lxc_cmd_set_terminal_winch_request), ++ .data = &data, ++ }, ++ }; + -+ int timeout; ++ 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; +} -+defs_hook; + -+void free_defs_hook(defs_hook *ptr); ++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)); + -+defs_hook *make_defs_hook(yajl_val tree, struct parser_context *ctx, parser_error *err); ++ rsp.ret = lxc_set_terminal_winsz(&handler->conf->console, data->height, data->width);; + -+yajl_gen_status gen_defs_hook(yajl_gen g, defs_hook *ptr, struct parser_context *ctx, parser_error *err); ++ return lxc_cmd_rsp_send_reap(fd, &rsp); + -+#ifdef __cplusplus +} +#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 -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" + }; + + 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; + -+#define MAX_NUM_STR_LEN 21 ++ runtime_sock_dir = generate_named_unix_sock_dir(name); ++ if (runtime_sock_dir == NULL) ++ return -1; + -+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); -+} ++ if (mkdir_p(runtime_sock_dir, 0700) < 0) ++ return log_error_errno(-1, errno, "Failed to create container runtime unix sock directory %s", path); + -+yajl_gen_status reformat_uint(void *ctx, long long unsigned int num) { -+ char numstr[MAX_NUM_STR_LEN]; -+ int ret; ++ if (generate_named_unix_sock_path(name, suffix, path, sizeof(path)) != 0) ++ return -1; + -+ 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)); -+} ++ 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); ++ } + -+yajl_gen_status reformat_int(void *ctx, long long int num) { -+ char numstr[MAX_NUM_STR_LEN]; -+ int ret; ++ 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 + -+ 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)); -+} + #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; + -+yajl_gen_status reformat_double(void *ctx, double num) { -+ yajl_gen g = (yajl_gen) ctx; -+ return yajl_gen_double(g, num); -+} ++ rundir = get_rundir(); ++ if (!rundir) ++ rundir = strdup("/var/run"); + -+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 (asprintf(&exec_sock_dir, "%s/lxc/%s", rundir, name) < 0) { ++ return log_error_errno(NULL, errno, "Failed to allocate memory"); ++ } + -+yajl_gen_status reformat_null(void *ctx) { -+ yajl_gen g = (yajl_gen) ctx; -+ return yajl_gen_null(g); ++ return move_ptr(exec_sock_dir); +} + -+yajl_gen_status reformat_bool(void *ctx, int boolean) { -+ yajl_gen g = (yajl_gen) ctx; -+ return yajl_gen_bool(g, boolean); -+} ++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; + -+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); -+} ++ if (container_name == NULL || sock_name == NULL) ++ return -1; + -+yajl_gen_status reformat_start_map(void *ctx) { -+ yajl_gen g = (yajl_gen) ctx; -+ return yajl_gen_map_open(g); -+} ++ sock_dir = generate_named_unix_sock_dir(container_name); ++ if (sock_dir == NULL) ++ return -1; + -+yajl_gen_status reformat_end_map(void *ctx) { -+ yajl_gen g = (yajl_gen) ctx; -+ return yajl_gen_map_close(g); -+} ++ short_sock_name = strdup(sock_name); ++ if (strlen(short_sock_name) > MAX_SOCK_NAME_LENGTH) ++ short_sock_name[MAX_SOCK_NAME_LENGTH] = '\0'; + -+yajl_gen_status reformat_start_array(void *ctx) { -+ yajl_gen g = (yajl_gen) ctx; -+ return yajl_gen_array_open(g); -+} ++ 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"); + -+yajl_gen_status reformat_end_array(void *ctx) { -+ yajl_gen g = (yajl_gen) ctx; -+ return yajl_gen_array_close(g); ++ return 0; +} ++#endif + -+bool json_gen_init(yajl_gen *g, struct parser_context *ctx) { -+ *g = yajl_gen_alloc(NULL); -+ if (NULL == *g) { -+ return false; + 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; + -+ } -+ 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; -+} ++ if (file_exists(path)) { ++ client_fd = lxc_named_unix_connect(path); ++ if (client_fd < 0) ++ 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); -+} ++ return client_fd; ++ } ++#endif + -+void *safe_malloc(size_t size) { -+ void *ret = NULL; -+ if (size == 0) { -+ abort(); -+ } -+ ret = calloc(1, size); -+ if (ret == NULL) { -+ abort(); -+ } -+ return ret; -+} + 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); + -+int common_safe_double(const char *numstr, double *converted) { -+ char *err_str = NULL; -+ double d; ++#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 */ + -+ if (numstr == NULL) { -+ return -EINVAL; -+ } + #endif /* __LXC_COMMANDS_UTILS_H */ +diff --git a/src/lxc/exec_commands.c b/src/lxc/exec_commands.c +new file mode 100644 +index 0000000..bd81d66 +--- /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 ++ ******************************************************************************/ + -+ errno = 0; -+ d = strtod(numstr, &err_str); -+ if (errno > 0) { -+ return -errno; -+ } ++#ifndef _GNU_SOURCE ++#define _GNU_SOURCE 1 ++#endif ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include + -+ if (err_str == NULL || err_str == numstr || *err_str != '\0') { -+ return -EINVAL; -+ } ++#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" + -+ *converted = d; -+ return 0; -+} ++lxc_log_define(commands_exec, lxc); + -+int common_safe_uint8(const char *numstr, uint8_t *converted) { -+ char *err = NULL; -+ unsigned long int uli; ++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 (numstr == NULL) { -+ return -EINVAL; -+ } ++ if (cmd >= LXC_EXEC_CMD_MAX) ++ return "Invalid request"; + -+ errno = 0; -+ uli = strtoul(numstr, &err, 0); -+ if (errno > 0) { -+ return -errno; -+ } ++ return cmdname[cmd]; ++} + -+ if (err == NULL || err == numstr || *err != '\0') { -+ return -EINVAL; -+ } ++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; + -+ if (uli > UINT8_MAX) { -+ return -ERANGE; -+ } ++ /*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"); ++ } + -+ *converted = (uint8_t)uli; -+ return 0; -+} ++ 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)); + -+int common_safe_uint16(const char *numstr, uint16_t *converted) { -+ char *err = NULL; -+ unsigned long int uli; ++ if (errno == ECONNRESET || errno == EAGAIN || errno == EWOULDBLOCK) { ++ errno = ECONNRESET; /*isulad set errno ECONNRESET when timeout */ ++ return -1; ++ } + -+ if (numstr == NULL) { -+ return -EINVAL; -+ } ++ return -1; ++ } ++ TRACE("Command \"%s\" received response", lxc_exec_cmd_str(cmd->req.cmd)); + -+ errno = 0; -+ uli = strtoul(numstr, &err, 0); -+ if (errno > 0) { -+ return -errno; -+ } ++ if (rsp->datalen == 0) { ++ DEBUG("Response data length for command \"%s\" is 0", ++ lxc_exec_cmd_str(cmd->req.cmd)); ++ return ret; ++ } + -+ if (err == NULL || err == numstr || *err != '\0') { -+ return -EINVAL; -+ } ++ 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; ++ } + -+ if (uli > UINT16_MAX) { -+ return -ERANGE; -+ } ++ 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; ++ } + -+ *converted = (uint16_t)uli; -+ return 0; -+} ++ 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; ++ } + -+int common_safe_uint32(const char *numstr, uint32_t *converted) { -+ char *err = NULL; -+ unsigned long long int ull; ++ return ret; ++} + -+ if (numstr == NULL) { -+ return -EINVAL; -+ } ++static int lxc_exec_cmd_rsp_send(int fd, struct lxc_exec_cmd_rsp *rsp) ++{ ++ ssize_t ret; + -+ errno = 0; -+ ull = strtoull(numstr, &err, 0); -+ if (errno > 0) { -+ return -errno; -+ } ++ 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 (err == NULL || err == numstr || *err != '\0') { -+ return -EINVAL; -+ } ++ if (!rsp->data || rsp->datalen <= 0) ++ return 0; + -+ if (ull > UINT32_MAX) { -+ return -ERANGE; -+ } ++ 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; ++ } + -+ *converted = (uint32_t)ull; -+ return 0; ++ return 0; +} + -+int common_safe_uint64(const char *numstr, uint64_t *converted) { -+ char *err = NULL; -+ unsigned long long int ull; ++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; + -+ if (numstr == NULL) { -+ return -EINVAL; -+ } ++ client_fd = lxc_cmd_connect(name, lxcpath, hashed_sock_name, suffix); ++ if (client_fd < 0) ++ return -1; + -+ errno = 0; -+ ull = strtoull(numstr, &err, 0); -+ if (errno > 0) { -+ return -errno; -+ } ++ 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 (err == NULL || err == numstr || *err != '\0') { -+ return -EINVAL; -+ } ++ if (cmd->req.datalen <= 0) ++ return client_fd; + -+ *converted = (uint64_t)ull; -+ return 0; -+} ++ 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; + -+int common_safe_uint(const char *numstr, unsigned int *converted) { -+ char *err = NULL; -+ unsigned long long int ull; ++ return client_fd; + -+ if (numstr == NULL) { -+ return -EINVAL; -+ } ++on_error: ++ saved_errno = errno; ++ close(client_fd); ++ errno = saved_errno; + -+ errno = 0; -+ ull = strtoull(numstr, &err, 0); -+ if (errno > 0) { -+ return -errno; -+ } ++ return -1; ++} + -+ if (err == NULL || err == numstr || *err != '\0') { -+ return -EINVAL; -+ } ++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; + -+ if (ull > UINT_MAX) { -+ return -ERANGE; -+ } ++ 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; ++ } + -+ *converted = (unsigned int)ull; -+ return 0; -+} ++ ret = lxc_exec_cmd_rsp_recv(client_fd, cmd); + -+int common_safe_int8(const char *numstr, int8_t *converted) { -+ char *err = NULL; -+ long int li; ++ saved_errno = errno; ++ close(client_fd); ++ errno = saved_errno; ++ return ret; ++} + -+ if (numstr == NULL) { -+ return -EINVAL; -+ } ++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 }; + -+ errno = 0; -+ li = strtol(numstr, &err, 0); -+ if (errno > 0) { -+ return -errno; -+ } ++ data.height = height; ++ data.width = width; + -+ if (err == NULL || err == numstr || *err != '\0') { -+ return -EINVAL; -+ } ++ 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, ++ }, ++ }; + -+ if (li > INT8_MAX || li < INT8_MIN) { -+ return -ERANGE; -+ } ++ ret = lxc_exec_cmd(name, &cmd, lxcpath, NULL, suffix); ++ if (ret < 0) { ++ ERROR("Failed to send command to container"); ++ return -1; ++ } + -+ *converted = (int8_t)li; -+ return 0; ++ if (cmd.rsp.ret != 0) { ++ ERROR("Command response error:%d", cmd.rsp.ret); ++ return -1; ++ } ++ return 0; +} + -+int common_safe_int16(const char *numstr, int16_t *converted) { -+ char *err = NULL; -+ long int li; ++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)); + -+ if (numstr == NULL) { -+ return -EINVAL; -+ } ++ rsp.ret = lxc_set_terminal_winsz(handler->terminal, data->height, data->width);; + -+ errno = 0; -+ li = strtol(numstr, &err, 0); -+ if (errno > 0) { -+ return -errno; -+ } ++ return lxc_exec_cmd_rsp_send(fd, &rsp); + -+ if (err == NULL || err == numstr || *err != '\0') { -+ return -EINVAL; -+ } ++} + -+ if (li > INT16_MAX || li < INT16_MIN) { -+ return -ERANGE; -+ } ++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 *); + -+ *converted = (int16_t)li; -+ return 0; ++ 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); +} + -+int common_safe_int32(const char *numstr, int32_t *converted) { -+ char *err = NULL; -+ long long int lli; ++static void lxc_exec_cmd_fd_cleanup(int fd, struct lxc_epoll_descr *descr) ++{ ++ lxc_mainloop_del_handler(descr, fd); ++ close(fd); ++ return; ++} + -+ if (numstr == NULL) { -+ 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; + -+ errno = 0; -+ lli = strtol(numstr, &err, 0); -+ if (errno > 0) { -+ return -errno; -+ } ++ 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 (err == NULL || err == numstr || *err != '\0') { -+ return -EINVAL; -+ } ++ if (errno == EACCES) { ++ /* We don't care for the peer, just send and close. */ ++ struct lxc_exec_cmd_rsp rsp = {.ret = ret}; + -+ if (lli > INT32_MAX || lli < INT32_MIN) { -+ return -ERANGE; -+ } ++ lxc_exec_cmd_rsp_send(fd, &rsp); ++ } + -+ *converted = (int32_t)lli; -+ return 0; -+} ++ goto out_close; ++ } + -+int common_safe_int64(const char *numstr, int64_t *converted) { -+ char *err = NULL; -+ long long int lli; ++ if (ret == 0) ++ goto out_close; + -+ if (numstr == NULL) { -+ 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; ++ } + -+ errno = 0; -+ lli = strtoll(numstr, &err, 0); -+ if (errno > 0) { -+ return -errno; -+ } ++ 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 (err == NULL || err == numstr || *err != '\0') { -+ return -EINVAL; -+ } ++ 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; ++ } + -+ *converted = (int64_t)lli; -+ return 0; ++ 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; +} + -+int common_safe_int(const char *numstr, int *converted) { -+ char *err = NULL; -+ long long int lli; ++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; + -+ if (numstr == NULL) { -+ return -EINVAL; -+ } ++ connection = accept(fd, NULL, 0); ++ if (connection < 0) { ++ SYSERROR("Failed to accept connection to run command"); ++ return LXC_MAINLOOP_ERROR; ++ } + -+ errno = 0; -+ lli = strtol(numstr, &err, 0); -+ if (errno > 0) { -+ return -errno; -+ } ++ ret = fcntl(connection, F_SETFD, FD_CLOEXEC); ++ if (ret < 0) { ++ SYSERROR("Failed to set close-on-exec on incoming command connection"); ++ goto out_close; ++ } + -+ if (err == NULL || err == numstr || *err != '\0') { -+ return -EINVAL; -+ } ++ 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 (lli > INT_MAX || lli < INT_MIN) { -+ return -ERANGE; -+ } ++ ret = lxc_mainloop_add_handler(descr, connection, lxc_exec_cmd_handler, data); ++ if (ret) { ++ ERROR("Failed to add command handler"); ++ goto out_close; ++ } + -+ *converted = (int)lli; -+ return 0; -+} ++out: ++ return ret; + -+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; -+ } -+ 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); ++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}; + -+ } -+ 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_int(g, map->values[i]); -+ if (yajl_gen_status_ok != stat) { -+ GEN_SET_ERROR_AND_RETURN(stat, err); -+ } -+ } ++ if (name == NULL || suffix == NULL) ++ return -1; + -+ 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; -+} ++ if (generate_named_unix_sock_path(name, suffix, path, sizeof(path)) != 0) ++ return -1; + -+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); -+ } ++ (void)unlink(path); ++ ++ return 0; +} -+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; -+ } -+ 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; -+ } -+ } ++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 (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; ++ exec_sock_dir = generate_named_unix_sock_dir(name); ++ if (exec_sock_dir == NULL) ++ return -1; + -+ if (map == 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 ((SIZE_MAX / sizeof(int) - 1) < map->len) { -+ return -1; -+ } ++ if (generate_named_unix_sock_path(name, suffix, path, sizeof(path)) != 0) ++ return -1; + -+ len = map->len + 1; -+ keys = safe_malloc(len * sizeof(int)); -+ vals = safe_malloc(len * sizeof(int)); ++ TRACE("Creating unix socket \"%s\"", path); + -+ 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; ++ 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); ++ } ++ } + -+ map->len++; -+ return 0; ++ 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}; + -+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); ++ 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]); + -+ } -+ 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); -+ } -+ } ++ 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); + -+ 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; -+} ++ return -1; ++ } + -+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); -+ } ++ 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; +} -+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]; ++#endif + -+ 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; -+ } -+ } ++int lxc_exec_cmd_mainloop_add(struct lxc_epoll_descr *descr, struct lxc_exec_command_handler *handler) ++{ ++ int ret; ++ int fd = handler->maincmd_fd; + -+ 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 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; ++ 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); ++ } + -+ if (map == NULL) { ++ 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 */ ++ ++ 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 (P->tty == 0) ++ P->tty = -1; /* the old notty val, update elsewhere bef. moving to 0 */ ++ return P; ++} + -+ if ((SIZE_MAX / sizeof(int) - 1) < map->len || (SIZE_MAX / sizeof(bool) - 1) < map->len) { -+ return -1; ++/* 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; + } + -+ len = map->len + 1; -+ keys = safe_malloc(len * sizeof(int)); -+ vals = safe_malloc(len * sizeof(bool)); ++ if ((lxc_file2str(filename, sbuf, sizeof(sbuf))) == -1) { ++ SYSERROR("Failed to read pidfile %s", filename); ++ goto out; ++ } + -+ if (map->len) { -+ (void)memcpy(keys, map->keys, map->len * sizeof(int)); -+ (void)memcpy(vals, map->values, map->len * sizeof(bool)); ++ pid_info = lxc_stat2proc(sbuf); ++ if (!pid_info) { ++ ERROR("Failed to get proc stat info"); ++ goto out; + } -+ 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; ++ startat = pid_info->start_time; ++out: ++ free(pid_info); ++ return startat; +} + -+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; -+ 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); ++// 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; ++} ++ ++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; + } -+ stat = reformat_start_map(g); -+ if (yajl_gen_status_ok != stat) { -+ GEN_SET_ERROR_AND_RETURN(stat, err); + ++ 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; + } -+ 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); ++ ++ // **src is not a digit ++ if (err_str == *src) { ++ if (!required) { ++ ERROR("Integer part is missing."); ++ return -1; + } -+ stat = reformat_string(g, map->values[i], strlen(map->values[i]));; -+ if (yajl_gen_status_ok != stat) { -+ GEN_SET_ERROR_AND_RETURN(stat, err); ++ // 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; + } + -+ 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); ++ // normal case ++ if (*err_str == delim) { ++ err_str++; ++ } else if (*err_str != '\0') { ++ ERROR("Invalid digit string."); ++ return -1; + } -+ return yajl_gen_status_ok; ++ ++ *src = err_str; // update src to next valid context in line. ++ return 0; +} + -+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; ++static void hold_string(const char delim, char **src, char **dst) ++{ ++ for (*dst = *src; **src != delim; ++(*src)) { ++ if (**src == '\0') { ++ break; + } -+ free(map->keys); -+ map->keys = NULL; -+ free(map->values); -+ map->values = NULL; -+ free(map); ++ } ++ ++ if (**src == delim) { ++ **src = '\0'; ++ ++(*src); + } +} -+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]; + -+ 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; -+ } -+ } ++static int parse_line_pw(const char delim, char *line, struct passwd *result) ++{ ++ int ret = 0; ++ bool required = false; ++ char *walker = NULL; + -+ 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 : ""); -+ } -+ } ++ walker = strpbrk(line, "\n"); ++ if (walker != NULL) { ++ // clear newline char ++ *walker = '\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; + -+ if (map == NULL) { -+ return -1; ++ 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 ((SIZE_MAX / sizeof(int) - 1) < map->len || (SIZE_MAX / sizeof(char *) - 1) < map->len) { -+ return -1; ++ 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; + } + -+ len = map->len + 1; -+ keys = safe_malloc(len * sizeof(int)); -+ vals = safe_malloc(len * sizeof(char *)); ++ hold_string(delim, &line, &result->pw_gecos); + -+ 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 : ""); ++ hold_string(delim, &line, &result->pw_dir); + -+ map->len++; ++ result->pw_shell = line; + return 0; +} + -+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; ++char *util_left_trim_space(char *str) ++{ ++ char *begin = str; ++ char *tmp = str; ++ while (isspace(*begin)) { ++ begin++; + } -+ if (!len && !(ptx->options & GEN_OPTIONS_SIMPLIFY)) { -+ yajl_gen_config(g, yajl_gen_beautify, 0); ++ while ((*tmp++ = *begin++)) { + } -+ stat = reformat_start_map(g); -+ if (yajl_gen_status_ok != stat) { -+ GEN_SET_ERROR_AND_RETURN(stat, err); ++ return str; ++} + -+ } -+ 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); -+ } ++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; + } + -+ 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); ++ if (buflen <= 1) { ++ ERROR("Inadequate buffer length was given."); ++ return -1; + } -+ return yajl_gen_status_ok; -+} + -+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 : ""); ++ buff_end = buffer + buflen - 1; ++ flockfile(stream); + -+ 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; -+ } ++ 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; + } -+ } -+ 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; -+ } ++ (void)util_left_trim_space(buffer); ++ // skip comment line and empty line ++ if (walker[0] == '#' || walker[0] == '\0') { ++ continue; ++ } + -+ if ((SIZE_MAX / sizeof(char *) - 1) < map->len || (SIZE_MAX / sizeof(int) - 1) < map->len) { -+ return -1; ++ if (parse_line_pw(delim, walker, resbuf) == 0) { ++ got = true; ++ break; ++ } + } -+ -+ len = map->len + 1; -+ keys = safe_malloc(len * sizeof(char *)); -+ vals = safe_malloc(len * sizeof(int)); -+ -+ if (map->len) { -+ (void)memcpy(keys, map->keys, map->len * sizeof(char *)); -+ (void)memcpy(vals, map->values, map->len * sizeof(int)); ++ if (!got) { ++ *result = NULL; ++ ret = ERANGE; ++ goto out; + } -+ 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; + -+ map->len++; -+ return 0; ++ *result = resbuf; ++ ret = 0; ++out: ++ funlockfile(stream); ++ return ret; +} +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 + -+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); ++#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); + -+ } -+ 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); ++#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 : ""); + } -+ stat = reformat_bool(g, map->values[i]); -+ if (yajl_gen_status_ok != stat) { -+ GEN_SET_ERROR_AND_RETURN(stat, err); ++ } ++ { ++ 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 : ""); ++ } ++ } + } + } -+ -+ 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_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 ++ { ++ 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 : ""); ++ } ++ } + } -+ 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; ++ { ++ 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; ++ } + } -+ 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 : ""); ++ } ++ 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 (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; -+ } ++ 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; +} + -+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; -+ -+ if (map == NULL) { -+ return -1; -+ } -+ -+ if ((SIZE_MAX / sizeof(char *) - 1) < map->len || (SIZE_MAX / sizeof(bool) - 1) < map->len) { -+ return -1; ++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; + } -+ -+ len = map->len + 1; -+ keys = safe_malloc(len * sizeof(char *)); -+ vals = safe_malloc(len * sizeof(bool)); -+ -+ if (map->len) { -+ (void)memcpy(keys, map->keys, map->len * sizeof(char *)); -+ (void)memcpy(vals, map->values, map->len * sizeof(bool)); ++ 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(map->keys); -+ map->keys = keys; -+ free(map->values); -+ map->values = vals; -+ map->keys[map->len] = safe_strdup(key ? key : ""); -+ map->values[map->len] = val; -+ -+ map->len++; -+ return 0; ++ free(ptr); +} + -+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 gen_defs_hook(yajl_gen g, defs_hook *ptr, struct parser_context *ctx, 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); -+ } ++ *err = 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); + } -+ for (i = 0; i < len; i++) { -+ stat = reformat_string(g, map->keys[i], strlen(map->keys[i])); -+ if (yajl_gen_status_ok != stat) { ++ 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; + } -+ stat = reformat_string(g, map->values[i], strlen(map->values[i]));; -+ if (yajl_gen_status_ok != stat) { ++ 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) { ++ 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 + -+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 : ""); ++#include ++#include ++#include "json_common.h" + -+ 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; ++#ifdef __cplusplus ++extern "C" { ++#endif + -+ if (map == NULL) { -+ return -1; -+ } ++typedef struct { ++ char *path; + -+ 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; -+ } -+ } ++ char **args; ++ size_t args_len; + -+ if ((SIZE_MAX / sizeof(char *) - 1) < map->len) { -+ return -1; -+ } ++ char **env; ++ size_t env_len; + -+ len = map->len + 1; -+ keys = safe_malloc(len * sizeof(char *)); -+ vals = safe_malloc(len * sizeof(char *)); ++ int timeout; + -+ 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 : ""); ++} ++defs_hook; + -+ map->len++; -+ return 0; ++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 +} -diff --git a/src/lxc/json/json_common.h b/src/lxc/json/json_common.h ++#endif ++ ++#endif +diff --git a/src/lxc/json/json_common.c b/src/lxc/json/json_common.c new file mode 100755 -index 0000000..60aa5fd +index 0000000..ec20c59 --- /dev/null -+++ b/src/lxc/json/json_common.h -@@ -0,0 +1,185 @@ ++++ b/src/lxc/json/json_common.c +@@ -0,0 +1,1153 @@ +// Auto generated file. Do not edit! -+#ifndef _JSON_COMMON_H -+#define _JSON_COMMON_H -+ -+#include ++#define _GNU_SOURCE +#include -+#include -+#include -+#include -+#include -+#include -+#include "utils.h" ++#include ++#include ++#include "json_common.h" + -+#ifdef __cplusplus -+extern "C" { -+#endif ++#define MAX_NUM_STR_LEN 21 + -+# undef linux ++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); ++} + -+//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 ++yajl_gen_status reformat_uint(void *ctx, long long unsigned int num) { ++ char numstr[MAX_NUM_STR_LEN]; ++ int ret; + -+#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; \ ++ 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)); ++} + -+typedef char *parser_error; -+ -+struct parser_context { -+ unsigned int options; -+ FILE *stderr; -+}; ++yajl_gen_status reformat_int(void *ctx, long long int num) { ++ char numstr[MAX_NUM_STR_LEN]; ++ int ret; + -+yajl_gen_status reformat_number(void *ctx, const char *str, size_t len); ++ 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)); ++} + -+yajl_gen_status reformat_uint(void *ctx, long long unsigned int num); ++yajl_gen_status reformat_double(void *ctx, double num) { ++ yajl_gen g = (yajl_gen) ctx; ++ return yajl_gen_double(g, num); ++} + -+yajl_gen_status reformat_int(void *ctx, long long int num); ++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); ++} + -+yajl_gen_status reformat_double(void *ctx, double num); ++yajl_gen_status reformat_null(void *ctx) { ++ yajl_gen g = (yajl_gen) ctx; ++ return yajl_gen_null(g); ++} + -+yajl_gen_status reformat_string(void *ctx, const char *str, size_t len); ++yajl_gen_status reformat_bool(void *ctx, int boolean) { ++ yajl_gen g = (yajl_gen) ctx; ++ return yajl_gen_bool(g, boolean); ++} + -+yajl_gen_status reformat_null(void *ctx); ++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_bool(void *ctx, int boolean); ++yajl_gen_status reformat_start_map(void *ctx) { ++ yajl_gen g = (yajl_gen) ctx; ++ return yajl_gen_map_open(g); ++} + -+yajl_gen_status reformat_map_key(void *ctx, const char *str, size_t len); ++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_map(void *ctx); ++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_map(void *ctx); ++yajl_gen_status reformat_end_array(void *ctx) { ++ yajl_gen g = (yajl_gen) ctx; ++ return yajl_gen_array_close(g); ++} + -+yajl_gen_status reformat_start_array(void *ctx); ++bool json_gen_init(yajl_gen *g, struct parser_context *ctx) { ++ *g = yajl_gen_alloc(NULL); ++ if (NULL == *g) { ++ return false; + -+yajl_gen_status reformat_end_array(void *ctx); ++ } ++ 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; ++} + -+bool json_gen_init(yajl_gen *g, struct parser_context *ctx); ++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); ++} + -+yajl_val get_val(yajl_val tree, const char *name, yajl_type type); ++void *safe_malloc(size_t size) { ++ void *ret = NULL; ++ if (size == 0) { ++ abort(); ++ } ++ ret = calloc(1, size); ++ if (ret == NULL) { ++ abort(); ++ } ++ return ret; ++} + -+void *safe_malloc(size_t size); ++int common_safe_double(const char *numstr, double *converted) { ++ char *err_str = NULL; ++ double d; + -+int common_safe_double(const char *numstr, double *converted); ++ if (numstr == NULL) { ++ return -EINVAL; ++ } + -+int common_safe_uint8(const char *numstr, uint8_t *converted); ++ errno = 0; ++ d = strtod(numstr, &err_str); ++ if (errno > 0) { ++ return -errno; ++ } + -+int common_safe_uint16(const char *numstr, uint16_t *converted); ++ if (err_str == NULL || err_str == numstr || *err_str != '\0') { ++ return -EINVAL; ++ } + -+int common_safe_uint32(const char *numstr, uint32_t *converted); ++ *converted = d; ++ return 0; ++} + -+int common_safe_uint64(const char *numstr, uint64_t *converted); ++int common_safe_uint8(const char *numstr, uint8_t *converted) { ++ char *err = NULL; ++ unsigned long int uli; + -+int common_safe_uint(const char *numstr, unsigned int *converted); ++ if (numstr == NULL) { ++ return -EINVAL; ++ } + -+int common_safe_int8(const char *numstr, int8_t *converted); ++ errno = 0; ++ uli = strtoul(numstr, &err, 0); ++ if (errno > 0) { ++ return -errno; ++ } + -+int common_safe_int16(const char *numstr, int16_t *converted); ++ if (err == NULL || err == numstr || *err != '\0') { ++ return -EINVAL; ++ } + -+int common_safe_int32(const char *numstr, int32_t *converted); ++ if (uli > UINT8_MAX) { ++ return -ERANGE; ++ } + -+int common_safe_int64(const char *numstr, int64_t *converted); ++ *converted = (uint8_t)uli; ++ return 0; ++} + -+int common_safe_int(const char *numstr, int *converted); ++int common_safe_uint16(const char *numstr, uint16_t *converted) { ++ char *err = NULL; ++ unsigned long int uli; + -+typedef struct { -+ int *keys; -+ int *values; -+ size_t len; -+} json_map_int_int; ++ if (numstr == NULL) { ++ return -EINVAL; ++ } + -+void free_json_map_int_int(json_map_int_int *map); ++ errno = 0; ++ uli = strtoul(numstr, &err, 0); ++ if (errno > 0) { ++ return -errno; ++ } + -+json_map_int_int *make_json_map_int_int(yajl_val src, struct parser_context *ctx, parser_error *err); ++ if (err == NULL || err == numstr || *err != '\0') { ++ return -EINVAL; ++ } + -+yajl_gen_status gen_json_map_int_int(void *ctx, json_map_int_int *map, struct parser_context *ptx, parser_error *err); ++ if (uli > UINT16_MAX) { ++ return -ERANGE; ++ } + -+int append_json_map_int_int(json_map_int_int *map, int key, int val); ++ *converted = (uint16_t)uli; ++ return 0; ++} + -+typedef struct { -+ int *keys; -+ bool *values; -+ size_t len; -+} json_map_int_bool; ++int common_safe_uint32(const char *numstr, uint32_t *converted) { ++ char *err = NULL; ++ unsigned long long int ull; + -+void free_json_map_int_bool(json_map_int_bool *map); ++ if (numstr == NULL) { ++ return -EINVAL; ++ } + -+json_map_int_bool *make_json_map_int_bool(yajl_val src, struct parser_context *ctx, parser_error *err); ++ errno = 0; ++ ull = strtoull(numstr, &err, 0); ++ if (errno > 0) { ++ return -errno; ++ } + -+yajl_gen_status gen_json_map_int_bool(void *ctx, json_map_int_bool *map, struct parser_context *ptx, parser_error *err); ++ if (err == NULL || err == numstr || *err != '\0') { ++ return -EINVAL; ++ } + -+int append_json_map_int_bool(json_map_int_bool *map, int key, bool val); ++ if (ull > UINT32_MAX) { ++ return -ERANGE; ++ } + -+typedef struct { -+ int *keys; -+ char **values; -+ size_t len; -+} json_map_int_string; ++ *converted = (uint32_t)ull; ++ return 0; ++} + -+void free_json_map_int_string(json_map_int_string *map); ++int common_safe_uint64(const char *numstr, uint64_t *converted) { ++ char *err = NULL; ++ unsigned long long int ull; + -+json_map_int_string *make_json_map_int_string(yajl_val src, struct parser_context *ctx, parser_error *err); ++ if (numstr == NULL) { ++ return -EINVAL; ++ } + -+yajl_gen_status gen_json_map_int_string(void *ctx, json_map_int_string *map, struct parser_context *ptx, parser_error *err); ++ errno = 0; ++ ull = strtoull(numstr, &err, 0); ++ if (errno > 0) { ++ return -errno; ++ } + -+int append_json_map_int_string(json_map_int_string *map, int key, const char *val); ++ if (err == NULL || err == numstr || *err != '\0') { ++ return -EINVAL; ++ } + -+typedef struct { -+ char **keys; -+ int *values; -+ size_t len; -+} json_map_string_int; ++ *converted = (uint64_t)ull; ++ return 0; ++} + -+void free_json_map_string_int(json_map_string_int *map); ++int common_safe_uint(const char *numstr, unsigned int *converted) { ++ char *err = NULL; ++ unsigned long long int ull; + -+json_map_string_int *make_json_map_string_int(yajl_val src, struct parser_context *ctx, parser_error *err); ++ if (numstr == NULL) { ++ return -EINVAL; ++ } + -+yajl_gen_status gen_json_map_string_int(void *ctx, json_map_string_int *map, struct parser_context *ptx, parser_error *err); ++ errno = 0; ++ ull = strtoull(numstr, &err, 0); ++ if (errno > 0) { ++ return -errno; ++ } + -+int append_json_map_string_int(json_map_string_int *map, const char *key, int val); ++ if (err == NULL || err == numstr || *err != '\0') { ++ return -EINVAL; ++ } + -+typedef struct { -+ char **keys; -+ bool *values; -+ size_t len; -+} json_map_string_bool; ++ if (ull > UINT_MAX) { ++ return -ERANGE; ++ } + -+void free_json_map_string_bool(json_map_string_bool *map); ++ *converted = (unsigned int)ull; ++ return 0; ++} + -+json_map_string_bool *make_json_map_string_bool(yajl_val src, struct parser_context *ctx, parser_error *err); ++int common_safe_int8(const char *numstr, int8_t *converted) { ++ char *err = NULL; ++ long int li; + -+yajl_gen_status gen_json_map_string_bool(void *ctx, json_map_string_bool *map, struct parser_context *ptx, parser_error *err); ++ if (numstr == NULL) { ++ return -EINVAL; ++ } + -+int append_json_map_string_bool(json_map_string_bool *map, const char *key, bool val); ++ errno = 0; ++ li = strtol(numstr, &err, 0); ++ if (errno > 0) { ++ return -errno; ++ } + -+typedef struct { -+ char **keys; -+ char **values; -+ size_t len; -+} json_map_string_string; ++ if (err == NULL || err == numstr || *err != '\0') { ++ return -EINVAL; ++ } + -+void free_json_map_string_string(json_map_string_string *map); ++ if (li > INT8_MAX || li < INT8_MIN) { ++ return -ERANGE; ++ } + -+json_map_string_string *make_json_map_string_string(yajl_val src, struct parser_context *ctx, parser_error *err); ++ *converted = (int8_t)li; ++ return 0; ++} + -+yajl_gen_status gen_json_map_string_string(void *ctx, json_map_string_string *map, struct parser_context *ptx, parser_error *err); ++int common_safe_int16(const char *numstr, int16_t *converted) { ++ char *err = NULL; ++ long int li; + -+int append_json_map_string_string(json_map_string_string *map, const char *key, const char *val); ++ 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; ++ } ++ ++ *converted = (int64_t)lli; ++ return 0; ++} ++ ++int common_safe_int(const char *numstr, int *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 > INT_MAX || lli < INT_MIN) { ++ return -ERANGE; ++ } ++ ++ *converted = (int)lli; ++ 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 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_int(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_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); ++ } ++} ++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; ++ } ++ 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; ++ } ++ } ++ ++ 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; ++ } ++ } ++ ++ 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 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; ++ ++ if (map == NULL) { ++ return -1; ++ } ++ ++ if ((SIZE_MAX / sizeof(int) - 1) < map->len || (SIZE_MAX / sizeof(bool) - 1) < map->len) { ++ return -1; ++ } ++ ++ len = map->len + 1; ++ keys = safe_malloc(len * sizeof(int)); ++ vals = safe_malloc(len * sizeof(bool)); ++ ++ 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; ++ ++ 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 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_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_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]; ++ ++ 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 (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 : ""); ++ } ++ } ++ } ++ 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; ++ ++ if (map == NULL) { ++ return -1; ++ } ++ ++ if ((SIZE_MAX / sizeof(int) - 1) < map->len || (SIZE_MAX / sizeof(char *) - 1) < map->len) { ++ return -1; ++ } ++ ++ len = map->len + 1; ++ keys = safe_malloc(len * sizeof(int)); ++ vals = safe_malloc(len * sizeof(char *)); ++ ++ 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 : ""); ++ ++ map->len++; ++ return 0; ++} ++ ++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); ++ ++ } ++ 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); ++ } ++ } ++ ++ 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_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 : ""); ++ ++ 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; ++ } ++ } ++ } ++ } ++ 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; ++ } ++ ++ if ((SIZE_MAX / sizeof(char *) - 1) < map->len || (SIZE_MAX / sizeof(int) - 1) < map->len) { ++ return -1; ++ } ++ ++ len = map->len + 1; ++ keys = safe_malloc(len * sizeof(char *)); ++ vals = safe_malloc(len * sizeof(int)); ++ ++ 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; ++ ++ map->len++; ++ return 0; ++} ++ ++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); ++ ++ } ++ 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); ++ } ++ } ++ ++ 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_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 : ""); ++ ++ 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; ++} ++ ++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; ++ ++ if (map == NULL) { ++ return -1; ++ } ++ ++ 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(char *)); ++ vals = safe_malloc(len * sizeof(bool)); ++ ++ 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; ++ ++ map->len++; ++ return 0; ++} ++ ++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); ++ ++int common_safe_double(const char *numstr, double *converted); ++ ++int common_safe_uint8(const char *numstr, uint8_t *converted); ++ ++int common_safe_uint16(const char *numstr, uint16_t *converted); ++ ++int common_safe_uint32(const char *numstr, uint32_t *converted); ++ ++int common_safe_uint64(const char *numstr, uint64_t *converted); ++ ++int common_safe_uint(const char *numstr, unsigned int *converted); ++ ++int common_safe_int8(const char *numstr, int8_t *converted); ++ ++int common_safe_int16(const char *numstr, int16_t *converted); ++ ++int common_safe_int32(const char *numstr, int32_t *converted); ++ ++int common_safe_int64(const char *numstr, int64_t *converted); ++ ++int common_safe_int(const char *numstr, int *converted); ++ ++typedef struct { ++ int *keys; ++ int *values; ++ size_t len; ++} json_map_int_int; ++ ++void free_json_map_int_int(json_map_int_int *map); ++ ++json_map_int_int *make_json_map_int_int(yajl_val src, struct parser_context *ctx, parser_error *err); ++ ++yajl_gen_status gen_json_map_int_int(void *ctx, json_map_int_int *map, struct parser_context *ptx, parser_error *err); ++ ++int append_json_map_int_int(json_map_int_int *map, int key, int val); ++ ++typedef struct { ++ int *keys; ++ bool *values; ++ size_t len; ++} json_map_int_bool; ++ ++void free_json_map_int_bool(json_map_int_bool *map); ++ ++json_map_int_bool *make_json_map_int_bool(yajl_val src, 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); ++ ++int append_json_map_int_bool(json_map_int_bool *map, int key, bool val); ++ ++typedef struct { ++ int *keys; ++ char **values; ++ size_t len; ++} json_map_int_string; ++ ++void free_json_map_int_string(json_map_int_string *map); ++ ++json_map_int_string *make_json_map_int_string(yajl_val src, struct parser_context *ctx, parser_error *err); ++ ++yajl_gen_status gen_json_map_int_string(void *ctx, json_map_int_string *map, struct parser_context *ptx, parser_error *err); ++ ++int append_json_map_int_string(json_map_int_string *map, int key, const char *val); ++ ++typedef struct { ++ char **keys; ++ int *values; ++ size_t len; ++} json_map_string_int; ++ ++void free_json_map_string_int(json_map_string_int *map); ++ ++json_map_string_int *make_json_map_string_int(yajl_val src, struct parser_context *ctx, parser_error *err); ++ ++yajl_gen_status gen_json_map_string_int(void *ctx, json_map_string_int *map, struct parser_context *ptx, parser_error *err); ++ ++int append_json_map_string_int(json_map_string_int *map, const char *key, int val); ++ ++typedef struct { ++ char **keys; ++ bool *values; ++ size_t len; ++} json_map_string_bool; ++ ++void free_json_map_string_bool(json_map_string_bool *map); ++ ++json_map_string_bool *make_json_map_string_bool(yajl_val src, struct parser_context *ctx, 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); ++ ++int append_json_map_string_bool(json_map_string_bool *map, const char *key, bool val); ++ ++typedef struct { ++ char **keys; ++ char **values; ++ 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); ++ ++oci_runtime_spec_hooks *make_oci_runtime_spec_hooks(yajl_val tree, 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); + +#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 +diff --git a/src/lxc/json/read-file.c b/src/lxc/json/read-file.c new file mode 100644 -index 0000000..6abeef4 +index 0000000..34ebeed --- /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 ++++ b/src/lxc/json/read-file.c +@@ -0,0 +1,95 @@ ++#include ++#include ++#include ++#include ++#include ++#include +#include -+#include -+#include "logger_json_file.h" ++#include + -+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; ++#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 (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; -+} ++ if (buf) { ++ memcpy(tmpbuf, buf, off); + -+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); -+} ++ memset(buf, 0, off); + -+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; ++ free(buf); + } -+ 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; ++ ++ buf = tmpbuf; ++ ret = fread(buf + off, 1, BUFSIZ, stream); ++ if (!ret && ferror(stream)) { ++ tmpbuf = NULL; ++ goto out; + } -+ 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; ++ if (ret < BUFSIZ || feof(stream)) { ++ *length = off + ret + 1; ++ buf[*length - 1] = '\0'; ++ return buf; + } -+ stat = reformat_string(g, str, strlen(str)); -+ if (yajl_gen_status_ok != stat) -+ GEN_SET_ERROR_AND_RETURN(stat, err); ++ off += BUFSIZ; + } -+ 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); ++out: ++ if (buf) { ++ free(buf); + } -+ stat = reformat_end_map(g); -+ if (yajl_gen_status_ok != stat) -+ GEN_SET_ERROR_AND_RETURN(stat, err); -+ return yajl_gen_status_ok; -+} ++ if (tmpbuf) { ++ free(tmpbuf); ++ } ++ return NULL; + ++} + -+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; ++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 (filename == NULL || err == NULL) ++ if (!path || !length) { + 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"); ++ if (strlen(path) > PATH_MAX || NULL == realpath(path, rpath)) { + 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) ++ fd = open(rpath, O_RDONLY | O_CLOEXEC); ++ if (fd < 0) { + return NULL; ++ } + -+ *err = NULL; -+ content = fread_file(stream, &filesize); -+ if (content == NULL) { -+ *err = safe_strdup("cannot read the file"); ++ fp = fdopen(fd, "r"); ++ tmperrno = errno; ++ if (!fp) { ++ close(fd); ++ errno = tmperrno; + return NULL; + } -+ ptr = logger_json_file_parse_data(content, ctx, err); -+ free(content); -+ return ptr; ++ ++ buf = fread_file(fp, length); ++ fclose(fp); ++ return buf; +} +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 + -+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; ++#include ++#include + -+ if (jsondata == NULL || err == NULL) -+ return NULL; ++extern char *fread_file(FILE *stream, size_t *length); + -+ *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; ++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); ++ ++#define ISSLASH(C) ((C) == '/') ++#define IS_ABSOLUTE_FILE_NAME(F) (ISSLASH ((F)[0])) ++ ++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; + } -+ ptr = make_logger_json_file(tree, ctx, err); -+ yajl_tree_free(tree); -+ return ptr; ++ return false; +} -+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; ++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++ = '/'; ++ } ++ ++ if (dest + (endpos - stpos) >= limit_respath) { ++ ERROR("Path is too long"); ++ if (dest > respath + 1) { ++ dest--; ++ } ++ *dest = '\0'; ++ return -1; ++ } + -+ *err = NULL; -+ if (ctx == NULL) { -+ ctx = &tmp_ctx; -+ memset(&tmp_ctx, 0, sizeof(tmp_ctx)); ++ memcpy(dest, stpos, (size_t)(endpos - stpos)); ++ dest += endpos - stpos; ++ *dest = '\0'; + } ++ *dst = dest; ++ return 0; ++} + -+ if (!json_gen_init(&g, ctx)) { -+ *err = safe_strdup("Json_gen init failed"); -+ goto out; ++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; ++ ++ if (path == NULL || path[0] == '\0' || \ ++ realpath == NULL || (realpath_len < PATH_MAX)) { ++ return NULL; + } -+ 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; ++ ++ respath = realpath; ++ ++ memset(respath, 0, realpath_len); ++ limit_respath = respath + PATH_MAX; ++ ++ 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; + } -+ 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 (do_clean_path(respath, limit_respath, stpos, &dest)) { ++ goto error; + } + -+ if (gen_len == SIZE_MAX) { -+ *err = safe_strdup("Invalid buffer length"); -+ goto free_out; ++ if (dest > respath + 1 && ISSLASH(dest[-1])) { ++ --dest; + } -+ json_buf = safe_malloc(gen_len + 1); -+ (void)memcpy(json_buf, gen_buf, gen_len); -+ json_buf[gen_len] = '\0'; ++ *dest = '\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 ++ return respath; + -+#include -+#include -+#include "json_common.h" ++error: ++ return NULL; ++} + -+#ifdef __cplusplus -+extern "C" { -+#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; + -+typedef struct { -+ uint8_t *log; -+ size_t log_len; ++ if (*dest + (end - start) < *rpath_limit) { ++ return 0; ++ } + -+ char *stream; ++ 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; ++ } + -+ char *time; ++ 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; + -+ uint8_t *attrs; -+ size_t attrs_len; ++ *dest = *rpath + dest_offset; + ++ return 0; +} -+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); ++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 *logger_json_file_parse_file(const char *filename, struct parser_context *ctx, parser_error *err); ++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; + -+logger_json_file *logger_json_file_parse_file_stream(FILE *stream, struct parser_context *ctx, parser_error *err); ++ if (++(*num_links) > MAXSYMLINKS) { ++ ERROR("Too many links in '%s'", *fullpath); ++ goto out; ++ } + -+logger_json_file *logger_json_file_parse_data(const char *jsondata, struct parser_context *ctx, parser_error *err); ++ buf = lxc_common_calloc_s(PATH_MAX); ++ if (buf == NULL) { ++ ERROR("Out of memory"); ++ goto out; ++ } + -+char *logger_json_file_generate_json(logger_json_file *ptr, struct parser_context *ctx, parser_error *err); ++ n = readlink(*rpath, buf, PATH_MAX - 1); ++ if (n < 0) { ++ goto out; ++ } ++ buf[n] = '\0'; + -+#ifdef __cplusplus -+} -+#endif ++ if (*extra_buf == NULL) { ++ *extra_buf = lxc_common_calloc_s(PATH_MAX); ++ if (*extra_buf == NULL) { ++ ERROR("Out of memory"); ++ goto out; ++ } ++ } + -+#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" ++ len = strlen(*end); ++ if (len >= (size_t)(PATH_MAX - n)) { ++ ERROR("Path is too long"); ++ goto out; ++ } + -+#include "log.h" -+#include "utils.h" ++ memmove(&(*extra_buf)[n], *end, len + 1); ++ memcpy(*extra_buf, buf, (size_t)n); + -+#define PARSE_ERR_BUFFER_SIZE 1024 ++ *fullpath = *end = *extra_buf; + -+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 (do_get_symlinks_copy_buf(buf, prefix, prefix_len, rpath, dest) != 0) { ++ goto out; ++ } + -+ 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; ++ ret = 0; ++out: ++ free(buf); ++ return ret; +} -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); ++static bool do_eval_symlinks_in_scope_is_symlink(const char *path) ++{ ++ struct stat st; + -+#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" ++ if (lstat(path, &st) < 0) { ++ return true; ++ } + -+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 (!S_ISLNK(st.st_mode)) { ++ return true; ++ } ++ return false; ++} + -+ 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 void do_eval_symlinks_skip_slash(const char **start, const char **end) ++{ ++ while (ISSLASH(**start)) { ++ ++(*start); ++ } ++ ++ for (*end = *start; **end && !ISSLASH(**end); ++(*end)) { ++ } +} + -+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 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; ++ } ++ } +} + -+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; ++static inline bool is_current_char(const char c) ++{ ++ return c == '.'; +} -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" ++static inline bool is_specify_current(const char *end, const char *start) ++{ ++ return (end - start == 1) && is_current_char(start[0]); ++} + -+#ifdef __cplusplus -+extern "C" { -+#endif ++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]); ++} + -+typedef struct { -+ defs_hook **prestart; -+ size_t prestart_len; ++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)++ = '/'; ++ } + -+ defs_hook **poststart; -+ size_t poststart_len; ++ nret = do_path_realloc(start, end, rpath, dest, &rpath_limit); ++ if (nret != 0) { ++ nret = -1; ++ goto out; ++ } + -+ defs_hook **poststop; -+ size_t poststop_len; ++ 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; +} -+oci_runtime_spec_hooks; + -+void free_oci_runtime_spec_hooks(oci_runtime_spec_hooks *ptr); ++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; ++ } + -+oci_runtime_spec_hooks *make_oci_runtime_spec_hooks(yajl_val tree, struct parser_context *ctx, parser_error *err); ++ root = cleanpath(rootpath, resroot, sizeof(resroot)); ++ if (root == NULL) { ++ 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); ++ if (!strcmp(fullpath, root)) { ++ return safe_strdup(fullpath); ++ } + -+#ifdef __cplusplus ++ 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; ++ ++ prefix = root; ++ prefix_len = (size_t)strlen(prefix); ++ if (!strcmp(prefix, "/")) { ++ prefix_len = 0; ++ } ++ ++ dest = rpath; ++ if (prefix_len) { ++ memcpy(rpath, prefix, prefix_len); ++ dest += prefix_len; ++ } ++ *dest++ = '/'; ++ ++ if (do_eval_symlinks_in_scope(fullpath, prefix, prefix_len, &rpath, &dest, ++ rpath_limit)) { ++ goto out; ++ } ++ ++ if (dest > rpath + prefix_len + 1 && ISSLASH(dest[-1])) { ++ --dest; ++ } ++ *dest = '\0'; ++ return rpath; ++ ++out: ++ free(rpath); ++ return NULL; +} -+#endif + -+#endif -diff --git a/src/lxc/json/read-file.h b/src/lxc/json/read-file.h ++// 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; ++ ++ full = cleanpath(fullpath, resfull, PATH_MAX); ++ if (!full) { ++ ERROR("Failed to get cleaned path"); ++ return NULL; ++ } ++ ++ root = cleanpath(rootpath, resroot, PATH_MAX); ++ if (!root) { ++ ERROR("Failed to get cleaned path"); ++ return NULL; ++ } ++ ++ return eval_symlinks_in_scope(full, root); ++} ++ ++// 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 new file mode 100644 -index 0000000..5d6e0eb +index 0000000..59bbc59 --- /dev/null -+++ b/src/lxc/json/read-file.h -@@ -0,0 +1,11 @@ -+#ifndef READ_FILE_H -+#define READ_FILE_H -+ -+#include -+#include ++++ 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_ + -+extern char *fread_file(FILE *stream, size_t *length); ++#include + -+extern char *read_file(const char *path, size_t *length); ++/* ++ * 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); + +#endif -- 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 deleted file mode 100644 index e39be2e3586bb864a4a27eed1bf3649037446e54..0000000000000000000000000000000000000000 --- a/0001-refactor-patch-code-of-utils-commands-and-so-on.patch +++ /dev/null @@ -1,2368 +0,0 @@ -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-refactor-patch-code-of-isulad-for-conf-exec-attach.patch b/0002-iSulad-adapt-security-conf-attach-cgroup-and-start.patch similarity index 41% rename from 0002-refactor-patch-code-of-isulad-for-conf-exec-attach.patch rename to 0002-iSulad-adapt-security-conf-attach-cgroup-and-start.patch index 00c07a530d90ec93ba22964a0855777097ab1675..6e2c7c2aef9d2ab55db924432125fe8da92234a9 100644 --- a/0002-refactor-patch-code-of-isulad-for-conf-exec-attach.patch +++ b/0002-iSulad-adapt-security-conf-attach-cgroup-and-start.patch @@ -1,1301 +1,1569 @@ -From 7166cf40250f00544e204a33da668b56ed4b13ca Mon Sep 17 00:00:00 2001 +From ef27d69db952dc64fc3c476a89c3e822c891e663 Mon Sep 17 00:00:00 2001 From: haozi007 -Date: Mon, 18 Jul 2022 11:30:33 +0800 -Subject: [PATCH] refactor patch code of isulad for conf/exec/attach +Date: Mon, 17 Jul 2023 20:40:48 +0800 +Subject: [PATCH 2/2] [iSulad] adapt security conf attach cgroup and start Signed-off-by: haozi007 --- - 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(-) + 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(-) -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 +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" +#ifdef HAVE_ISULAD -+#include -+#include "sync.h" -+#include "path.h" -+#include "utils.h" -+#include "loop.h" -+#endif ++#include "exec_commands.h" + - #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(); ++typedef enum { ++ ATTACH_INIT, ++ ATTACH_TIMEOUT, ++ ATTACH_MAX, ++} attach_timeout_t; + -+#endif ++static volatile attach_timeout_t g_attach_timeout_state = ATTACH_INIT; + - 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); -+ } ++struct attach_timeout_conf { ++ int64_t timeout; ++ unsigned long long start_time; ++ pid_t pid; ++}; +#endif + - 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; - } + lxc_log_define(attach, lxc); + /* 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 -+ 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); ++ struct lxc_terminal *terminal; +#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 - return 0; + static void put_attach_payload(struct attach_payload *p) +@@ -1127,6 +1148,48 @@ static void put_attach_payload(struct attach_payload *p) } -@@ -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 -+ // 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; ++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; + } -+ free(mntdata); + -+ flags = MS_SLAVE | MS_REC; -+ if (pflags) -+ flags = pflags; ++ if (terminal->pipes[0][0] >= 0) { ++ ret = dup2(terminal->pipes[0][0], STDIN_FILENO); ++ if (ret < 0) ++ goto out; ++ } + -+ /* 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][0] >= 0) { ++ close(terminal->pipes[1][0]); ++ terminal->pipes[1][0] = -1; + } + -+ /* 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[1][1] >= 0) { ++ ret = dup2(terminal->pipes[1][1], STDOUT_FILENO); ++ if (ret < 0) ++ goto out; + } -+ 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][0] >= 0) { ++ close(terminal->pipes[2][0]); ++ terminal->pipes[2][0] = -1; + } + -+ 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; ++ if (terminal->pipes[2][1] >= 0) { ++ ret = dup2(terminal->pipes[2][1], STDERR_FILENO); ++ if (ret < 0) ++ goto out; + } ++ ++ setsid(); ++out: ++ return ret; ++} +#endif + - 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) + __noreturn static void do_attach(struct attach_payload *ap) { - int ret; - char **opts; + 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; +#ifdef HAVE_ISULAD -+ __do_free char *devpts_mntopts = NULL; -+#else - char devpts_mntopts[256]; ++ 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 - char *mntopt_sets[5]; - char default_devpts_mntopts[256] = "gid=5,newinstance,ptmxmode=0666,mode=0620"; - if (conf->pty_max <= 0) - return log_debug(0, "No new devpts instance will be mounted since no pts devices are requested"); + /* + * 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"); + } +#ifdef HAVE_ISULAD -+ 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; ++ /* 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; + } -+ } else { -+ if (asprintf(&devpts_mntopts, "%s,max=%zu", default_devpts_mntopts, conf->pty_max) < 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 - 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 + /* 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; + } - (void)umount2("/dev/pts", MNT_DETACH); ++#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; + } ++#endif -@@ -1580,9 +1735,14 @@ static inline bool wants_console(const struct lxc_terminal *terminal) - return !terminal->path || strcmp(terminal->path, "none"); - } + 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); + } +#ifdef HAVE_ISULAD -+static int lxc_setup_dev_console(const struct lxc_rootfs *rootfs, -+ const struct lxc_terminal *console, const char *mount_label) -+#else - static int lxc_setup_dev_console(const struct lxc_rootfs *rootfs, - const struct lxc_terminal *console, - int pts_mnt_fd) ++ // 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 - { - 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"); ++ + 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) + } + if (options->attach_flags & LXC_ATTACH_TERMINAL) { +#ifdef HAVE_ISULAD -+ if (console->pts > 0) { ++ /* 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 { ++#else + ret = lxc_terminal_prepare_login(ap->terminal_pts_fd); +#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); - -+#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, - } ++#ifdef HAVE_ISULAD ++ } ++#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; - 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); ++#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; ++ } ++#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; - 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); ++#ifdef HAVE_ISULAD ++ if (prctl(PR_SET_KEEPCAPS, 0) < 0) { ++ SYSERROR("Failed to clear permitted capabilities"); ++ goto on_error; ++ } + ++ 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 + - return 0; + 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); } +#ifdef HAVE_ISULAD -+static int lxc_setup_ttydir_console(const struct lxc_rootfs *rootfs, -+ const struct lxc_terminal *console, -+ char *ttydir, const char *mount_label) ++static int lxc_attach_terminal(const char *name, const char *lxcpath, struct lxc_conf *conf, ++ struct lxc_terminal *terminal, lxc_attach_options_t *options) +#else - static int lxc_setup_ttydir_console(const struct lxc_rootfs *rootfs, - const struct lxc_terminal *console, - char *ttydir, int pts_mnt_fd) + static int lxc_attach_terminal(const char *name, const char *lxcpath, struct lxc_conf *conf, + struct lxc_terminal *terminal) +#endif { int ret; - 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"); + + lxc_terminal_init(terminal); +#ifdef HAVE_ISULAD -+ 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 ++ /* 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 - -+#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 ++ + ret = lxc_terminal_create(name, lxcpath, conf, terminal); if (ret < 0) - 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; - } - -+#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); + 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); } -+#else -+static int lxc_setup_console(const struct lxc_rootfs *rootfs, -+ const struct lxc_terminal *console, char *ttydir, const char *mount_label) -+{ -+ if (!ttydir) -+ return lxc_setup_dev_console(rootfs, console, mount_label); -+ return lxc_setup_ttydir_console(rootfs, console, ttydir, mount_label); -+} -+#endif -+ -+#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) ++#ifdef HAVE_ISULAD ++/* isulad: attach timeout thread function */ ++static void* wait_attach_timeout(void *arg) +{ -+ struct mount_opt *mo; ++ struct attach_timeout_conf *conf = (struct attach_timeout_conf *)arg; + -+ /* If opt is found in mount_opt, set or clear flags. -+ * Otherwise append it to data. */ -+ -+ 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; ++ 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); + } + } + -+ /* 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; ++out: ++ free(conf); ++ return ((void *)0); ++} + -+ if (mo->clear) -+ *pflags &= ~mo->flag; -+ else -+ *pflags |= mo->flag; ++/* 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; + -+ return; ++ timeout_conf = malloc(sizeof(struct attach_timeout_conf)); ++ if (timeout_conf == NULL) { ++ ERROR("Failed to malloc attach timeout conf"); ++ ret = -1; ++ goto out; + } + -+ if (strlen(*data)) -+ (void)strlcat(*data, ",", size); ++ 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; ++ } + -+ (void)strlcat(*data, opt, size); ++out: ++ return ret; +} + -+int parse_mntopts(const char *mntopts, unsigned long *mntflags, unsigned long *pflags, char **mntdata) ++static int attach_signal_handler(int fd, uint32_t events, void *data, ++ struct lxc_epoll_descr *descr) +{ -+ char *data, *p, *s; -+ size_t size; ++ 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); + -+ *mntdata = NULL; -+ *mntflags = 0L; -+ *pflags = 0L; ++ if (ret != sizeof(siginfo)) ++ return log_error(LXC_MAINLOOP_ERROR, "Unexpected size for struct signalfd_siginfo"); + -+ if (!mntopts) -+ return 0; ++ /* 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); ++ } + -+ s = safe_strdup(mntopts); ++ return LXC_MAINLOOP_CONTINUE; ++} + -+ size = strlen(s) + 1; -+ data = malloc(size); -+ if (!data) { -+ free(s); -+ return -1; ++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; + } -+ *data = 0; + -+ lxc_iterate_parts(p, s, ",") -+ parse_mntopt(p, mntflags, pflags, &data, size); ++ ret = pthread_sigmask(SIG_BLOCK, &mask, oldmask); ++ if (ret < 0) ++ return log_error_errno(-EBADF, errno, ++ "Failed to set signal mask"); + -+ if (*data) -+ *mntdata = data; -+ else -+ free(data); -+ free(s); ++ ret = signalfd(-1, &mask, SFD_CLOEXEC); ++ if (ret < 0) ++ return log_error_errno(-EBADF, ++ errno, "Failed to create signal file descriptor"); + -+ return 0; ++ TRACE("Created signal file descriptor %d", ret); ++ ++ return ret; +} +#endif - - 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 -+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) ++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 - 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) + 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; - char srcbuf[PATH_MAX]; -@@ -1881,8 +2169,13 @@ static int mount_entry(const char *fsname, const char *target, - srcpath = srcbuf; + 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; ++ ++ exec_command.maincmd_fd = -1; ++ exec_command.terminal = &terminal; ++ ++ int isulad_sigfd; ++ sigset_t isulad_oldmask; ++ struct lxc_epoll_descr isulad_descr = {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; + ++#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; ++#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, } + if (options->attach_flags & LXC_ATTACH_TERMINAL) { +#ifdef HAVE_ISULAD -+ ret = safe_mount(srcpath, target, fstype, mountflags & ~MS_REMOUNT, data, -+ rootfs, mount_label); ++ ret = lxc_attach_terminal(name, lxcpath, conf, &terminal, options); +#else - ret = safe_mount(srcpath, target, fstype, mountflags & ~MS_REMOUNT, data, - rootfs); + 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; ++ } +#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) { - 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, ++#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 (hasmntopt(mntent, "create=dir")) { - ret = mkdir_p(path, 0755); +#ifdef HAVE_ISULAD -+ 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); ++ /* 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); + } -+#else - if (ret < 0 && errno != EEXIST) - return log_error_errno(-1, errno, "Failed to create directory \"%s\"", path); ++ 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); ++ } ++ close(ipc_sockets[0]); ++ close(ipc_sockets[1]); +#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; - if (!hasmntopt(mntent, "create=file")) -@@ -2028,29 +2328,56 @@ static int mount_entry_create_dir_file(const struct mntent *mntent, - p2 = dirname(p1); ++#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]); - ret = mkdir_p(p2, 0755); +@@ -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); +#ifdef HAVE_ISULAD -+ 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); ++ if (exec_command.maincmd_fd != -1) { ++ close_prot_errno_disarm(exec_command.maincmd_fd); ++ } +#endif + } - ret = mknod(path, S_IFREG | 0000, 0); + /* 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 -+ if (ret < 0 && errno != EEXIST) { -+ lxc_write_error_message(rootfs->errfd, "%s:%d: open %s: %s.", __FILE__, __LINE__, path, strerror(errno)); -+ return -errno; -+ } ++ .terminal = &terminal, ++#endif + }; +- ++#ifdef HAVE_ISULAD ++ if (options->attach_flags & LXC_ATTACH_TERMINAL && terminal.tty_state) { +#else - if (ret < 0 && errno != EEXIST) - return -errno; + if (options->attach_flags & LXC_ATTACH_TERMINAL) { +#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, - return 0; - } + /* 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; - /* rootfs, lxc_name, and lxc_path can be NULL when the container is created - * without a rootfs. */ +#ifdef HAVE_ISULAD -+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) ++ 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 - { - __do_free char *mntdata = NULL; - unsigned long mntflags = 0, pflags = 0; - char *rootfs_path = NULL; - int ret; - bool dev, optional, relative; + TRACE("Initialized terminal mainloop"); + } + +#ifdef HAVE_ISULAD -+ const char *dest = path; -+ char *rpath = NULL; ++ /* 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. */ + 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, - 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; + *attached_process = attached_pid; -+#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; ++#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; + } -+ dest = rpath; ++ } ++ /* 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 + -+ 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; + /* 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 = mount_entry_create_dir_file(mntent, dest, rootfs, lxc_name, -+ lxc_path); +#endif + - if (ret < 0) { + if (options->attach_flags & LXC_ATTACH_TERMINAL) { +#ifdef HAVE_ISULAD -+ free(rpath); ++ ret = isulad_safe_mainloop(&descr, -1); ++#else + ret = lxc_mainloop(&descr, -1); +#endif - if (optional) - return 0; - -@@ -2069,6 +2428,29 @@ static inline int mount_entry_on_generic(struct mntent *mntent, + if (ret < 0) { + ret_parent = -1; + to_cleanup_pid = attached_pid; + } } - cull_mntent_opt(mntent); +#ifdef HAVE_ISULAD -+ ret = parse_mntopts(mntent->mnt_opts, &mntflags, &pflags, &mntdata); -+ if (ret < 0) { -+ free(rpath); -+ return -1; -+ } -+ -+ // 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); ++ // 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 + -+ 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); + close_mainloop: ++#ifdef HAVE_ISULAD ++ if (options->attach_flags & LXC_ATTACH_TERMINAL) { ++ lxc_mainloop_close(&isulad_descr); ++ lxc_mainloop_close(&descr); + } -+ -+ free(rpath); +#else - 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); + if (options->attach_flags & LXC_ATTACH_TERMINAL) + lxc_mainloop_close(&descr); +#endif - return ret; - } -@@ -2098,13 +2481,25 @@ static inline int mount_entry_on_systemfs(struct mntent *mntent) - if (ret < 0 || ret >= sizeof(path)) - return -1; - + 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); +#ifdef HAVE_ISULAD -+ return mount_entry_on_generic(mntent, path, NULL, NULL, NULL, NULL); -+#else - return mount_entry_on_generic(mntent, path, NULL, NULL, NULL); ++ if (exec_command.maincmd_fd != -1) { ++ close_prot_errno_disarm(exec_command.maincmd_fd); ++ } ++ lxc_exec_unix_sock_delete(name, suffix); +#endif + } + + put_attach_context(ctx); + return ret_parent; } +#ifdef HAVE_ISULAD -+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) ++int lxc_attach_run_command(void *payload, int msg_fd) +#else - static int mount_entry_on_absolute_rootfs(struct mntent *mntent, - const struct lxc_rootfs *rootfs, - const char *lxc_name, - const char *lxc_path) + int lxc_attach_run_command(void *payload) +#endif { - int offset; - char *aux; -@@ -2140,13 +2535,25 @@ skipabs: - if (ret < 0 || ret >= PATH_MAX) - return -1; + int ret = -1; + lxc_attach_command_t *cmd = payload; +@@ -1838,10 +2330,19 @@ int lxc_attach_run_command(void *payload) + } + } +#ifdef HAVE_ISULAD -+ 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); ++ /* isulad: write error messages */ ++ lxc_write_error_message(msg_fd, "exec: \"%s\": %s.", cmd->program, strerror(errno)); +#endif ++ + return syserror_ret(ret, "Failed to exec \"%s\"", cmd->program); } +#ifdef HAVE_ISULAD -+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) ++int lxc_attach_run_shell(void* payload, int msg_fd) +#else - static int mount_entry_on_relative_rootfs(struct mntent *mntent, - const struct lxc_rootfs *rootfs, - const char *lxc_name, - const char *lxc_path) + int lxc_attach_run_shell(void* payload) +#endif { - 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; + __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; +#ifdef HAVE_ISULAD -+ return mount_entry_on_generic(mntent, path, rootfs, lxc_name, lxc_path, mount_label); ++__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); +#else - return mount_entry_on_generic(mntent, path, rootfs, lxc_name, lxc_path); + __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); +#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 -+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) ++typedef int (*lxc_attach_exec_t)(void* payload, int msg_fd); +#else - 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) + typedef int (*lxc_attach_exec_t)(void* payload); +#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 -+ //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); ++ 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 -+ - if (ret < 0) - return -1; - } -@@ -2195,9 +2650,15 @@ static inline void __auto_endmntent__(FILE **f) - - #define __do_endmntent __attribute__((__cleanup__(__auto_endmntent__))) + } 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 -+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 - 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) ++ /* .init_fifo = */ {NULL, NULL, NULL}, \ +#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); + } + /*! +@@ -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 -+ ret = mount_file_entries(conf, rootfs, f, lxc_name, lxc_path, mount_label); ++extern int lxc_attach_run_command(void* payload, int msg_fd); +#else - ret = mount_file_entries(conf, rootfs, f, lxc_name, lxc_path); + extern int lxc_attach_run_command(void* payload); +#endif - if (ret < 0) - ERROR("Failed to set up mount entries"); - -@@ -2285,10 +2750,17 @@ FILE *make_anonymous_mount_file(struct lxc_list *mount, - return f; - } + /*! + * \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 -+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) ++extern int lxc_attach_run_shell(void* payload, int msg_fd); +#else - 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) + extern int lxc_attach_run_shell(void* payload); +#endif - { - __do_fclose FILE *f = NULL; - -@@ -2296,7 +2768,11 @@ static int setup_mount_entries(const struct lxc_conf *conf, - if (!f) - return -1; + #ifdef __cplusplus + } +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 -+ return mount_file_entries(conf, rootfs, f, lxc_name, lxc_path, mount_label); ++ if (cgroup_ops->data_init(cgroup_ops, conf)) { +#else - return mount_file_entries(conf, rootfs, f, lxc_name, lxc_path); + if (cgroup_ops->data_init(cgroup_ops)) { +#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; + 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 -+ /* 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; -+ } ++ 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); ++#else + int (*data_init)(struct cgroup_ops *ops); + void (*payload_destroy)(struct cgroup_ops *ops, struct lxc_handler *handler); +#endif - capid = parse_cap(keep_entry); - if (capid == -2) - continue; -@@ -2443,7 +2929,11 @@ static int parse_resource(const char *res) - return resid; - } + 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 +#ifdef HAVE_ISULAD -+int setup_resource_limits(struct lxc_list *limits, pid_t pid, int errfd) -+#else - int setup_resource_limits(struct lxc_list *limits, pid_t pid) ++#include ++#include "path.h" ++#include "loop.h" +#endif - { - 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); ++ + lxc_log_define(conf, lxc); - #if HAVE_PRLIMIT || HAVE_PRLIMIT64 + /* +@@ -122,6 +128,11 @@ char *lxchook_names[NUM_LXC_HOOKS] = { + "clone", + "destroy", + "start-host" +#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); ++ , "oci-prestart", ++ "oci-poststart", ++ "oci-poststop" +#endif + }; - 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); + struct mount_opt { +@@ -284,6 +295,21 @@ static struct limit_opt limit_opt[] = { + #endif + }; +#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; ++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 + - return new; - } - -@@ -3001,7 +3521,11 @@ again: - null_endofword(target); - ret = mount(NULL, target, NULL, MS_SLAVE, NULL); - if (ret < 0) { + 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 -+ SYSERROR("Failed to recursively turn old root mount tree: %s into dependent mount. Continuing...", target); ++ { 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 - SYSERROR("Failed to recursively turn old root mount tree into dependent mount. Continuing..."); + { 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 }, +#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); - } + /* /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"); +#ifdef HAVE_ISULAD -+ ret = safe_mount(path, destpath, "none", MS_BIND, NULL, conf->rootfs.mount, conf->lsm_se_mount_context); ++ 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); +#else - ret = safe_mount(path, destpath, "none", MS_BIND, NULL, conf->rootfs.mount); + ret = safe_mount(source, destination, + default_mounts[i].fstype, + mflags, + default_mounts[i].options, + rootfs->path ? rootfs->mount : NULL); +#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"); + 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; } -+#ifndef HAVE_ISULAD - turn_into_dependent_mounts(); ++#ifdef HAVE_ISULAD ++ if (systemd != NULL && !strcmp(systemd, "true")) { ++ ret = mount(path, path, "", MS_BIND, NULL); +#else -+ if (!conf->rootfs.options) { -+ turn_into_dependent_mounts(); -+ } + 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); +#endif + } else { + __do_free char *fallback_path = NULL; - ret = run_lxc_hooks(name, "pre-mount", conf, NULL); - if (ret < 0) -@@ -3182,15 +3716,29 @@ static int lxc_setup_boot_id(void) +@@ -1253,9 +1305,17 @@ static int mount_autodev(const char *name, const struct lxc_rootfs *rootfs, - 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; + if (path) { + fallback_path = must_make_path(path, "/dev", NULL); +#ifdef HAVE_ISULAD -+ bool setup_dev = true; -+ bool setup_proc = true; ++ 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); +#endif - - ret = lxc_setup_rootfs_prepare_root(lxc_conf, name, lxcpath); - if (ret < 0) + } else { +#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"); -+ } ++ ret = safe_mount("none", "dev", "tmpfs", 0, mount_options, NULL, rootfs->lsm_se_mount_context); +#else - return log_error(-1, "Failed to setup rootfs"); + ret = safe_mount("none", "dev", "tmpfs", 0, mount_options, NULL); +#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"); + } } + 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); -+#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); - } ++#ifdef HAVE_ISULAD ++ ret = safe_mount(rootfs->buf, path, 0, MS_BIND, NULL, get_rootfs_mnt(rootfs), rootfs->lsm_se_mount_context); ++#else + ret = safe_mount(rootfs->buf, path, 0, MS_BIND, NULL, get_rootfs_mnt(rootfs)); +#endif + if (ret < 0) + return log_error_errno(-1, errno, "Failed to bind mount host device node \"%s\" to \"%s\"", rootfs->buf, path); - if (lxc_conf->autodev > 0) { +@@ -1410,12 +1474,23 @@ static int lxc_fill_autodev(struct lxc_rootfs *rootfs) + static int lxc_mount_rootfs(struct lxc_rootfs *rootfs) + { + int ret; +#ifdef HAVE_ISULAD -+ 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); ++ unsigned long flags; +#endif + + if (!rootfs->path) { + ret = mount("", "/", NULL, MS_SLAVE | MS_REC, 0); 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"); + return log_error_errno(-1, errno, "Failed to recursively turn root mount tree into dependent mount"); +#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(lxc_conf, lxc_conf->auto_mounts & LXC_AUTO_CGROUP_MASK, handler); -+ if (ret < 0) -+ return log_error(-1, "Failed to setup remaining automatic mounts"); ++ 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 + 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); + ++#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; ++ } +#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 -+ ret = setup_mount(lxc_conf, &lxc_conf->rootfs, lxc_conf->fstab, name, lxcpath, lxc_conf->lsm_se_mount_context); ++ __do_free char *devpts_mntopts = NULL; +#else - ret = setup_mount(lxc_conf, &lxc_conf->rootfs, lxc_conf->fstab, name, lxcpath); + char devpts_mntopts[256]; +#endif - if (ret < 0) - return log_error(-1, "Failed to setup mounts"); + char *mntopt_sets[5]; + char default_devpts_mntopts[256] = "gid=5,newinstance,ptmxmode=0666,mode=0620"; - if (!lxc_list_empty(&lxc_conf->mount_list)) { +@@ -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. + */ +- +#ifdef HAVE_ISULAD -+ ret = setup_mount_entries(lxc_conf, &lxc_conf->rootfs, -+ &lxc_conf->mount_list, name, lxcpath, lxc_conf->lsm_se_mount_context); ++ 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 { +#else - ret = setup_mount_entries(lxc_conf, &lxc_conf->rootfs, - &lxc_conf->mount_list, name, lxcpath); + ret = strnprintf(devpts_mntopts, sizeof(devpts_mntopts), "%s,max=%zu", + default_devpts_mntopts, pty_max); +#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; - if (lxc_conf->is_execute) { -@@ -3278,6 +3856,7 @@ int lxc_setup(struct lxc_handler *handler) - } - } +@@ -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 -+#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"); + 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 + } + + 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"); ++ } ++ } +#endif - ret = run_lxc_hooks(name, "mount", lxc_conf, NULL); + /* 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 if (ret < 0) -@@ -3295,21 +3875,45 @@ int lxc_setup(struct lxc_handler *handler) - if (ret < 0) - return log_error(-1, "Failed to run autodev hooks"); + 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; + } +#ifdef HAVE_ISULAD -+ ret = lxc_fill_autodev(&lxc_conf->rootfs, lxc_conf->lsm_se_mount_context); ++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 - ret = lxc_fill_autodev(&lxc_conf->rootfs); + 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 (ret < 0) - return log_error(-1, "Failed to populate \"/dev\""); + { + 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; } +- ++#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: 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"); ++ // 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; + } + } ++ 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; ++ } ++ } + - /* Make sure any start hooks are in the container */ - if (!verify_start_hooks(lxc_conf)) - return log_error(-1, "Failed to verify start hooks"); ++ /* 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; -+#ifndef HAVE_ISULAD - ret = lxc_create_tmp_proc_mount(lxc_conf); - if (ret < 0) - return log_error(-1, "Failed to \"/proc\" LSMs"); ++#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); + ++#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; + } - ret = lxc_setup_console(&lxc_conf->rootfs, &lxc_conf->console, - lxc_conf->ttys.dir, pts_mnt_fd); +@@ -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); +#else -+ if (setup_proc) { -+ ret = lxc_create_tmp_proc_mount(lxc_conf); -+ if (ret < 0) -+ return log_error(-1, "Failed to \"/proc\" LSMs"); + 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"); + } ++#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 = lxc_setup_console(&lxc_conf->rootfs, &lxc_conf->console, -+ lxc_conf->ttys.dir, lxc_conf->lsm_se_mount_context); + 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); +#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 console"); + return log_error(-1, "Failed to setup remaining automatic mounts"); ++#endif -@@ -3317,6 +3921,12 @@ int lxc_setup(struct lxc_handler *handler) + ret = run_lxc_hooks(name, "mount", lxc_conf, NULL); if (ret < 0) - return log_error(-1, "Failed to setup \"/dev\" symlinks"); +@@ -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"); +#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"); -+ } ++ if (setup_proc) +#endif - ret = lxc_setup_rootfs_switch_root(&lxc_conf->rootfs); + ret = lxc_create_tmp_proc_mount(lxc_conf); if (ret < 0) - 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(); + return log_error(-1, "Failed to mount transient procfs instance for LSMs"); +#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(lxc_conf); ++ ret = lxc_setup_devpts_child(handler); + if (ret < 0) { + return log_error(-1, "Failed to setup new devpts instance for '%s'", name); + } + } +#else - ret = lxc_setup_devpts(lxc_conf); + ret = lxc_setup_devpts_child(handler); if (ret < 0) - return log_error(-1, "Failed to setup new devpts instance"); + return log_error(-1, "Failed to prepare new devpts instance"); +#endif - ret = lxc_create_ttys(handler); + ret = lxc_finish_devpts_child(handler); if (ret < 0) - return -1; +@@ -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 -+ /*isulad: set system umask */ -+ umask(lxc_conf->umask); -+#endif ++ /* 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(); + ++#ifdef HAVE_ISULAD ++ /*isulad: set system umask */ ++ umask(lxc_conf->umask); ++#endif + ret = setup_personality(lxc_conf->personality); if (ret < 0) - 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"); - } + 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"); +#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) { @@ -1313,13 +1581,14 @@ index 0078996..378cf9f 100644 + } +#endif + - 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); + 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); free(conf->shmount.path_host); free(conf->shmount.path_cont); ++ +#ifdef HAVE_ISULAD + free(conf->container_info_file); + if (conf->exit_fd != -1) { @@ -1339,12 +1608,13 @@ index 0078996..378cf9f 100644 + free(conf->lsm_se_mount_context); + free(conf->lsm_se_keyring_context); +#endif ++ free(conf); } -@@ -4775,3 +5452,1315 @@ struct lxc_list *sort_cgroup_settings(struct lxc_list *cgroup_settings) +@@ -5798,3 +6177,1321 @@ int lxc_set_environment(const struct lxc_conf *conf) - return result; + return 0; } + +#ifdef HAVE_ISULAD @@ -1422,7 +1692,8 @@ index 0078996..378cf9f 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)); -+ 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 + } + } + @@ -1957,7 +2228,8 @@ index 0078996..378cf9f 100644 + + // 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; @@ -1996,16 +2268,19 @@ index 0078996..378cf9f 100644 +static int setup_rootfs_mountopts(const struct lxc_rootfs *rootfs) +{ + unsigned long mflags, mntflags, pflags; -+ char *mntdata = NULL; ++ __do_free char *mntdata = NULL; + + if(!rootfs || !rootfs->options) + return 0; + -+ if (parse_mntopts(rootfs->options, &mntflags, &pflags, &mntdata) < 0) { -+ free(mntdata); ++ if (parse_mntopts_legacy(rootfs->options, &mntflags, &mntdata) < 0) { + return -1; + } -+ free(mntdata); ++ ++ ret = parse_propagationopts(rootfs->options, &pflags); ++ if (ret < 0) { ++ return -EINVAL; ++ } + + if (mntflags & MS_RDONLY) { + mflags = add_required_remount_flags("/", NULL, MS_BIND | MS_REC | mntflags | pflags | MS_REMOUNT); @@ -2117,7 +2392,8 @@ index 0078996..378cf9f 100644 +{ + 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" @@ -2132,11 +2408,6 @@ index 0078996..378cf9f 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]); @@ -2160,6 +2431,11 @@ index 0078996..378cf9f 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; +} @@ -2305,552 +2581,1905 @@ index 0078996..378cf9f 100644 + + 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); ++ 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; ++ } + -+ 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); ++ // for free tmp in caller ++ *tmp_dup = tmp; ++ pdot = strstr(tmp, ":"); ++ if (pdot != NULL) { ++ *pdot = '\0'; ++ if (pdot != tmp) { ++ // uid found ++ *uid = tmp; ++ } + -+ if (kill(conf->pid, SIGKILL) && errno != ESRCH) { -+ ERROR("Send kill signal failed"); -+ goto out; ++ if (*(pdot + 1) != '\0') { ++ // gid found ++ *gid = pdot + 1; ++ } ++ } else { ++ // No : found ++ if (*tmp != '\0') { ++ *uid = tmp; ++ } + } + } + -+out: -+ free(conf); -+ return ((void *)0); ++ return 0; +} + -+static int run_ocihook_buffer(struct oci_hook_conf *oconf, const char *inmsg) ++static int get_attach_uid_gid(const char *username, uid_t *user_id, gid_t *group_id) +{ -+ 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; ++ char *tmp = NULL; ++ char *uid = NULL; ++ char *gid = NULL; + -+ hookenvs = merge_ocihook_env(oconf->ocihook->env, oconf->ocihook->env_len, &hookenvs_len); -+ if (!hookenvs) { -+ ERROR("Out of memory."); ++ // parse uid and gid by username ++ if (parse_user_id(username, &uid, &gid, &tmp) != 0) { + 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; ++ if (uid != NULL) { ++ *user_id = (unsigned int)atoll(uid); + } -+ -+ conf = malloc(sizeof(struct wait_conf)); -+ if (conf == NULL) { -+ SYSERROR("Failed to malloc."); -+ goto on_error; ++ if (gid != NULL) { ++ *group_id = (unsigned int)atoll(gid); + } + -+ memset(conf, 0x00, sizeof(struct wait_conf)); -+ -+ conf->pid = f->child_pid; -+ conf->startat = lxc_get_process_startat(conf->pid); ++ free(tmp); ++ return 0; ++} + -+ 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"); ++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; + } -+ 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; ++ gids_str = lxc_string_split(add_gids, ','); ++ if (gids_str == NULL) { ++ ERROR("Failed to split additional gids"); ++ return -1; + } + -+ 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; ++ len = lxc_array_len((void **)gids_str); ++ if (len > max_gids) { ++ ERROR("Too many gids"); ++ return -1; + } + -+ return 0; ++ g = calloc(len, sizeof(gid_t)); ++ if (g == NULL) { ++ ERROR("Out of memory"); ++ return -1; ++ } + -+on_error: -+ if (f) { -+ if (f->pipe >= 0) -+ close(f->pipe); -+ free(f); ++ 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; + } + -+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); ++ *gids = g; ++ *gids_len = len; ++ return 0; + -+ free(err_args_msg); -+ free(err_envs_msg); ++err_out: ++ free(g); + return -1; +} ++#endif + -+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; + 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 + -+ INFO("Executing script \"%s\" for container \"%s\", config section \"%s\".", -+ script, name, section); ++/*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; + -+ inmsg = generate_json_str(name, lxcpath, rootfs); -+ if (!inmsg) { -+ return -1; ++ 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 = run_ocihook_buffer(oconf, inmsg); -+ free(inmsg); -+ inmsg = NULL; -+ return ret; -+} ++ ret = lxc_wait_for_pid_status(pid); ++ if (ret < 0) { ++ free(*errmsg); ++ *errmsg = safe_strdup("Internal error, failed to wait attached process"); ++ goto out; ++ } + -+static char *get_root_path(const char *path, const char *backend) -+{ -+ char *ret = NULL; -+ char *tmp = NULL; ++ if (WIFEXITED(ret)) ++ wexit = WEXITSTATUS(ret); ++ else ++ wexit = -1; + -+ if (!path) { -+ ret = safe_strdup("/"); -+ return ret; -+ } -+ if (!backend) { -+ goto default_out; ++ if (WIFSIGNALED(ret)) { ++ signal = WTERMSIG(ret); ++ wexit = EXIT_SIGNAL_OFFSET + signal; + } + -+ 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; -+ } ++ WARN("Execd pid %d exit with %d", pid, wexit); + -+default_out: -+ ret = safe_strdup(path); -+ return ret; ++out: ++ if (c->lxc_conf->errmsg) { ++ free(*errmsg); ++ *errmsg = safe_strdup(c->lxc_conf->errmsg); ++ } ++ return wexit; +} + -+static int do_run_oci_hooks(const char *name, const char *lxcpath, struct lxc_conf *lc, int which, int errfd) ++static void close_msg_pipe(int *errpipe) +{ -+ 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; ++ if (errpipe[0] >= 0) { ++ close(errpipe[0]); ++ errpipe[0] = -1; + } -+ -+ 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 (errpipe[1] >= 0) { ++ close(errpipe[1]); ++ errpipe[1] = -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); ++/*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; + } -+ break; -+ default: ++ ++ 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; + } -+ if (rootpath) -+ free(rootpath); -+ return ret; ++ ++ 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 run_oci_hooks(const char *name, const char *hookname, struct lxc_conf *conf, const char *lxcpath) ++int main(int argc, char *argv[]) +{ -+ int which = -1; -+ -+ if (strcmp(hookname, "oci-prestart") == 0) { -+ which = OCI_HOOK_PRESTART; -+ if (!lxcpath) { -+ ERROR("oci hook require lxcpath"); -+ return -1; ++ 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); + } -+ 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; ++ ++ 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); + } -+ 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; ++ ++ 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 -+ return -1; ++ } + -+ return 0; -+} ++ if (!c->may_control(c)) { ++ ERROR("Insufficent privileges to control %s", c->name); ++ lxc_container_put(c); ++ exit(EXIT_FAILURE); ++ } + -+/*isulad clear init args*/ -+int lxc_clear_init_args(struct lxc_conf *lxc_conf) -+{ -+ int i; ++ if (remount_sys_proc) ++ attach_options.attach_flags |= LXC_ATTACH_REMOUNT_PROC_SYS; + -+ for (i = 0; i < lxc_conf->init_argc; i++) { -+ free(lxc_conf->init_argv[i]); -+ lxc_conf->init_argv[i] = NULL; ++ 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; + } -+ free(lxc_conf->init_argv); -+ lxc_conf->init_argv = NULL; -+ lxc_conf->init_argc = 0; + -+ return 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; + -+/*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.argc > 0) { ++ command.program = my_args.argv[0]; ++ command.argv = (char**)my_args.argv; ++ } + -+ return 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); ++ } ++ } + -+/*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.uid != LXC_INVALID_UID) ++ attach_options.uid = my_args.uid; + -+ 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; -+} ++ if (my_args.gid != LXC_INVALID_GID) ++ attach_options.gid = my_args.gid; + -+/*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; ++ attach_options.suffix = my_args.suffix; + -+ lxc_list_for_each_safe(it, &c->rootfs.maskedpaths, next) { -+ lxc_list_del(it); -+ free(it->elem); -+ free(it); ++ if (my_args.disable_pty) { ++ attach_options.disable_pty = true; + } -+ 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; ++ if (my_args.open_stdin) { ++ attach_options.open_stdin = true; ++ } + -+ lxc_list_for_each_safe(it, &c->rootfs.ropaths, next) { -+ lxc_list_del(it); -+ free(it->elem); -+ free(it); ++ if (my_args.workdir) { ++ attach_options.initial_cwd = my_args.workdir; + } -+ return 0; -+} + -+/*isulad: close error pipe */ -+void lxc_close_error_pipe(int *errpipe) -+{ -+ if (errpipe[0] >= 0) { -+ close(errpipe[0]); -+ errpipe[0] = -1; ++ if (my_args.add_gids) { ++ attach_options.add_gids = my_args.add_gids; ++ attach_options.add_gids_len = my_args.add_gids_len; + } -+ if (errpipe[1] >= 0) { -+ close(errpipe[1]); -+ errpipe[1] = -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); + } -+} -+#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]; - -+#ifdef HAVE_ISULAD -+ unsigned long pflags; + -+ if (parse_mntopts(mntent.mnt_opts, &flags, &pflags, &mntdata) < 0) -+ goto err; ++ lxc_container_put(c); ++ if (wexit >= 0) ++ exit(wexit); ++ ++ exit(EXIT_FAILURE); ++} +#else - if (parse_mntopts(mntent.mnt_opts, &flags, &mntdata) < 0) - goto err; -+#endif - - 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 @@ + int main(int argc, char *argv[]) + { + int ret = -1; +@@ -408,3 +883,4 @@ out: - lxc_log_define(execute, start); + exit(EXIT_FAILURE); + } ++#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" +#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) ++#include ++#include "isulad_utils.h" +#endif - { - 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]); ++ + lxc_log_define(lxc_start, lxc); + 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 -+ lxc_write_error_message(fd, "Failed to exec: \"%s\": %s.", argv[0], strerror(errno)); ++ {"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 - free(argv); - out1: - return 1; -@@ -88,14 +95,26 @@ static struct lxc_operations execute_start_ops = { - .post_start = execute_post_start + LXC_COMMON_OPTIONS }; +@@ -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 -+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) ++"\ ++ --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 - { -+ - struct execute_args args = {.argv = argv, .quiet = quiet}; - - TRACE("Doing lxc_execute"); - handler->conf->is_execute = true; ++, + .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; +#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); ++ 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; } -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; - } +@@ -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; + } +#ifdef HAVE_ISULAD -+ssize_t lxc_write_nointr_for_fifo(int fd, const char *buf, size_t count) -+{ -+ ssize_t nret = 0; -+ ssize_t nwritten; ++ /* 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 (buf == NULL) { -+ return -1; -+ } ++ 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]); ++ } + -+ 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; -+ } -+ } ++ /* 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); ++ } + -+ return nwritten; -+} -+#endif ++ if (my_args.disable_pty) { ++ c->want_disable_pty(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; -+} ++ if (my_args.open_stdin) { ++ c->want_open_stdin(c, true); ++ } + -+static int apparmor_relabel(const char *path, const char *label, bool shared) { -+ return 0; -+} ++ /* isulad: add start timeout */ ++ if(my_args.start_timeout) { ++ c->set_start_timeout(c, my_args.start_timeout); ++ } +#endif + - 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 */ + 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) { +#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 */ ++ 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"); - /* 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 + if (my_args.daemonize) +@@ -318,5 +420,8 @@ int main(int argc, char *argv[]) + out: + lxc_container_put(c); +#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 ++ free(container_info_file); +#endif -+ - extern int lxc_arguments_parse(struct lxc_arguments *args, int argc, - char *const argv[]); - + exit(err); + } -- 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 deleted file mode 100644 index c7e81d3b3785ced80900ba2700ececb6ec2c4e46..0000000000000000000000000000000000000000 --- a/0003-refactor-patch-code-of-isulad-for-selinux-attach.patch +++ /dev/null @@ -1,1243 +0,0 @@ -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-refactor-patch-code-of-lxccontianer-and-so-on.patch b/0004-refactor-patch-code-of-lxccontianer-and-so-on.patch deleted file mode 100644 index 3afaced4eaad32ea7ee445c6da8e8f36ff3f62cd..0000000000000000000000000000000000000000 --- a/0004-refactor-patch-code-of-lxccontianer-and-so-on.patch +++ /dev/null @@ -1,2947 +0,0 @@ -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: WangFengTu ---- - 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/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; - -+#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 4c27e7d..22d7255 100644 ---- a/src/lxc/confile.c -+++ b/src/lxc/confile.c -@@ -147,6 +147,19 @@ lxc_config_define(tty_dir); - lxc_config_define(uts_name); - lxc_config_define(sysctl); - lxc_config_define(proc); -+#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); -+lxc_config_define(rootfs_ro_paths); -+lxc_config_define(systemd); -+lxc_config_define(console_log_driver); -+lxc_config_define(console_syslog_tag); -+lxc_config_define(console_syslog_facility); -+lxc_config_define(selinux_mount_context); -+#endif - - /* - * 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, }, -+ { "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, }, -+#endif - }; - - 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 */ -+ replaced = lxc_string_replace(SPACE_MAGIC_STR, " ", value); -+ if(!replaced) -+ goto on_error; -+ -+ list_item->elem = replaced; -+#else - list_item->elem = strdup(value); -+#endif - } - - 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) { - ERROR("The \"lxc.console.rotate\" config key can only be set " - "to 0 or 1"); - return -1; - } -+#endif - - return 0; - } -@@ -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; - }; - -+#ifdef HAVE_ISULAD -+// escape_string_decode compress some escape characters -+static char *escape_string_decode(const char *src) -+{ -+ size_t src_end = 0; -+ size_t dst_end = 0; -+ size_t len = 0; -+ char *dst = NULL; -+ -+ if (src == NULL) { -+ return NULL; -+ } -+ -+ len = strlen(src); -+ if (len == 0) { -+ return NULL; -+ } -+ -+ dst = calloc(1, len + 1); -+ if (dst == NULL) { -+ ERROR("Out of memory"); -+ return NULL; -+ } -+ -+ while(src_end < len) { -+ if (src[src_end] == '\\') { -+ switch (src[++src_end]) -+ { -+ case 'r': dst[dst_end] = '\r'; break; -+ case 'n': dst[dst_end] = '\n'; break; -+ case 'f': dst[dst_end] = '\f'; break; -+ case 'b': dst[dst_end] = '\b'; break; -+ case 't': dst[dst_end] = '\t'; break; -+ case '\\': dst[dst_end] = '\\'; break; -+ // default do not decode -+ default: dst[dst_end++] = '\\'; dst[dst_end] = src[src_end]; break; -+ } -+ } else { -+ dst[dst_end] = src[src_end]; -+ } -+ dst_end++; -+ src_end++; -+ } -+ -+ return dst; -+} -+#endif -+ - static int parse_line(char *buffer, void *data) - { - 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 -+ char *value_decode = NULL; -+#endif - - /* 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; - } - -+#ifdef HAVE_ISULAD -+ value_decode = escape_string_decode(value); -+ if (value_decode == NULL) { -+ ERROR("Value %s decode failed", value); -+ } -+ ret = config->set(key, value_decode ? value_decode: value, plc->conf, NULL); -+#else - ret = config->set(key, value, plc->conf, NULL); -+#endif - - 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; -+#ifdef HAVE_ISULAD -+ if (strcmp(new_item->key, LXC_IMAGE_OCI_KEY) == 0) { -+ c->set_oci_type(c, true); -+ continue; -+ } -+#endif - bret = c->set_config_item(c, new_item->key, new_item->val); - if (!bret) - break; -@@ -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, -+ struct lxc_conf *lxc_conf, void *data) -+{ -+ int ret = 0; -+ char **tmp = NULL; -+ char *new_value = NULL; -+ -+ ret = set_config_string_item(&new_value, value); -+ if (ret || !new_value) -+ return ret; -+ -+ tmp = (char **)realloc(lxc_conf->init_argv, (lxc_conf->init_argc + 1) * sizeof(char *)); -+ if (!tmp) { -+ ERROR("Out of memory"); -+ free(new_value); -+ return -1; -+ } -+ -+ lxc_conf->init_argv = tmp; -+ -+ lxc_conf->init_argv[lxc_conf->init_argc] = new_value; -+ lxc_conf->init_argc++; -+ -+ return 0; -+} -+ -+/* isulad: get config init args */ -+static int get_config_init_args(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_argc; i++) { -+ strprint(retv, inlen, "%s", c->init_argv[i]); -+ } -+ -+ return fulllen; -+} -+ -+/* isulad: clr config init args*/ -+static inline int clr_config_init_args(const char *key, struct lxc_conf *c, -+ void *data) -+{ -+ 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) -+{ -+ int ret = 0, major = 0, minor = 0; -+ uid_t uid = (uid_t)-1; -+ gid_t gid = (gid_t)-1; -+ char name[4096] = {0}; /* MAX dev path name */ -+ char type[3] = {0}; -+ char *replace_value = NULL; -+ mode_t filemode = 0; -+ struct lxc_list *iter = NULL; -+ struct lxc_list *dev_list = NULL; -+ struct lxc_populate_devs *dev_elem = NULL; -+ -+ if (lxc_config_value_empty(value)) -+ return lxc_clear_populate_devices(lxc_conf); -+ -+ /* lxc.populate.device = PATH_IN_CONTAINER:DEVICETYPE:MAJOR:MINOR:MODE:UID:GID -+ * For e.g. lxc.populate.device = /dev/sda:b:8:0:0666:0:0 -+ */ -+ ret = sscanf(value, "%4095[^:]:%2[^:]:%i:%i:%i:%u:%u", name, type, &major, &minor, &filemode, &uid, &gid); -+ if (ret != 7) -+ return -1; -+ -+ /* find existing list element */ -+ lxc_list_for_each(iter, &lxc_conf->populate_devs) { -+ dev_elem = iter->elem; -+ -+ if (strcmp(name, dev_elem->name) != 0) -+ continue; -+ -+ replace_value = safe_strdup(type); -+ -+ free(dev_elem->type); -+ dev_elem->type = replace_value; -+ dev_elem->file_mode = filemode; -+ dev_elem->maj = major; -+ dev_elem->min = minor; -+ dev_elem->uid = (uid_t)uid; -+ dev_elem->gid = (gid_t)gid; -+ return 0; -+ } -+ -+ /* allocate list element */ -+ dev_list = malloc(sizeof(*dev_list)); -+ if (dev_list == NULL) -+ goto on_error; -+ -+ lxc_list_init(dev_list); -+ -+ dev_elem = malloc(sizeof(*dev_elem)); -+ if (dev_elem == NULL) -+ goto on_error; -+ memset(dev_elem, 0, sizeof(*dev_elem)); -+ -+ dev_elem->name = safe_strdup(name); -+ -+ dev_elem->type = safe_strdup(type); -+ -+ dev_elem->file_mode = filemode; -+ dev_elem->maj = major; -+ dev_elem->min = minor; -+ dev_elem->uid = (uid_t)uid; -+ dev_elem->gid = (gid_t)gid; -+ -+ lxc_list_add_elem(dev_list, dev_elem); -+ -+ lxc_list_add_tail(&lxc_conf->populate_devs, dev_list); -+ -+ return 0; -+ -+on_error: -+ free(dev_list); -+ if (dev_elem) { -+ free(dev_elem->name); -+ free(dev_elem->type); -+ free(dev_elem); -+ } -+ return -1; -+} -+ -+/* isulad: get config populate device -+ * If you ask for 'lxc.populate.device', then all populate device -+ * entries will be printed, in 'lxc.populate.device = path_in_container:type:major:minor:mode:uid:gid' format. -+ * For e.g. lxc.populate.device = /dev/sda:b:8:0:0666:0:0 -+ */ -+static int get_config_populate_device(const char *key, char *retv, int inlen, -+ struct lxc_conf *c, void *data) -+{ -+ int len; -+ struct lxc_list *it = NULL; -+ int fulllen = 0; -+ -+ if (!retv) -+ inlen = 0; -+ else -+ memset(retv, 0, inlen); -+ -+ lxc_list_for_each(it, &c->populate_devs) { -+ struct lxc_populate_devs *elem = it->elem; -+ strprint(retv, inlen, "lxc.populate.device = %s:%s:%d:%d:%o:%u:%u\n", -+ elem->name, elem->type, elem->maj, -+ elem->min, elem->file_mode, elem->uid, elem->gid); -+ } -+ -+ return fulllen; -+} -+ -+/* isulad: clr config populate devices*/ -+static inline int clr_config_populate_device(const char *key, struct lxc_conf *c, -+ void *data) -+{ -+ return lxc_clear_populate_devices(c); -+} -+ -+/* isulad: set config for umask */ -+static int set_config_umask(const char *key, const char *value, -+ struct lxc_conf *lxc_conf, void *data) -+{ -+ if (lxc_config_value_empty(value)) { -+ ERROR("Empty umask"); -+ return -1; -+ } -+ -+ if (strcmp(value, "normal") == 0) { -+ lxc_conf->umask = 0022; -+ return 0; -+ } else if (strcmp(value, "secure") == 0) { -+ lxc_conf->umask = 0027; -+ return 0; -+ } else { -+ ERROR("Invalid native umask: %s", value); -+ return -1; -+ } -+} -+ -+/* isulad add: get umask value*/ -+static int get_config_umask(const char *key, char *retv, int inlen, -+ struct lxc_conf *c, void *data) -+{ -+ return lxc_get_conf_size_t(c, retv, inlen, c->umask); -+} -+ -+/* isulad add: clear umask value */ -+static inline int clr_config_umask(const char *key, struct lxc_conf *c, -+ void *data) -+{ -+ c->umask = 0027; -+ return 0; -+} -+ -+/* isulad: set config for rootfs masked paths */ -+static int set_config_rootfs_masked_paths(const char *key, const char *value, -+ struct lxc_conf *lxc_conf, void *data) -+{ -+ struct lxc_list *list_item = NULL; -+ -+ if (lxc_config_value_empty(value)) -+ return lxc_clear_rootfs_masked_paths(lxc_conf); -+ -+ list_item = malloc(sizeof(*list_item)); -+ if (list_item == NULL) -+ goto on_error; -+ -+ list_item->elem = safe_strdup(value); -+ -+ lxc_list_add_tail(&lxc_conf->rootfs.maskedpaths, list_item); -+ -+ return 0; -+ -+on_error: -+ free(list_item); -+ -+ return -1; -+} -+ -+// isulad: get config rootfs masked paths -+static int get_config_rootfs_masked_paths(const char *key, char *retv, int inlen, -+ struct lxc_conf *c, void *data) -+{ -+ int len, fulllen = 0; -+ struct lxc_list *it = NULL; -+ -+ if (!retv) -+ inlen = 0; -+ else -+ memset(retv, 0, inlen); -+ -+ lxc_list_for_each(it, &c->rootfs.maskedpaths) { -+ strprint(retv, inlen, "%s\n", (char *)it->elem); -+ } -+ -+ return fulllen; -+} -+ -+/* isulad: set config for rootfs ro paths */ -+static int set_config_rootfs_ro_paths(const char *key, const char *value, -+ struct lxc_conf *lxc_conf, void *data) -+{ -+ struct lxc_list *list_item = NULL; -+ -+ if (lxc_config_value_empty(value)) -+ return lxc_clear_rootfs_ro_paths(lxc_conf); -+ -+ list_item = malloc(sizeof(*list_item)); -+ if (list_item == NULL) -+ goto on_error; -+ -+ list_item->elem = safe_strdup(value); -+ -+ lxc_list_add_tail(&lxc_conf->rootfs.ropaths, list_item); -+ -+ return 0; -+ -+on_error: -+ free(list_item); -+ -+ return -1; -+} -+ -+// isulad: get config rootfs ro paths -+static int get_config_rootfs_ro_paths(const char *key, char *retv, int inlen, -+ struct lxc_conf *c, void *data) -+{ -+ int len, fulllen = 0; -+ struct lxc_list *it = NULL; -+ -+ if (!retv) -+ inlen = 0; -+ else -+ memset(retv, 0, inlen); -+ -+ lxc_list_for_each(it, &c->rootfs.ropaths) { -+ strprint(retv, inlen, "%s\n", (char *)it->elem); -+ } -+ -+ return fulllen; -+} -+ -+/* isulad: clr config rootfs masked paths */ -+static inline int clr_config_rootfs_masked_paths(const char *key, struct lxc_conf *c, -+ void *data) -+{ -+ return lxc_clear_rootfs_masked_paths(c); -+} -+ -+/* isulad: clr config rootfs ro paths */ -+static inline int clr_config_rootfs_ro_paths(const char *key, struct lxc_conf *c, -+ void *data) -+{ -+ return lxc_clear_rootfs_ro_paths(c); -+} -+ -+/* isulad: set config for systemd */ -+static int set_config_systemd(const char *key, const char *value, -+ struct lxc_conf *lxc_conf, void *data) -+{ -+ if (lxc_config_value_empty(value)) { -+ ERROR("Empty umask"); -+ return -1; -+ } -+ lxc_conf->systemd = strdup(value); -+ return 0; -+} -+ -+/* isulad add: get systemd value*/ -+static int get_config_systemd(const char *key, char *retv, int inlen, -+ struct lxc_conf *c, void *data) -+{ -+ return lxc_get_conf_str(retv, inlen, c->systemd); -+} -+ -+/* isulad add: clear systemd value */ -+static inline int clr_config_systemd(const char *key, struct lxc_conf *c, -+ void *data) -+{ -+ free(c->systemd); -+ c->systemd = NULL; -+ return 0; -+} -+ -+static int set_config_console_log_driver(const char *key, const char *value, -+ struct lxc_conf *lxc_conf, void *data) -+{ -+ return set_config_string_item(&lxc_conf->console.log_driver, value); -+} -+ -+static int set_config_console_syslog_tag(const char *key, const char *value, -+ struct lxc_conf *lxc_conf, void *data) -+{ -+ if (value == NULL) { -+ return -1; -+ } -+ return set_config_string_item(&lxc_conf->console.log_syslog_tag, value); -+} -+ -+static int parse_facility(const char *facility) -+{ -+#define FACILITIES_LEN 20 -+ const char *facility_keys[FACILITIES_LEN] = { -+ "kern", "user", "mail", "daemon", "auth", -+ "syslog", "lpr", "news", "uucp", "cron", "authpriv", "ftp", -+ "local0", "local1", "local2", "local3", "local4", "local5", "local6", "local7" -+ }; -+ const int facilities[FACILITIES_LEN] = { -+ LOG_KERN, LOG_USER, LOG_MAIL, LOG_DAEMON, LOG_AUTH, LOG_SYSLOG, -+ LOG_LPR, LOG_NEWS, LOG_UUCP, LOG_CRON, LOG_AUTHPRIV, LOG_FTP, -+ LOG_LOCAL0, LOG_LOCAL1, LOG_LOCAL2, LOG_LOCAL3, LOG_LOCAL4, -+ LOG_LOCAL5, LOG_LOCAL6, LOG_LOCAL7 -+ }; -+ int i = 0; -+ -+ if (facility == NULL) { -+ return -1; -+ } -+ -+ for (; i < FACILITIES_LEN; i++) { -+ if (strcmp(facility, facility_keys[i]) == 0) { -+ return facilities[i]; -+ } -+ } -+ -+ return -1; -+} -+ -+static int set_config_console_syslog_facility(const char *key, const char *value, -+ struct lxc_conf *lxc_conf, void *data) -+{ -+ int facility; -+ -+ facility = parse_facility(value); -+ if (facility < 0) { -+ NOTICE("Invalid facility: %s", value); -+ facility = LOG_DAEMON; -+ } -+ -+ lxc_conf->console.log_syslog_facility = facility; -+ return 0; -+} -+ -+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->lsm_se_mount_context, value); -+} -+ -+static int get_config_console_log_driver(const char *key, char *retv, int inlen, -+ struct lxc_conf *c, void *data) -+{ -+ return lxc_get_conf_str(retv, inlen, c->console.log_driver); -+} -+ -+static int get_config_console_syslog_tag(const char *key, char *retv, int inlen, -+ struct lxc_conf *c, void *data) -+{ -+ return lxc_get_conf_str(retv, inlen, c->console.log_syslog_tag); -+} -+ -+static int get_config_console_syslog_facility(const char *key, char *retv, int inlen, -+ struct lxc_conf *c, void *data) -+{ -+ return lxc_get_conf_int(c, retv, inlen, c->console.log_syslog_facility); -+} -+ -+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); -+} -+ -+static inline int clr_config_console_log_driver(const char *key, -+ struct lxc_conf *c, void *data) -+{ -+ free(c->console.log_driver); -+ c->console.log_driver = NULL; -+ return 0; -+} -+ -+static inline int clr_config_console_syslog_tag(const char *key, -+ struct lxc_conf *c, void *data) -+{ -+ free(c->console.log_syslog_tag); -+ c->console.log_syslog_tag= NULL; -+ return 0; -+} -+ -+static inline int clr_config_console_syslog_facility(const char *key, -+ struct lxc_conf *c, void *data) -+{ -+ c->console.log_syslog_facility = LOG_DAEMON; -+ return 0; -+} -+ -+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; -+ return 0; -+} -+#endif -diff --git a/src/lxc/lxccontainer.c b/src/lxc/lxccontainer.c -index aac6214..3f75184 100644 ---- a/src/lxc/lxccontainer.c -+++ b/src/lxc/lxccontainer.c -@@ -62,6 +62,10 @@ - #include "utils.h" - #include "version.h" - -+#ifdef HAVE_ISULAD -+#include "exec_commands.h" -+#endif -+ - #if HAVE_OPENSSL - #include - #endif -@@ -83,6 +87,11 @@ - - lxc_log_define(lxccontainer, lxc); - -+#ifdef HAVE_ISULAD -+typedef bool (*func_is_io_stat_read)(const char *value); -+typedef bool (*func_is_io_stat_write)(const char *value); -+#endif -+ - 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) -@@ -281,6 +290,13 @@ static void lxc_container_free(struct lxc_container *c) - free(c->config_path); - c->config_path = NULL; - -+#ifdef HAVE_ISULAD -+ free(c->exit_fifo); -+ c->exit_fifo = NULL; -+ free(c->ocihookfile); -+ c->ocihookfile = NULL; -+#endif -+ - free(c); - } - -@@ -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; - } - -+#ifdef HAVE_ISULAD -+static bool load_ocihooks_locked(struct lxc_container *c) -+{ -+ parser_error err = NULL; -+ oci_runtime_spec_hooks *hooks = NULL; -+ -+ if (!c->lxc_conf) -+ c->lxc_conf = lxc_conf_init(); -+ -+ if (!c->lxc_conf) -+ return false; -+ -+ hooks = oci_runtime_spec_hooks_parse_file(c->ocihookfile, NULL, &err); -+ if (!hooks) { -+ fprintf(stderr, "parse oci hooks config failed: %s\n", err); -+ free(err); -+ return true; -+ } -+ c->lxc_conf->ocihooks = hooks; -+ -+ if (err) -+ free(err); -+ return true; -+} -+ -+/* -+ * isulad: set oci hook file path -+ * */ -+static bool set_oci_hook_config_filename(struct lxc_container *c) -+{ -+#define OCI_HOOK_JSON_FILE_NAME "ocihooks.json" -+ char *newpath = NULL; -+ int len, ret; -+ -+ if (!c->config_path) -+ return false; -+ -+ /* $lxc_path + "/" + c->name + "/" + "config" + '\0' */ -+ if (strlen(c->config_path) + strlen(c->name) > SIZE_MAX - strlen(OCI_HOOK_JSON_FILE_NAME) - 3) -+ return false; -+ len = strlen(c->config_path) + strlen(c->name) + strlen(OCI_HOOK_JSON_FILE_NAME) + 3; -+ -+ newpath = malloc(len); -+ if (newpath == NULL) -+ return false; -+ -+ ret = snprintf(newpath, len, "%s/%s/%s", c->config_path, c->name, OCI_HOOK_JSON_FILE_NAME); -+ if (ret < 0 || ret >= len) { -+ fprintf(stderr, "Error printing out config file name\n"); -+ free(newpath); -+ return false; -+ } -+ -+ free(c->ocihookfile); -+ c->ocihookfile = newpath; -+ -+ return true; -+} -+#endif -+ - static bool do_lxcapi_load_config(struct lxc_container *c, const char *alt_file) - { - int lret; -@@ -656,6 +733,11 @@ static bool do_lxcapi_load_config(struct lxc_container *c, const char *alt_file) - - ret = load_config_locked(c, fname); - -+#ifdef HAVE_ISULAD -+ if (ret && file_exists(c->ocihookfile)) -+ ret = load_ocihooks_locked(c); -+#endif -+ - if (need_disklock) - container_disk_unlock(c); - else -@@ -855,6 +937,33 @@ static bool wait_on_daemonized_start(struct lxc_handler *handler, int pid) - return true; - } - -+#ifdef HAVE_ISULAD -+/* isulad: use init argv as init cmd */ -+static char **use_init_args(char **init_argv, size_t init_args) -+{ -+ size_t i; -+ int nargs = 0; -+ char **argv; -+ -+ if (!init_argv) -+ return NULL; -+ -+ do { -+ argv = malloc(sizeof(char *)); -+ } while (!argv); -+ -+ argv[0] = NULL; -+ for (i = 0; i < init_args; i++) -+ push_arg(&argv, init_argv[i], &nargs); -+ -+ if (nargs == 0) { -+ free(argv); -+ return NULL; -+ } -+ return argv; -+} -+#endif -+ - static bool do_lxcapi_start(struct lxc_container *c, int useinit, char * const argv[]) - { - int ret; -@@ -865,6 +974,11 @@ static bool do_lxcapi_start(struct lxc_container *c, int useinit, char * const a - NULL, - }; - char **init_cmd = NULL; -+#ifdef HAVE_ISULAD -+ int keepfds[] = {-1, -1, -1, -1, -1}; -+ ssize_t size_read; -+ char errbuf[BUFSIZ + 1] = {0}; -+#endif - - /* container does exist */ - if (!c) -@@ -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); - } - -+#ifdef HAVE_ISULAD -+ if (!argv) { -+ argv = init_cmd = use_init_args(conf->init_argv, conf->init_argc); -+ } -+ -+ if (c->image_type_oci) { -+ handler->image_type_oci = true; -+ } -+#endif -+ - /* ... otherwise use default_args. */ - if (!argv) { - if (useinit) { -@@ -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; - -+#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"); -+ free_init_cmd(init_cmd); -+ lxc_put_handler(handler); -+ return false; -+ } -+#endif -+ - pid_first = fork(); - if (pid_first < 0) { - free_init_cmd(init_cmd); - lxc_put_handler(handler); -+#ifdef HAVE_ISULAD -+ lxc_close_error_pipe(conf->errpipe); -+#endif - return false; - } - -@@ -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; -+#ifdef HAVE_ISULAD -+ close(conf->errpipe[1]); -+ conf->errpipe[1] = -1; -+#endif - - /* Wait for container to tell us whether it started - * successfully. - */ - started = wait_on_daemonized_start(handler, pid_first); -+#ifdef HAVE_ISULAD -+ if (!started) { -+ size_read = read(conf->errpipe[0], errbuf, BUFSIZ); -+ if (size_read > 0) { -+ conf->errmsg = safe_strdup(errbuf); -+ } -+ } -+ close(conf->errpipe[0]); -+ conf->errpipe[0] = -1; -+#endif - - free_init_cmd(init_cmd); - lxc_put_handler(handler); -@@ -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); -+#ifdef HAVE_ISULAD -+ lxc_close_error_pipe(conf->errpipe); -+#endif - _exit(EXIT_SUCCESS); - } - -@@ -995,7 +1149,18 @@ static bool do_lxcapi_start(struct lxc_container *c, int useinit, char * const a - _exit(EXIT_FAILURE); - } - -+#ifdef HAVE_ISULAD -+ keepfds[0] = handler->conf->maincmd_fd; -+ keepfds[1] = handler->state_socket_pair[0]; -+ keepfds[2] = handler->state_socket_pair[1]; -+ keepfds[4] = conf->errpipe[1]; -+ close(conf->errpipe[0]); -+ conf->errpipe[0] = -1; -+ ret = lxc_check_inherited(conf, true, keepfds, -+ sizeof(keepfds) / sizeof(keepfds[0])); -+#else - ret = inherit_fds(handler, true); -+#endif - if (ret < 0) - _exit(EXIT_FAILURE); - -@@ -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 -+ lxc_close_error_pipe(conf->errpipe); -+#endif - - SYSERROR("Failed to write monitor pid to \"%s\"", c->pidfile); - -@@ -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); -+#ifdef HAVE_ISULAD -+ lxc_close_error_pipe(conf->errpipe); -+#endif - - SYSERROR("Failed to write monitor pid to \"%s\"", c->pidfile); - -@@ -1051,6 +1222,19 @@ static bool do_lxcapi_start(struct lxc_container *c, int useinit, char * const a - } - } - -+#ifdef HAVE_ISULAD -+ /* isulad: open exit fifo */ -+ if (c->exit_fifo) { -+ conf->exit_fd = lxc_open(c->exit_fifo, O_WRONLY | O_NONBLOCK | O_CLOEXEC, 0); -+ if (conf->exit_fd < 0) { -+ ERROR("Failed to open exit fifo %s: %s.", c->exit_fifo, strerror(errno)); -+ lxc_put_handler(handler); -+ ret = 1; -+ goto on_error; -+ } -+ } -+#endif -+ - conf->reboot = REBOOT_NONE; - - /* Unshare the mount namespace if requested */ -@@ -1082,19 +1266,53 @@ reboot: - } - } - -+#ifdef HAVE_ISULAD -+ keepfds[0] = handler->conf->maincmd_fd; -+ keepfds[1] = handler->state_socket_pair[0]; -+ keepfds[2] = handler->state_socket_pair[1]; -+ -+ /* keep exit fifo fd */ -+ if (conf->exit_fd >= 0) { -+ keepfds[3] = conf->exit_fd; -+ } -+ /* isulad: keep errpipe fd */ -+ if (c->daemonize) -+ keepfds[4] = conf->errpipe[1]; -+ -+ ret = lxc_check_inherited(conf, c->daemonize, keepfds, -+ sizeof(keepfds) / sizeof(keepfds[0])); -+ if (ret < 0) { -+ lxc_put_handler(handler); -+ ret = 1; -+ goto on_error; -+ } -+#else - ret = inherit_fds(handler, c->daemonize); - if (ret < 0) { - lxc_put_handler(handler); - ret = 1; - goto on_error; - } -+#endif - -+#ifndef HAVE_ISULAD - if (useinit) - ret = lxc_execute(c->name, argv, 1, handler, c->config_path, - c->daemonize, &c->error_num); - else - ret = lxc_start(argv, handler, c->config_path, c->daemonize, - &c->error_num); -+#else -+ if (useinit) { -+ ret = lxc_execute(c->name, argv, 1, handler, c->config_path, -+ c->daemonize, &c->error_num, c->start_timeout); -+ } else { -+ handler->disable_pty = c->disable_pty; -+ handler->open_stdin = c->open_stdin; -+ ret = lxc_start(argv, handler, c->config_path, c->daemonize, -+ &c->error_num, c->start_timeout); -+ } -+#endif - - if (conf->reboot == REBOOT_REQ) { - INFO("Container requested reboot"); -@@ -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; -+#ifdef HAVE_ISULAD -+ // isulad: keep default signal the same as docker -+ int haltsignal = SIGTERM; -+#else - int haltsignal = SIGPWR; -+#endif - pid_t pid = -1; - lxc_state_t states[MAX_STATE] = {0}; - int killret, ret; -@@ -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; -+#ifndef HAVE_ISULAD - else if (task_blocks_signal(pid, (SIGRTMIN + 3))) - haltsignal = (SIGRTMIN + 3); -- -+#endif - - /* - * Add a new state client before sending the shutdown signal so -@@ -2938,6 +3173,21 @@ static int lxc_unlink_exec_wrapper(void *data) - return unlink(arg); - } - -+#ifdef HAVE_ISULAD -+static void container_sock_dir_delete(const char *name) -+{ -+ __do_free char *sock_dir = NULL; -+ -+ sock_dir = generate_named_unix_sock_dir(name); -+ if (sock_dir == NULL) { -+ ERROR("Failed to generate exec unix sock dir"); -+ return; -+ } -+ -+ (void)lxc_rmdir_onedev(sock_dir, NULL); -+} -+#endif -+ - static bool container_destroy(struct lxc_container *c, - struct lxc_storage *storage) - { -@@ -2948,8 +3198,19 @@ static bool container_destroy(struct lxc_container *c, - bool bret = false; - int ret = 0; - -+#ifdef HAVE_ISULAD -+ if (!c) -+ return false; -+ // isulad: if container is not defined, we need to remove disk lock file -+ // which is created in lxc_container_new. -+ if (!do_lxcapi_is_defined(c)) { -+ container_disk_removelock(c); -+ return false; -+ } -+#else - if (!c || !do_lxcapi_is_defined(c)) - return false; -+#endif - - conf = c->lxc_conf; - if (container_disk_lock(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); -+#ifdef HAVE_ISULAD -+ char msg[BUFSIZ] = { 0 }; -+ ret = snprintf(msg, BUFSIZ, "Failed to destroy directory \"%s\": %s", path, errno ? strerror(errno) : "error"); -+ if (ret < 0 || ret >= BUFSIZ) { -+ ERROR("Sprintf failed"); -+ goto out; -+ } -+ c->error_string = safe_strdup(msg); -+#endif - goto out; - } -+#ifdef HAVE_ISULAD -+ container_sock_dir_delete(c->name); -+#endif - INFO("Destroyed directory \"%s\" for \"%s\"", path, c->name); - - on_success: -@@ -3081,6 +3354,11 @@ out: - free(path); - - container_disk_unlock(c); -+#ifdef HAVE_ISULAD -+ if (bret && container_disk_removelock(c)) { -+ bret = false; -+ } -+#endif - return bret; - } - -@@ -4030,8 +4308,13 @@ static int lxcapi_attach(struct lxc_container *c, - - current_config = c->lxc_conf; - -+#ifdef HAVE_ISULAD -+ ret = lxc_attach(c, exec_function, exec_payload, options, -+ attached_process, &c->lxc_conf->errmsg); -+#else - ret = lxc_attach(c, exec_function, exec_payload, options, - attached_process); -+#endif - current_config = NULL; - return ret; - } -@@ -4051,7 +4334,11 @@ static int do_lxcapi_attach_run_wait(struct lxc_container *c, - command.program = (char *)program; - command.argv = (char **)argv; - -+#ifdef HAVE_ISULAD -+ ret = lxc_attach(c, lxc_attach_run_command, &command, options, &pid, NULL); -+#else - ret = lxc_attach(c, lxc_attach_run_command, &command, options, &pid); -+#endif - if (ret < 0) - return ret; - -@@ -5230,7 +5517,561 @@ static int do_lxcapi_seccomp_notify_fd(struct lxc_container *c) - - WRAP_API(int, lxcapi_seccomp_notify_fd) - -+#ifdef HAVE_ISULAD -+/* isulad add set console fifos*/ -+static bool do_lxcapi_set_terminal_default_fifos(struct lxc_container *c, const char *in, const char *out, const char *err) -+{ -+ struct lxc_conf *conf = NULL; -+ -+ if (!c || !c->lxc_conf) -+ return false; -+ if (container_mem_lock(c)) { -+ ERROR("Error getting mem lock"); -+ return false; -+ } -+ -+ conf = c->lxc_conf; -+ if (in) { -+ if (conf->console.init_fifo[0]) -+ free(conf->console.init_fifo[0]); -+ conf->console.init_fifo[0] = safe_strdup(in); -+ } -+ if (out) { -+ if (conf->console.init_fifo[1]) -+ free(conf->console.init_fifo[1]); -+ conf->console.init_fifo[1] = safe_strdup(out); -+ } -+ if (err) { -+ if (conf->console.init_fifo[2]) -+ free(conf->console.init_fifo[2]); -+ conf->console.init_fifo[2] = safe_strdup(err); -+ } -+ -+ container_mem_unlock(c); -+ return true; -+} -+ -+WRAP_API_3(bool, lxcapi_set_terminal_default_fifos, const char *, const char *, const char *) -+ -+/* isulad add set info file path */ -+static bool do_lxcapi_set_container_info_file(struct lxc_container *c, const char *info_file) -+{ -+ struct lxc_conf *conf = NULL; -+ -+ if (!c || !c->lxc_conf || !info_file) -+ return false; -+ if (container_mem_lock(c)) { -+ ERROR("Error getting mem lock"); -+ return false; -+ } -+ -+ conf = c->lxc_conf; -+ if (conf->container_info_file) -+ free(conf->container_info_file); -+ conf->container_info_file = safe_strdup(info_file); -+ -+ container_mem_unlock(c); -+ return true; -+} -+ -+WRAP_API_1(bool, lxcapi_set_container_info_file, const char *) -+ -+static bool do_lxcapi_want_disable_pty(struct lxc_container *c, bool state) -+{ -+ if (!c || !c->lxc_conf) -+ return false; -+ -+ if (container_mem_lock(c)) -+ return false; -+ -+ c->disable_pty = state; -+ -+ container_mem_unlock(c); -+ -+ return true; -+} -+ -+WRAP_API_1(bool, lxcapi_want_disable_pty, bool) -+ -+static bool do_lxcapi_want_open_stdin(struct lxc_container *c, bool state) -+{ -+ if (!c || !c->lxc_conf) -+ return false; -+ -+ if (container_mem_lock(c)) -+ return false; -+ -+ c->open_stdin = state; -+ -+ container_mem_unlock(c); -+ -+ return true; -+} -+ -+WRAP_API_1(bool, lxcapi_want_open_stdin, bool) -+ -+/* isulad add clean resources */ -+static bool do_lxcapi_add_terminal_fifo(struct lxc_container *c, const char *in_fifo, const char *out_fifo, const char *err_fifo) -+{ -+ bool ret = true; -+ -+ if (!c || !c->lxc_conf) -+ return false; -+ if (container_mem_lock(c)) { -+ ERROR("Error getting mem lock"); -+ return false; -+ } -+ -+ if (lxc_cmd_set_terminal_fifos(c->name, c->config_path, in_fifo, out_fifo, err_fifo)) { -+ ERROR("Error set console fifos"); -+ ret = false; -+ } -+ -+ container_mem_unlock(c); -+ return ret; -+} -+ -+WRAP_API_3(bool, lxcapi_add_terminal_fifo, const char *, const char *, const char *) -+ -+static bool do_lxcapi_set_terminal_winch(struct lxc_container *c, unsigned int height, unsigned int width) -+{ -+ bool ret = true; -+ -+ if (!c || !c->lxc_conf) -+ return false; -+ if (container_mem_lock(c)) { -+ ERROR("Error getting mem lock"); -+ return false; -+ } -+ -+ if (lxc_cmd_set_terminal_winch(c->name, c->config_path, height, width)) { -+ ERROR("Error set terminal winch"); -+ ret = false; -+ } -+ -+ container_mem_unlock(c); -+ return ret; -+} -+ -+WRAP_API_2(bool, lxcapi_set_terminal_winch, unsigned int, unsigned int) -+ -+static bool do_lxcapi_set_exec_terminal_winch(struct lxc_container *c, const char *suffix, unsigned int height, unsigned int width) -+{ -+ bool ret = true; -+ -+ if (!c || !c->lxc_conf) -+ return false; -+ if (container_mem_lock(c)) { -+ ERROR("Error getting mem lock"); -+ return false; -+ } -+ -+ if (lxc_exec_cmd_set_terminal_winch(c->name, c->config_path, suffix, height, width)) { -+ ERROR("Error set terminal winch"); -+ ret = false; -+ } -+ -+ container_mem_unlock(c); -+ return ret; -+} -+ -+WRAP_API_3(bool, lxcapi_set_exec_terminal_winch, const char *, unsigned int, unsigned int) -+ -+/* isulad add clean resources */ -+static bool do_lxcapi_clean_container_resource(struct lxc_container *c, pid_t pid) -+{ -+ int ret; -+ -+ if (!c) -+ return false; -+ -+ ret = do_lxcapi_clean_resource(c->name, c->config_path, c->lxc_conf, pid); -+ if (ret) -+ ERROR("Failed to clean container %s resource", c->name); -+ return ret == 0; -+ -+} -+ -+WRAP_API_1(bool, lxcapi_clean_container_resource, pid_t) -+ -+/* isulad get coantainer pids */ -+static bool do_lxcapi_get_container_pids(struct lxc_container *c, pid_t **pids,size_t *pids_len) -+{ -+ int ret; -+ -+ if (!c) -+ return false; -+ -+ ret = do_lxcapi_get_pids(c->name, c->config_path, c->lxc_conf, pids,pids_len); -+ if (ret) -+ ERROR("Failed to get container %s pids", c->name); -+ return ret == 0; -+ -+} -+ -+WRAP_API_2(bool, lxcapi_get_container_pids, pid_t **,size_t *) -+ -+/* isulad add start timeout */ -+static bool do_lxcapi_set_start_timeout(struct lxc_container *c, unsigned int start_timeout) -+{ -+ if (!c || !c->lxc_conf) -+ return false; -+ if (container_mem_lock(c)) { -+ ERROR("Error getting mem lock"); -+ return false; -+ } -+ c->start_timeout = start_timeout; -+ container_mem_unlock(c); -+ return true; -+} -+ -+WRAP_API_1(bool, lxcapi_set_start_timeout, unsigned int) -+ -+/* isulad add set image type */ -+static bool do_lxcapi_set_oci_type(struct lxc_container *c, bool image_type_oci) -+{ -+ if (!c || !c->lxc_conf) -+ return false; -+ if (container_mem_lock(c)) { -+ ERROR("Error getting mem lock"); -+ return false; -+ } -+ c->image_type_oci = image_type_oci; -+ container_mem_unlock(c); -+ return true; -+} -+ -+WRAP_API_1(bool, lxcapi_set_oci_type, bool) -+ -+static uint64_t metrics_get_ull(struct lxc_container *c, struct cgroup_ops *cgroup_ops, const char *item) -+{ -+ char buf[81] = {0}; -+ int len = 0; -+ uint64_t val = 0; -+ -+ len = cgroup_ops->get(cgroup_ops, item, buf, sizeof(buf) - 1, c->name, c->config_path); -+ if (len <= 0) { -+ DEBUG("unable to read cgroup item %s", item); -+ return 0; -+ } -+ -+ val = strtoull(buf, NULL, 0); -+ return val; -+} -+ -+static uint64_t metrics_get_ull_with_max(struct lxc_container *c, struct cgroup_ops *cgroup_ops, const char *item) -+{ -+ char buf[81] = {0}; -+ int len = 0; -+ uint64_t val = 0; -+ -+ len = cgroup_ops->get(cgroup_ops, item, buf, sizeof(buf) - 1, c->name, c->config_path); -+ if (len <= 0) { -+ DEBUG("unable to read cgroup item %s", item); -+ return 0; -+ } -+ -+ if (strcmp(buf, "max") == 0) { -+ return ULONG_MAX; -+ } -+ -+ val = strtoull(buf, NULL, 0); -+ return val; -+} -+ -+static inline bool is_blk_metrics_read(const char *value) -+{ -+ return strcmp(value, "Read") == 0; -+} -+ -+static inline bool is_blk_metrics_write(const char *value) -+{ -+ return strcmp(value, "Write") == 0; -+} -+ -+static inline bool is_blk_metrics_total(const char *value) -+{ -+ return strcmp(value, "Total") == 0; -+} -+ -+static void metrics_get_blk_stats(struct lxc_container *c, struct cgroup_ops *cgroup_ops, const char *item, struct lxc_blkio_metrics *stats) -+{ -+ char *buf = NULL; -+ int i = 0; -+ int len = 0; -+ int ret = 0; -+ char **lines = NULL; -+ char **cols = NULL; -+ -+ len = cgroup_ops->get(cgroup_ops, item, NULL, 0, c->name, c->config_path); -+ if (len <= 0) { -+ DEBUG("unable to read cgroup item %s", item); -+ return; -+ } -+ -+ buf = malloc(len + 1); -+ (void)memset(buf, 0, len + 1); -+ ret = cgroup_ops->get(cgroup_ops, item, buf, len, c->name, c->config_path); -+ if (ret <= 0) { -+ DEBUG("unable to read cgroup item %s", item); -+ goto out; -+ } -+ -+ lines = lxc_string_split_and_trim(buf, '\n'); -+ if (lines == NULL) { -+ goto out; -+ } -+ -+ (void)memset(stats, 0, sizeof(struct lxc_blkio_metrics)); -+ -+ for (i = 0; lines[i]; i++) { -+ cols = lxc_string_split_and_trim(lines[i], ' '); -+ if (cols == NULL) { -+ goto err_out; -+ } -+ if (lxc_array_len((void **)cols) == 3) { -+ if (is_blk_metrics_read(cols[1])) { -+ stats->read += strtoull(cols[2], NULL, 0); -+ } else if (is_blk_metrics_write(cols[1])) { -+ stats->write += strtoull(cols[2], NULL, 0); -+ } -+ } -+ if (lxc_array_len((void **)cols) == 2 && is_blk_metrics_total(cols[0])) { -+ stats->total = strtoull(cols[1], NULL, 0); -+ } -+ -+ lxc_free_array((void **)cols, free); -+ } -+err_out: -+ lxc_free_array((void **)lines, free); -+out: -+ free(buf); -+ return; -+} -+ -+static void metrics_get_io_stats_v2(struct lxc_container *c, struct cgroup_ops *cgroup_ops, const char *item, struct lxc_blkio_metrics *stats, func_is_io_stat_read is_io_stat_read, func_is_io_stat_write is_io_stat_write) -+{ -+ char *buf = NULL; -+ int i = 0; -+ int j = 0; -+ int len = 0; -+ int ret = 0; -+ char **lines = NULL; -+ char **cols = NULL; -+ char **kv = NULL; -+ -+ len = cgroup_ops->get(cgroup_ops, item, NULL, 0, c->name, c->config_path); -+ if (len <= 0) { -+ DEBUG("unable to read cgroup item %s", item); -+ return; -+ } -+ -+ buf = malloc(len + 1); -+ (void)memset(buf, 0, len + 1); -+ ret = cgroup_ops->get(cgroup_ops, item, buf, len, c->name, c->config_path); -+ if (ret <= 0) { -+ DEBUG("unable to read cgroup item %s", item); -+ goto out; -+ } -+ -+ lines = lxc_string_split_and_trim(buf, '\n'); -+ if (lines == NULL) { -+ goto out; -+ } -+ -+ (void)memset(stats, 0, sizeof(struct lxc_blkio_metrics)); -+ // line example: -+ // 259:0 rbytes=0 wbytes=12288 rios=0 wios=4 dbytes=0 dios=0 -+ for (i = 0; lines[i]; i++) { -+ cols = lxc_string_split_and_trim(lines[i], ' '); -+ if (cols == NULL || lxc_array_len((void **)cols) < 2) { -+ goto err_out; -+ } -+ len = lxc_array_len((void **)cols); -+ for (j = 1; j < len; j++) { -+ kv = lxc_string_split(cols[j], '='); -+ if (kv == NULL || lxc_array_len((void **)kv) != 2) { -+ lxc_free_array((void **)kv, free); -+ continue; -+ } -+ if (is_io_stat_read(kv[0])) { -+ stats->read += strtoull(kv[1], NULL, 0); -+ } else if (is_io_stat_write(kv[0])) { -+ stats->write += strtoull(kv[1], NULL, 0); -+ } -+ lxc_free_array((void **)kv, free); -+ } -+ lxc_free_array((void **)cols, free); -+ } -+ -+ stats->total = stats->read + stats->write; -+ -+err_out: -+ lxc_free_array((void **)lines, free); -+out: -+ free(buf); -+ return; -+} -+ -+static uint64_t metrics_match_get_ull(struct lxc_container *c, struct cgroup_ops *cgroup_ops, const char *item, const char *match, int column) -+{ -+#define BUFSIZE 4096 -+ char buf[BUFSIZE] = {0}; -+ int i = 0; -+ int j = 0; -+ int len = 0; -+ uint64_t val = 0; -+ char **lines = NULL; -+ char **cols = NULL; -+ size_t matchlen = 0; -+ -+ len = cgroup_ops->get(cgroup_ops, item, buf, sizeof(buf) - 1, c->name, c->config_path); -+ if (len <= 0) { -+ DEBUG("unable to read cgroup item %s", item); -+ goto err_out; -+ } -+ -+ lines = lxc_string_split_and_trim(buf, '\n'); -+ if (lines == NULL) { -+ goto err_out; -+ } -+ -+ matchlen = strlen(match); -+ for (i = 0; lines[i]; i++) { -+ if (strncmp(lines[i], match, matchlen) != 0) { -+ continue; -+ } -+ -+ cols = lxc_string_split_and_trim(lines[i], ' '); -+ if (cols == NULL) { -+ goto err1; -+ } -+ for (j = 0; cols[j]; j++) { -+ if (j == column) { -+ val = strtoull(cols[j], NULL, 0); -+ break; -+ } -+ } -+ lxc_free_array((void **)cols, free); -+ break; -+ } -+err1: -+ lxc_free_array((void **)lines, free); -+err_out: -+ return val; -+} -+ -+static bool is_io_stat_rbytes(const char *value) -+{ -+ return strcmp(value, "rbytes") == 0; -+} -+ -+static bool is_io_stat_wbytes(const char *value) -+{ -+ return strcmp(value, "wbytes") == 0; -+} -+ -+static bool is_io_stat_rios(const char *value) -+{ -+ return strcmp(value, "rios") == 0; -+} -+ -+static bool is_io_stat_wios(const char *value) -+{ -+ return strcmp(value, "wios") == 0; -+} -+ -+static bool unified_metrics_get(struct lxc_container *c, struct cgroup_ops *cgroup_ops, struct lxc_container_metrics *metrics) -+{ -+ // cpu -+ metrics->cpu_use_nanos = metrics_match_get_ull(c, cgroup_ops, "cpu.stat", "usage_usec", 1) * 1000; -+ metrics->cpu_use_user = metrics_match_get_ull(c, cgroup_ops, "cpu.stat", "user_usec", 1) * 1000; -+ metrics->cpu_use_sys = metrics_match_get_ull(c, cgroup_ops, "cpu.stat", "system_usec", 1) * 1000; -+ -+ // io -+ metrics_get_io_stats_v2(c, cgroup_ops, "io.stat", &metrics->io_service_bytes, is_io_stat_rbytes, is_io_stat_wbytes); -+ metrics_get_io_stats_v2(c, cgroup_ops, "io.stat", &metrics->io_serviced, is_io_stat_rios, is_io_stat_wios); -+ -+ // memory -+ metrics->mem_used = metrics_get_ull(c, cgroup_ops, "memory.current"); -+ metrics->mem_limit = metrics_get_ull_with_max(c, cgroup_ops, "memory.max"); -+ metrics->inactive_file_total = metrics_match_get_ull(c, cgroup_ops, "memory.stat", "inactive_file", 1); -+ metrics->cache = metrics_match_get_ull(c, cgroup_ops, "memory.stat", "file", 1); -+ metrics->cache_total = metrics->cache; -+ -+ // cgroup v2 does not support kernel memory -+ metrics->kmem_used = 0; -+ metrics->kmem_limit = 0; -+ -+ // pids -+ metrics->pids_current = metrics_get_ull(c, cgroup_ops, "pids.current"); -+ -+ return true; -+} -+ -+/* isulad add get container metrics */ -+static bool do_lxcapi_get_container_metrics(struct lxc_container *c, struct lxc_container_metrics *metrics) -+{ -+ call_cleaner(cgroup_exit) struct cgroup_ops *cgroup_ops = NULL; -+ const char *state = NULL; -+ if (c == NULL || c->lxc_conf == NULL || metrics == NULL) { -+ return false; -+ } -+ -+ state = c->state(c); -+ metrics->state = state; -+ -+ if (!is_stopped(c)) { -+ metrics->init = c->init_pid(c); -+ } else { -+ metrics->init = -1; -+ } -+ -+ cgroup_ops = cgroup_init(c->lxc_conf); -+ if (cgroup_ops == NULL) { -+ return false; -+ } -+ -+ if (cgroup_ops->cgroup_layout == CGROUP_LAYOUT_UNIFIED) { -+ return unified_metrics_get(c, cgroup_ops, metrics); -+ } -+ -+ metrics->cpu_use_nanos = metrics_get_ull(c, cgroup_ops, "cpuacct.usage"); -+ metrics->pids_current = metrics_get_ull(c, cgroup_ops, "pids.current"); -+ -+ 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); -+ -+ // Try to read CFQ stats available on all CFQ enabled kernels first -+ metrics_get_blk_stats(c, cgroup_ops, "blkio.io_serviced_recursive", &metrics->io_serviced); -+ if (metrics->io_serviced.read == 0 && metrics->io_serviced.write == 0 && metrics->io_serviced.total == 0) { -+ metrics_get_blk_stats(c, cgroup_ops, "blkio.throttle.io_service_bytes", &metrics->io_service_bytes); -+ metrics_get_blk_stats(c, cgroup_ops, "blkio.throttle.io_serviced", &metrics->io_serviced); -+ } else { -+ metrics_get_blk_stats(c, cgroup_ops, "blkio.io_service_bytes_recursive", &metrics->io_service_bytes); -+ } -+ -+ metrics->mem_used = metrics_get_ull(c, cgroup_ops, "memory.usage_in_bytes"); -+ metrics->mem_limit = metrics_get_ull(c, cgroup_ops, "memory.limit_in_bytes"); -+ metrics->kmem_used = metrics_get_ull(c, cgroup_ops, "memory.kmem.usage_in_bytes"); -+ metrics->kmem_limit = metrics_get_ull(c, cgroup_ops, "memory.kmem.limit_in_bytes"); -+ -+ metrics->cache = metrics_match_get_ull(c, cgroup_ops, "memory.stat", "cache", 1); -+ metrics->cache_total = metrics_match_get_ull(c, cgroup_ops, "memory.stat", "total_cache", 1); -+ metrics->inactive_file_total = metrics_match_get_ull(c, cgroup_ops, "memory.stat", "total_inactive_file", 1); -+ -+ return true; -+} -+ -+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; -@@ -5283,10 +6124,24 @@ struct lxc_container *lxc_container_new(const char *name, const char *configpath - goto err; - } - -+#ifdef HAVE_ISULAD -+ if (!set_oci_hook_config_filename(c)) { -+ fprintf(stderr, "Error allocating oci hooks file pathname\n"); -+ goto err; -+ } -+ -+ if (load_config && file_exists(c->configfile)) { -+ if (!lxcapi_load_config(c, NULL)) { -+ fprintf(stderr, "Failed to load config for %s\n", name); -+ goto err; -+ } -+ } -+#else - if (file_exists(c->configfile) && !lxcapi_load_config(c, NULL)) { - fprintf(stderr, "Failed to load config for %s\n", name); - goto err; - } -+#endif - - rc = ongoing_create(c); - switch (rc) { -@@ -5310,6 +6165,9 @@ struct lxc_container *lxc_container_new(const char *name, const char *configpath - - 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; -@@ -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; -+ c->add_terminal_fifos = lxcapi_add_terminal_fifo; -+ c->set_terminal_winch = lxcapi_set_terminal_winch; -+ c->set_exec_terminal_winch = lxcapi_set_exec_terminal_winch; -+ c->want_disable_pty = lxcapi_want_disable_pty; -+ c->want_open_stdin = lxcapi_want_open_stdin; -+ c->clean_container_resource = lxcapi_clean_container_resource; -+ c->get_container_pids = lxcapi_get_container_pids; -+ c->set_start_timeout = lxcapi_set_start_timeout; -+ c->set_oci_type = lxcapi_set_oci_type; -+ c->get_container_metrics = lxcapi_get_container_metrics; -+#endif - return c; - - err: -@@ -5379,6 +6250,19 @@ err: - return NULL; - } - -+#ifdef HAVE_ISULAD -+// isulad: new container without load config to save time -+struct lxc_container *lxc_container_without_config_new(const char *name, const char *configpath) -+{ -+ return do_lxc_container_new(name, configpath, false); -+} -+ -+struct lxc_container *lxc_container_new(const char *name, const char *configpath) -+{ -+ return do_lxc_container_new(name, configpath, true); -+} -+#endif -+ - int lxc_get_wait_states(const char **states) - { - int i; -@@ -5557,11 +6441,21 @@ int list_active_containers(const char *lxcpath, char ***nret, - continue; - } - -+#ifdef HAVE_ISULAD -+ if (ct_name && ct_name_cnt) { -+ if (array_contains(&ct_name, p, ct_name_cnt)) { -+ if (is_hashed) -+ free(p); -+ continue; -+ } -+ } -+#else - if (array_contains(&ct_name, p, ct_name_cnt)) { - if (is_hashed) - free(p); - continue; - } -+#endif - - if (!add_to_array(&ct_name, p, ct_name_cnt)) { - if (is_hashed) -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 -+ if (l == NULL) -+ fprintf(stderr, "Failed to create lock for %s, path %s\n", name, lxcpath); -+#endif - return l; - } - -@@ -370,3 +374,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 -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) - - close_prot_errno_disarm(descr->epfd); - } -+ -+#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/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 -+ -+#include "path.h" -+#include "log.h" -+#include "isulad_utils.h" -+ -+lxc_log_define(lxc_path_ui, lxc); -+ -+#define ISSLASH(C) ((C) == '/') -+#define IS_ABSOLUTE_FILE_NAME(F) (ISSLASH ((F)[0])) -+#define IS_RELATIVE_FILE_NAME(F) (! IS_ABSOLUTE_FILE_NAME (F)) -+ -+bool specify_current_dir(const char *path) -+{ -+ 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; -+} -+ -+bool has_traling_path_separator(const char *path) -+{ -+ return path && strlen(path) && (path[strlen(path) - 1] == '/'); -+} -+ -+// 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) -+{ -+ char *respath = NULL; -+ size_t len; -+ -+ if (strlen(cleanedpath) > (SIZE_MAX - 3)) { -+ return NULL; -+ } -+ -+ len = strlen(cleanedpath) + 3; -+ respath = malloc(len); -+ if (respath == NULL) { -+ ERROR("Out of memory"); -+ return NULL; -+ } -+ memset(respath, 0x00, len); -+ strcat(respath, cleanedpath); -+ -+ if (!specify_current_dir(cleanedpath) && specify_current_dir(originalpath)) { -+ if (!has_traling_path_separator(respath)) -+ strcat(respath, "/"); -+ strcat(respath, "."); -+ } -+ -+ if (!has_traling_path_separator(respath) && -+ has_traling_path_separator(originalpath)) -+ strcat(respath, "/"); -+ -+ return respath; -+} -+ -+ -+// 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) -+{ -+ ssize_t i; -+ size_t len; -+ -+ len = strlen(path); -+ if (len >= PATH_MAX) { -+ ERROR("Invalid path"); -+ return false; -+ } -+ i = len - 1; -+ while (i >= 0 && path[i] != '/') -+ i--; -+ -+ *dir = malloc(i + 2); -+ if (*dir == NULL) { -+ ERROR("Out of memory"); -+ return false; -+ } -+ memcpy(*dir, path, i + 1); -+ *(*dir + i + 1) = '\0'; -+ -+ *base = safe_strdup(path + i + 1); -+ -+ 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; -+} -+ -+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++ = '/'; -+ } -+ -+ if (dest + (endpos - stpos) >= limit_respath) { -+ ERROR("Path is too long"); -+ if (dest > respath + 1) { -+ dest--; -+ } -+ *dest = '\0'; -+ return -1; -+ } -+ -+ memcpy(dest, stpos, (size_t)(endpos - stpos)); -+ dest += endpos - stpos; -+ *dest = '\0'; -+ } -+ *dst = dest; -+ return 0; -+} -+ -+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; -+ -+ if (path == NULL || path[0] == '\0' || \ -+ realpath == NULL || (realpath_len < PATH_MAX)) { -+ return NULL; -+ } -+ -+ respath = realpath; -+ -+ memset(respath, 0, realpath_len); -+ limit_respath = respath + PATH_MAX; -+ -+ 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; -+ } -+ -+ if (do_clean_path(respath, limit_respath, stpos, &dest)) { -+ goto error; -+ } -+ -+ if (dest > respath + 1 && ISSLASH(dest[-1])) { -+ --dest; -+ } -+ *dest = '\0'; -+ -+ return respath; -+ -+error: -+ return NULL; -+} -+ -+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; -+ -+ if (*dest + (end - start) < *rpath_limit) { -+ return 0; -+ } -+ -+ 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; -+ } -+ -+ 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; -+ -+ *dest = *rpath + dest_offset; -+ -+ return 0; -+} -+ -+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; -+} -+ -+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; -+ } -+ -+ n = readlink(*rpath, buf, PATH_MAX - 1); -+ if (n < 0) { -+ goto out; -+ } -+ buf[n] = '\0'; -+ -+ if (*extra_buf == NULL) { -+ *extra_buf = lxc_common_calloc_s(PATH_MAX); -+ if (*extra_buf == NULL) { -+ ERROR("Out of memory"); -+ goto out; -+ } -+ } -+ -+ len = strlen(*end); -+ if (len >= PATH_MAX - n) { -+ ERROR("Path is too long"); -+ goto out; -+ } -+ -+ 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: -+ free(buf); -+ return ret; -+} -+ -+static bool do_eval_symlinks_in_scope_is_symlink(const char *path) -+{ -+ struct stat st; -+ -+ if (lstat(path, &st) < 0) { -+ return true; -+ } -+ -+ if (!S_ISLNK(st.st_mode)) { -+ return true; -+ } -+ return false; -+} -+ -+static void do_eval_symlinks_skip_slash(const char **start, const char **end) -+{ -+ while (ISSLASH(**start)) { -+ ++(*start); -+ } -+ -+ for (*end = *start; **end && !ISSLASH(**end); ++(*end)) { -+ } -+} -+ -+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; -+ } -+ } -+} -+ -+static inline bool is_current_char(const char c) -+{ -+ return c == '.'; -+} -+ -+static inline bool is_specify_current(const char *end, const char *start) -+{ -+ return (end - start == 1) && is_current_char(start[0]); -+} -+ -+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: -+ free(extra_buf); -+ return nret; -+} -+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; -+ -+ prefix = root; -+ prefix_len = (size_t)strlen(prefix); -+ if (!strcmp(prefix, "/")) { -+ prefix_len = 0; -+ } -+ -+ dest = rpath; -+ if (prefix_len) { -+ memcpy(rpath, prefix, prefix_len); -+ dest += prefix_len; -+ } -+ *dest++ = '/'; -+ -+ if (do_eval_symlinks_in_scope(fullpath, prefix, prefix_len, &rpath, &dest, -+ rpath_limit)) { -+ goto out; -+ } -+ -+ if (dest > rpath + prefix_len + 1 && ISSLASH(dest[-1])) { -+ --dest; -+ } -+ *dest = '\0'; -+ return rpath; -+ -+out: -+ free(rpath); -+ return NULL; -+} -+ -+// 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; -+ -+ full = cleanpath(fullpath, resfull, PATH_MAX); -+ if (!full) { -+ ERROR("Failed to get cleaned path"); -+ return NULL; -+ } -+ -+ root = cleanpath(rootpath, resroot, PATH_MAX); -+ if (!root) { -+ ERROR("Failed to get cleaned path"); -+ return NULL; -+ } -+ -+ return eval_symlinks_in_scope(full, root); -+} -+ -+// 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) -+{ -+ char resolved[PATH_MAX] = {0}, *cleanedpath = NULL; -+ char *fullpath = NULL; -+ size_t len; -+ -+ if (!rootpath || !path || !scopepath) -+ return -1; -+ -+ *scopepath = NULL; -+ -+ cleanedpath = cleanpath(path, resolved, PATH_MAX); -+ if (!cleanedpath) { -+ ERROR("Failed to get cleaned path"); -+ return -1; -+ } -+ -+ len = strlen(rootpath) + strlen(cleanedpath) + 1; -+ fullpath = malloc(len); -+ if (!fullpath) { -+ ERROR("Out of memory"); -+ return -1; -+ } -+ snprintf(fullpath, len, "%s%s", rootpath, cleanedpath); -+ -+ *scopepath = follow_symlink_in_scope(fullpath, rootpath); -+ -+ free(fullpath); -+ return 0; -+} -+ -+// 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. -+ 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; -+ } -+ -+ 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, - - 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; - } -@@ -124,6 +128,35 @@ bool dir_detect(const char *path) - return false; - } - -+#ifdef HAVE_ISULAD -+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 - int dir_mount(struct lxc_storage *bdev) - { - __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 - - 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 -+#include "lxclock.h" -+#endif - #include "utils.h" - - 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 -+ int ret = 0; -+ int loopfd, lret; -+ struct lxc_lock *l = NULL; -+#else - int ret, loopfd; -+#endif - char loname[PATH_MAX]; - const char *src; - -@@ -226,13 +235,35 @@ 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; -+ } -+ -+ lret = lxclock(l, 0); -+ if (lret) { -+ SYSERROR("try to lock failed when mount fs"); -+ ret = -1; -+ 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 -+ ret = -1; -+ goto out; -+#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: -+ lret = lxcunlock(l); -+ if (lret) { -+ 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 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 -+#include "block.h" -+#endif - - #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 -+/* 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 - }; - - 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 -+ 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) - ret = true; --- -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 deleted file mode 100644 index 46c3e2bbdd08a6d951abe830e3b417094560e8db..0000000000000000000000000000000000000000 --- a/0005-refactor-patch-code-of-attach-and-seccomp.patch +++ /dev/null @@ -1,1517 +0,0 @@ -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-refactor-patch-about-namespace-log-terminal.patch b/0006-refactor-patch-about-namespace-log-terminal.patch deleted file mode 100644 index d3db741e7cdf4b7a5d47734500fb790b268b986f..0000000000000000000000000000000000000000 --- a/0006-refactor-patch-about-namespace-log-terminal.patch +++ /dev/null @@ -1,1164 +0,0 @@ -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 deleted file mode 100644 index 84f70485aee537b2cfff4764cb96a4780588be54..0000000000000000000000000000000000000000 --- a/0007-refactor-patches-on-terminal.c-start.c-and-so-on.patch +++ /dev/null @@ -1,2726 +0,0 @@ -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/0009-fix-HOME-env-of-container-unset-error.patch b/0009-fix-HOME-env-of-container-unset-error.patch deleted file mode 100644 index 799a7e71c85942f07524a88a0f116f16ec6b663f..0000000000000000000000000000000000000000 --- a/0009-fix-HOME-env-of-container-unset-error.patch +++ /dev/null @@ -1,316 +0,0 @@ -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 deleted file mode 100644 index e4ea3c1b4d729db4c1b99deff3f814c84756499c..0000000000000000000000000000000000000000 --- a/0010-check-yajl-only-when-have-isulad.patch +++ /dev/null @@ -1,70 +0,0 @@ -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 deleted file mode 100644 index b935b8b57148eb395cc132c0dc44919f74a9a485..0000000000000000000000000000000000000000 --- a/0011-drop-security_context_t.patch +++ /dev/null @@ -1,29 +0,0 @@ -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 deleted file mode 100644 index 61686e0a99317d98af66e89ca9e5ab46faaf61c8..0000000000000000000000000000000000000000 --- a/0012-only-set-user-or-image-set-non-empty-HOME.patch +++ /dev/null @@ -1,50 +0,0 @@ -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 deleted file mode 100644 index 41a72e1d9e657b30a2fb2f81a27aa6215afd449f..0000000000000000000000000000000000000000 --- a/0013-return-fail-if-no-args-or-no-rootfs-path-found.patch +++ /dev/null @@ -1,38 +0,0 @@ -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 deleted file mode 100644 index 2c79051b612e82449381157eab3153800d9c17e1..0000000000000000000000000000000000000000 --- a/0014-fix-tools-using-option-give-error-message.patch +++ /dev/null @@ -1,25 +0,0 @@ -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 deleted file mode 100644 index 9243c493eb915ffadbaf429fcb8e33f821678848..0000000000000000000000000000000000000000 --- a/0015-fix-do-mask-pathes-after-parent-mounted.patch +++ /dev/null @@ -1,44 +0,0 @@ -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 deleted file mode 100644 index 9538da7781bdaa78d96f32346fd75c754ec3a8de..0000000000000000000000000000000000000000 --- a/0016-skip-kill-cgroup-processes-if-no-hierarchies.patch +++ /dev/null @@ -1,36 +0,0 @@ -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 deleted file mode 100644 index b8b0696cdf7a23486f3957d2141369d0aafbdfc6..0000000000000000000000000000000000000000 --- a/0017-lxc-Add-sw64-architecture.patch +++ /dev/null @@ -1,26 +0,0 @@ -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 deleted file mode 100644 index 5247304fa62c6e01d5c4166f40fb9b3201010a89..0000000000000000000000000000000000000000 --- a/0018-add-macro-to-adapt-musl-libc.patch +++ /dev/null @@ -1,33 +0,0 @@ -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 deleted file mode 100644 index 77f75711bbd2e4f9db0c96f705ca6abfd0734c50..0000000000000000000000000000000000000000 --- a/0019-add-lxc-attach-add-gids-option.patch +++ /dev/null @@ -1,178 +0,0 @@ -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 deleted file mode 100644 index a9d54706bedb2281c8deaa788e725b4bc6bff3c0..0000000000000000000000000000000000000000 --- a/0020-add-sscanf-adapation-code-for-musl.patch +++ /dev/null @@ -1,31 +0,0 @@ -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 deleted file mode 100644 index 6fe236a675f429295df2b04367b4f1cfd12274e6..0000000000000000000000000000000000000000 --- a/0021-change-the-suffi-parameter-in-lxc-attach-help-output.patch +++ /dev/null @@ -1,26 +0,0 @@ -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 deleted file mode 100644 index e524ed9631f9729b0d10bd76648ca95190878279..0000000000000000000000000000000000000000 --- a/0022-fix-cve-CVE-2022-47952-log-leaks-root-information.patch +++ /dev/null @@ -1,51 +0,0 @@ -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 deleted file mode 100644 index 91d30a7dd9706192b6cbdd1c1191f28dd1375cc9..0000000000000000000000000000000000000000 --- a/0023-fix-lxc-write-error-message.patch +++ /dev/null @@ -1,26 +0,0 @@ -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 deleted file mode 100644 index f8b7984d39e38485ab4571c954265e825fb9bce6..0000000000000000000000000000000000000000 --- a/0024-remove-process-inheritable-capability.patch +++ /dev/null @@ -1,27 +0,0 @@ -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 deleted file mode 100644 index e162e3b8135ef8bbb060a0b0c55cec35b0b00739..0000000000000000000000000000000000000000 --- a/0025-fix-ops-hierarchies-cause-coredump.patch +++ /dev/null @@ -1,32 +0,0 @@ -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 deleted file mode 100644 index b21789a4eac5b656c2a10c99fd91615f2fe1c116..0000000000000000000000000000000000000000 --- a/0026-meminfo-cri-1.25.patch +++ /dev/null @@ -1,55 +0,0 @@ -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 deleted file mode 100644 index 7f68cf1fbb7dc11ba76e9c60b6015370bbeccad7..0000000000000000000000000000000000000000 --- a/0027-add-loongarch64-support-for-lxc.patch +++ /dev/null @@ -1,238 +0,0 @@ -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 deleted file mode 100644 index 9f7a775acc5d47b6f14c4a14e030035fcf1c3dde..0000000000000000000000000000000000000000 --- a/0028-use-ocihooks-env-after-getenv.patch +++ /dev/null @@ -1,51 +0,0 @@ -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 deleted file mode 100644 index 697e039eb426a4e011169a4f2c6ca007160e89fb..0000000000000000000000000000000000000000 --- a/0029-fix-mixed-use-of-signed-and-unsigned-type.patch +++ /dev/null @@ -1,51 +0,0 @@ -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 deleted file mode 100644 index 5113f37f51b71d158e402ad4583f62ace6ddea3f..0000000000000000000000000000000000000000 --- a/0030-remove-unused-meminfo-stats.patch +++ /dev/null @@ -1,48 +0,0 @@ -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 deleted file mode 100644 index cef5a250f30175b8a451a451b7c1e3852819111f..0000000000000000000000000000000000000000 --- a/0031-lxc-attach-Fix-lost-return-codes-of-spawned-processe.patch +++ /dev/null @@ -1,39 +0,0 @@ -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 deleted file mode 100644 index b8289070c5cac7be61722f5653dd07731a09503c..0000000000000000000000000000000000000000 --- a/0032-fix-load-bpf-failed.patch +++ /dev/null @@ -1,30 +0,0 @@ -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 deleted file mode 100644 index 6c0bc4ca8df35efcf2d984f9efb46a7c26144e34..0000000000000000000000000000000000000000 --- a/0033-fix-mount-device-path-incorrect.patch +++ /dev/null @@ -1,27 +0,0 @@ -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 deleted file mode 100644 index f6a2ed21437bb388e6efdf5682693f8feeafa855..0000000000000000000000000000000000000000 --- a/0034-add-secure-compile-macro.patch +++ /dev/null @@ -1,65 +0,0 @@ -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/apply-patches b/apply-patches index 136ca222f7342c0bd70378f07514f68b0261a7f1..bf6f8d430250df681060dd79553840f24c10d1c9 100755 --- a/apply-patches +++ b/apply-patches @@ -27,6 +27,12 @@ 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 @@ -36,11 +42,9 @@ do patch -p1 -F1 -s < $cwd/$line done -git init . git add . -git config --local user.name "isuladci" -git config --local user.email "isulad@ci.com" -git commit -m "init repo" +git commit -m "change for iSulad" + 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 deleted file mode 100644 index 88376b2b8687616c874225ca8c983b2a78993ba0..0000000000000000000000000000000000000000 Binary files a/lxc-4.0.3.tar.gz and /dev/null differ diff --git a/lxc-5.0.2.tar.gz b/lxc-5.0.2.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..846afc3f95d128cb5ea4d57b1d2b34b8e10f5640 Binary files /dev/null and b/lxc-5.0.2.tar.gz differ diff --git a/lxc.spec b/lxc.spec index 013d402837d7e19423f7151469516038df3b258f..e52a93740e2966c4dae703b64ae6eaf62196e5c9 100644 --- a/lxc.spec +++ b/lxc.spec @@ -1,57 +1,24 @@ -%global _release 2022102421 +%global _release 1 Name: lxc -Version: 4.0.3 +Version: 5.0.2 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-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 +Source0: https://linuxcontainers.org/downloads/lxc/lxc-5.0.2.tar.gz + +Patch0001: 0001-iSulad-add-json-files-and-adapt-to-meson.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) +BuildRequires: pkgconfig(bash-completion) meson %ifarch riscv64 BuildRequires: libatomic_ops %endif -Requires: lxc-libs = 4.0.3-%{release} +Requires: lxc-libs = 5.0.2-%{release} %package libs Summary: Runtime library files for %{name} @@ -83,7 +50,7 @@ boot an entire "containerized" system, and to manage and debug your containers. %package devel Summary: Development files for lxc -Requires: lxc = 4.0.3-%{release} +Requires: lxc = 5.0.2-%{release} Requires: pkgconfig %description devel @@ -99,19 +66,14 @@ BuildArch: noarch This package contains documentation for lxc for creating containers. %prep -%autosetup -n lxc-4.0.3 -Sgit -p1 +%autosetup -n lxc-5.0.2 -Sgit -p1 %build %ifarch riscv64 export LDFLAGS="%{build_ldflags} -latomic -pthread" %endif -%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} +meson setup -Disulad=false -Dtests=true -Dprefix=/usr build +meson compile -C build %install %{make_install} @@ -142,11 +104,9 @@ 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 README %{buildroot}%{_pkgdocdir} -cp -a doc/api/html/* %{buildroot}%{_pkgdocdir}/api/ +cp -a AUTHORS %{buildroot}%{_pkgdocdir} %endif # cache dir @@ -163,7 +123,7 @@ rm -rf %{buildroot}%{_libdir}/liblxc.la rm -rf %{buildroot}%{_sbindir}/init.%{name}.static rm -rf %{buildroot}%{_sysconfdir}/default/%{name} %check -%make_build check +meson test -C build %post @@ -177,7 +137,8 @@ rm -rf %{buildroot}%{_sysconfdir}/default/%{name} %{_datadir}/%{name}/%{name}.functions %dir %{_datadir}/bash-completion %dir %{_datadir}/bash-completion/completions -%{_datadir}/bash-completion/completions/lxc +%{_datadir}/bash-completion/completions/* + %files libs %defattr(-,root,root) %{_libdir}/liblxc.so @@ -196,10 +157,12 @@ rm -rf %{buildroot}%{_sysconfdir}/default/%{name} %{_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} @@ -228,503 +191,8 @@ rm -rf %{buildroot}%{_sysconfdir}/default/%{name} %endif %changelog -* 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: modify source0 address - -* Mon Aug 03 2020 openEuler Buildteam - 4.0.3-2020080301 -- Type:enhancement -- ID:NA -- SUG:NA -- DESC: add debug packages - -* Mon Apr 20 2020 openEuler Buildteam - 4.0.3-2020071501 +* Thu Jul 13 2023 haozi007 - 5.0.2-1 - Type:enhancement - ID:NA - SUG:NA -- DESC: update lxc to 4.0.3 +- DESC: update to 5.0.2