lcr/src/lcrcontainer_extend.c
gaohuatao 2030cf1cdf lcr: encode some escape charactors of lxc config file string
Signed-off-by: gaohuatao <gaohuatao@huawei.com>
(cherry picked from commit d98eedabdedcf5946cb4e2995ba6a5a1776b987d)
Signed-off-by: gaohuatao <gaohuatao@huawei.com>
2020-04-01 23:37:42 -04:00

1082 lines
26 KiB
C

/******************************************************************************
* Copyright (c) Huawei Technologies Co., Ltd. 2018-2019. All rights reserved.
* lcr licensed under the Mulan PSL v1.
* You can use this software according to the terms and conditions of the Mulan PSL v1.
* You may obtain a copy of Mulan PSL v1 at:
* http://license.coscl.org.cn/MulanPSL
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
* PURPOSE.
* See the Mulan PSL v1 for more details.
* Author: wujing
* Create: 2018-11-08
* Description: provide container definition
******************************************************************************/
/*
* liblcrapi
*/
#define _GNU_SOURCE
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <signal.h>
#include <lxc/lxccontainer.h>
#include "constants.h"
#include "error.h"
#include "lcrcontainer.h"
#include "lcrcontainer_extend.h"
#include "utils.h"
#include "log.h"
#include "conf.h"
#include "oci_runtime_hooks.h"
static struct lxc_container *lcr_new_container(const char *name, const char *path)
{
struct lxc_container *c = lxc_container_new(name, path);
if (c == NULL) {
ERROR("Failed to delete container.");
return NULL;
}
if (!c->is_defined(c)) {
ERROR("No such container");
lcr_set_error_message(LCR_ERR_RUNTIME, "No such container:%s or the configuration files has been corrupted",
name);
goto out_put;
}
if (!c->may_control(c)) {
ERROR("Insufficent privileges to control");
goto out_put;
}
return c;
out_put:
lxc_container_put(c);
return NULL;
}
static int realloc_annotations(oci_runtime_spec *oci_spec, size_t new_lens)
{
size_t new_size = 0;
unsigned long old_size = 0;
char **fkey = NULL;
char **fval = NULL;
int nret = 0;
if (new_lens < 1) {
return 0;
}
if (!oci_spec->annotations) {
oci_spec->annotations = util_common_calloc_s(sizeof(json_map_string_string));
if (!oci_spec->annotations) {
ERROR("Out of memory");
nret = -1;
goto out;
}
}
if (new_lens > SIZE_MAX / sizeof(char *) - oci_spec->annotations->len) {
ERROR("Too many annotations!");
nret = -1;
goto out;
}
new_size = (oci_spec->annotations->len + new_lens) * sizeof(char *);
old_size = oci_spec->annotations->len * sizeof(char *);
nret = mem_realloc((void **)&fkey, new_size, oci_spec->annotations->keys, old_size);
if (nret) {
ERROR("Failed to realloc memory for files limit variables");
nret = -1;
goto out;
}
oci_spec->annotations->keys = fkey;
nret = mem_realloc((void **)&fval, new_size, oci_spec->annotations->values, old_size);
if (nret) {
ERROR("Failed to realloc memory for files limit variables");
nret = -1;
goto out;
}
oci_spec->annotations->values = fval;
oci_spec->annotations->len += new_lens;
out:
return nret;
}
static int make_annotations(oci_runtime_spec *container, const struct lxc_container *c, int fpos)
{
int ret = -1;
int nret;
char default_path[PATH_MAX] = { 0 };
char *realpath = NULL;
json_map_string_string *anno = container->annotations;
if (fpos == -1) {
if (realloc_annotations(container, 1)) {
ERROR("Realloc annotations failed");
goto out;
}
fpos = (int)(anno->len - 1);
anno->keys[fpos] = util_strdup_s("log.console.file");
anno->values[fpos] = NULL;
}
if (!anno->values[fpos]) {
nret = snprintf(default_path, PATH_MAX, "%s/%s/%s", c->config_path, c->name, "console.log");
if (nret < 0 || nret >= PATH_MAX) {
ERROR("create default path: %s failed", default_path);
goto out;
}
if (anno->values[fpos]) {
free(anno->values[fpos]);
}
anno->values[fpos] = util_strdup_s(default_path);
}
if (strcmp("none", anno->values[fpos]) == 0) {
DEBUG("Disable console log.");
ret = 0;
goto out;
}
if (util_ensure_path(&realpath, anno->values[fpos])) {
ERROR("Invalid log path: %s, error: %s.", anno->values[fpos], strerror(errno));
goto out;
}
ret = 0;
out:
free(realpath);
return ret;
}
static inline bool is_annotations_key_console_file(const char *key)
{
return strcmp(key, "log.console.file") == 0;
}
static int check_annotations(oci_runtime_spec *container, const struct lxc_container *c)
{
size_t i;
int fpos = -1;
bool ret = false;
if (c == NULL) {
return 0;
}
if (!container->annotations) {
SAFE_MALLOC(container->annotations, sizeof(json_map_string_string), ret);
if (!ret) {
goto out;
}
} else {
for (i = 0; i < container->annotations->len; i++) {
if (is_annotations_key_console_file(container->annotations->keys[i])) {
fpos = (int)i;
}
}
}
if (make_annotations(container, c, fpos)) {
goto out;
}
ret = true;
out:
return ret ? 0 : -1;
}
static int trans_rootfs_linux(struct lcr_list *lcr_conf, oci_runtime_spec *container,
char **seccomp)
{
int ret = -1;
struct lcr_list *node = NULL;
/* lxc.rootfs
* lxc.rootfs.options
*/
if (container->root || container->linux) {
node = trans_oci_root(container->root, container->linux);
if (node == NULL) {
ERROR("Failed to translate rootfs configure");
goto out;
}
lcr_list_merge(lcr_conf, node);
}
/* lxc.idmap */
if (container->linux) {
node = trans_oci_linux(container->linux, seccomp);
if (node == NULL) {
ERROR("Failed to translate linux configure");
goto out;
}
lcr_list_merge(lcr_conf, node);
}
ret = 0;
out:
return ret;
}
static int trans_hostname_hooks_process_mounts(struct lcr_list *lcr_conf, const oci_runtime_spec *container)
{
int ret = -1;
/* lxc.uts.name */
struct lcr_list *node = trans_oci_hostname(container->hostname);
if (node == NULL) {
ERROR("Failed to translate hostname");
goto out;
}
lcr_list_add_tail(lcr_conf, node);
/* lxc.init_{u|g}id
* lxc.init_cmd
* lxc.environment
* lxc.cap.{drop/keep}
* lxc.limit.*
* lxc.aa_profile
* lxc.selinux.context
*/
node = trans_oci_process(container->process);
if (node == NULL) {
ERROR("Failed to translate hooks");
goto out;
}
lcr_list_merge(lcr_conf, node);
/* lxc.mount.entry */
node = trans_oci_mounts(container);
if (node == NULL) {
ERROR("Failed to translate mount entry configure");
goto out;
}
lcr_list_merge(lcr_conf, node);
ret = 0;
out:
return ret;
}
static bool do_stop_and_wait(struct lxc_container *c, long timeout, bool force)
{
pid_t pid;
int sret = 0;
bool ret = true;
pid = c->init_pid(c);
if (pid < 1) {
ERROR("Container is not running");
return false;
}
if (!force) {
sret = kill(pid, SIGTERM);
if (sret < 0) {
if (errno == ESRCH) {
return true;
}
}
ret = c->wait(c, "STOPPED", (int)timeout);
if (ret) {
return true;
}
}
sret = kill(pid, SIGKILL);
if (sret < 0) {
if (errno == ESRCH) {
return true;
}
}
ret = c->wait(c, "STOPPED", -1);
if (!ret) {
ERROR("Failed to stop container %s", c->name);
}
return ret;
}
static bool do_stop(struct lxc_container *c, long timeout, bool force)
{
bool ret = true;
if (force && timeout) {
ERROR("-k should not use with -T");
return false;
}
if (!force && timeout < -1) {
ERROR("Timeout should be >= -1");
return false;
}
if (!c->is_defined(c)) {
ERROR("No such container");
ret = false;
goto out;
}
if (!c->may_control(c)) {
ERROR("Insufficent privleges to contol");
ret = false;
goto out;
}
if (!c->is_running(c)) {
DEBUG("%s is already stopped", c->name);
goto out;
}
ret = do_stop_and_wait(c, timeout, force);
out:
return ret;
}
static int lcr_spec_write_seccomp_line(int fd, const char *seccomp)
{
size_t len;
char *line = NULL;
int ret = -1;
int nret;
if (strlen(seccomp) > SIZE_MAX - strlen("lxc.seccomp.profile") - 3 - 1) {
ERROR("the length of lxc.seccomp is too long!");
goto cleanup;
}
len = strlen("lxc.seccomp.profile") + 3 + strlen(seccomp) + 1;
line = util_common_calloc_s(len * sizeof(char));
if (line == NULL) {
ERROR("Out of memory");
goto cleanup;
}
nret = snprintf(line, len, "%s = %s", "lxc.seccomp.profile", seccomp);
if (nret < 0 || (size_t)nret >= len) {
ERROR("Sprintf failed");
goto cleanup;
}
if ((size_t)nret > len - 1) {
nret = (int)(len - 1);
}
line[nret] = '\n';
if (write(fd, line, len) == -1) {
SYSERROR("Write failed");
goto cleanup;
}
ret = 0;
cleanup:
free(line);
return ret;
}
static char *lcr_save_seccomp_file(const char *bundle, const char *seccomp_conf)
{
char seccomp[PATH_MAX] = { 0 };
char *real_seccomp = NULL;
int fd = -1;
int nret;
ssize_t written_cnt;
nret = snprintf(seccomp, sizeof(seccomp), "%s/seccomp", bundle);
if (nret < 0 || (size_t)nret >= sizeof(seccomp)) {
goto cleanup;
}
nret = util_ensure_path(&real_seccomp, seccomp);
if (nret < 0) {
ERROR("Failed to ensure path %s", seccomp);
goto cleanup;
}
fd = util_open(real_seccomp, O_CREAT | O_TRUNC | O_CLOEXEC | O_WRONLY, CONFIG_FILE_MODE);
if (fd == -1) {
SYSERROR("Create file %s failed", real_seccomp);
goto cleanup;
}
written_cnt = write(fd, seccomp_conf, strlen(seccomp_conf));
close(fd);
if (written_cnt == -1) {
SYSERROR("write seccomp_conf failed");
goto cleanup;
}
return real_seccomp;
cleanup:
free(real_seccomp);
return NULL;
}
static struct lcr_container_info *info_new(struct lcr_container_info **info, size_t *size)
{
struct lcr_container_info *m = NULL;
struct lcr_container_info *n = NULL;
size_t length = 0;
int nret = 0;
if (*size > SIZE_MAX / sizeof(struct lcr_container_info) - 1) {
return NULL;
}
length = (*size + 1) * sizeof(struct lcr_container_info);
nret = mem_realloc((void **)&n, length, (void *)(*info), (*size) * sizeof(struct lcr_container_info));
if (nret < 0) {
return NULL;
}
*info = n;
m = *info + *size;
(*size)++;
// *INDENT-OFF*
*m = (struct lcr_container_info) {
.name = NULL, .state = NULL, .interface = NULL, .ipv4 = NULL, .ipv6 = NULL, .ram = 0.0, .swap = 0.0, .init = -1
};
// *INDENT-ON*
return m;
}
static void free_arr(char **array, size_t size)
{
size_t i;
for (i = 0; i < size; i++) {
free(array[i]);
array[i] = NULL;
}
free(array);
}
/*
* Get a complete list of active containers for a given lcrpath.
* return Number of containers, or -1 on error.
**/
int lcr_list_active_containers(const char *lcrpath, struct lcr_container_info **info_arr)
{
char **c = NULL;
int n = 0;
int nret = -1;
size_t info_size = 0;
const char *path = lcrpath ? lcrpath : LCRPATH;
n = list_active_containers(path, &c, NULL);
if (n == -1) {
n = 0;
}
nret = lcr_containers_info_get(path, info_arr, &info_size, c, n);
if ((info_arr == NULL) && nret == 0) {
return -1;
} else if ((info_arr == NULL) || nret == -1) {
lcr_containers_info_free(info_arr, info_size);
return -1;
}
return (int)info_size;
}
bool lcr_delete_with_force(const char *name, const char *lcrpath, bool force)
{
struct lxc_container *c = NULL;
const char *path = lcrpath ? lcrpath : LCRPATH;
bool ret = false;
pid_t pid = 0;
clear_error_message(&g_lcr_error);
if (name == NULL) {
ERROR("Missing container name");
return false;
}
engine_set_log_prefix(name);
c = lcr_new_container(name, path);
if (c == NULL) {
engine_free_log_prefix();
return false;
}
if (c->is_running(c)) {
if (!force) {
ERROR("Container %s is running, Stop the container before remove", name);
lcr_set_error_message(LCR_ERR_RUNTIME, "Container %s is running, Stop the container before remove", name);
goto out_put;
} else {
pid = c->init_pid(c);
if (pid < 1) {
ERROR("Container is not running");
goto clean_delete;
}
ret = do_stop(c, 0, true);
if (!ret) {
ERROR("Failed to stop container %s", name);
goto out_put;
}
}
}
clean_delete:
ret = lcr_clean(name, path, NULL, NULL, pid);
if (!ret) {
ERROR("Failed to clean resource");
}
ret = lcr_delete(name, path);
if (!ret) {
ERROR("Failed to delete container");
}
out_put:
lxc_container_put(c);
engine_free_log_prefix();
return ret;
}
void lcr_free_config(struct lcr_list *lcr_conf)
{
struct lcr_list *it = NULL;
struct lcr_list *next = NULL;
if (lcr_conf == NULL) {
return;
}
lcr_list_for_each_safe(it, lcr_conf, next) {
lcr_list_del(it);
free_lcr_list_node(it);
}
}
int lcr_containers_info_get(const char *lcrpath, struct lcr_container_info **info, size_t *size, char **containers,
int num)
{
struct lcr_container_info *in = NULL;
struct lxc_container *c = NULL;
int i;
int nret = -1;
if ((lcrpath == NULL) || num == 0) {
goto err_out;
}
for (i = 0; i < num; i++) {
const char *st = NULL;
const char *name = containers[i];
bool run_flag = true;
if (name == NULL) {
continue;
}
c = lxc_container_without_config_new(name, lcrpath);
if (c == NULL) {
continue;
}
if (!c->is_defined(c)) {
goto put_container;
}
st = c->state(c);
if (st == NULL) {
st = "UNKNOWN";
}
run_flag = (strcmp(st, "STOPPED") != 0);
/* Now it makes sense to allocate memory */
in = info_new(info, size);
if (in == NULL) {
goto put_container;
}
in->running = run_flag;
in->name = util_strdup_s(name);
in->state = util_strdup_s(st);
if (run_flag) {
in->init = c->init_pid(c);
}
put_container:
lxc_container_put(c);
}
nret = 0;
err_out:
free_arr(containers, (size_t)num);
return nret;
}
/*
* Transform container JSON into oci_runtime_spec struct
*/
bool container_parse(const char *oci_filename, const char *oci_json_data, oci_runtime_spec **container)
{
struct parser_context ctx = { OPT_PARSE_STRICT, stderr };
parser_error err = NULL;
bool ret = true;
if (oci_json_data == NULL) {
*container = oci_runtime_spec_parse_file(oci_filename, &ctx, &err);
} else {
*container = oci_runtime_spec_parse_data(oci_json_data, &ctx, &err);
}
if (*container == NULL) {
ERROR("Failed to get OCI spec: %s", err);
ret = false;
goto out_free;
}
out_free:
free(err);
return ret;
}
static int merge_annotations(const oci_runtime_spec *container, struct lcr_list *lcr_conf)
{
int ret = 0;
struct lcr_list *tmp = NULL;
if (container->annotations != NULL) {
tmp = trans_annotations(container->annotations);
if (tmp == NULL) {
ERROR("Failed to translate annotations configure");
ret = -1;
goto out;
}
lcr_list_merge(lcr_conf, tmp);
}
out:
return ret;
}
static int merge_needed_lxc_conf(struct lcr_list *lcr_conf)
{
int ret = 0;
struct lcr_list *tmp = get_needed_lxc_conf();
if (tmp == NULL) {
ERROR("Failed to append other lxc configure");
ret = -1;
goto out;
}
lcr_list_merge(lcr_conf, tmp);
out:
return ret;
}
struct lcr_list *lcr_oci2lcr(const struct lxc_container *c, oci_runtime_spec *container,
char **seccomp)
{
struct lcr_list *lcr_conf = NULL;
lcr_conf = util_common_calloc_s(sizeof(*lcr_conf));
if (lcr_conf == NULL) {
goto out_free;
}
lcr_list_init(lcr_conf);
if (check_annotations(container, c)) {
ERROR("Check annotations failed");
goto out_free;
}
if (trans_rootfs_linux(lcr_conf, container, seccomp)) {
goto out_free;
}
if (trans_hostname_hooks_process_mounts(lcr_conf, container)) {
goto out_free;
}
/* annotations.files.limit */
if (merge_annotations(container, lcr_conf) != 0) {
goto out_free;
}
/* Append other lxc configurations */
if (merge_needed_lxc_conf(lcr_conf) != 0) {
goto out_free;
}
return lcr_conf;
out_free:
lcr_free_config(lcr_conf);
free(lcr_conf);
return NULL;
}
static int lcr_open_config_file(const char *bundle)
{
char config[PATH_MAX] = { 0 };
char *real_config = NULL;
int fd = -1;
int nret;
nret = snprintf(config, sizeof(config), "%s/config", bundle);
if (nret < 0 || (size_t)nret >= sizeof(config)) {
goto out;
}
nret = util_ensure_path(&real_config, config);
if (nret < 0) {
ERROR("Failed to ensure path %s", config);
goto out;
}
fd = util_open(real_config, O_CREAT | O_TRUNC | O_CLOEXEC | O_WRONLY, CONFIG_FILE_MODE);
if (fd == -1) {
ERROR("Create file %s failed, %s", real_config, strerror(errno));
lcr_set_error_message(LCR_ERR_RUNTIME, "Create file %s failed, %s", real_config, strerror(errno));
goto out;
}
out:
free(real_config);
return fd;
}
// escape_string_encode unzip some escape characters
static char *escape_string_encode(const char *src)
{
size_t src_end = 0;
size_t dst_end = 0;
size_t len = 0;
char *dst = NULL;
if (src == NULL) {
return NULL;
}
len = strlen(src);
if (len == 0) {
return NULL;
}
dst = util_common_calloc_s(2 * len + 1);
if (dst == NULL) {
ERROR("Out of memory");
return NULL;
}
while (src_end < len) {
switch (src[src_end++]) {
case '\r':
dst[dst_end++] = '\\';
dst[dst_end++] = 'r';
break;
case '\n':
dst[dst_end++] = '\\';
dst[dst_end++] = 'n';
break;
case '\f':
dst[dst_end++] = '\\';
dst[dst_end++] = 'f';
break;
case '\b':
dst[dst_end++] = '\\';
dst[dst_end++] = 'b';
break;
case '\t':
dst[dst_end++] = '\\';
dst[dst_end++] = 't';
break;
case '\\':
dst[dst_end++] = '\\';
dst[dst_end++] = '\\';
break;
// default do not encode
default:
dst[dst_end++] = src[src_end - 1];
break;
}
}
return dst;
}
static int lcr_spec_write_config(int fd, const struct lcr_list *lcr_conf)
{
struct lcr_list *it = NULL;
size_t len;
char *line = NULL;
char *line_encode = NULL;
int ret = -1;
lcr_list_for_each(it, lcr_conf) {
lcr_config_item_t *item = it->elem;
int nret;
if (item != NULL) {
if (strlen(item->value) > ((SIZE_MAX - strlen(item->name)) - 4)) {
goto cleanup;
}
len = strlen(item->name) + 3 + strlen(item->value) + 1;
line = util_common_calloc_s(len);
if (line == NULL) {
ERROR("Out of memory");
goto cleanup;
}
nret = snprintf(line, len, "%s = %s", item->name, item->value);
if (nret < 0 || (size_t)nret >= len) {
ERROR("Sprintf failed");
goto cleanup;
}
line_encode = escape_string_encode(line);
if (line_encode == NULL) {
ERROR("String encode failed");
goto cleanup;
}
nret = strlen(line_encode);
line_encode[nret] = '\n';
if (write(fd, line_encode, nret + 1) == -1) {
SYSERROR("Write failed");
goto cleanup;
}
free(line);
line = NULL;
free(line_encode);
line_encode = NULL;
}
}
ret = 0;
cleanup:
free(line);
free(line_encode);
return ret;
}
char *lcr_get_bundle(const char *lcrpath, const char *name)
{
size_t len = 0;
int nret = 0;
char *bundle = NULL;
struct stat s;
if (strlen(name) > ((SIZE_MAX - strlen(lcrpath)) - 2)) {
goto cleanup;
}
/* bundle = lcrpath + '/' + name + '\0' */
len = strlen(lcrpath) + strlen(name) + 2;
bundle = util_common_calloc_s(len);
if (bundle == NULL) {
ERROR("Out of memory");
goto cleanup;
}
nret = snprintf(bundle, len, "%s/%s", lcrpath, name);
if (nret < 0 || (size_t)nret >= len) {
ERROR("Print bundle string failed");
goto cleanup;
}
if (stat(bundle, &s) != 0) {
switch (errno) {
case EACCES:
ERROR("You lack permission to access %s", bundle);
break;
case ENOENT:
ERROR("Bundle %s does not exist", bundle);
break;
default:
ERROR("Access %s failed: %s\n", bundle, strerror(errno));
}
goto cleanup;
}
return bundle;
cleanup:
free(bundle);
return NULL;
}
bool lcr_save_spec(const char *name, const char *lcrpath, const struct lcr_list *lcr_conf, const char *seccomp_conf)
{
bool bret = false;
const char *path = lcrpath ? lcrpath : LCRPATH;
char *bundle = NULL;
char *seccomp = NULL;
int fd = -1;
int nret = 0;
if (name == NULL) {
ERROR("Missing container name");
return bret;
}
bundle = lcr_get_bundle(path, name);
if (bundle == NULL) {
goto out_free;
}
if (seccomp_conf != NULL) {
seccomp = lcr_save_seccomp_file(bundle, seccomp_conf);
if (seccomp == NULL) {
goto out_free;
}
}
fd = lcr_open_config_file(bundle);
if (fd == -1) {
goto out_free;
}
if (lcr_spec_write_config(fd, lcr_conf)) {
goto out_free;
}
if (seccomp_conf != NULL) {
nret = lcr_spec_write_seccomp_line(fd, seccomp);
if (nret) {
goto out_free;
}
}
bret = true;
out_free:
free(bundle);
free(seccomp);
if (fd != -1) {
close(fd);
}
return bret;
}
static int lcr_write_file(const char *path, const char *data, size_t len)
{
char *real_path = NULL;
int fd = -1;
int ret = -1;
if (path == NULL || strlen(path) == 0 || data == NULL || len == 0) {
return -1;
}
if (util_ensure_path(&real_path, path) < 0) {
ERROR("Failed to ensure path %s", path);
goto out_free;
}
fd = util_open(real_path, O_CREAT | O_TRUNC | O_CLOEXEC | O_WRONLY, CONFIG_FILE_MODE);
if (fd == -1) {
ERROR("Create file %s failed", real_path);
lcr_set_error_message(LCR_ERR_RUNTIME, "Create file %s failed", real_path);
goto out_free;
}
if (write(fd, data, len) == -1) {
ERROR("write data to %s failed: %s", real_path, strerror(errno));
goto out_free;
}
ret = 0;
out_free:
if (fd != -1) {
close(fd);
}
free(real_path);
return ret;
}
static bool lcr_write_ocihooks(const char *path, const oci_runtime_spec_hooks *hooks)
{
bool ret = false;
struct parser_context ctx = { OPT_PARSE_STRICT, stderr };
parser_error err = NULL;
char *json_hooks = oci_runtime_spec_hooks_generate_json(hooks, &ctx, &err);
if (json_hooks == NULL) {
ERROR("Failed to generate json: %s", err);
goto out_free;
}
if (lcr_write_file(path, json_hooks, strlen(json_hooks)) == -1) {
ERROR("write json hooks failed: %s", strerror(errno));
goto out_free;
}
ret = true;
out_free:
free(err);
free(json_hooks);
return ret;
}
static bool lcr_save_ocihooks(const char *name, const char *lcrpath, const oci_runtime_spec_hooks *hooks)
{
const char *path = lcrpath ? lcrpath : LCRPATH;
char ocihook[PATH_MAX] = { 0 };
char *bundle = NULL;
bool bret = false;
int nret = 0;
if (name == NULL) {
ERROR("Missing name");
return false;
}
bundle = lcr_get_bundle(path, name);
if (bundle == NULL) {
return false;
}
nret = snprintf(ocihook, sizeof(ocihook), "%s/%s", bundle, OCIHOOKSFILE);
if (nret < 0 || (size_t)nret >= sizeof(ocihook)) {
ERROR("Failed to print string");
goto out_free;
}
bret = lcr_write_ocihooks(ocihook, hooks);
out_free:
free(bundle);
return bret;
}
bool translate_spec(const struct lxc_container *c, oci_runtime_spec *container)
{
bool ret = false;
struct lcr_list *lcr_conf = NULL;
char *seccomp_conf = NULL;
INFO("Translate new specification file");
lcr_conf = lcr_oci2lcr(c, container, &seccomp_conf);
if (lcr_conf == NULL) {
ERROR("Translate configuration failed");
goto out_free_conf;
}
if (container->hooks != NULL && !lcr_save_ocihooks(c->name, c->config_path, container->hooks)) {
ERROR("Failed to save %s", OCIHOOKSFILE);
goto out_free_conf;
}
if (!lcr_save_spec(c->name, c->config_path, lcr_conf, seccomp_conf)) {
ERROR("Failed to save configuration");
goto out_free_conf;
}
ret = true;
out_free_conf:
lcr_free_config(lcr_conf);
free(lcr_conf);
free(seccomp_conf);
return ret;
}