Projects
home:zhoujc:Mega:23.09
lxc
_service:tar_scm:0004-iSulad-adapt-confile-lxcc...
Sign Up
Log In
Username
Password
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File _service:tar_scm:0004-iSulad-adapt-confile-lxccontainer-and-start.patch of Package lxc
From 3e7fb35a35cff34be2bb7ace0b239d540fe0657f Mon Sep 17 00:00:00 2001 From: zhangxiaoyu <zhangxiaoyu58@huawei.com> Date: Wed, 26 Jul 2023 14:57:33 +0800 Subject: [PATCH] [iSulad] adapt confile lxccontainer and start Signed-off-by: zhangxiaoyu <zhangxiaoyu58@huawei.com> --- src/lxc/conf.c | 11 - src/lxc/conf.h | 4 - src/lxc/confile.c | 558 +++++++++++++++++++++++++ src/lxc/lxccontainer.c | 899 +++++++++++++++++++++++++++++++++++++++- src/lxc/lxccontainer.h | 197 +++++++++ src/lxc/start.c | 902 +++++++++++++++++++++++++++++++++++++++++ src/lxc/start.h | 18 + 7 files changed, 2573 insertions(+), 16 deletions(-) diff --git a/src/lxc/conf.c b/src/lxc/conf.c index a0e0375..187e60e 100644 --- a/src/lxc/conf.c +++ b/src/lxc/conf.c @@ -5242,7 +5242,6 @@ void lxc_conf_free(struct lxc_conf *conf) } free(conf->systemd); lxc_clear_init_args(conf); - lxc_clear_init_groups(conf); lxc_clear_populate_devices(conf); lxc_clear_rootfs_masked_paths(conf); lxc_clear_rootfs_ro_paths(conf); @@ -7427,16 +7426,6 @@ int lxc_clear_init_args(struct lxc_conf *lxc_conf) return 0; } -/*isulad clear init groups*/ -int lxc_clear_init_groups(struct lxc_conf *lxc_conf) -{ - free(lxc_conf->init_groups); - lxc_conf->init_groups = NULL; - lxc_conf->init_groups_len = 0; - - return 0; -} - /*isulad: clear populate devices*/ int lxc_clear_populate_devices(struct lxc_conf *c) { diff --git a/src/lxc/conf.h b/src/lxc/conf.h index 683b8ba..108e05b 100644 --- a/src/lxc/conf.h +++ b/src/lxc/conf.h @@ -622,9 +622,6 @@ struct lxc_conf { char **init_argv; size_t init_argc; - gid_t *init_groups; - size_t init_groups_len; - /* populate devices */ struct lxc_list populate_devs; mode_t umask; // umask value @@ -794,7 +791,6 @@ __hidden extern int parse_cap(const char *cap_name, __u32 *cap); #ifdef HAVE_ISULAD // isulad add __hidden int lxc_clear_init_args(struct lxc_conf *lxc_conf); -__hidden int lxc_clear_init_groups(struct lxc_conf *lxc_conf); __hidden int lxc_clear_populate_devices(struct lxc_conf *c); __hidden int lxc_clear_rootfs_masked_paths(struct lxc_conf *c); __hidden int lxc_clear_rootfs_ro_paths(struct lxc_conf *c); diff --git a/src/lxc/confile.c b/src/lxc/confile.c index 7966d32..1492776 100644 --- a/src/lxc/confile.c +++ b/src/lxc/confile.c @@ -157,6 +157,18 @@ lxc_config_define(uts_name); lxc_config_define(sysctl); lxc_config_define(proc); lxc_config_define(sched_core); +#ifdef HAVE_ISULAD +lxc_config_define(init_args); +lxc_config_define(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 static int set_config_unsupported_key(const char *key, const char *value, struct lxc_conf *lxc_conf, void *data) @@ -274,6 +286,18 @@ static struct lxc_config_t config_jump_table[] = { { "lxc.uts.name", true, set_config_uts_name, get_config_uts_name, clr_config_uts_name, }, { "lxc.sysctl", false, set_config_sysctl, get_config_sysctl, clr_config_sysctl, }, { "lxc.proc", false, set_config_proc, get_config_proc, clr_config_proc, }, +#ifdef HAVE_ISULAD + { "lxc.isulad.init.args", set_config_init_args, get_config_init_args, clr_config_init_args, }, + { "lxc.isulad.populate.device", set_config_populate_device, get_config_populate_device, clr_config_populate_device, }, + { "lxc.isulad.umask", set_config_umask, get_config_umask, clr_config_umask, }, + { "lxc.isulad.rootfs.maskedpaths", set_config_rootfs_masked_paths, get_config_rootfs_masked_paths, clr_config_rootfs_masked_paths, }, + { "lxc.isulad.rootfs.ropaths", set_config_rootfs_ro_paths, get_config_rootfs_ro_paths, clr_config_rootfs_ro_paths, }, + { "lxc.isulad.systemd", set_config_systemd, get_config_systemd, clr_config_systemd, }, + { "lxc.console.logdriver", set_config_console_log_driver, get_config_console_log_driver, clr_config_console_log_driver, }, + { "lxc.console.syslog_tag", set_config_console_syslog_tag, get_config_console_syslog_tag, clr_config_console_syslog_tag, }, + { "lxc.console.syslog_facility", set_config_console_syslog_facility, get_config_console_syslog_facility, clr_config_console_syslog_facility, }, + { "lxc.selinux.mount_context", set_config_selinux_mount_context, get_config_selinux_mount_context, clr_config_selinux_mount_context, }, +#endif }; static struct lxc_config_t unsupported_config_key = { @@ -1588,7 +1612,12 @@ static int set_config_environment(const char *key, const char *value, if (!new_env) return ret_errno(ENOMEM); +#ifdef HAVE_ISULAD + /* isulad: recover space replaced by SPACE_MAGIC_STR */ + dup = lxc_string_replace(SPACE_MAGIC_STR, " ", value); +#else dup = strdup(value); +#endif if (!dup) return ret_errno(ENOMEM); @@ -2558,8 +2587,11 @@ static int set_config_console_rotate(const char *key, const char *value, if (ret) return ret_errno(EINVAL); +#ifndef HAVE_ISULAD + /* isulad: support rotate muti-files */ if (lxc_conf->console.log_rotate > 1) return log_error_errno(-EINVAL, EINVAL, "The \"lxc.console.rotate\" config key can only be set to 0 or 1"); +#endif return 0; } @@ -3049,6 +3081,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) { __do_free char *linep = NULL; @@ -3058,6 +3138,9 @@ static int parse_line(char *buffer, void *data) int ret; char *dup = buffer; struct parse_line_conf *plc = data; +#ifdef HAVE_ISULAD + __do_free char *value_decode = NULL; +#endif if (!plc->conf) return syserror_set(-EINVAL, "Missing config"); @@ -3118,7 +3201,15 @@ static int parse_line(char *buffer, void *data) } config = lxc_get_config(key); +#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 return config->set(key, value, plc->conf, NULL); +#endif } static struct new_config_item *parse_new_conf_line(char *buffer) @@ -3222,6 +3313,12 @@ bool lxc_config_define_load(struct lxc_list *defines, struct lxc_container *c) 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; @@ -6764,3 +6861,464 @@ static int clr_config_sched_core(const char *key, struct lxc_conf *c, void *data c->sched_core = false; return 0; } + + +#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 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 8df6059..d4495f7 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 <openssl/evp.h> #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) @@ -272,6 +281,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); } @@ -652,6 +668,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; @@ -685,6 +761,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 @@ -884,6 +965,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; @@ -894,6 +1002,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) @@ -940,6 +1053,30 @@ 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); + } + + // 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; + } +#endif + /* ... otherwise use default_args. */ if (!argv) { if (useinit) { @@ -959,10 +1096,23 @@ static bool do_lxcapi_start(struct lxc_container *c, int useinit, char * const a 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; } @@ -972,11 +1122,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); @@ -1012,6 +1176,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); } @@ -1024,7 +1191,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); @@ -1057,6 +1235,9 @@ static bool do_lxcapi_start(struct lxc_container *c, int useinit, char * const a if (w < 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); @@ -1070,6 +1251,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); @@ -1080,6 +1264,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 */ @@ -1111,19 +1308,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"); @@ -2065,7 +2296,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; @@ -2084,9 +2320,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 @@ -2939,6 +3176,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) { @@ -2949,8 +3201,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)) @@ -3070,8 +3333,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: @@ -3082,6 +3357,11 @@ out: free(path); container_disk_unlock(c); +#ifdef HAVE_ISULAD + if (bret && container_disk_removelock(c)) { + bret = false; + } +#endif return bret; } @@ -4042,8 +4322,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; } @@ -4063,7 +4348,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; @@ -5257,6 +5546,560 @@ static int do_lxcapi_seccomp_notify_fd_active(struct lxc_container *c) WRAP_API(int, lxcapi_seccomp_notify_fd_active) +#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->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); + + // 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 + struct lxc_container *lxc_container_new(const char *name, const char *configpath) { struct lxc_container *c; @@ -5310,10 +6153,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) { @@ -5337,6 +6194,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; @@ -5400,6 +6260,20 @@ struct lxc_container *lxc_container_new(const char *name, const char *configpath c->umount = lxcapi_umount; c->seccomp_notify_fd = lxcapi_seccomp_notify_fd; c->seccomp_notify_fd_active = lxcapi_seccomp_notify_fd_active; +#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; @@ -5408,6 +6282,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; @@ -5578,11 +6465,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/lxccontainer.h b/src/lxc/lxccontainer.h index 3386bff..06e8f0b 100644 --- a/src/lxc/lxccontainer.h +++ b/src/lxc/lxccontainer.h @@ -26,6 +26,10 @@ extern "C" { #define LXC_CREATE_MAXFLAGS (1 << 1) /*!< Number of \c LXC_CREATE* flags */ #define LXC_MOUNT_API_V1 1 +#ifdef HAVE_ISULAD +#define LXC_IMAGE_OCI_KEY "lxc.imagetype.oci" +#endif + struct bdev_specs; struct lxc_snapshot; @@ -40,6 +44,44 @@ 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; + uint64_t rss_bytes; + uint64_t page_faults; + uint64_t major_page_faults; + /* Kernel Memory usage */ + uint64_t kmem_used; + uint64_t kmem_limit; + /* Cache usage */ + uint64_t cache; + uint64_t cache_total; + /* total inactive file */ + uint64_t inactive_file_total; +}; +#endif + /*! * An LXC container. * @@ -107,6 +149,38 @@ struct lxc_container { /*! Full path to configuration file */ char *config_path; +#ifdef HAVE_ISULAD + /*! isulad: + * \private + * exit FIFO File to open used monitor the state of lxc monitor process. + */ + char *exit_fifo; + /*! Whether container wishes to create pty or pipes for console log */ + bool disable_pty; + + /*! Whether container wishes to keep stdin active */ + bool open_stdin; + + /*! + * \private + * isulad: support oci hook from json file + * full path of json file + * */ + char *ocihookfile; + + /*! isulad: + * \private + * start_timeout. + */ + unsigned int start_timeout; + + /*! isulad: + * \private + * image_type_oci + */ + bool image_type_oci; +#endif + /*! * \brief Determine if \c /var/lib/lxc/$name/config exists. * @@ -884,6 +958,115 @@ struct lxc_container { * \return Mount fd of the container's devpts instance. */ int (*devpts_fd)(struct lxc_container *c); + +#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 }; /*! @@ -1017,6 +1200,20 @@ struct lxc_console_log { */ struct lxc_container *lxc_container_new(const char *name, const char *configpath); +#ifdef HAVE_ISULAD +/*! + * \brief Create a new container without loading config. + * + * \param name Name to use for container. + * \param configpath Full path to configuration file to use. + * + * \return Newly-allocated container, or \c NULL on error. + * + * \note This function can only used for listing container. + */ +struct lxc_container *lxc_container_without_config_new(const char *name, const char *configpath); +#endif + /*! * \brief Add a reference to the specified container. * diff --git a/src/lxc/start.c b/src/lxc/start.c index 9f68304..70af128 100644 --- a/src/lxc/start.c +++ b/src/lxc/start.c @@ -344,7 +344,11 @@ static int setup_signal_fd(sigset_t *oldmask) { int ret; sigset_t mask; +#ifdef HAVE_ISULAD + const int signals[] = {SIGBUS, SIGILL, SIGSEGV, SIGWINCH, SIGTERM}; +#else const int signals[] = {SIGBUS, SIGILL, SIGSEGV, SIGWINCH}; +#endif /* Block everything except serious error signals. */ ret = sigfillset(&mask); @@ -625,6 +629,16 @@ int lxc_poll(const char *name, struct lxc_handler *handler) TRACE("Mainloop is ready"); +#ifdef HAVE_ISULAD + // iSulad: close stdin pipe if we do not want open_stdin with container stdin + if (!handler->conf->console.open_stdin) { + if (handler->conf->console.pipes[0][1] > 0) { + close(handler->conf->console.pipes[0][1]); + handler->conf->console.pipes[0][1] = -1; + } + } +#endif + ret = lxc_mainloop(&descr, -1); if (descr.type == LXC_MAINLOOP_EPOLL) close_prot_errno_disarm(descr.epfd); @@ -634,7 +648,11 @@ int lxc_poll(const char *name, struct lxc_handler *handler) if (console) { ret = lxc_terminal_mainloop_add(&descr_console, console); if (ret == 0) +#ifdef HAVE_ISULAD + ret = isulad_safe_mainloop(&descr_console, 100); +#else ret = lxc_mainloop(&descr_console, 0); +#endif } out_mainloop_console: @@ -718,6 +736,12 @@ struct lxc_handler *lxc_init_handler(struct lxc_handler *old, } handler->name = name; + +#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 @@ -768,6 +792,10 @@ int lxc_init(const char *name, struct lxc_handler *handler) int ret; const char *loglevel; struct lxc_conf *conf = handler->conf; +#ifdef HAVE_ISULAD + conf->console.disable_pty = handler->disable_pty; + conf->console.open_stdin = handler->open_stdin; +#endif handler->monitor_pid = lxc_raw_getpid(); status_fd = open("/proc/self/status", O_RDONLY | O_CLOEXEC); @@ -908,6 +936,186 @@ void lxc_expose_namespace_environment(const struct lxc_handler *handler) } } + +#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; @@ -945,14 +1153,44 @@ void lxc_end(struct lxc_handler *handler) handler->lsm_ops->cleanup(handler->lsm_ops, handler->conf, handler->lxcpath); + +#ifdef HAVE_ISULAD + // close maincmd fd before destroy cgroup for isulad + if (handler->conf->reboot == REBOOT_NONE) { + /* For all new state clients simply close the command socket. + * This will inform all state clients that the container is + * STOPPED and also prevents a race between a open()/close() on + * the command socket causing a new process to get ECONNREFUSED + * because we haven't yet closed the command socket. + */ + close_prot_errno_disarm(handler->conf->maincmd_fd); + TRACE("Closed command socket"); + } + int retry_count = 0; + int max_retry = 10; +retry: + if (cgroup_ops != NULL && !cgroup_ops->payload_destroy(cgroup_ops, handler)) { + TRACE("Trying to kill all subprocess"); + signal_all_processes(handler); + TRACE("Finished kill all subprocess"); + if (retry_count < max_retry) { + usleep(100 * 1000); /* 100 millisecond */ + retry_count++; + goto retry; + } + SYSERROR("Failed to destroy cgroup path for container: \"%s\"", handler->name); + } +#else if (cgroup_ops) { cgroup_ops->payload_destroy(cgroup_ops, handler); cgroup_ops->monitor_destroy(cgroup_ops, handler); } +#endif put_lxc_rootfs(&handler->conf->rootfs, true); if (handler->conf->reboot == REBOOT_NONE) { +#ifndef HAVE_ISULAD /* For all new state clients simply close the command socket. * This will inform all state clients that the container is * STOPPED and also prevents a race between a open()/close() on @@ -961,12 +1199,23 @@ void lxc_end(struct lxc_handler *handler) */ close_prot_errno_disarm(handler->conf->maincmd_fd); TRACE("Closed command socket"); +#endif /* This function will try to connect to the legacy lxc-monitord * state server and only exists for backwards compatibility. */ lxc_monitor_send_state(name, STOPPED, handler->lxcpath); +#ifdef HAVE_ISULAD + /* isuald: write exit code to exit fifo */ + if (handler->conf->exit_fd >= 0) { + ret = write(handler->conf->exit_fd, &handler->exit_code, sizeof(int)); + if (ret != sizeof(int)) { + SYSERROR("Failed to write to exit code to exit fifo."); + } + } +#endif + /* The command socket is closed so no one can acces the command * socket anymore so there's no need to lock it. */ @@ -1060,6 +1309,25 @@ static int do_start(void *data) lxc_sync_fini_parent(handler); +#ifdef HAVE_ISULAD + sigset_t mask; + + /*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_one_fd(data_sock1, &status_fd, NULL, 0) < 0) { ERROR("Failed to receive status file descriptor from parent process"); goto out_warn_father; @@ -1153,7 +1421,11 @@ static int do_start(void *data) * means that migration won't work, but at least we won't spew output * where it isn't wanted. */ +#ifdef HAVE_ISULAD + if (!handler->disable_pty && handler->daemonize && !handler->conf->autodev) { +#else if (handler->daemonize && !handler->conf->autodev) { +#endif char path[PATH_MAX]; ret = strnprintf(path, sizeof(path), "%s/dev/null", @@ -1269,6 +1541,9 @@ static int do_start(void *data) /* Setup the container, ip, names, utsname, ... */ ret = lxc_setup(handler); if (ret < 0) { +#ifdef HAVE_ISULAD + lxc_write_error_message(handler->conf->errpipe[1], "Failed to setup lxc, please check the config file."); +#endif ERROR("Failed to setup container \"%s\"", handler->name); goto out_warn_father; } @@ -1291,6 +1566,43 @@ static int do_start(void *data) DEBUG("Set PR_SET_NO_NEW_PRIVS to block execve() gainable privileges"); } +#ifdef HAVE_ISULAD + /* isulad: dup2 pipe[0][0] to container stdin, pipe[1][1] to container stdout, pipe[2][1] to container stderr */ + if (handler->disable_pty) { + if (handler->conf->console.pipes[0][1] >= 0) { + close(handler->conf->console.pipes[0][1]); + handler->conf->console.pipes[0][1] = -1; + } + + 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 + /* If we mounted a temporary proc, then unmount it now. */ tmp_proc_unmount(handler->conf); @@ -1307,7 +1619,11 @@ static int do_start(void *data) close_prot_errno_disarm(handler->sigfd); +#ifdef HAVE_ISULAD + if (!handler->disable_pty && handler->conf->console.pty < 0 && handler->daemonize) { +#else if (handler->conf->console.pty < 0 && handler->daemonize) { +#endif if (devnull_fd < 0) { devnull_fd = open_devnull(); if (devnull_fd < 0) @@ -1326,6 +1642,16 @@ static int do_start(void *data) setsid(); if (handler->conf->init_cwd) { +#ifdef HAVE_ISULAD + /* try to craete workdir if not exist */ + struct stat st; + if (stat(handler->conf->init_cwd, &st) < 0 && mkdir_p(handler->conf->init_cwd, 0755) < 0) { + SYSERROR("Try to create directory \"%s\" as workdir failed", handler->conf->init_cwd); + lxc_write_error_message(handler->conf->errpipe[1], "%s:%d: Failed to create workdir: %s.", + __FILE__, __LINE__, strerror(errno)); + goto out_warn_father; + } +#endif ret = chdir(handler->conf->init_cwd); if (ret < 0) { SYSERROR("Could not change directory to \"%s\"", @@ -1372,12 +1698,26 @@ static int do_start(void *data) } } +#ifdef HAVE_ISULAD + if (prctl(PR_SET_KEEPCAPS, 1) < 0) { + SYSERROR("Failed to keep permitted capabilities"); + goto out_warn_father; + } +#endif + /* The container has been setup. We can now switch to an unprivileged * uid/gid. */ new_uid = handler->conf->init_uid; new_gid = handler->conf->init_gid; +#ifdef HAVE_ISULAD + // isulad: set env home in container, must before "Avoid unnecessary syscalls." + if (lxc_setup_env_home(new_uid) < 0) { + goto out_warn_father; + } +#endif + /* Avoid unnecessary syscalls. */ if (new_uid == nsuid) new_uid = LXC_INVALID_UID; @@ -1419,6 +1759,19 @@ static int do_start(void *data) goto out_warn_father; } +#ifdef HAVE_ISULAD + /* isulad: drop the cap of current process */ + if (prctl(PR_SET_KEEPCAPS, 0) < 0) { + SYSERROR("Failed to clear permitted capabilities"); + goto out_warn_father; + } + + 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); @@ -1433,7 +1786,12 @@ static int do_start(void *data) * After this call, we are in error because this ops should not return * as it execs. */ +#ifdef HAVE_ISULAD + close_prot_errno_disarm(status_fd); + handler->ops->start(handler, handler->data, handler->daemonize ? handler->conf->errpipe[1] : -1); +#else handler->ops->start(handler, handler->data); +#endif out_warn_father: /* @@ -1604,6 +1962,94 @@ static inline void resolve_cgroup_clone_flags(struct lxc_handler *handler) handler->ns_unshare_flags |= CLONE_NEWCGROUP; } +#ifdef HAVE_ISULAD +static int lxc_write_container_info(char *filename, pid_t pid, pid_t p_pid, + unsigned long long start_at, unsigned long long p_start_at) +{ + FILE *pid_fp = NULL; + int ret = 0; + + 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 @@ -1741,6 +2187,32 @@ static int lxc_spawn(struct lxc_handler *handler) handler->clone_flags &= ~CLONE_PIDFD; TRACE("Cloned child process %d", handler->pid); +#ifdef HAVE_ISULAD + /* isulad: close pipe after clone */ + if (handler->conf->console.pipes[0][0] >= 0) { + close(handler->conf->console.pipes[0][0]); + handler->conf->console.pipes[0][0] = -1; + } + + if (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 + ret = core_scheduling(handler); if (ret < 0) goto out_delete_net; @@ -1757,6 +2229,13 @@ static int lxc_spawn(struct lxc_handler *handler) if (ret < 0) SYSERROR("Failed to set environment variable: LXC_PID=%s", pidstr); +#ifdef HAVE_ISULAD + if (handler->cgroup_ops->container_cgroup) { + if (setenv("LXC_CGROUP_PATH", handler->cgroup_ops->container_cgroup, 1)) + SYSERROR("Failed to set environment variable: LXC_CGROUP_PATH=%s.", handler->cgroup_ops->container_cgroup); + } +#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); @@ -1848,7 +2327,11 @@ static int lxc_spawn(struct lxc_handler *handler) goto out_delete_net; } +#ifdef HAVE_ISULAD + ret = setup_resource_limits(conf, handler->pid, conf->errpipe[1]); +#else ret = setup_resource_limits(conf, handler->pid); +#endif if (ret < 0) { ERROR("Failed to setup resource limits"); goto out_delete_net; @@ -1911,6 +2394,27 @@ static int lxc_spawn(struct lxc_handler *handler) goto out_delete_net; } +#ifdef HAVE_ISULAD + /* isulad: Run oci prestart hook at here */ + ret = run_oci_hooks(name, "oci-prestart", conf, lxcpath); + if (ret < 0) { + ERROR("Failed to run oci prestart hooks"); + goto out_delete_net; + } + + if (START_TIMEOUT == global_timeout_state) { + lxc_write_error_message(conf->errpipe[1], "Starting the container \"%s\" timeout.", name); + ERROR("Starting the container \"%s\" timeout.", name); + goto out_delete_net; + } + + /* Tell the child to continue its initialization. We'll get + * LXC_SYNC_POST_OCI_PRESTART_HOOK when it is ready for us to run oci prestart hooks. + */ + if (lxc_sync_barrier_child(handler, LXC_SYNC_POST_OCI_PRESTART_HOOK)) + goto out_delete_net; +#endif + if (!lxc_sync_wake_child(handler, START_SYNC_FDS)) goto out_delete_net; @@ -1969,6 +2473,22 @@ static int lxc_spawn(struct lxc_handler *handler) if (ret < 0) goto out_abort; +#ifdef HAVE_ISULAD + /* isulad: Run oci prestart hook at here */ + ret = run_oci_hooks(name, "oci-poststart", conf, lxcpath); + if (ret < 0) { + ERROR("Failed to run oci poststart hooks"); + goto out_abort; + } + + if (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)); @@ -2014,9 +2534,82 @@ static int lxc_inherit_namespaces(struct lxc_handler *handler) return 0; } +#ifdef HAVE_ISULAD +/* isulad: start timeout thread function */ +static void* wait_start_timeout(void *arg) +{ + 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; @@ -2032,6 +2625,17 @@ int __lxc_start(struct lxc_handler *handler, struct lxc_operations *ops, handler->daemonize = daemonize; cgroup_ops = handler->cgroup_ops; +#ifdef HAVE_ISULAD + /* isulad: add start timeout limit */ + if (start_timeout > 0) { + ret = create_start_timeout_thread(conf, start_timeout); + if (ret) { + ERROR("Failed to create start timeout thread for container \"%s\".", name); + goto out_abort; + } + } +#endif + if (!attach_block_device(handler->conf)) { ERROR("Failed to attach block device"); ret = -1; @@ -2116,11 +2720,13 @@ int __lxc_start(struct lxc_handler *handler, struct lxc_operations *ops, goto out_delete_network; } +#ifndef HAVE_ISULAD if (!handler->init_died && handler->pid > 0) { ERROR("Child process is not killed"); ret = -1; goto out_delete_network; } +#endif status = lxc_wait_for_pid_status(handler->pid); if (status < 0) @@ -2130,6 +2736,20 @@ int __lxc_start(struct lxc_handler *handler, struct lxc_operations *ops, * reboot. This should mean it was an lxc-execute which simply exited. * In any case, treat it as a 'halt'. */ +#ifdef HAVE_ISULAD + // isulad: recored log for container init exit + if (WIFSIGNALED(status)) { + int signal_nr = WTERMSIG(status); + exit_code = EXIT_SIGNAL_OFFSET + signal_nr; + ERROR("Container \"%s\" init exited with signal %d", name, signal_nr); + } else if (WIFEXITED(status)) { + exit_code = WEXITSTATUS(status); + ERROR("Container \"%s\" init exited with status %d", name, exit_code); + } else { + exit_code = -1; + ERROR("Container \"%s\" init exited with unknown status", name); + } +#else if (WIFSIGNALED(status)) { int signal_nr = WTERMSIG(status); switch(signal_nr) { @@ -2148,16 +2768,25 @@ int __lxc_start(struct lxc_handler *handler, struct lxc_operations *ops, break; } } +#endif ret = lxc_restore_phys_nics_to_netns(handler); if (ret < 0) ERROR("Failed to move physical network devices back to parent network namespace"); +#ifdef HAVE_ISULAD + lxc_monitor_send_exit_code(name, exit_code, handler->lxcpath); +#else lxc_monitor_send_exit_code(name, status, handler->lxcpath); +#endif lxc_error_set_and_log(handler->pid, status); if (error_num) *error_num = handler->exit_status; +#ifdef HAVE_ISULAD + handler->exit_code = exit_code; /* record exit code */ +#endif + lxc_delete_network(handler); detach_block_device(handler->conf); lxc_end(handler); @@ -2187,7 +2816,11 @@ struct start_args { char *const *argv; }; +#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; @@ -2195,6 +2828,9 @@ static int start(struct lxc_handler *handler, void* data) execvp(arg->argv[0], arg->argv); SYSERROR("Failed to exec \"%s\"", arg->argv[0]); +#ifdef HAVE_ISULAD + lxc_write_error_message(fd, "exec: \"%s\": %s.", arg->argv[0], strerror(errno)); +#endif return 0; } @@ -2212,14 +2848,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, @@ -2291,3 +2935,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/start.h b/src/lxc/start.h index bbd1a83..d03e5d5 100644 --- a/src/lxc/start.h +++ b/src/lxc/start.h @@ -153,7 +153,11 @@ struct execute_args { }; struct lxc_operations { +#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 *); }; @@ -184,12 +188,26 @@ static inline int inherit_fds(struct lxc_handler *handler, bool closeall) ARRAY_SIZE(handler->keep_fds)); } +#ifdef HAVE_ISULAD +__hidden extern int __lxc_start(struct lxc_handler *handler, + struct lxc_operations* ops, void *data, const char *lxcpath, + bool daemonize, int *error_num, unsigned int start_timeout); +#else __hidden extern int __lxc_start(struct lxc_handler *, struct lxc_operations *, void *, const char *, bool, int *); +#endif __hidden extern int resolve_clone_flags(struct lxc_handler *handler); __hidden extern void lxc_expose_namespace_environment(const 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 + static inline bool container_uses_namespace(const struct lxc_handler *handler, unsigned int ns_flag) { -- 2.25.1
Locations
Projects
Search
Status Monitor
Help
Open Build Service
OBS Manuals
API Documentation
OBS Portal
Reporting a Bug
Contact
Mailing List
Forums
Chat (IRC)
Twitter
Open Build Service (OBS)
is an
openSUSE project
.
浙ICP备2022010568号-2