3569 lines
105 KiB
Diff
3569 lines
105 KiB
Diff
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
|
|
|