lxc/0010-IO-refact-terminal-progress.patch

3569 lines
105 KiB
Diff
Raw Normal View History

From 1dce19b2ce4d01c12f3f4eda0666457f2fd3c42c Mon Sep 17 00:00:00 2001
From: LiFeng <lifeng68@huawei.com>
Date: Mon, 13 Apr 2020 18:11:59 +0800
Subject: [PATCH 10/49] IO: refact terminal progress
Signed-off-by: LiFeng <lifeng68@huawei.com>
---
configure.ac | 3 +
src/lxc/Makefile.am | 24 +-
src/lxc/attach.c | 20 +-
src/lxc/attach_options.h | 5 +
src/lxc/conf.c | 10 +
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/logger_json_file.c | 246 ++++++++
src/lxc/json/logger_json_file.h | 45 ++
src/lxc/json/oci_runtime_hooks.c | 52 ++
src/lxc/json/oci_runtime_hooks.h | 15 +
src/lxc/json/oci_runtime_spec.c | 195 +++++++
src/lxc/json/oci_runtime_spec.h | 37 ++
src/lxc/json/read-file.c | 95 ++++
src/lxc/json/read-file.h | 11 +
src/lxc/lxccontainer.c | 36 ++
src/lxc/lxccontainer.h | 24 +
src/lxc/terminal.c | 783 ++++++++++++++++++++++++++
src/lxc/terminal.h | 20 +
src/lxc/tools/arguments.h | 1 +
src/lxc/tools/lxc_start.c | 12 +
23 files changed, 3208 insertions(+), 6 deletions(-)
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
create mode 100755 src/lxc/json/json_common.h
create mode 100644 src/lxc/json/logger_json_file.c
create mode 100644 src/lxc/json/logger_json_file.h
create mode 100644 src/lxc/json/oci_runtime_hooks.c
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
diff --git a/configure.ac b/configure.ac
index 5f386d9..56d0cb7 100644
--- a/configure.ac
+++ b/configure.ac
@@ -119,6 +119,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],
diff --git a/src/lxc/Makefile.am b/src/lxc/Makefile.am
index d8c2492..23935e5 100644
--- a/src/lxc/Makefile.am
+++ b/src/lxc/Makefile.am
@@ -53,7 +53,12 @@ noinst_HEADERS = api_extensions.h \
uuid.h
#if HAVE_ISULAD
-noinst_HEADERS += isulad_utils.h path.h
+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
#endif
if IS_BIONIC
@@ -159,10 +164,16 @@ liblxc_la_SOURCES = af_unix.c af_unix.h \
version.h \
$(LSM_SOURCES)
-#if HAVE_ISULAD
+if HAVE_ISULAD
liblxc_la_SOURCES += isulad_utils.c isulad_utils.h \
- path.c path.h
-#endif
+ 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
+endif
if IS_BIONIC
liblxc_la_SOURCES += ../include/fexecve.c ../include/fexecve.h \
@@ -223,6 +234,7 @@ AM_CFLAGS = -DLXCROOTFSMOUNT=\"$(LXCROOTFSMOUNT)\" \
-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
@@ -271,6 +283,10 @@ 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@
+endif
+
liblxc_la_LIBADD = $(CAP_LIBS) \
$(OPENSSL_LIBS) \
$(SELINUX_LIBS) \
diff --git a/src/lxc/attach.c b/src/lxc/attach.c
index 56d62ed..78b4700 100644
--- a/src/lxc/attach.c
+++ b/src/lxc/attach.c
@@ -898,12 +898,28 @@ on_error:
}
static int lxc_attach_terminal(struct lxc_conf *conf,
- struct lxc_terminal *terminal)
+ struct lxc_terminal *terminal, lxc_attach_options_t *options)
{
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]);
+ }
+#endif
+
ret = lxc_terminal_create(terminal);
if (ret < 0)
return log_error(-1, "Failed to create terminal");
@@ -1097,7 +1113,7 @@ int lxc_attach(struct lxc_container *container, lxc_attach_exec_t exec_function,
}
if (options->attach_flags & LXC_ATTACH_TERMINAL) {
- ret = lxc_attach_terminal(conf, &terminal);
+ ret = lxc_attach_terminal(conf, &terminal, options);
if (ret < 0) {
ERROR("Failed to setup new terminal");
free(cwd);
diff --git a/src/lxc/attach_options.h b/src/lxc/attach_options.h
index ec8bea1..3a02ee5 100644
--- a/src/lxc/attach_options.h
+++ b/src/lxc/attach_options.h
@@ -113,6 +113,11 @@ 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*/
+#endif
+
} lxc_attach_options_t;
/*! Default attach options to use */
diff --git a/src/lxc/conf.c b/src/lxc/conf.c
index 1f779b9..1487b73 100644
--- a/src/lxc/conf.c
+++ b/src/lxc/conf.c
@@ -2669,6 +2669,16 @@ struct lxc_conf *lxc_conf_init(void)
/* isulad add begin */
lxc_list_init(&new->populate_devs);
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);
#endif
return new;
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 <string.h>
+#include <read-file.h>
+#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 : "");
+ }
+ }
+ {
+ yajl_val tmp = get_val(tree, "args", yajl_t_array);
+ if (tmp != NULL && YAJL_GET_ARRAY(tmp) != NULL && YAJL_GET_ARRAY(tmp)->len > 0) {
+ size_t i;
+ ret->args_len = YAJL_GET_ARRAY(tmp)->len;
+ if (YAJL_GET_ARRAY(tmp)->len > SIZE_MAX / sizeof(*ret->args) - 1) {
+ free_defs_hook(ret);
+ return NULL;
+ }
+ ret->args = safe_malloc((YAJL_GET_ARRAY(tmp)->len + 1) * sizeof(*ret->args));
+ for (i = 0; i < YAJL_GET_ARRAY(tmp)->len; i++) {
+ yajl_val val = YAJL_GET_ARRAY(tmp)->values[i];
+ if (val != NULL) {
+ char *str = YAJL_GET_STRING(val);
+ ret->args[i] = safe_strdup(str ? str : "");
+ }
+ }
+ }
+ }
+ {
+ yajl_val tmp = get_val(tree, "env", yajl_t_array);
+ if (tmp != NULL && YAJL_GET_ARRAY(tmp) != NULL && YAJL_GET_ARRAY(tmp)->len > 0) {
+ size_t i;
+ ret->env_len = YAJL_GET_ARRAY(tmp)->len;
+ if (YAJL_GET_ARRAY(tmp)->len > SIZE_MAX / sizeof(*ret->env) - 1) {
+ free_defs_hook(ret);
+ return NULL;
+ }
+ ret->env = safe_malloc((YAJL_GET_ARRAY(tmp)->len + 1) * sizeof(*ret->env));
+ for (i = 0; i < YAJL_GET_ARRAY(tmp)->len; i++) {
+ yajl_val val = YAJL_GET_ARRAY(tmp)->values[i];
+ if (val != NULL) {
+ char *str = YAJL_GET_STRING(val);
+ ret->env[i] = safe_strdup(str ? str : "");
+ }
+ }
+ }
+ }
+ {
+ yajl_val val = get_val(tree, "timeout", yajl_t_number);
+ if (val != NULL) {
+ int invalid = common_safe_int(YAJL_GET_NUMBER(val), (int *)&ret->timeout);
+ if (invalid) {
+ if (asprintf(err, "Invalid value '%s' with type 'integer' for key 'timeout': %s", YAJL_GET_NUMBER(val), strerror(-invalid)) < 0)
+ *err = safe_strdup("error allocating memory");
+ free_defs_hook(ret);
+ return NULL;
+ }
+ }
+ }
+ if (ret->path == NULL) {
+ if (asprintf(err, "Required field '%s' not present", "path") < 0)
+ *err = safe_strdup("error allocating memory");
+ free_defs_hook(ret);
+ return NULL;
+ }
+
+ if (tree->type == yajl_t_object && (ctx->options & PARSE_OPTIONS_STRICT)) {
+ int i;
+ for (i = 0; i < tree->u.object.len; i++)
+ if (strcmp(tree->u.object.keys[i], "path") &&
+ strcmp(tree->u.object.keys[i], "args") &&
+ strcmp(tree->u.object.keys[i], "env") &&
+ strcmp(tree->u.object.keys[i], "timeout")) {
+ if (ctx->stderr > 0)
+ fprintf(ctx->stderr, "WARNING: unknown key found: %s\n", tree->u.object.keys[i]);
+ }
+ }
+ return ret;
+}
+
+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);
+}
+
+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 <sys/types.h>
+#include <stdint.h>
+#include "json_common.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct {
+ char *path;
+
+ char **args;
+ size_t args_len;
+
+ char **env;
+ size_t env_len;
+
+ int timeout;
+
+}
+defs_hook;
+
+void free_defs_hook(defs_hook *ptr);
+
+defs_hook *make_defs_hook(yajl_val tree, struct parser_context *ctx, parser_error *err);
+
+yajl_gen_status gen_defs_hook(yajl_gen g, defs_hook *ptr, struct parser_context *ctx, parser_error *err);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/lxc/json/json_common.c b/src/lxc/json/json_common.c
new file mode 100755
index 0000000..ec20c59
--- /dev/null
+++ b/src/lxc/json/json_common.c
@@ -0,0 +1,1153 @@
+// Auto generated file. Do not edit!
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <errno.h>
+#include <limits.h>
+#include "json_common.h"
+
+#define MAX_NUM_STR_LEN 21
+
+yajl_gen_status reformat_number(void *ctx, const char *str, size_t len) {
+ yajl_gen g = (yajl_gen) ctx;
+ return yajl_gen_number(g, str, len);
+}
+
+yajl_gen_status reformat_uint(void *ctx, long long unsigned int num) {
+ char numstr[MAX_NUM_STR_LEN];
+ int ret;
+
+ 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));
+}
+
+yajl_gen_status reformat_int(void *ctx, long long int num) {
+ char numstr[MAX_NUM_STR_LEN];
+ int ret;
+
+ 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_double(void *ctx, double num) {
+ yajl_gen g = (yajl_gen) ctx;
+ return yajl_gen_double(g, 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_null(void *ctx) {
+ yajl_gen g = (yajl_gen) ctx;
+ return yajl_gen_null(g);
+}
+
+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_map_key(void *ctx, const char *str, size_t len) {
+ yajl_gen g = (yajl_gen) ctx;
+ return yajl_gen_string(g, (const unsigned char *)str, len);
+}
+
+yajl_gen_status reformat_start_map(void *ctx) {
+ yajl_gen g = (yajl_gen) ctx;
+ return yajl_gen_map_open(g);
+}
+
+yajl_gen_status reformat_end_map(void *ctx) {
+ yajl_gen g = (yajl_gen) ctx;
+ return yajl_gen_map_close(g);
+}
+
+yajl_gen_status reformat_start_array(void *ctx) {
+ yajl_gen g = (yajl_gen) ctx;
+ return yajl_gen_array_open(g);
+}
+
+yajl_gen_status reformat_end_array(void *ctx) {
+ yajl_gen g = (yajl_gen) ctx;
+ return yajl_gen_array_close(g);
+}
+
+bool json_gen_init(yajl_gen *g, struct parser_context *ctx) {
+ *g = yajl_gen_alloc(NULL);
+ if (NULL == *g) {
+ return false;
+
+ }
+ yajl_gen_config(*g, yajl_gen_beautify, !(ctx->options & GEN_OPTIONS_SIMPLIFY));
+ yajl_gen_config(*g, yajl_gen_validate_utf8, !(ctx->options & GEN_OPTIONS_NOT_VALIDATE_UTF8));
+ return true;
+}
+
+yajl_val get_val(yajl_val tree, const char *name, yajl_type type) {
+ const char *path[] = { name, NULL };
+ return yajl_tree_get(tree, path, type);
+}
+
+void *safe_malloc(size_t size) {
+ void *ret = NULL;
+ if (size == 0) {
+ abort();
+ }
+ ret = calloc(1, size);
+ if (ret == NULL) {
+ abort();
+ }
+ return ret;
+}
+
+int common_safe_double(const char *numstr, double *converted) {
+ char *err_str = NULL;
+ double d;
+
+ if (numstr == NULL) {
+ return -EINVAL;
+ }
+
+ errno = 0;
+ d = strtod(numstr, &err_str);
+ if (errno > 0) {
+ return -errno;
+ }
+
+ if (err_str == NULL || err_str == numstr || *err_str != '\0') {
+ return -EINVAL;
+ }
+
+ *converted = d;
+ return 0;
+}
+
+int common_safe_uint8(const char *numstr, uint8_t *converted) {
+ char *err = NULL;
+ unsigned long int uli;
+
+ if (numstr == NULL) {
+ return -EINVAL;
+ }
+
+ errno = 0;
+ uli = strtoul(numstr, &err, 0);
+ if (errno > 0) {
+ return -errno;
+ }
+
+ if (err == NULL || err == numstr || *err != '\0') {
+ return -EINVAL;
+ }
+
+ if (uli > UINT8_MAX) {
+ return -ERANGE;
+ }
+
+ *converted = (uint8_t)uli;
+ return 0;
+}
+
+int common_safe_uint16(const char *numstr, uint16_t *converted) {
+ char *err = NULL;
+ unsigned long int uli;
+
+ if (numstr == NULL) {
+ return -EINVAL;
+ }
+
+ errno = 0;
+ uli = strtoul(numstr, &err, 0);
+ if (errno > 0) {
+ return -errno;
+ }
+
+ if (err == NULL || err == numstr || *err != '\0') {
+ return -EINVAL;
+ }
+
+ if (uli > UINT16_MAX) {
+ return -ERANGE;
+ }
+
+ *converted = (uint16_t)uli;
+ return 0;
+}
+
+int common_safe_uint32(const char *numstr, uint32_t *converted) {
+ char *err = NULL;
+ unsigned long long int ull;
+
+ if (numstr == NULL) {
+ return -EINVAL;
+ }
+
+ errno = 0;
+ ull = strtoull(numstr, &err, 0);
+ if (errno > 0) {
+ return -errno;
+ }
+
+ if (err == NULL || err == numstr || *err != '\0') {
+ return -EINVAL;
+ }
+
+ if (ull > UINT32_MAX) {
+ return -ERANGE;
+ }
+
+ *converted = (uint32_t)ull;
+ return 0;
+}
+
+int common_safe_uint64(const char *numstr, uint64_t *converted) {
+ char *err = NULL;
+ unsigned long long int ull;
+
+ if (numstr == NULL) {
+ return -EINVAL;
+ }
+
+ errno = 0;
+ ull = strtoull(numstr, &err, 0);
+ if (errno > 0) {
+ return -errno;
+ }
+
+ if (err == NULL || err == numstr || *err != '\0') {
+ return -EINVAL;
+ }
+
+ *converted = (uint64_t)ull;
+ return 0;
+}
+
+int common_safe_uint(const char *numstr, unsigned int *converted) {
+ char *err = NULL;
+ unsigned long long int ull;
+
+ if (numstr == NULL) {
+ return -EINVAL;
+ }
+
+ errno = 0;
+ ull = strtoull(numstr, &err, 0);
+ if (errno > 0) {
+ return -errno;
+ }
+
+ if (err == NULL || err == numstr || *err != '\0') {
+ return -EINVAL;
+ }
+
+ if (ull > UINT_MAX) {
+ return -ERANGE;
+ }
+
+ *converted = (unsigned int)ull;
+ return 0;
+}
+
+int common_safe_int8(const char *numstr, int8_t *converted) {
+ char *err = NULL;
+ long int li;
+
+ if (numstr == NULL) {
+ return -EINVAL;
+ }
+
+ errno = 0;
+ li = strtol(numstr, &err, 0);
+ if (errno > 0) {
+ return -errno;
+ }
+
+ if (err == NULL || err == numstr || *err != '\0') {
+ return -EINVAL;
+ }
+
+ if (li > INT8_MAX || li < INT8_MIN) {
+ return -ERANGE;
+ }
+
+ *converted = (int8_t)li;
+ return 0;
+}
+
+int common_safe_int16(const char *numstr, int16_t *converted) {
+ char *err = NULL;
+ long int li;
+
+ if (numstr == NULL) {
+ return -EINVAL;
+ }
+
+ errno = 0;
+ li = strtol(numstr, &err, 0);
+ if (errno > 0) {
+ return -errno;
+ }
+
+ if (err == NULL || err == numstr || *err != '\0') {
+ return -EINVAL;
+ }
+
+ if (li > INT16_MAX || li < INT16_MIN) {
+ return -ERANGE;
+ }
+
+ *converted = (int16_t)li;
+ return 0;
+}
+
+int common_safe_int32(const char *numstr, int32_t *converted) {
+ char *err = NULL;
+ long long int lli;
+
+ if (numstr == NULL) {
+ return -EINVAL;
+ }
+
+ errno = 0;
+ lli = strtol(numstr, &err, 0);
+ if (errno > 0) {
+ return -errno;
+ }
+
+ if (err == NULL || err == numstr || *err != '\0') {
+ return -EINVAL;
+ }
+
+ if (lli > INT32_MAX || lli < INT32_MIN) {
+ return -ERANGE;
+ }
+
+ *converted = (int32_t)lli;
+ return 0;
+}
+
+int common_safe_int64(const char *numstr, int64_t *converted) {
+ char *err = NULL;
+ long long int lli;
+
+ if (numstr == NULL) {
+ return -EINVAL;
+ }
+
+ errno = 0;
+ lli = strtoll(numstr, &err, 0);
+ if (errno > 0) {
+ return -errno;
+ }
+
+ if (err == NULL || err == numstr || *err != '\0') {
+ return -EINVAL;
+ }
+
+ *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..60aa5fd
--- /dev/null
+++ b/src/lxc/json/json_common.h
@@ -0,0 +1,185 @@
+// Auto generated file. Do not edit!
+#ifndef _JSON_COMMON_H
+#define _JSON_COMMON_H
+
+#include <stdbool.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <yajl/yajl_tree.h>
+#include <yajl/yajl_gen.h>
+#include "utils.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+# undef linux
+
+//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 <string.h>
+#include <read-file.h>
+#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 <sys/types.h>
+#include <stdint.h>
+#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 <read-file.h>
+#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 <string.h>
+#include <read-file.h>
+#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 <sys/types.h>
+#include <stdint.h>
+#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
diff --git a/src/lxc/json/read-file.c b/src/lxc/json/read-file.c
new file mode 100644
index 0000000..70e73e5
--- /dev/null
+++ b/src/lxc/json/read-file.c
@@ -0,0 +1,95 @@
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+
+#include <config.h>
+#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, 0640);
+ 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/json/read-file.h b/src/lxc/json/read-file.h
new file mode 100644
index 0000000..5d6e0eb
--- /dev/null
+++ b/src/lxc/json/read-file.h
@@ -0,0 +1,11 @@
+#ifndef READ_FILE_H
+#define READ_FILE_H
+
+#include <stddef.h>
+#include <stdio.h>
+
+extern char *fread_file(FILE *stream, size_t *length);
+
+extern char *read_file(const char *path, size_t *length);
+
+#endif
diff --git a/src/lxc/lxccontainer.c b/src/lxc/lxccontainer.c
index 33bb3ec..891fc62 100644
--- a/src/lxc/lxccontainer.c
+++ b/src/lxc/lxccontainer.c
@@ -5294,6 +5294,41 @@ 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)
{
@@ -5461,6 +5496,7 @@ struct lxc_container *lxc_container_new(const char *name, const char *configpath
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;
#endif
return c;
diff --git a/src/lxc/lxccontainer.h b/src/lxc/lxccontainer.h
index edfff32..4a9ba13 100644
--- a/src/lxc/lxccontainer.h
+++ b/src/lxc/lxccontainer.h
@@ -876,6 +876,30 @@ struct lxc_container {
* \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);
#endif
};
diff --git a/src/lxc/terminal.c b/src/lxc/terminal.c
index 1b170ca..c8cd83f 100644
--- a/src/lxc/terminal.c
+++ b/src/lxc/terminal.c
@@ -28,6 +28,9 @@
#include "syscall_wrappers.h"
#include "terminal.h"
#include "utils.h"
+#ifdef HAVE_ISULAD
+#include "logger_json_file.h"
+#endif
#if HAVE_PTY_H
#include <pty.h>
@@ -318,6 +321,426 @@ static int lxc_terminal_write_log_file(struct lxc_terminal *terminal, char *buf,
return bytes_read;
}
+#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_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 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;
+
+ lxc_list_for_each_safe(it, list, next) {
+ elem = it->elem;
+ if (is_err) {
+ if (elem->err_fd >= 0)
+ lxc_write_nointr(elem->err_fd, buf, r);
+ } else {
+ if (elem->out_fd >= 0)
+ lxc_write_nointr(elem->out_fd, buf, r);
+ }
+ }
+
+ 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->master) {
+ terminal->master = -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 master 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]) {
+ w_log = isulad_lxc_terminal_write_log_file(terminal, "stdout", NULL, 0);
+ terminal->pipes[1][0] = -EBADF;
+ } else if (fd == terminal->pipes[2][0]) {
+ w_log = isulad_lxc_terminal_write_log_file(terminal, "stderr", NULL, 0);
+ terminal->pipes[2][0] = -EBADF;
+ }
+ if (w_log < 0)
+ TRACE("Failed to write %d bytes to terminal log", r);
+ close(fd);
+ return LXC_MAINLOOP_CONTINUE;
+ } else if (fd == terminal->pipes[0][1]) {
+ TRACE("closed stdin pipe of container stdin");
+ terminal->pipes[0][1] = -EBADF;
+ close(fd);
+ return LXC_MAINLOOP_CONTINUE;
+ } else {
+ ERROR("Handler received unexpected file descriptor");
+ }
+ close(fd);
+ return LXC_MAINLOOP_CLOSE;
+ }
+
+ if (fd == terminal->peer || lxc_terminal_is_fifo(fd, &terminal->fifos)) {
+ if (terminal->master > 0)
+ w = lxc_write_nointr(terminal->master, 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->master || 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->master || 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 +797,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 +825,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->master < 0) {
+ INFO("Terminal is not initialized");
+ return 0;
+ }
+
+ ret = lxc_mainloop_add_handler(descr, terminal->master,
+ lxc_terminal_io_cb, terminal);
+ if (ret < 0) {
+ ERROR("Failed to add handler for terminal master fd %d to "
+ "mainloop", terminal->master);
+ return -1;
+ }
+
+ return 0;
+}
+#else
int lxc_terminal_mainloop_add(struct lxc_epoll_descr *descr,
struct lxc_terminal *terminal)
{
@@ -426,6 +954,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)
{
@@ -760,6 +1289,31 @@ void lxc_terminal_delete(struct lxc_terminal *terminal)
if (terminal->log_fd >= 0)
close(terminal->log_fd);
terminal->log_fd = -1;
+
+#ifdef HAVE_ISULAD
+ /* 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 +1382,215 @@ 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;
+}
+
+static int use_unix_newline(int master_fd)
+{
+ struct termios oldtios;
+ int ret;
+
+ ret = tcgetattr(master_fd, &oldtios);
+ if (ret < 0)
+ return -1;
+ oldtios.c_oflag &= ~ONLCR;
+ ret = tcsetattr(master_fd, TCSAFLUSH, &oldtios);
+ if (ret < 0)
+ return -1;
+ return 0;
+}
+
+int lxc_terminal_create(struct lxc_terminal *terminal)
+{
+ int ret;
+
+ if (!terminal->disable_pty) {
+ ret = openpty(&terminal->master, &terminal->slave, NULL, NULL, NULL);
+ if (ret < 0) {
+ SYSERROR("Failed to open terminal");
+ return -1;
+ }
+
+ ret = ttyname_r(terminal->slave, terminal->name, sizeof(terminal->name));
+ if (ret < 0) {
+ SYSERROR("Failed to retrieve name of terminal slave");
+ goto err;
+ }
+
+ /* isulad: clear ONLCR flag */
+ ret = use_unix_newline(terminal->master);
+ if (ret < 0) {
+ SYSERROR("Failed to clear ONLCR flag on terminal master");
+ goto err;
+ }
+
+ ret = fd_cloexec(terminal->master, true);
+ if (ret < 0) {
+ SYSERROR("Failed to set FD_CLOEXEC flag on terminal master");
+ goto err;
+ }
+
+ /* isulad: make master NONBLOCK */
+ ret = fd_nonblock(terminal->master);
+ if (ret < 0) {
+ SYSERROR("Failed to set O_NONBLOCK flag on terminal master");
+ goto err;
+ }
+
+ ret = fd_cloexec(terminal->slave, true);
+ if (ret < 0) {
+ SYSERROR("Failed to set FD_CLOEXEC flag on terminal slave");
+ 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_NONBLOCK | O_CLOEXEC)) {
+ ERROR("Failed to create stdout pipe");
+ goto err;
+ }
+ /* for stderr */
+ if (pipe2(terminal->pipes[2], O_NONBLOCK | 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;
+}
+#else
int lxc_terminal_create(struct lxc_terminal *terminal)
{
int ret;
@@ -868,6 +1631,7 @@ err:
lxc_terminal_delete(terminal);
return -ENODEV;
}
+#endif
int lxc_terminal_setup(struct lxc_conf *conf)
{
@@ -1146,6 +1910,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 +1931,13 @@ 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);
+#endif
}
int lxc_terminal_map_ids(struct lxc_conf *c, struct lxc_terminal *terminal)
diff --git a/src/lxc/terminal.h b/src/lxc/terminal.h
index 1283cb3..dfc03c6 100644
--- a/src/lxc/terminal.h
+++ b/src/lxc/terminal.h
@@ -88,8 +88,28 @@ 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
*
diff --git a/src/lxc/tools/arguments.h b/src/lxc/tools/arguments.h
index 91f4e9a..214949b 100644
--- a/src/lxc/tools/arguments.h
+++ b/src/lxc/tools/arguments.h
@@ -42,6 +42,7 @@ struct lxc_arguments {
const char *share_ns[32]; /* size must be greater than LXC_NS_MAX */
#ifdef HAVE_ISULAD
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 */
#endif
/* for lxc-console */
diff --git a/src/lxc/tools/lxc_start.c b/src/lxc/tools/lxc_start.c
index 83ee75a..4c4c820 100644
--- a/src/lxc/tools/lxc_start.c
+++ b/src/lxc/tools/lxc_start.c
@@ -125,6 +125,15 @@ static int my_parser(struct lxc_arguments *args, int c, char *arg)
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;
#endif
}
return 0;
@@ -306,6 +315,9 @@ int main(int argc, char *argv[])
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]);
+ }
#endif
if (my_args.console)
--
1.8.3.1