1285 lines
33 KiB
Diff
1285 lines
33 KiB
Diff
From 481e3bf2c164d5303c6f827fc2bcbb67508d0ff5 Mon Sep 17 00:00:00 2001
|
|
From: LiFeng <lifeng68@huawei.com>
|
|
Date: Sat, 11 Apr 2020 17:12:44 +0800
|
|
Subject: [PATCH 03/49] confile: add lxc.isulad.populate.device interface
|
|
|
|
Signed-off-by: LiFeng <lifeng68@huawei.com>
|
|
---
|
|
src/lxc/Makefile.am | 9 +
|
|
src/lxc/conf.c | 126 ++++++++++
|
|
src/lxc/conf.h | 25 ++
|
|
src/lxc/confile.c | 120 ++++++++-
|
|
src/lxc/isulad_utils.c | 99 ++++++++
|
|
src/lxc/isulad_utils.h | 20 ++
|
|
src/lxc/path.c | 655 +++++++++++++++++++++++++++++++++++++++++++++++++
|
|
src/lxc/path.h | 65 +++++
|
|
src/lxc/utils.h | 3 +
|
|
9 files changed, 1121 insertions(+), 1 deletion(-)
|
|
create mode 100644 src/lxc/isulad_utils.c
|
|
create mode 100644 src/lxc/isulad_utils.h
|
|
create mode 100644 src/lxc/path.c
|
|
create mode 100644 src/lxc/path.h
|
|
|
|
diff --git a/src/lxc/Makefile.am b/src/lxc/Makefile.am
|
|
index e7fc844..21441c0 100644
|
|
--- a/src/lxc/Makefile.am
|
|
+++ b/src/lxc/Makefile.am
|
|
@@ -52,6 +52,10 @@ noinst_HEADERS = api_extensions.h \
|
|
utils.h \
|
|
uuid.h
|
|
|
|
+#if HAVE_ISULAD
|
|
+noinst_HEADERS += isulad_utils.h path.h
|
|
+#endif
|
|
+
|
|
if IS_BIONIC
|
|
noinst_HEADERS += ../include/fexecve.h \
|
|
../include/lxcmntent.h \
|
|
@@ -154,6 +158,11 @@ liblxc_la_SOURCES = af_unix.c af_unix.h \
|
|
version.h \
|
|
$(LSM_SOURCES)
|
|
|
|
+#if HAVE_ISULAD
|
|
+liblxc_la_SOURCES += isulad_utils.c isulad_utils.h \
|
|
+ path.c path.h
|
|
+#endif
|
|
+
|
|
if IS_BIONIC
|
|
liblxc_la_SOURCES += ../include/fexecve.c ../include/fexecve.h \
|
|
../include/lxcmntent.c ../include/lxcmntent.h \
|
|
diff --git a/src/lxc/conf.c b/src/lxc/conf.c
|
|
index 62a6979..e9c0a37 100644
|
|
--- a/src/lxc/conf.c
|
|
+++ b/src/lxc/conf.c
|
|
@@ -2564,6 +2564,11 @@ struct lxc_conf *lxc_conf_init(void)
|
|
memset(&new->ns_share, 0, sizeof(char *) * LXC_NS_MAX);
|
|
seccomp_conf_init(new);
|
|
|
|
+#ifdef HAVE_ISULAD
|
|
+ /* isulad add begin */
|
|
+ lxc_list_init(&new->populate_devs);
|
|
+#endif
|
|
+
|
|
return new;
|
|
}
|
|
|
|
@@ -3274,6 +3279,99 @@ static int lxc_setup_boot_id(void)
|
|
return 0;
|
|
}
|
|
|
|
+#ifdef HAVE_ISULAD
|
|
+/* isulad: setup devices which will be populated in the container.*/
|
|
+static int setup_populate_devs(const struct lxc_rootfs *rootfs, struct lxc_list *devs)
|
|
+{
|
|
+ int ret = 0;
|
|
+ char *pathdirname = NULL;
|
|
+ char path[MAXPATHLEN];
|
|
+ mode_t file_mode = 0;
|
|
+ struct lxc_populate_devs *dev_elem = NULL;
|
|
+ struct lxc_list *it = NULL;
|
|
+ mode_t cur_mask;
|
|
+
|
|
+ INFO("Populating devices into container");
|
|
+ cur_mask = umask(0000);
|
|
+ lxc_list_for_each(it, devs) {
|
|
+ ret = 0;
|
|
+ dev_elem = it->elem;
|
|
+
|
|
+ ret = snprintf(path, MAXPATHLEN, "%s/%s", rootfs->path ? rootfs->mount : "", dev_elem->name);
|
|
+ if (ret < 0 || ret >= MAXPATHLEN) {
|
|
+ ret = -1;
|
|
+ goto reset_umask;
|
|
+ }
|
|
+
|
|
+ /* create any missing directories */
|
|
+ pathdirname = safe_strdup(path);
|
|
+ pathdirname = dirname(pathdirname);
|
|
+ ret = mkdir_p(pathdirname, 0755);
|
|
+ free(pathdirname);
|
|
+ if (ret < 0) {
|
|
+ WARN("Failed to create target directory");
|
|
+ ret = -1;
|
|
+ goto reset_umask;
|
|
+ }
|
|
+
|
|
+ if (!strcmp(dev_elem->type, "c")) {
|
|
+ file_mode = dev_elem->file_mode | S_IFCHR;
|
|
+ } else if (!strcmp(dev_elem->type, "b")) {
|
|
+ file_mode = dev_elem->file_mode | S_IFBLK;
|
|
+ } else {
|
|
+ ERROR("Failed to parse devices type '%s'", dev_elem->type);
|
|
+ ret = -1;
|
|
+ goto reset_umask;
|
|
+ }
|
|
+
|
|
+ DEBUG("Try to mknod '%s':'%d':'%d':'%d'\n", path,
|
|
+ file_mode, dev_elem->maj, dev_elem->min);
|
|
+
|
|
+ ret = mknod(path, file_mode, makedev(dev_elem->maj, dev_elem->min));
|
|
+ if (ret && errno != EEXIST) {
|
|
+ SYSERROR("Failed to mknod '%s':'%d':'%d':'%d'", dev_elem->name,
|
|
+ file_mode, dev_elem->maj, dev_elem->min);
|
|
+
|
|
+ char hostpath[MAXPATHLEN];
|
|
+ FILE *pathfile = NULL;
|
|
+
|
|
+ // Unprivileged containers cannot create devices, so
|
|
+ // try to bind mount the device from the host
|
|
+ ret = snprintf(hostpath, MAXPATHLEN, "/dev/%s", dev_elem->name);
|
|
+ if (ret < 0 || ret >= MAXPATHLEN) {
|
|
+ ret = -1;
|
|
+ goto reset_umask;
|
|
+ }
|
|
+ pathfile = lxc_fopen(path, "wb");
|
|
+ if (!pathfile) {
|
|
+ SYSERROR("Failed to create device mount target '%s'", path);
|
|
+ ret = -1;
|
|
+ goto reset_umask;
|
|
+ }
|
|
+ fclose(pathfile);
|
|
+ if (safe_mount(hostpath, path, 0, MS_BIND, NULL,
|
|
+ rootfs->path ? rootfs->mount : NULL) != 0) {
|
|
+ SYSERROR("Failed bind mounting device %s from host into container",
|
|
+ dev_elem->name);
|
|
+ ret = -1;
|
|
+ goto reset_umask;
|
|
+ }
|
|
+ }
|
|
+ if (chown(path, dev_elem->uid, dev_elem->gid) < 0) {
|
|
+ ERROR("Error chowning %s", path);
|
|
+ ret = -1;
|
|
+ goto reset_umask;
|
|
+ }
|
|
+ }
|
|
+
|
|
+reset_umask:
|
|
+ (void)umask(cur_mask);
|
|
+
|
|
+ INFO("Populated devices into container /dev");
|
|
+ return ret;
|
|
+}
|
|
+#endif
|
|
+
|
|
int lxc_setup(struct lxc_handler *handler)
|
|
{
|
|
int ret;
|
|
@@ -3382,6 +3480,15 @@ int lxc_setup(struct lxc_handler *handler)
|
|
return log_error(-1, "Failed to populate \"/dev\"");
|
|
}
|
|
|
|
+#ifdef HAVE_ISULAD
|
|
+ /* isulad: setup devices which will be populated in the container. */
|
|
+ if (!lxc_list_empty(&lxc_conf->populate_devs)) {
|
|
+ if (setup_populate_devs(&lxc_conf->rootfs, &lxc_conf->populate_devs) != 0) {
|
|
+ return log_error(-1, "Failed to setup devices in the container");
|
|
+ }
|
|
+ }
|
|
+#endif
|
|
+
|
|
/* Make sure any start hooks are in the container */
|
|
if (!verify_start_hooks(lxc_conf))
|
|
return log_error(-1, "Failed to verify start hooks");
|
|
@@ -3837,6 +3944,7 @@ void lxc_conf_free(struct lxc_conf *conf)
|
|
free(conf->shmount.path_cont);
|
|
#ifdef HAVE_ISULAD
|
|
lxc_clear_init_args(conf);
|
|
+ lxc_clear_populate_devices(conf);
|
|
#endif
|
|
free(conf);
|
|
}
|
|
@@ -4661,4 +4769,22 @@ int lxc_clear_init_args(struct lxc_conf *lxc_conf)
|
|
|
|
return 0;
|
|
}
|
|
+
|
|
+/*isulad: clear populate devices*/
|
|
+int lxc_clear_populate_devices(struct lxc_conf *c)
|
|
+{
|
|
+ struct lxc_list *it = NULL;
|
|
+ struct lxc_list *next = NULL;
|
|
+
|
|
+ lxc_list_for_each_safe(it, &c->populate_devs, next) {
|
|
+ struct lxc_populate_devs *dev_elem = it->elem;
|
|
+ lxc_list_del(it);
|
|
+ free(dev_elem->name);
|
|
+ free(dev_elem->type);
|
|
+ free(dev_elem);
|
|
+ free(it);
|
|
+ }
|
|
+ return 0;
|
|
+}
|
|
+
|
|
#endif
|
|
diff --git a/src/lxc/conf.h b/src/lxc/conf.h
|
|
index 8a198e4..452458c 100644
|
|
--- a/src/lxc/conf.h
|
|
+++ b/src/lxc/conf.h
|
|
@@ -230,6 +230,27 @@ struct device_item {
|
|
int global_rule;
|
|
};
|
|
|
|
+#ifdef HAVE_ISULAD
|
|
+/*
|
|
+ * iSulad: Defines a structure to store the devices which will
|
|
+ * be attached in container
|
|
+ * @name : the target device name in container
|
|
+ * @type : the type of target device "c" or "b"
|
|
+ * @mode : file mode for the device
|
|
+ * @maj : major number for the device
|
|
+ * @min : minor number for the device
|
|
+ */
|
|
+struct lxc_populate_devs {
|
|
+ char *name;
|
|
+ char *type;
|
|
+ mode_t file_mode;
|
|
+ int maj;
|
|
+ int min;
|
|
+ uid_t uid;
|
|
+ gid_t gid;
|
|
+};
|
|
+#endif
|
|
+
|
|
struct lxc_conf {
|
|
/* Pointer to the name of the container. Do not free! */
|
|
const char *name;
|
|
@@ -403,6 +424,9 @@ struct lxc_conf {
|
|
/* isulad add: init args used to repalce init_cmd*/
|
|
char **init_argv;
|
|
size_t init_argc;
|
|
+
|
|
+ /* populate devices*/
|
|
+ struct lxc_list populate_devs;
|
|
#endif
|
|
|
|
};
|
|
@@ -479,5 +503,6 @@ extern int userns_exec_minimal(const struct lxc_conf *conf,
|
|
int (*fn_child)(void *), void *fn_child_data);
|
|
#ifdef HAVE_ISULAD
|
|
int lxc_clear_init_args(struct lxc_conf *lxc_conf);
|
|
+int lxc_clear_populate_devices(struct lxc_conf *c);
|
|
#endif
|
|
#endif /* __LXC_CONF_H */
|
|
diff --git a/src/lxc/confile.c b/src/lxc/confile.c
|
|
index e535beb..f0772f9 100644
|
|
--- a/src/lxc/confile.c
|
|
+++ b/src/lxc/confile.c
|
|
@@ -149,6 +149,7 @@ lxc_config_define(sysctl);
|
|
lxc_config_define(proc);
|
|
#ifdef HAVE_ISULAD
|
|
lxc_config_define(init_args);
|
|
+lxc_config_define(populate_device);
|
|
#endif
|
|
|
|
/*
|
|
@@ -264,7 +265,7 @@ static struct lxc_config_t config_jump_table[] = {
|
|
{ "lxc.proc", set_config_proc, get_config_proc, clr_config_proc, },
|
|
#ifdef HAVE_ISULAD
|
|
{ "lxc.isulad.init.args", set_config_init_args, get_config_init_args, clr_config_init_args, },
|
|
-
|
|
+ { "lxc.isulad.populate.device", set_config_populate_device, get_config_populate_device, clr_config_populate_device, },
|
|
#endif
|
|
};
|
|
|
|
@@ -6155,4 +6156,121 @@ static inline int clr_config_init_args(const char *key, struct lxc_conf *c,
|
|
{
|
|
return lxc_clear_init_args(c);
|
|
}
|
|
+
|
|
+/* isulad: set config for populate device */
|
|
+static int set_config_populate_device(const char *key, const char *value,
|
|
+ struct lxc_conf *lxc_conf, void *data)
|
|
+{
|
|
+ int ret = 0, major = 0, minor = 0;
|
|
+ uid_t uid = (uid_t)-1;
|
|
+ gid_t gid = (gid_t)-1;
|
|
+ char name[4096] = {0}; /* MAX dev path name */
|
|
+ char type[3] = {0};
|
|
+ char *replace_value = NULL;
|
|
+ mode_t filemode = 0;
|
|
+ struct lxc_list *iter = NULL;
|
|
+ struct lxc_list *dev_list = NULL;
|
|
+ struct lxc_populate_devs *dev_elem = NULL;
|
|
+
|
|
+ if (lxc_config_value_empty(value))
|
|
+ return lxc_clear_populate_devices(lxc_conf);
|
|
+
|
|
+ /* lxc.populate.device = PATH_IN_CONTAINER:DEVICETYPE:MAJOR:MINOR:MODE:UID:GID
|
|
+ * For e.g. lxc.populate.device = /dev/sda:b:8:0:0666:0:0
|
|
+ */
|
|
+ ret = sscanf(value, "%4095[^:]:%2[^:]:%i:%i:%i:%u:%u", name, type, &major, &minor, &filemode, &uid, &gid);
|
|
+ if (ret != 7)
|
|
+ return -1;
|
|
+
|
|
+ /* find existing list element */
|
|
+ lxc_list_for_each(iter, &lxc_conf->populate_devs) {
|
|
+ dev_elem = iter->elem;
|
|
+
|
|
+ if (strcmp(name, dev_elem->name) != 0)
|
|
+ continue;
|
|
+
|
|
+ replace_value = safe_strdup(type);
|
|
+
|
|
+ free(dev_elem->type);
|
|
+ dev_elem->type = replace_value;
|
|
+ dev_elem->file_mode = filemode;
|
|
+ dev_elem->maj = major;
|
|
+ dev_elem->min = minor;
|
|
+ dev_elem->uid = (uid_t)uid;
|
|
+ dev_elem->gid = (gid_t)gid;
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ /* allocate list element */
|
|
+ dev_list = malloc(sizeof(*dev_list));
|
|
+ if (dev_list == NULL)
|
|
+ goto on_error;
|
|
+
|
|
+ lxc_list_init(dev_list);
|
|
+
|
|
+ dev_elem = malloc(sizeof(*dev_elem));
|
|
+ if (dev_elem == NULL)
|
|
+ goto on_error;
|
|
+ memset(dev_elem, 0, sizeof(*dev_elem));
|
|
+
|
|
+ dev_elem->name = safe_strdup(name);
|
|
+
|
|
+ dev_elem->type = safe_strdup(type);
|
|
+
|
|
+ dev_elem->file_mode = filemode;
|
|
+ dev_elem->maj = major;
|
|
+ dev_elem->min = minor;
|
|
+ dev_elem->uid = (uid_t)uid;
|
|
+ dev_elem->gid = (gid_t)gid;
|
|
+
|
|
+ lxc_list_add_elem(dev_list, dev_elem);
|
|
+
|
|
+ lxc_list_add_tail(&lxc_conf->populate_devs, dev_list);
|
|
+
|
|
+ return 0;
|
|
+
|
|
+on_error:
|
|
+ free(dev_list);
|
|
+ if (dev_elem) {
|
|
+ free(dev_elem->name);
|
|
+ free(dev_elem->type);
|
|
+ free(dev_elem);
|
|
+ }
|
|
+ return -1;
|
|
+}
|
|
+
|
|
+/* isulad: get config populate device
|
|
+ * If you ask for 'lxc.populate.device', then all populate device
|
|
+ * entries will be printed, in 'lxc.populate.device = path_in_container:type:major:minor:mode:uid:gid' format.
|
|
+ * For e.g. lxc.populate.device = /dev/sda:b:8:0:0666:0:0
|
|
+ */
|
|
+static int get_config_populate_device(const char *key, char *retv, int inlen,
|
|
+ struct lxc_conf *c, void *data)
|
|
+{
|
|
+ int len;
|
|
+ struct lxc_list *it = NULL;
|
|
+ int fulllen = 0;
|
|
+
|
|
+ if (!retv)
|
|
+ inlen = 0;
|
|
+ else
|
|
+ memset(retv, 0, inlen);
|
|
+
|
|
+ lxc_list_for_each(it, &c->populate_devs) {
|
|
+ struct lxc_populate_devs *elem = it->elem;
|
|
+ strprint(retv, inlen, "lxc.populate.device = %s:%s:%d:%d:%o:%u:%u\n",
|
|
+ elem->name, elem->type, elem->maj,
|
|
+ elem->min, elem->file_mode, elem->uid, elem->gid);
|
|
+ }
|
|
+
|
|
+ return fulllen;
|
|
+}
|
|
+
|
|
+/* isulad: clr config populate devices*/
|
|
+static inline int clr_config_populate_device(const char *key, struct lxc_conf *c,
|
|
+ void *data)
|
|
+{
|
|
+ return lxc_clear_populate_devices(c);
|
|
+}
|
|
+
|
|
#endif
|
|
diff --git a/src/lxc/isulad_utils.c b/src/lxc/isulad_utils.c
|
|
new file mode 100644
|
|
index 0000000..b282404
|
|
--- /dev/null
|
|
+++ b/src/lxc/isulad_utils.c
|
|
@@ -0,0 +1,99 @@
|
|
+/* SPDX-License-Identifier: LGPL-2.1+ */
|
|
+/******************************************************************************
|
|
+ * Copyright (c) Huawei Technologies Co., Ltd. 2020. Allrights reserved
|
|
+ * Description: isulad utils
|
|
+ * Author: lifeng
|
|
+ * Create: 2020-04-11
|
|
+******************************************************************************/
|
|
+
|
|
+#include <stdlib.h>
|
|
+#include <string.h>
|
|
+#include <sys/types.h>
|
|
+#include <sys/stat.h>
|
|
+#include <fcntl.h>
|
|
+
|
|
+#include "isulad_utils.h"
|
|
+#include "log.h"
|
|
+#include "path.h"
|
|
+#include "file_utils.h"
|
|
+
|
|
+lxc_log_define(isulad_utils, lxc);
|
|
+
|
|
+void *lxc_common_calloc_s(size_t size)
|
|
+{
|
|
+ if (size == 0 || size > SIZE_MAX) {
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ return calloc((size_t)1, size);
|
|
+}
|
|
+
|
|
+int lxc_mem_realloc(void **newptr, size_t newsize, void *oldptr, size_t oldsize)
|
|
+{
|
|
+ void *tmp = NULL;
|
|
+
|
|
+ if (newsize == 0) {
|
|
+ goto err_out;
|
|
+ }
|
|
+
|
|
+ tmp = lxc_common_calloc_s(newsize);
|
|
+ if (tmp == NULL) {
|
|
+ ERROR("Failed to malloc memory");
|
|
+ goto err_out;
|
|
+ }
|
|
+
|
|
+ if (oldptr != NULL) {
|
|
+ memcpy(tmp, oldptr, (newsize < oldsize) ? newsize : oldsize);
|
|
+
|
|
+ memset(oldptr, 0, oldsize);
|
|
+
|
|
+ free(oldptr);
|
|
+ }
|
|
+
|
|
+ *newptr = tmp;
|
|
+ return 0;
|
|
+
|
|
+err_out:
|
|
+ return -1;
|
|
+}
|
|
+
|
|
+char *safe_strdup(const char *src)
|
|
+{
|
|
+ char *dst = NULL;
|
|
+
|
|
+ if (src == NULL) {
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ dst = strdup(src);
|
|
+ if (dst == NULL) {
|
|
+ abort();
|
|
+ }
|
|
+
|
|
+ return dst;
|
|
+}
|
|
+
|
|
+int lxc_open(const char *filename, int flags, mode_t mode)
|
|
+{
|
|
+ char rpath[PATH_MAX] = {0x00};
|
|
+
|
|
+ if (cleanpath(filename, rpath, sizeof(rpath)) == NULL) {
|
|
+ return -1;
|
|
+ }
|
|
+ if (mode) {
|
|
+ return open(rpath, (int)((unsigned int)flags | O_CLOEXEC), mode);
|
|
+ } else {
|
|
+ return open(rpath, (int)((unsigned int)flags | O_CLOEXEC));
|
|
+ }
|
|
+}
|
|
+
|
|
+FILE *lxc_fopen(const char *filename, const char *mode)
|
|
+{
|
|
+ char rpath[PATH_MAX] = {0x00};
|
|
+
|
|
+ if (cleanpath(filename, rpath, sizeof(rpath)) == NULL) {
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ return fopen_cloexec(rpath, mode);
|
|
+}
|
|
diff --git a/src/lxc/isulad_utils.h b/src/lxc/isulad_utils.h
|
|
new file mode 100644
|
|
index 0000000..7a6ab00
|
|
--- /dev/null
|
|
+++ b/src/lxc/isulad_utils.h
|
|
@@ -0,0 +1,20 @@
|
|
+/* SPDX-License-Identifier: LGPL-2.1+ */
|
|
+/******************************************************************************
|
|
+ * Copyright (c) Huawei Technologies Co., Ltd. 2020. Allrights reserved
|
|
+ * Description: isulad utils
|
|
+ * Author: lifeng
|
|
+ * Create: 2020-04-11
|
|
+******************************************************************************/
|
|
+#ifndef __iSULAD_UTILS_H
|
|
+#define __iSULAD_UTILS_H
|
|
+
|
|
+#include <stdio.h>
|
|
+
|
|
+extern int lxc_mem_realloc(void **newptr, size_t newsize, void *oldptr, size_t oldsize);
|
|
+extern void *lxc_common_calloc_s(size_t size);
|
|
+extern char *safe_strdup(const char *src);
|
|
+
|
|
+extern int lxc_open(const char *filename, int flags, mode_t mode);
|
|
+extern FILE *lxc_fopen(const char *filename, const char *mode);
|
|
+
|
|
+#endif
|
|
diff --git a/src/lxc/path.c b/src/lxc/path.c
|
|
new file mode 100644
|
|
index 0000000..65b8aad
|
|
--- /dev/null
|
|
+++ b/src/lxc/path.c
|
|
@@ -0,0 +1,655 @@
|
|
+/* SPDX-License-Identifier: LGPL-2.1+ */
|
|
+/******************************************************************************
|
|
+ * Copyright (c) Huawei Technologies Co., Ltd. 2020. Allrights reserved
|
|
+ * Description: isulad utils
|
|
+ * Author: lifeng
|
|
+ * Create: 2020-04-11
|
|
+******************************************************************************/
|
|
+#include <unistd.h>
|
|
+#include <stdlib.h>
|
|
+#include <limits.h>
|
|
+#include <string.h>
|
|
+#include <stdio.h>
|
|
+#include <sys/types.h>
|
|
+#include <sys/stat.h>
|
|
+#include <sys/param.h>
|
|
+#include <libgen.h>
|
|
+
|
|
+#include "path.h"
|
|
+#include "log.h"
|
|
+#include "isulad_utils.h"
|
|
+
|
|
+lxc_log_define(lxc_path_ui, lxc);
|
|
+
|
|
+#define ISSLASH(C) ((C) == '/')
|
|
+#define IS_ABSOLUTE_FILE_NAME(F) (ISSLASH ((F)[0]))
|
|
+#define IS_RELATIVE_FILE_NAME(F) (! IS_ABSOLUTE_FILE_NAME (F))
|
|
+
|
|
+bool specify_current_dir(const char *path)
|
|
+{
|
|
+ char *basec = NULL, *bname = NULL;
|
|
+ bool res = false;
|
|
+
|
|
+ basec = safe_strdup(path);
|
|
+
|
|
+ bname = basename(basec);
|
|
+ if (bname == NULL) {
|
|
+ free(basec);
|
|
+ ERROR("Out of memory");
|
|
+ return false;
|
|
+ }
|
|
+ res = !strcmp(bname, ".");
|
|
+ free(basec);
|
|
+ return res;
|
|
+}
|
|
+
|
|
+bool has_traling_path_separator(const char *path)
|
|
+{
|
|
+ return path && strlen(path) && (path[strlen(path) - 1] == '/');
|
|
+}
|
|
+
|
|
+// PreserveTrailingDotOrSeparator returns the given cleaned path
|
|
+// and appends a trailing `/.` or `/` if its corresponding original
|
|
+// path ends with a trailing `/.` or `/`. If the cleaned
|
|
+// path already ends in a `.` path segment, then another is not added. If the
|
|
+// clean path already ends in a path separator, then another is not added.
|
|
+char *preserve_trailing_dot_or_separator(const char *cleanedpath,
|
|
+ const char *originalpath)
|
|
+{
|
|
+ char *respath = NULL;
|
|
+ size_t len;
|
|
+
|
|
+ if (strlen(cleanedpath) > (SIZE_MAX - 3)) {
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ len = strlen(cleanedpath) + 3;
|
|
+ respath = malloc(len);
|
|
+ if (respath == NULL) {
|
|
+ ERROR("Out of memory");
|
|
+ return NULL;
|
|
+ }
|
|
+ memset(respath, 0x00, len);
|
|
+ strcat(respath, cleanedpath);
|
|
+
|
|
+ if (!specify_current_dir(cleanedpath) && specify_current_dir(originalpath)) {
|
|
+ if (!has_traling_path_separator(respath))
|
|
+ strcat(respath, "/");
|
|
+ strcat(respath, ".");
|
|
+ }
|
|
+
|
|
+ if (!has_traling_path_separator(respath) &&
|
|
+ has_traling_path_separator(originalpath))
|
|
+ strcat(respath, "/");
|
|
+
|
|
+ return respath;
|
|
+}
|
|
+
|
|
+
|
|
+// Split splits path immediately following the final Separator,
|
|
+// separating it into a directory and file name component.
|
|
+// If there is no Separator in path, Split returns an empty dir
|
|
+// and file set to path.
|
|
+// The returned values have the property that path = dir+file.
|
|
+bool filepath_split(const char *path, char **dir, char **base)
|
|
+{
|
|
+ ssize_t i;
|
|
+ size_t len;
|
|
+
|
|
+ len = strlen(path);
|
|
+ if (len >= PATH_MAX) {
|
|
+ ERROR("Invalid path");
|
|
+ return false;
|
|
+ }
|
|
+ i = len - 1;
|
|
+ while (i >= 0 && path[i] != '/')
|
|
+ i--;
|
|
+
|
|
+ *dir = malloc(i + 2);
|
|
+ if (*dir == NULL) {
|
|
+ ERROR("Out of memory");
|
|
+ return false;
|
|
+ }
|
|
+ memcpy(*dir, path, i + 1);
|
|
+ *(*dir + i + 1) = '\0';
|
|
+
|
|
+ *base = safe_strdup(path + i + 1);
|
|
+
|
|
+ return true;
|
|
+}
|
|
+
|
|
+
|
|
+static bool do_clean_path_continue(const char *endpos, const char *stpos, const char *respath, char **dst)
|
|
+{
|
|
+ if (endpos - stpos == 1 && stpos[0] == '.') {
|
|
+ return true;
|
|
+ } else if (endpos - stpos == 2 && stpos[0] == '.' && stpos[1] == '.') {
|
|
+ char *dest = *dst;
|
|
+ if (dest <= respath + 1) {
|
|
+ return true;
|
|
+ }
|
|
+ for (--dest; dest > respath && !ISSLASH(dest[-1]); --dest) {
|
|
+ *dst = dest;
|
|
+ return true;
|
|
+ }
|
|
+ *dst = dest;
|
|
+ return true;
|
|
+ }
|
|
+ return false;
|
|
+}
|
|
+
|
|
+int do_clean_path(const char *respath, const char *limit_respath,
|
|
+ const char *stpos, char **dst)
|
|
+{
|
|
+ char *dest = *dst;
|
|
+ const char *endpos = NULL;
|
|
+
|
|
+ for (endpos = stpos; *stpos; stpos = endpos) {
|
|
+ while (ISSLASH(*stpos)) {
|
|
+ ++stpos;
|
|
+ }
|
|
+
|
|
+ for (endpos = stpos; *endpos && !ISSLASH(*endpos); ++endpos) {
|
|
+ }
|
|
+
|
|
+ if (endpos - stpos == 0) {
|
|
+ break;
|
|
+ } else if (do_clean_path_continue(endpos, stpos, respath, &dest)) {
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ if (!ISSLASH(dest[-1])) {
|
|
+ *dest++ = '/';
|
|
+ }
|
|
+
|
|
+ if (dest + (endpos - stpos) >= limit_respath) {
|
|
+ ERROR("Path is too long");
|
|
+ if (dest > respath + 1) {
|
|
+ dest--;
|
|
+ }
|
|
+ *dest = '\0';
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ memcpy(dest, stpos, (size_t)(endpos - stpos));
|
|
+ dest += endpos - stpos;
|
|
+ *dest = '\0';
|
|
+ }
|
|
+ *dst = dest;
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+char *cleanpath(const char *path, char *realpath, size_t realpath_len)
|
|
+{
|
|
+ char *respath = NULL;
|
|
+ char *dest = NULL;
|
|
+ const char *stpos = NULL;
|
|
+ const char *limit_respath = NULL;
|
|
+
|
|
+ if (path == NULL || path[0] == '\0' || \
|
|
+ realpath == NULL || (realpath_len < PATH_MAX)) {
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ respath = realpath;
|
|
+
|
|
+ memset(respath, 0, realpath_len);
|
|
+ limit_respath = respath + PATH_MAX;
|
|
+
|
|
+ if (!IS_ABSOLUTE_FILE_NAME(path)) {
|
|
+ if (!getcwd(respath, PATH_MAX)) {
|
|
+ ERROR("Failed to getcwd");
|
|
+ respath[0] = '\0';
|
|
+ goto error;
|
|
+ }
|
|
+ dest = strchr(respath, '\0');
|
|
+ if (dest == NULL) {
|
|
+ ERROR("Failed to get the end of respath");
|
|
+ goto error;
|
|
+ }
|
|
+ if (strlen(path) > (PATH_MAX - strlen(respath) - 1)) {
|
|
+ ERROR("Path is too long");
|
|
+ goto error;
|
|
+ }
|
|
+ strcat(respath, path);
|
|
+ stpos = path;
|
|
+ } else {
|
|
+ dest = respath;
|
|
+ *dest++ = '/';
|
|
+ stpos = path;
|
|
+ }
|
|
+
|
|
+ if (do_clean_path(respath, limit_respath, stpos, &dest)) {
|
|
+ goto error;
|
|
+ }
|
|
+
|
|
+ if (dest > respath + 1 && ISSLASH(dest[-1])) {
|
|
+ --dest;
|
|
+ }
|
|
+ *dest = '\0';
|
|
+
|
|
+ return respath;
|
|
+
|
|
+error:
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
+static int do_path_realloc(const char *start, const char *end,
|
|
+ char **rpath, char **dest, const char **rpath_limit)
|
|
+{
|
|
+ long long dest_offset = *dest - *rpath;
|
|
+ char *new_rpath = NULL;
|
|
+ size_t new_size;
|
|
+ int nret = 0;
|
|
+ size_t gap = 0;
|
|
+
|
|
+ if (*dest + (end - start) < *rpath_limit) {
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ gap = (size_t)(end - start) + 1;
|
|
+ new_size = (size_t)(*rpath_limit - *rpath);
|
|
+ if (new_size > SIZE_MAX - gap) {
|
|
+ ERROR("Out of range!");
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ if (gap > PATH_MAX) {
|
|
+ new_size += gap;
|
|
+ } else {
|
|
+ new_size += PATH_MAX;
|
|
+ }
|
|
+ nret = lxc_mem_realloc((void **)&new_rpath, new_size, *rpath, PATH_MAX);
|
|
+ if (nret) {
|
|
+ ERROR("Failed to realloc memory for files limit variables");
|
|
+ return -1;
|
|
+ }
|
|
+ *rpath = new_rpath;
|
|
+ *rpath_limit = *rpath + new_size;
|
|
+
|
|
+ *dest = *rpath + dest_offset;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int do_get_symlinks_copy_buf(const char *buf, const char *prefix, size_t prefix_len,
|
|
+ char **rpath, char **dest)
|
|
+{
|
|
+ if (IS_ABSOLUTE_FILE_NAME(buf)) {
|
|
+ if (prefix_len) {
|
|
+ memcpy(*rpath, prefix, prefix_len);
|
|
+ }
|
|
+ *dest = *rpath + prefix_len;
|
|
+ *(*dest)++ = '/';
|
|
+ } else {
|
|
+ if (*dest > *rpath + prefix_len + 1) {
|
|
+ for (--(*dest); *dest > *rpath && !ISSLASH((*dest)[-1]); --(*dest)) {
|
|
+ continue;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int do_get_symlinks(const char **fullpath, const char *prefix, size_t prefix_len,
|
|
+ char **rpath, char **dest, const char **end,
|
|
+ int *num_links, char **extra_buf)
|
|
+{
|
|
+ char *buf = NULL;
|
|
+ size_t len;
|
|
+ ssize_t n;
|
|
+ int ret = -1;
|
|
+
|
|
+ if (++(*num_links) > MAXSYMLINKS) {
|
|
+ ERROR("Too many links in '%s'", *fullpath);
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+ buf = lxc_common_calloc_s(PATH_MAX);
|
|
+ if (buf == NULL) {
|
|
+ ERROR("Out of memory");
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+ n = readlink(*rpath, buf, PATH_MAX - 1);
|
|
+ if (n < 0) {
|
|
+ goto out;
|
|
+ }
|
|
+ buf[n] = '\0';
|
|
+
|
|
+ if (*extra_buf == NULL) {
|
|
+ *extra_buf = lxc_common_calloc_s(PATH_MAX);
|
|
+ if (*extra_buf == NULL) {
|
|
+ ERROR("Out of memory");
|
|
+ goto out;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ len = strlen(*end);
|
|
+ if (len >= PATH_MAX - n) {
|
|
+ ERROR("Path is too long");
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+ memmove(&(*extra_buf)[n], *end, len + 1);
|
|
+ memcpy(*extra_buf, buf, (size_t)n);
|
|
+
|
|
+ *fullpath = *end = *extra_buf;
|
|
+
|
|
+ if (do_get_symlinks_copy_buf(buf, prefix, prefix_len, rpath, dest) != 0) {
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+ ret = 0;
|
|
+out:
|
|
+ free(buf);
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static bool do_eval_symlinks_in_scope_is_symlink(const char *path)
|
|
+{
|
|
+ struct stat st;
|
|
+
|
|
+ if (lstat(path, &st) < 0) {
|
|
+ return true;
|
|
+ }
|
|
+
|
|
+ if (!S_ISLNK(st.st_mode)) {
|
|
+ return true;
|
|
+ }
|
|
+ return false;
|
|
+}
|
|
+
|
|
+static void do_eval_symlinks_skip_slash(const char **start, const char **end)
|
|
+{
|
|
+ while (ISSLASH(**start)) {
|
|
+ ++(*start);
|
|
+ }
|
|
+
|
|
+ for (*end = *start; **end && !ISSLASH(**end); ++(*end)) {
|
|
+ }
|
|
+}
|
|
+
|
|
+static inline void skip_dest_traling_slash(char **dest, char **rpath, size_t prefix_len)
|
|
+{
|
|
+ if (*dest > *rpath + prefix_len + 1) {
|
|
+ for (--(*dest); *dest > *rpath && !ISSLASH((*dest)[-1]); --(*dest)) {
|
|
+ continue;
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
+static inline bool is_current_char(const char c)
|
|
+{
|
|
+ return c == '.';
|
|
+}
|
|
+
|
|
+static inline bool is_specify_current(const char *end, const char *start)
|
|
+{
|
|
+ return (end - start == 1) && is_current_char(start[0]);
|
|
+}
|
|
+
|
|
+static inline bool is_specify_parent(const char *end, const char *start)
|
|
+{
|
|
+ return (end - start == 2) && is_current_char(start[0]) && is_current_char(start[1]);
|
|
+}
|
|
+
|
|
+static int do_eval_symlinks_in_scope(const char *fullpath, const char *prefix,
|
|
+ size_t prefix_len,
|
|
+ char **rpath, char **dest, const char *rpath_limit)
|
|
+{
|
|
+ const char *start = NULL;
|
|
+ const char *end = NULL;
|
|
+ char *extra_buf = NULL;
|
|
+ int nret = 0;
|
|
+ int num_links = 0;
|
|
+
|
|
+ start = fullpath + prefix_len;
|
|
+ for (end = start; *start; start = end) {
|
|
+ do_eval_symlinks_skip_slash(&start, &end);
|
|
+ if (end - start == 0) {
|
|
+ break;
|
|
+ } else if (is_specify_current(end, start)) {
|
|
+ ;
|
|
+ } else if (is_specify_parent(end, start)) {
|
|
+ skip_dest_traling_slash(dest, rpath, prefix_len);
|
|
+ } else {
|
|
+ if (!ISSLASH((*dest)[-1])) {
|
|
+ *(*dest)++ = '/';
|
|
+ }
|
|
+
|
|
+ nret = do_path_realloc(start, end, rpath, dest, &rpath_limit);
|
|
+ if (nret != 0) {
|
|
+ nret = -1;
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+ memcpy(*dest, start, (size_t)(end - start));
|
|
+ *dest += end - start;
|
|
+ **dest = '\0';
|
|
+
|
|
+ if (do_eval_symlinks_in_scope_is_symlink(*rpath)) {
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ nret = do_get_symlinks(&fullpath, prefix, prefix_len, rpath, dest, &end, &num_links, &extra_buf);
|
|
+ if (nret != 0) {
|
|
+ nret = -1;
|
|
+ goto out;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+out:
|
|
+ free(extra_buf);
|
|
+ return nret;
|
|
+}
|
|
+static char *eval_symlinks_in_scope(const char *fullpath, const char *rootpath)
|
|
+{
|
|
+ char resroot[PATH_MAX] = {0};
|
|
+ char *root = NULL;
|
|
+ char *rpath = NULL;
|
|
+ char *dest = NULL;
|
|
+ char *prefix = NULL;
|
|
+ const char *rpath_limit = NULL;
|
|
+ size_t prefix_len;
|
|
+
|
|
+ if (fullpath == NULL || rootpath == NULL) {
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ root = cleanpath(rootpath, resroot, sizeof(resroot));
|
|
+ if (root == NULL) {
|
|
+ ERROR("Failed to get cleaned path");
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ if (!strcmp(fullpath, root)) {
|
|
+ return safe_strdup(fullpath);
|
|
+ }
|
|
+
|
|
+ if (strstr(fullpath, root) == NULL) {
|
|
+ ERROR("Path '%s' is not in '%s'", fullpath, root);
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ rpath = lxc_common_calloc_s(PATH_MAX);
|
|
+ if (rpath == NULL) {
|
|
+ ERROR("Out of memory");
|
|
+ goto out;
|
|
+ }
|
|
+ rpath_limit = rpath + PATH_MAX;
|
|
+
|
|
+ prefix = root;
|
|
+ prefix_len = (size_t)strlen(prefix);
|
|
+ if (!strcmp(prefix, "/")) {
|
|
+ prefix_len = 0;
|
|
+ }
|
|
+
|
|
+ dest = rpath;
|
|
+ if (prefix_len) {
|
|
+ memcpy(rpath, prefix, prefix_len);
|
|
+ dest += prefix_len;
|
|
+ }
|
|
+ *dest++ = '/';
|
|
+
|
|
+ if (do_eval_symlinks_in_scope(fullpath, prefix, prefix_len, &rpath, &dest,
|
|
+ rpath_limit)) {
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+ if (dest > rpath + prefix_len + 1 && ISSLASH(dest[-1])) {
|
|
+ --dest;
|
|
+ }
|
|
+ *dest = '\0';
|
|
+ return rpath;
|
|
+
|
|
+out:
|
|
+ free(rpath);
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
+// FollowSymlinkInScope is a wrapper around evalSymlinksInScope that returns an
|
|
+// absolute path. This function handles paths in a platform-agnostic manner.
|
|
+char *follow_symlink_in_scope(const char *fullpath, const char *rootpath)
|
|
+{
|
|
+ char resfull[PATH_MAX] = {0}, *full = NULL;
|
|
+ char resroot[PATH_MAX] = {0}, *root = NULL;
|
|
+
|
|
+ full = cleanpath(fullpath, resfull, PATH_MAX);
|
|
+ if (!full) {
|
|
+ ERROR("Failed to get cleaned path");
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ root = cleanpath(rootpath, resroot, PATH_MAX);
|
|
+ if (!root) {
|
|
+ ERROR("Failed to get cleaned path");
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ return eval_symlinks_in_scope(full, root);
|
|
+}
|
|
+
|
|
+// GetResourcePath evaluates `path` in the scope of the container's rootpath, with proper path
|
|
+// sanitisation. Symlinks are all scoped to the rootpath of the container, as
|
|
+// though the container's rootpath was `/`.
|
|
+//
|
|
+// The BaseFS of a container is the host-facing path which is bind-mounted as
|
|
+// `/` inside the container. This method is essentially used to access a
|
|
+// particular path inside the container as though you were a process in that
|
|
+// container.
|
|
+int get_resource_path(const char *rootpath, const char *path,
|
|
+ char **scopepath)
|
|
+{
|
|
+ char resolved[PATH_MAX] = {0}, *cleanedpath = NULL;
|
|
+ char *fullpath = NULL;
|
|
+ size_t len;
|
|
+
|
|
+ if (!rootpath || !path || !scopepath)
|
|
+ return -1;
|
|
+
|
|
+ *scopepath = NULL;
|
|
+
|
|
+ cleanedpath = cleanpath(path, resolved, PATH_MAX);
|
|
+ if (!cleanedpath) {
|
|
+ ERROR("Failed to get cleaned path");
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ len = strlen(rootpath) + strlen(cleanedpath) + 1;
|
|
+ fullpath = malloc(len);
|
|
+ if (!fullpath) {
|
|
+ ERROR("Out of memory");
|
|
+ return -1;
|
|
+ }
|
|
+ snprintf(fullpath, len, "%s%s", rootpath, cleanedpath);
|
|
+
|
|
+ *scopepath = follow_symlink_in_scope(fullpath, rootpath);
|
|
+
|
|
+ free(fullpath);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+// Rel returns a relative path that is lexically equivalent to targpath when
|
|
+// joined to basepath with an intervening separator. That is,
|
|
+// Join(basepath, Rel(basepath, targpath)) is equivalent to targpath itself.
|
|
+// On success, the returned path will always be relative to basepath,
|
|
+// even if basepath and targpath share no elements.
|
|
+// An error is returned if targpath can't be made relative to basepath or if
|
|
+// knowing the current working directory would be necessary to compute it.
|
|
+// Rel calls Clean on the result.
|
|
+char *path_relative(const char *basepath, const char *targpath)
|
|
+{
|
|
+ char resbase[PATH_MAX] = {0}, *base = NULL;
|
|
+ char restarg[PATH_MAX] = {0}, *targ = NULL;
|
|
+ size_t bl = 0, tl = 0, b0 = 0, bi = 0, t0 = 0, ti = 0;
|
|
+
|
|
+ base = cleanpath(basepath, resbase, PATH_MAX);
|
|
+ if (!base) {
|
|
+ ERROR("Failed to get cleaned path");
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ targ = cleanpath(targpath, restarg, PATH_MAX);
|
|
+ if (!targ) {
|
|
+ ERROR("Failed to get cleaned path");
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ if (strcmp(base, targ) == 0)
|
|
+ return safe_strdup(".");
|
|
+
|
|
+ bl = strlen(base);
|
|
+ tl = strlen(targ);
|
|
+ while(true) {
|
|
+ while(bi < bl && !ISSLASH(base[bi]))
|
|
+ bi++;
|
|
+ while(ti < tl && !ISSLASH(targ[ti]))
|
|
+ ti++;
|
|
+ //not the same string
|
|
+ if (((bi - b0) != (ti - t0)) || strncmp(base + b0, targ + t0, bi - b0))
|
|
+ break;
|
|
+ if (bi < bl)
|
|
+ bi++;
|
|
+ if (ti < tl)
|
|
+ ti++;
|
|
+ b0 = bi;
|
|
+ t0 = ti;
|
|
+ }
|
|
+
|
|
+ if (b0 != bl) {
|
|
+ // Base elements left. Must go up before going down.
|
|
+ int seps = 0, i;
|
|
+ size_t ncopyed = 0, seps_size;
|
|
+ char *buf = NULL;
|
|
+
|
|
+ for (bi = b0; bi < bl; bi++) {
|
|
+ if (ISSLASH(base[bi]))
|
|
+ seps++;
|
|
+ }
|
|
+ //strlen(..) + strlen(/..) + '\0'
|
|
+ seps_size = 2 + seps * 3 + 1;
|
|
+ if (t0 != tl)
|
|
+ seps_size += 1 + tl - t0;
|
|
+
|
|
+ buf = calloc(seps_size, 1);
|
|
+ if (!buf) {
|
|
+ ERROR("Out of memory");
|
|
+ return NULL;
|
|
+ }
|
|
+ buf[ncopyed++] = '.';
|
|
+ buf[ncopyed++] = '.';
|
|
+ for (i = 0; i < seps; i++) {
|
|
+ buf[ncopyed++] = '/';
|
|
+ buf[ncopyed++] = '.';
|
|
+ buf[ncopyed++] = '.';
|
|
+ }
|
|
+ if (t0 != tl) {
|
|
+ buf[ncopyed++] = '/';
|
|
+ memcpy(buf + ncopyed, targ + t0, tl - t0 + 1);
|
|
+ }
|
|
+ return buf;
|
|
+ }
|
|
+
|
|
+ return safe_strdup(targ + t0);
|
|
+}
|
|
diff --git a/src/lxc/path.h b/src/lxc/path.h
|
|
new file mode 100644
|
|
index 0000000..2c60fb9
|
|
--- /dev/null
|
|
+++ b/src/lxc/path.h
|
|
@@ -0,0 +1,65 @@
|
|
+/* SPDX-License-Identifier: LGPL-2.1+ */
|
|
+/******************************************************************************
|
|
+ * Copyright (c) Huawei Technologies Co., Ltd. 2020. Allrights reserved
|
|
+ * Description: isulad utils
|
|
+ * Author: lifeng
|
|
+ * Create: 2020-04-11
|
|
+******************************************************************************/
|
|
+#ifndef __ISULAD_PATH_H_
|
|
+#define __ISULAD_PATH_H_
|
|
+
|
|
+#include <stdbool.h>
|
|
+
|
|
+bool specify_current_dir(const char *path);
|
|
+
|
|
+bool has_traling_path_separator(const char *path);
|
|
+
|
|
+// PreserveTrailingDotOrSeparator returns the given cleaned path
|
|
+// and appends a trailing `/.` or `/` if its corresponding original
|
|
+// path ends with a trailing `/.` or `/`. If the cleaned
|
|
+// path already ends in a `.` path segment, then another is not added. If the
|
|
+// clean path already ends in a path separator, then another is not added.
|
|
+char *preserve_trailing_dot_or_separator(const char *cleanedpath,
|
|
+ const char *originalpath);
|
|
+
|
|
+
|
|
+// Split splits path immediately following the final Separator,
|
|
+// separating it into a directory and file name component.
|
|
+// If there is no Separator in path, Split returns an empty dir
|
|
+// and file set to path.
|
|
+// The returned values have the property that path = dir+file.
|
|
+bool filepath_split(const char *path, char **dir, char **base);
|
|
+
|
|
+/*
|
|
+ * cleanpath is similar to realpath of glibc, but not expands symbolic links,
|
|
+ * and not check the existence of components of the path.
|
|
+ */
|
|
+char *cleanpath(const char *path, char *realpath, size_t realpath_len);
|
|
+
|
|
+
|
|
+// FollowSymlinkInScope is a wrapper around evalSymlinksInScope that returns an
|
|
+// absolute path. This function handles paths in a platform-agnostic manner.
|
|
+char *follow_symlink_in_scope(const char *fullpath, const char *rootpath);
|
|
+
|
|
+// GetResourcePath evaluates `path` in the scope of the container's rootpath, with proper path
|
|
+// sanitisation. Symlinks are all scoped to the rootpath of the container, as
|
|
+// though the container's rootpath was `/`.
|
|
+//
|
|
+// The BaseFS of a container is the host-facing path which is bind-mounted as
|
|
+// `/` inside the container. This method is essentially used to access a
|
|
+// particular path inside the container as though you were a process in that
|
|
+// container.
|
|
+int get_resource_path(const char *rootpath, const char *path,
|
|
+ char **scopepath);
|
|
+
|
|
+// Rel returns a relative path that is lexically equivalent to targpath when
|
|
+// joined to basepath with an intervening separator. That is,
|
|
+// Join(basepath, Rel(basepath, targpath)) is equivalent to targpath itself.
|
|
+// On success, the returned path will always be relative to basepath,
|
|
+// even if basepath and targpath share no elements.
|
|
+// An error is returned if targpath can't be made relative to basepath or if
|
|
+// knowing the current working directory would be necessary to compute it.
|
|
+// Rel calls Clean on the result.
|
|
+char *path_relative(const char *basepath, const char *targpath);
|
|
+
|
|
+#endif
|
|
diff --git a/src/lxc/utils.h b/src/lxc/utils.h
|
|
index 339217c..7b36133 100644
|
|
--- a/src/lxc/utils.h
|
|
+++ b/src/lxc/utils.h
|
|
@@ -27,6 +27,9 @@
|
|
#include "memory_utils.h"
|
|
#include "raw_syscalls.h"
|
|
#include "string_utils.h"
|
|
+#ifdef HAVE_ISULAD
|
|
+#include "isulad_utils.h"
|
|
+#endif
|
|
|
|
/* returns 1 on success, 0 if there were any failures */
|
|
extern int lxc_rmdir_onedev(const char *path, const char *exclude);
|
|
--
|
|
1.8.3.1
|
|
|