mirror of
https://git.proxmox.com/git/mirror_lxc
synced 2025-07-27 10:51:24 +00:00
Merge pull request #3952 from brauner/2021-08-25.list.2
conf: port more types to new list type
This commit is contained in:
commit
19202d882b
@ -782,7 +782,6 @@ static int lxc_attach_set_environment(struct attach_context *ctx,
|
|||||||
char **extra_env, char **extra_keep)
|
char **extra_env, char **extra_keep)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
struct lxc_list *iterator;
|
|
||||||
|
|
||||||
if (policy == LXC_ATTACH_CLEAR_ENV) {
|
if (policy == LXC_ATTACH_CLEAR_ENV) {
|
||||||
int path_kept = 0;
|
int path_kept = 0;
|
||||||
@ -863,17 +862,9 @@ static int lxc_attach_set_environment(struct attach_context *ctx,
|
|||||||
|
|
||||||
/* Set container environment variables.*/
|
/* Set container environment variables.*/
|
||||||
if (ctx->container->lxc_conf) {
|
if (ctx->container->lxc_conf) {
|
||||||
lxc_list_for_each(iterator, &ctx->container->lxc_conf->environment) {
|
ret = lxc_set_environment(ctx->container->lxc_conf);
|
||||||
char *env_tmp;
|
if (ret < 0)
|
||||||
|
return -1;
|
||||||
env_tmp = strdup((char *)iterator->elem);
|
|
||||||
if (!env_tmp)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
ret = putenv(env_tmp);
|
|
||||||
if (ret < 0)
|
|
||||||
return log_error_errno(-1, errno, "Failed to set environment variable: %s", (char *)iterator->elem);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set extra environment variables. */
|
/* Set extra environment variables. */
|
||||||
@ -1659,22 +1650,14 @@ int lxc_attach(struct lxc_container *container, lxc_attach_exec_t exec_function,
|
|||||||
goto on_error;
|
goto on_error;
|
||||||
|
|
||||||
/* Setup /proc limits */
|
/* Setup /proc limits */
|
||||||
if (!lxc_list_empty(&conf->procs)) {
|
ret = setup_proc_filesystem(conf, pid);
|
||||||
ret = setup_proc_filesystem(&conf->procs, pid);
|
if (ret < 0)
|
||||||
if (ret < 0)
|
goto on_error;
|
||||||
goto on_error;
|
|
||||||
|
|
||||||
TRACE("Setup /proc/%d settings", pid);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Setup resource limits */
|
/* Setup resource limits */
|
||||||
if (!lxc_list_empty(&conf->limits)) {
|
ret = setup_resource_limits(conf, pid);
|
||||||
ret = setup_resource_limits(&conf->limits, pid);
|
if (ret < 0)
|
||||||
if (ret < 0)
|
goto on_error;
|
||||||
goto on_error;
|
|
||||||
|
|
||||||
TRACE("Setup resource limits");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options->attach_flags & LXC_ATTACH_TERMINAL) {
|
if (options->attach_flags & LXC_ATTACH_TERMINAL) {
|
||||||
ret = lxc_attach_terminal_mainloop_init(&terminal, &descr);
|
ret = lxc_attach_terminal_mainloop_init(&terminal, &descr);
|
||||||
|
@ -575,7 +575,7 @@ __cgfsng_ops static void cgfsng_payload_destroy(struct cgroup_ops *ops,
|
|||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
WARN("Failed to detach bpf program from cgroup");
|
WARN("Failed to detach bpf program from cgroup");
|
||||||
|
|
||||||
if (!lxc_list_empty(&handler->conf->id_map)) {
|
if (!list_empty(&handler->conf->id_map)) {
|
||||||
struct generic_userns_exec_data wrap = {
|
struct generic_userns_exec_data wrap = {
|
||||||
.conf = handler->conf,
|
.conf = handler->conf,
|
||||||
.path_prune = ops->container_limit_cgroup,
|
.path_prune = ops->container_limit_cgroup,
|
||||||
@ -1363,7 +1363,7 @@ __cgfsng_ops static bool cgfsng_chown(struct cgroup_ops *ops,
|
|||||||
if (!conf)
|
if (!conf)
|
||||||
return ret_set_errno(false, EINVAL);
|
return ret_set_errno(false, EINVAL);
|
||||||
|
|
||||||
if (lxc_list_empty(&conf->id_map))
|
if (list_empty(&conf->id_map))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
wrap.origuid = geteuid();
|
wrap.origuid = geteuid();
|
||||||
@ -2289,7 +2289,7 @@ static int __cg_unified_attach(const struct hierarchy *h,
|
|||||||
if (unified_fd < 0)
|
if (unified_fd < 0)
|
||||||
return ret_errno(EBADF);
|
return ret_errno(EBADF);
|
||||||
|
|
||||||
if (!lxc_list_empty(&conf->id_map)) {
|
if (!list_empty(&conf->id_map)) {
|
||||||
struct userns_exec_unified_attach_data args = {
|
struct userns_exec_unified_attach_data args = {
|
||||||
.conf = conf,
|
.conf = conf,
|
||||||
.unified_fd = unified_fd,
|
.unified_fd = unified_fd,
|
||||||
@ -2707,11 +2707,8 @@ __cgfsng_ops static bool cgfsng_setup_limits_legacy(struct cgroup_ops *ops,
|
|||||||
struct lxc_conf *conf,
|
struct lxc_conf *conf,
|
||||||
bool do_devices)
|
bool do_devices)
|
||||||
{
|
{
|
||||||
__do_free struct lxc_list *sorted_cgroup_settings = NULL;
|
struct list_head *cgroup_settings;
|
||||||
struct lxc_list *cgroup_settings = &conf->cgroup;
|
struct lxc_cgroup *cgroup;
|
||||||
struct lxc_list *iterator, *next;
|
|
||||||
struct lxc_cgroup *cg;
|
|
||||||
bool ret = false;
|
|
||||||
|
|
||||||
if (!ops)
|
if (!ops)
|
||||||
return ret_set_errno(false, ENOENT);
|
return ret_set_errno(false, ENOENT);
|
||||||
@ -2720,7 +2717,7 @@ __cgfsng_ops static bool cgfsng_setup_limits_legacy(struct cgroup_ops *ops,
|
|||||||
return ret_set_errno(false, EINVAL);
|
return ret_set_errno(false, EINVAL);
|
||||||
|
|
||||||
cgroup_settings = &conf->cgroup;
|
cgroup_settings = &conf->cgroup;
|
||||||
if (lxc_list_empty(cgroup_settings))
|
if (list_empty(cgroup_settings))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (!ops->hierarchies)
|
if (!ops->hierarchies)
|
||||||
@ -2729,35 +2726,23 @@ __cgfsng_ops static bool cgfsng_setup_limits_legacy(struct cgroup_ops *ops,
|
|||||||
if (pure_unified_layout(ops))
|
if (pure_unified_layout(ops))
|
||||||
return log_warn_errno(true, EINVAL, "Ignoring legacy cgroup limits on pure cgroup2 system");
|
return log_warn_errno(true, EINVAL, "Ignoring legacy cgroup limits on pure cgroup2 system");
|
||||||
|
|
||||||
sorted_cgroup_settings = sort_cgroup_settings(cgroup_settings);
|
sort_cgroup_settings(conf);
|
||||||
if (!sorted_cgroup_settings)
|
list_for_each_entry(cgroup, cgroup_settings, head) {
|
||||||
return false;
|
if (do_devices == strnequal("devices", cgroup->subsystem, 7)) {
|
||||||
|
if (cg_legacy_set_data(ops, cgroup->subsystem, cgroup->value, strnequal("cpuset", cgroup->subsystem, 6))) {
|
||||||
lxc_list_for_each(iterator, sorted_cgroup_settings) {
|
|
||||||
cg = iterator->elem;
|
|
||||||
|
|
||||||
if (do_devices == strnequal("devices", cg->subsystem, 7)) {
|
|
||||||
if (cg_legacy_set_data(ops, cg->subsystem, cg->value, strnequal("cpuset", cg->subsystem, 6))) {
|
|
||||||
if (do_devices && (errno == EACCES || errno == EPERM)) {
|
if (do_devices && (errno == EACCES || errno == EPERM)) {
|
||||||
SYSWARN("Failed to set \"%s\" to \"%s\"", cg->subsystem, cg->value);
|
SYSWARN("Failed to set \"%s\" to \"%s\"", cgroup->subsystem, cgroup->value);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
SYSERROR("Failed to set \"%s\" to \"%s\"", cg->subsystem, cg->value);
|
SYSERROR("Failed to set \"%s\" to \"%s\"", cgroup->subsystem, cgroup->value);
|
||||||
goto out;
|
return false;
|
||||||
}
|
}
|
||||||
DEBUG("Set controller \"%s\" set to \"%s\"", cg->subsystem, cg->value);
|
DEBUG("Set controller \"%s\" set to \"%s\"", cgroup->subsystem, cgroup->value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = true;
|
|
||||||
INFO("Limits for the legacy cgroup hierarchies have been setup");
|
INFO("Limits for the legacy cgroup hierarchies have been setup");
|
||||||
out:
|
return true;
|
||||||
lxc_list_for_each_safe(iterator, sorted_cgroup_settings, next) {
|
|
||||||
lxc_list_del(iterator);
|
|
||||||
free(iterator);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -2793,9 +2778,10 @@ static int bpf_device_cgroup_prepare(struct cgroup_ops *ops,
|
|||||||
__cgfsng_ops static bool cgfsng_setup_limits(struct cgroup_ops *ops,
|
__cgfsng_ops static bool cgfsng_setup_limits(struct cgroup_ops *ops,
|
||||||
struct lxc_handler *handler)
|
struct lxc_handler *handler)
|
||||||
{
|
{
|
||||||
struct lxc_list *cgroup_settings, *iterator;
|
struct list_head *cgroup_settings;
|
||||||
struct hierarchy *h;
|
struct hierarchy *h;
|
||||||
struct lxc_conf *conf;
|
struct lxc_conf *conf;
|
||||||
|
struct lxc_cgroup *cgroup;
|
||||||
|
|
||||||
if (!ops)
|
if (!ops)
|
||||||
return ret_set_errno(false, ENOENT);
|
return ret_set_errno(false, ENOENT);
|
||||||
@ -2811,7 +2797,7 @@ __cgfsng_ops static bool cgfsng_setup_limits(struct cgroup_ops *ops,
|
|||||||
conf = handler->conf;
|
conf = handler->conf;
|
||||||
|
|
||||||
cgroup_settings = &conf->cgroup2;
|
cgroup_settings = &conf->cgroup2;
|
||||||
if (lxc_list_empty(cgroup_settings))
|
if (list_empty(cgroup_settings))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (!pure_unified_layout(ops))
|
if (!pure_unified_layout(ops))
|
||||||
@ -2821,18 +2807,17 @@ __cgfsng_ops static bool cgfsng_setup_limits(struct cgroup_ops *ops,
|
|||||||
return false;
|
return false;
|
||||||
h = ops->unified;
|
h = ops->unified;
|
||||||
|
|
||||||
lxc_list_for_each (iterator, cgroup_settings) {
|
list_for_each_entry(cgroup, cgroup_settings, head) {
|
||||||
struct lxc_cgroup *cg = iterator->elem;
|
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (strnequal("devices", cg->subsystem, 7))
|
if (strnequal("devices", cgroup->subsystem, 7))
|
||||||
ret = bpf_device_cgroup_prepare(ops, conf, cg->subsystem, cg->value);
|
ret = bpf_device_cgroup_prepare(ops, conf, cgroup->subsystem, cgroup->value);
|
||||||
else
|
else
|
||||||
ret = lxc_write_openat(h->path_lim, cg->subsystem, cg->value, strlen(cg->value));
|
ret = lxc_write_openat(h->path_lim, cgroup->subsystem, cgroup->value, strlen(cgroup->value));
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return log_error_errno(false, errno, "Failed to set \"%s\" to \"%s\"", cg->subsystem, cg->value);
|
return log_error_errno(false, errno, "Failed to set \"%s\" to \"%s\"", cgroup->subsystem, cgroup->value);
|
||||||
|
|
||||||
TRACE("Set \"%s\" to \"%s\"", cg->subsystem, cg->value);
|
TRACE("Set \"%s\" to \"%s\"", cgroup->subsystem, cgroup->value);
|
||||||
}
|
}
|
||||||
|
|
||||||
return log_info(true, "Limits for the unified cgroup hierarchy have been setup");
|
return log_info(true, "Limits for the unified cgroup hierarchy have been setup");
|
||||||
@ -3359,7 +3344,7 @@ static int initialize_cgroups(struct cgroup_ops *ops, struct lxc_conf *conf)
|
|||||||
*/
|
*/
|
||||||
ops->dfd_mnt = dfd;
|
ops->dfd_mnt = dfd;
|
||||||
|
|
||||||
ret = __initialize_cgroups(ops, conf->cgroup_meta.relative, !lxc_list_empty(&conf->id_map));
|
ret = __initialize_cgroups(ops, conf->cgroup_meta.relative, !list_empty(&conf->id_map));
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return syserror_ret(ret, "Failed to initialize cgroups");
|
return syserror_ret(ret, "Failed to initialize cgroups");
|
||||||
|
|
||||||
@ -3436,7 +3421,7 @@ static int __unified_attach_fd(const struct lxc_conf *conf, int fd_unified, pid_
|
|||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (!lxc_list_empty(&conf->id_map)) {
|
if (!list_empty(&conf->id_map)) {
|
||||||
struct userns_exec_unified_attach_data args = {
|
struct userns_exec_unified_attach_data args = {
|
||||||
.conf = conf,
|
.conf = conf,
|
||||||
.unified_fd = fd_unified,
|
.unified_fd = fd_unified,
|
||||||
|
@ -26,7 +26,6 @@
|
|||||||
|
|
||||||
struct lxc_handler;
|
struct lxc_handler;
|
||||||
struct lxc_conf;
|
struct lxc_conf;
|
||||||
struct lxc_list;
|
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
CGROUP_LAYOUT_UNKNOWN = -1,
|
CGROUP_LAYOUT_UNKNOWN = -1,
|
||||||
|
@ -114,11 +114,10 @@ static int do_child(void *vargv)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct lxc_list active_map;
|
static LIST_HEAD(active_map);
|
||||||
|
|
||||||
static int add_map_entry(long host_id, long ns_id, long range, int which)
|
static int add_map_entry(long host_id, long ns_id, long range, int which)
|
||||||
{
|
{
|
||||||
struct lxc_list *tmp = NULL;
|
|
||||||
struct id_map *newmap;
|
struct id_map *newmap;
|
||||||
|
|
||||||
newmap = malloc(sizeof(*newmap));
|
newmap = malloc(sizeof(*newmap));
|
||||||
@ -129,14 +128,8 @@ static int add_map_entry(long host_id, long ns_id, long range, int which)
|
|||||||
newmap->nsid = ns_id;
|
newmap->nsid = ns_id;
|
||||||
newmap->range = range;
|
newmap->range = range;
|
||||||
newmap->idtype = which;
|
newmap->idtype = which;
|
||||||
tmp = malloc(sizeof(*tmp));
|
|
||||||
if (!tmp) {
|
|
||||||
free(newmap);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
tmp->elem = newmap;
|
list_add_tail(&newmap->head, &active_map);
|
||||||
lxc_list_add_tail(&active_map, tmp);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -280,11 +273,9 @@ static bool do_map_self(void)
|
|||||||
{
|
{
|
||||||
struct id_map *map;
|
struct id_map *map;
|
||||||
long nsuid = 0, nsgid = 0;
|
long nsuid = 0, nsgid = 0;
|
||||||
struct lxc_list *tmp = NULL;
|
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
lxc_list_for_each(tmp, &active_map) {
|
list_for_each_entry(map, &active_map, head) {
|
||||||
map = tmp->elem;
|
|
||||||
if (map->idtype == ID_TYPE_UID) {
|
if (map->idtype == ID_TYPE_UID) {
|
||||||
if (is_in_ns_range(nsuid, map))
|
if (is_in_ns_range(nsuid, map))
|
||||||
nsuid += map->range;
|
nsuid += map->range;
|
||||||
@ -336,8 +327,6 @@ int main(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
lxc_list_init(&active_map);
|
|
||||||
|
|
||||||
while ((c = getopt(argc, argv, "m:hs")) != EOF) {
|
while ((c = getopt(argc, argv, "m:hs")) != EOF) {
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case 'm':
|
case 'm':
|
||||||
@ -359,7 +348,7 @@ int main(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if (lxc_list_empty(&active_map)) {
|
if (list_empty(&active_map)) {
|
||||||
ret = find_default_map();
|
ret = find_default_map();
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
fprintf(stderr, "Failed to find subuid or subgid allocation\n");
|
fprintf(stderr, "Failed to find subuid or subgid allocation\n");
|
||||||
|
791
src/lxc/conf.c
791
src/lxc/conf.c
File diff suppressed because it is too large
Load Diff
@ -78,6 +78,8 @@ struct lxc_cgroup {
|
|||||||
bool relative;
|
bool relative;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct list_head head;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void free_lxc_cgroup(struct lxc_cgroup *ptr)
|
static void free_lxc_cgroup(struct lxc_cgroup *ptr)
|
||||||
@ -95,6 +97,7 @@ define_cleanup_function(struct lxc_cgroup *, free_lxc_cgroup);
|
|||||||
struct rlimit {
|
struct rlimit {
|
||||||
unsigned long rlim_cur;
|
unsigned long rlim_cur;
|
||||||
unsigned long rlim_max;
|
unsigned long rlim_max;
|
||||||
|
struct list_head head;
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -106,6 +109,7 @@ struct rlimit {
|
|||||||
struct lxc_limit {
|
struct lxc_limit {
|
||||||
char *resource;
|
char *resource;
|
||||||
struct rlimit limit;
|
struct rlimit limit;
|
||||||
|
struct list_head head;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void free_lxc_limit(struct lxc_limit *ptr)
|
static void free_lxc_limit(struct lxc_limit *ptr)
|
||||||
@ -130,6 +134,7 @@ enum idtype {
|
|||||||
struct lxc_sysctl {
|
struct lxc_sysctl {
|
||||||
char *key;
|
char *key;
|
||||||
char *value;
|
char *value;
|
||||||
|
struct list_head head;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void free_lxc_sysctl(struct lxc_sysctl *ptr)
|
static void free_lxc_sysctl(struct lxc_sysctl *ptr)
|
||||||
@ -150,6 +155,7 @@ define_cleanup_function(struct lxc_sysctl *, free_lxc_sysctl);
|
|||||||
struct lxc_proc {
|
struct lxc_proc {
|
||||||
char *filename;
|
char *filename;
|
||||||
char *value;
|
char *value;
|
||||||
|
struct list_head head;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void free_lxc_proc(struct lxc_proc *ptr)
|
static void free_lxc_proc(struct lxc_proc *ptr)
|
||||||
@ -175,6 +181,7 @@ define_cleanup_function(struct lxc_proc *, free_lxc_proc);
|
|||||||
struct id_map {
|
struct id_map {
|
||||||
enum idtype idtype;
|
enum idtype idtype;
|
||||||
unsigned long hostid, nsid, range;
|
unsigned long hostid, nsid, range;
|
||||||
|
struct list_head head;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Defines the number of tty configured and contains the
|
/* Defines the number of tty configured and contains the
|
||||||
@ -204,13 +211,15 @@ struct lxc_mount_options {
|
|||||||
unsigned int create_file : 1;
|
unsigned int create_file : 1;
|
||||||
unsigned int optional : 1;
|
unsigned int optional : 1;
|
||||||
unsigned int relative : 1;
|
unsigned int relative : 1;
|
||||||
unsigned int recursive : 1;
|
unsigned int bind_recursively : 1;
|
||||||
|
unsigned int propagate_recursively : 1;
|
||||||
unsigned int bind : 1;
|
unsigned int bind : 1;
|
||||||
char userns_path[PATH_MAX];
|
char userns_path[PATH_MAX];
|
||||||
unsigned long mnt_flags;
|
unsigned long mnt_flags;
|
||||||
unsigned long prop_flags;
|
unsigned long prop_flags;
|
||||||
char *data;
|
char *data;
|
||||||
struct lxc_mount_attr attr;
|
struct lxc_mount_attr attr;
|
||||||
|
char *raw_options;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Defines a structure to store the rootfs location, the
|
/* Defines a structure to store the rootfs location, the
|
||||||
@ -219,7 +228,6 @@ struct lxc_mount_options {
|
|||||||
* @mount : where it is mounted
|
* @mount : where it is mounted
|
||||||
* @buf : static buffer to construct paths
|
* @buf : static buffer to construct paths
|
||||||
* @bev_type : optional backing store type
|
* @bev_type : optional backing store type
|
||||||
* @options : mount options
|
|
||||||
* @managed : whether it is managed by LXC
|
* @managed : whether it is managed by LXC
|
||||||
* @dfd_mnt : fd for @mount
|
* @dfd_mnt : fd for @mount
|
||||||
* @dfd_dev : fd for /dev of the container
|
* @dfd_dev : fd for /dev of the container
|
||||||
@ -238,8 +246,6 @@ struct lxc_rootfs {
|
|||||||
|
|
||||||
char buf[PATH_MAX];
|
char buf[PATH_MAX];
|
||||||
char *bdev_type;
|
char *bdev_type;
|
||||||
char *options;
|
|
||||||
unsigned long mountflags;
|
|
||||||
bool managed;
|
bool managed;
|
||||||
struct lxc_mount_options mnt_opts;
|
struct lxc_mount_options mnt_opts;
|
||||||
struct lxc_storage *storage;
|
struct lxc_storage *storage;
|
||||||
@ -331,6 +337,23 @@ struct timens_offsets {
|
|||||||
int64_t ns_monotonic;
|
int64_t ns_monotonic;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct environment_entry {
|
||||||
|
char *key;
|
||||||
|
char *val;
|
||||||
|
struct list_head head;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct cap_entry {
|
||||||
|
char *cap_name;
|
||||||
|
int cap;
|
||||||
|
struct list_head head;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct caps {
|
||||||
|
int keep;
|
||||||
|
struct list_head list;
|
||||||
|
};
|
||||||
|
|
||||||
struct lxc_conf {
|
struct lxc_conf {
|
||||||
/* Pointer to the name of the container. Do not free! */
|
/* Pointer to the name of the container. Do not free! */
|
||||||
const char *name;
|
const char *name;
|
||||||
@ -340,13 +363,13 @@ struct lxc_conf {
|
|||||||
struct utsname *utsname;
|
struct utsname *utsname;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
struct lxc_list cgroup;
|
struct list_head cgroup;
|
||||||
struct lxc_list cgroup2;
|
struct list_head cgroup2;
|
||||||
struct bpf_devices bpf_devices;
|
struct bpf_devices bpf_devices;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
struct lxc_list id_map;
|
struct list_head id_map;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Pointer to the idmap entry for the container's root uid in
|
* Pointer to the idmap entry for the container's root uid in
|
||||||
@ -369,8 +392,7 @@ struct lxc_conf {
|
|||||||
struct lxc_list mount_list;
|
struct lxc_list mount_list;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct lxc_list caps;
|
struct caps caps;
|
||||||
struct lxc_list keepcaps;
|
|
||||||
|
|
||||||
/* /dev/tty<idx> devices */
|
/* /dev/tty<idx> devices */
|
||||||
struct lxc_tty_info ttys;
|
struct lxc_tty_info ttys;
|
||||||
@ -430,14 +452,9 @@ struct lxc_conf {
|
|||||||
unsigned int monitor_unshare;
|
unsigned int monitor_unshare;
|
||||||
unsigned int monitor_signal_pdeath;
|
unsigned int monitor_signal_pdeath;
|
||||||
|
|
||||||
/* list of included files */
|
|
||||||
struct lxc_list includes;
|
|
||||||
/* config entries which are not "lxc.*" are aliens */
|
|
||||||
struct lxc_list aliens;
|
|
||||||
|
|
||||||
/* list of environment variables we'll add to the container when
|
/* list of environment variables we'll add to the container when
|
||||||
* started */
|
* started */
|
||||||
struct lxc_list environment;
|
struct list_head environment;
|
||||||
|
|
||||||
/* text representation of the config file */
|
/* text representation of the config file */
|
||||||
char *unexpanded_config;
|
char *unexpanded_config;
|
||||||
@ -468,7 +485,7 @@ struct lxc_conf {
|
|||||||
bool no_new_privs;
|
bool no_new_privs;
|
||||||
|
|
||||||
/* RLIMIT_* limits */
|
/* RLIMIT_* limits */
|
||||||
struct lxc_list limits;
|
struct list_head limits;
|
||||||
|
|
||||||
/* Contains generic info about the cgroup configuration for this
|
/* Contains generic info about the cgroup configuration for this
|
||||||
* container. Note that struct lxc_cgroup contains a union. It is only
|
* container. Note that struct lxc_cgroup contains a union. It is only
|
||||||
@ -490,10 +507,10 @@ struct lxc_conf {
|
|||||||
struct list_head state_clients;
|
struct list_head state_clients;
|
||||||
|
|
||||||
/* sysctls */
|
/* sysctls */
|
||||||
struct lxc_list sysctls;
|
struct list_head sysctls;
|
||||||
|
|
||||||
/* procs */
|
/* procs */
|
||||||
struct lxc_list procs;
|
struct list_head procs;
|
||||||
|
|
||||||
struct shmount {
|
struct shmount {
|
||||||
/* Absolute path to the shared mount point on the host */
|
/* Absolute path to the shared mount point on the host */
|
||||||
@ -519,11 +536,10 @@ __hidden extern void lxc_storage_put(struct lxc_conf *conf);
|
|||||||
__hidden extern int lxc_rootfs_init(struct lxc_conf *conf, bool userns);
|
__hidden extern int lxc_rootfs_init(struct lxc_conf *conf, bool userns);
|
||||||
__hidden extern int lxc_rootfs_prepare_parent(struct lxc_handler *handler);
|
__hidden extern int lxc_rootfs_prepare_parent(struct lxc_handler *handler);
|
||||||
__hidden extern int lxc_idmapped_mounts_parent(struct lxc_handler *handler);
|
__hidden extern int lxc_idmapped_mounts_parent(struct lxc_handler *handler);
|
||||||
__hidden extern int lxc_map_ids(struct lxc_list *idmap, pid_t pid);
|
__hidden extern int lxc_map_ids(struct list_head *idmap, pid_t pid);
|
||||||
__hidden extern int lxc_create_tty(const char *name, struct lxc_conf *conf);
|
__hidden extern int lxc_create_tty(const char *name, struct lxc_conf *conf);
|
||||||
__hidden extern void lxc_delete_tty(struct lxc_tty_info *ttys);
|
__hidden extern void lxc_delete_tty(struct lxc_tty_info *ttys);
|
||||||
__hidden extern int lxc_clear_config_caps(struct lxc_conf *c);
|
__hidden extern int lxc_clear_config_caps(struct lxc_conf *c);
|
||||||
__hidden extern int lxc_clear_config_keepcaps(struct lxc_conf *c);
|
|
||||||
__hidden extern int lxc_clear_cgroups(struct lxc_conf *c, const char *key, int version);
|
__hidden extern int lxc_clear_cgroups(struct lxc_conf *c, const char *key, int version);
|
||||||
__hidden extern int lxc_clear_mount_entries(struct lxc_conf *c);
|
__hidden extern int lxc_clear_mount_entries(struct lxc_conf *c);
|
||||||
__hidden extern int lxc_clear_automounts(struct lxc_conf *c);
|
__hidden extern int lxc_clear_automounts(struct lxc_conf *c);
|
||||||
@ -534,12 +550,11 @@ __hidden extern int lxc_clear_environment(struct lxc_conf *c);
|
|||||||
__hidden extern int lxc_clear_limits(struct lxc_conf *c, const char *key);
|
__hidden extern int lxc_clear_limits(struct lxc_conf *c, const char *key);
|
||||||
__hidden extern int lxc_delete_autodev(struct lxc_handler *handler);
|
__hidden extern int lxc_delete_autodev(struct lxc_handler *handler);
|
||||||
__hidden extern int lxc_clear_autodev_tmpfs_size(struct lxc_conf *c);
|
__hidden extern int lxc_clear_autodev_tmpfs_size(struct lxc_conf *c);
|
||||||
__hidden extern void lxc_clear_includes(struct lxc_conf *conf);
|
|
||||||
__hidden extern int lxc_setup_rootfs_prepare_root(struct lxc_conf *conf, const char *name,
|
__hidden extern int lxc_setup_rootfs_prepare_root(struct lxc_conf *conf, const char *name,
|
||||||
const char *lxcpath);
|
const char *lxcpath);
|
||||||
__hidden extern int lxc_setup(struct lxc_handler *handler);
|
__hidden extern int lxc_setup(struct lxc_handler *handler);
|
||||||
__hidden extern int lxc_setup_parent(struct lxc_handler *handler);
|
__hidden extern int lxc_setup_parent(struct lxc_handler *handler);
|
||||||
__hidden extern int setup_resource_limits(struct lxc_list *limits, pid_t pid);
|
__hidden extern int setup_resource_limits(struct lxc_conf *conf, pid_t pid);
|
||||||
__hidden extern int find_unmapped_nsid(const struct lxc_conf *conf, enum idtype idtype);
|
__hidden extern int find_unmapped_nsid(const struct lxc_conf *conf, enum idtype idtype);
|
||||||
__hidden extern int mapped_hostid(unsigned id, const struct lxc_conf *conf, enum idtype idtype);
|
__hidden extern int mapped_hostid(unsigned id, const struct lxc_conf *conf, enum idtype idtype);
|
||||||
__hidden extern int userns_exec_1(const struct lxc_conf *conf, int (*fn)(void *), void *data,
|
__hidden extern int userns_exec_1(const struct lxc_conf *conf, int (*fn)(void *), void *data,
|
||||||
@ -553,26 +568,23 @@ __hidden extern int parse_mount_attrs(struct lxc_mount_options *opts, const char
|
|||||||
__hidden extern void tmp_proc_unmount(struct lxc_conf *lxc_conf);
|
__hidden extern void tmp_proc_unmount(struct lxc_conf *lxc_conf);
|
||||||
__hidden extern void suggest_default_idmap(void);
|
__hidden extern void suggest_default_idmap(void);
|
||||||
__hidden extern FILE *make_anonymous_mount_file(struct lxc_list *mount, bool include_nesting_helpers);
|
__hidden extern FILE *make_anonymous_mount_file(struct lxc_list *mount, bool include_nesting_helpers);
|
||||||
__hidden extern struct lxc_list *sort_cgroup_settings(struct lxc_list *cgroup_settings);
|
__hidden extern void sort_cgroup_settings(struct lxc_conf *conf);
|
||||||
__hidden extern int run_script(const char *name, const char *section, const char *script, ...);
|
__hidden extern int run_script(const char *name, const char *section, const char *script, ...);
|
||||||
__hidden extern int run_script_argv(const char *name, unsigned int hook_version, const char *section,
|
__hidden extern int run_script_argv(const char *name, unsigned int hook_version, const char *section,
|
||||||
const char *script, const char *hookname, char **argsin);
|
const char *script, const char *hookname, char **argsin);
|
||||||
__hidden extern int in_caplist(int cap, struct lxc_list *caps);
|
|
||||||
|
|
||||||
|
__hidden extern bool has_cap(int cap, struct lxc_conf *conf);
|
||||||
static inline bool lxc_wants_cap(int cap, struct lxc_conf *conf)
|
static inline bool lxc_wants_cap(int cap, struct lxc_conf *conf)
|
||||||
{
|
{
|
||||||
if (lxc_caps_last_cap() < cap)
|
if (lxc_caps_last_cap() < cap)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!lxc_list_empty(&conf->keepcaps))
|
return has_cap(cap, conf);
|
||||||
return in_caplist(cap, &conf->keepcaps);
|
|
||||||
|
|
||||||
return !in_caplist(cap, &conf->caps);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
__hidden extern int setup_sysctl_parameters(struct lxc_list *sysctls);
|
__hidden extern int setup_sysctl_parameters(struct lxc_conf *conf);
|
||||||
__hidden extern int lxc_clear_sysctls(struct lxc_conf *c, const char *key);
|
__hidden extern int lxc_clear_sysctls(struct lxc_conf *c, const char *key);
|
||||||
__hidden extern int setup_proc_filesystem(struct lxc_list *procs, pid_t pid);
|
__hidden extern int setup_proc_filesystem(struct lxc_conf *conf, pid_t pid);
|
||||||
__hidden extern int lxc_clear_procs(struct lxc_conf *c, const char *key);
|
__hidden extern int lxc_clear_procs(struct lxc_conf *c, const char *key);
|
||||||
__hidden extern int lxc_clear_apparmor_raw(struct lxc_conf *c);
|
__hidden extern int lxc_clear_apparmor_raw(struct lxc_conf *c);
|
||||||
__hidden extern int lxc_clear_namespace(struct lxc_conf *c);
|
__hidden extern int lxc_clear_namespace(struct lxc_conf *c);
|
||||||
@ -607,6 +619,7 @@ static inline void put_lxc_mount_options(struct lxc_mount_options *mnt_opts)
|
|||||||
mnt_opts->prop_flags = 0;
|
mnt_opts->prop_flags = 0;
|
||||||
|
|
||||||
free_disarm(mnt_opts->data);
|
free_disarm(mnt_opts->data);
|
||||||
|
free_disarm(mnt_opts->raw_options);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void put_lxc_rootfs(struct lxc_rootfs *rootfs, bool unpin)
|
static inline void put_lxc_rootfs(struct lxc_rootfs *rootfs, bool unpin)
|
||||||
@ -642,4 +655,7 @@ static inline int lxc_personality(personality_t persona)
|
|||||||
return personality(persona);
|
return personality(persona);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
__hidden extern int lxc_set_environment(const struct lxc_conf *conf);
|
||||||
|
__hidden extern int parse_cap(const char *cap);
|
||||||
|
|
||||||
#endif /* __LXC_CONF_H */
|
#endif /* __LXC_CONF_H */
|
||||||
|
@ -1539,35 +1539,40 @@ static int set_config_group(const char *key, const char *value,
|
|||||||
static int set_config_environment(const char *key, const char *value,
|
static int set_config_environment(const char *key, const char *value,
|
||||||
struct lxc_conf *lxc_conf, void *data)
|
struct lxc_conf *lxc_conf, void *data)
|
||||||
{
|
{
|
||||||
__do_free struct lxc_list *list_item = NULL;
|
__do_free char *dup = NULL, *val = NULL;
|
||||||
|
__do_free struct environment_entry *new_env = NULL;
|
||||||
|
char *env_val;
|
||||||
|
|
||||||
if (lxc_config_value_empty(value))
|
if (lxc_config_value_empty(value))
|
||||||
return lxc_clear_environment(lxc_conf);
|
return lxc_clear_environment(lxc_conf);
|
||||||
|
|
||||||
list_item = lxc_list_new();
|
new_env = zalloc(sizeof(struct environment_entry));
|
||||||
if (!list_item)
|
if (!new_env)
|
||||||
return ret_errno(ENOMEM);
|
return ret_errno(ENOMEM);
|
||||||
|
|
||||||
if (!strchr(value, '=')) {
|
dup = strdup(value);
|
||||||
const char *env_val;
|
if (!dup)
|
||||||
const char *env_key = value;
|
return ret_errno(ENOMEM);
|
||||||
const char *env_var[3] = {0};
|
|
||||||
|
|
||||||
env_val = getenv(env_key);
|
env_val = strchr(dup, '=');
|
||||||
if (!env_val)
|
if (!env_val) {
|
||||||
return ret_errno(ENOENT);
|
env_val = getenv(dup);
|
||||||
|
|
||||||
env_var[0] = env_key;
|
|
||||||
env_var[1] = env_val;
|
|
||||||
list_item->elem = lxc_string_join("=", env_var, false);
|
|
||||||
} else {
|
} else {
|
||||||
list_item->elem = strdup(value);
|
*env_val = '\0';
|
||||||
|
env_val++;
|
||||||
}
|
}
|
||||||
|
if (!env_val)
|
||||||
|
return ret_errno(ENOENT);
|
||||||
|
|
||||||
if (!list_item->elem)
|
val = strdup(env_val);
|
||||||
|
if (!val)
|
||||||
return ret_errno(ENOMEM);
|
return ret_errno(ENOMEM);
|
||||||
|
|
||||||
lxc_list_add_tail(&lxc_conf->environment, move_ptr(list_item));
|
new_env->key = move_ptr(dup);
|
||||||
|
new_env->val = move_ptr(val);
|
||||||
|
|
||||||
|
list_add_tail(&new_env->head, &lxc_conf->environment);
|
||||||
|
move_ptr(new_env);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -1858,8 +1863,7 @@ static int set_config_signal_stop(const char *key, const char *value,
|
|||||||
static int __set_config_cgroup_controller(const char *key, const char *value,
|
static int __set_config_cgroup_controller(const char *key, const char *value,
|
||||||
struct lxc_conf *lxc_conf, int version)
|
struct lxc_conf *lxc_conf, int version)
|
||||||
{
|
{
|
||||||
__do_free struct lxc_list *cglist = NULL;
|
call_cleaner(free_lxc_cgroup) struct lxc_cgroup *new_cgroup = NULL;
|
||||||
call_cleaner(free_lxc_cgroup) struct lxc_cgroup *cgelem = NULL;
|
|
||||||
const char *subkey, *token;
|
const char *subkey, *token;
|
||||||
size_t token_len;
|
size_t token_len;
|
||||||
|
|
||||||
@ -1883,31 +1887,25 @@ static int __set_config_cgroup_controller(const char *key, const char *value,
|
|||||||
if (*subkey == '\0')
|
if (*subkey == '\0')
|
||||||
return ret_errno(EINVAL);
|
return ret_errno(EINVAL);
|
||||||
|
|
||||||
cglist = lxc_list_new();
|
new_cgroup = zalloc(sizeof(*new_cgroup));
|
||||||
if (!cglist)
|
if (!new_cgroup)
|
||||||
return ret_errno(ENOMEM);
|
return ret_errno(ENOMEM);
|
||||||
|
|
||||||
cgelem = zalloc(sizeof(*cgelem));
|
new_cgroup->subsystem = strdup(subkey);
|
||||||
if (!cgelem)
|
if (!new_cgroup->subsystem)
|
||||||
return ret_errno(ENOMEM);
|
return ret_errno(ENOMEM);
|
||||||
|
|
||||||
cgelem->subsystem = strdup(subkey);
|
new_cgroup->value = strdup(value);
|
||||||
if (!cgelem->subsystem)
|
if (!new_cgroup->value)
|
||||||
return ret_errno(ENOMEM);
|
return ret_errno(ENOMEM);
|
||||||
|
|
||||||
cgelem->value = strdup(value);
|
new_cgroup->version = version;
|
||||||
if (!cgelem->value)
|
|
||||||
return ret_errno(ENOMEM);
|
|
||||||
|
|
||||||
cgelem->version = version;
|
|
||||||
|
|
||||||
lxc_list_add_elem(cglist, move_ptr(cgelem));
|
|
||||||
|
|
||||||
if (version == CGROUP2_SUPER_MAGIC)
|
if (version == CGROUP2_SUPER_MAGIC)
|
||||||
lxc_list_add_tail(&lxc_conf->cgroup2, cglist);
|
list_add_tail(&new_cgroup->head, &lxc_conf->cgroup2);
|
||||||
else
|
else
|
||||||
lxc_list_add_tail(&lxc_conf->cgroup, cglist);
|
list_add_tail(&new_cgroup->head, &lxc_conf->cgroup);
|
||||||
move_ptr(cglist);
|
move_ptr(new_cgroup);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -2056,11 +2054,10 @@ static bool parse_limit_value(const char **value, rlim_t *res)
|
|||||||
static int set_config_prlimit(const char *key, const char *value,
|
static int set_config_prlimit(const char *key, const char *value,
|
||||||
struct lxc_conf *lxc_conf, void *data)
|
struct lxc_conf *lxc_conf, void *data)
|
||||||
{
|
{
|
||||||
__do_free struct lxc_list *list = NULL;
|
call_cleaner(free_lxc_limit) struct lxc_limit *new_lim = NULL;
|
||||||
call_cleaner(free_lxc_limit) struct lxc_limit *elem = NULL;
|
|
||||||
struct lxc_list *iter;
|
|
||||||
struct rlimit limit;
|
struct rlimit limit;
|
||||||
rlim_t limit_value;
|
rlim_t limit_value;
|
||||||
|
struct lxc_limit *lim;
|
||||||
|
|
||||||
if (lxc_config_value_empty(value))
|
if (lxc_config_value_empty(value))
|
||||||
return lxc_clear_limits(lxc_conf, key);
|
return lxc_clear_limits(lxc_conf, key);
|
||||||
@ -2107,32 +2104,25 @@ static int set_config_prlimit(const char *key, const char *value,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* find existing list element */
|
/* find existing list element */
|
||||||
lxc_list_for_each(iter, &lxc_conf->limits) {
|
list_for_each_entry(lim, &lxc_conf->limits, head) {
|
||||||
struct lxc_limit *cur = iter->elem;
|
if (!strequal(key, lim->resource))
|
||||||
|
|
||||||
if (!strequal(key, cur->resource))
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
cur->limit = limit;
|
lim->limit = limit;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* allocate list element */
|
new_lim = zalloc(sizeof(*new_lim));
|
||||||
list = lxc_list_new();
|
if (!new_lim)
|
||||||
if (!list)
|
|
||||||
return ret_errno(ENOMEM);
|
return ret_errno(ENOMEM);
|
||||||
|
|
||||||
elem = zalloc(sizeof(*elem));
|
new_lim->resource = strdup(key);
|
||||||
if (!elem)
|
if (!new_lim->resource)
|
||||||
return ret_errno(ENOMEM);
|
return ret_errno(ENOMEM);
|
||||||
|
|
||||||
elem->resource = strdup(key);
|
new_lim->limit = limit;
|
||||||
if (!elem->resource)
|
list_add_tail(&new_lim->head, &lxc_conf->limits);
|
||||||
return ret_errno(ENOMEM);
|
move_ptr(new_lim);
|
||||||
|
|
||||||
elem->limit = limit;
|
|
||||||
lxc_list_add_elem(list, move_ptr(elem));;
|
|
||||||
lxc_list_add_tail(&lxc_conf->limits, move_ptr(list));
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -2140,9 +2130,8 @@ static int set_config_prlimit(const char *key, const char *value,
|
|||||||
static int set_config_sysctl(const char *key, const char *value,
|
static int set_config_sysctl(const char *key, const char *value,
|
||||||
struct lxc_conf *lxc_conf, void *data)
|
struct lxc_conf *lxc_conf, void *data)
|
||||||
{
|
{
|
||||||
__do_free struct lxc_list *sysctl_list = NULL;
|
|
||||||
call_cleaner(free_lxc_sysctl) struct lxc_sysctl *sysctl_elem = NULL;
|
call_cleaner(free_lxc_sysctl) struct lxc_sysctl *sysctl_elem = NULL;
|
||||||
struct lxc_list *iter;
|
struct lxc_sysctl *sysctl, *nsysctl;
|
||||||
|
|
||||||
if (lxc_config_value_empty(value))
|
if (lxc_config_value_empty(value))
|
||||||
return clr_config_sysctl(key, lxc_conf, NULL);
|
return clr_config_sysctl(key, lxc_conf, NULL);
|
||||||
@ -2155,28 +2144,22 @@ static int set_config_sysctl(const char *key, const char *value,
|
|||||||
return ret_errno(EINVAL);
|
return ret_errno(EINVAL);
|
||||||
|
|
||||||
/* find existing list element */
|
/* find existing list element */
|
||||||
lxc_list_for_each(iter, &lxc_conf->sysctls) {
|
list_for_each_entry_safe(sysctl, nsysctl, &lxc_conf->sysctls, head) {
|
||||||
__do_free char *replace_value = NULL;
|
__do_free char *replace_value = NULL;
|
||||||
struct lxc_sysctl *cur = iter->elem;
|
|
||||||
|
|
||||||
if (!strequal(key, cur->key))
|
if (!strequal(key, sysctl->key))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
replace_value = strdup(value);
|
replace_value = strdup(value);
|
||||||
if (!replace_value)
|
if (!replace_value)
|
||||||
return ret_errno(EINVAL);
|
return ret_errno(EINVAL);
|
||||||
|
|
||||||
free(cur->value);
|
free(sysctl->value);
|
||||||
cur->value = move_ptr(replace_value);
|
sysctl->value = move_ptr(replace_value);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* allocate list element */
|
|
||||||
sysctl_list = lxc_list_new();
|
|
||||||
if (!sysctl_list)
|
|
||||||
return ret_errno(ENOMEM);
|
|
||||||
|
|
||||||
sysctl_elem = zalloc(sizeof(*sysctl_elem));
|
sysctl_elem = zalloc(sizeof(*sysctl_elem));
|
||||||
if (!sysctl_elem)
|
if (!sysctl_elem)
|
||||||
return ret_errno(ENOMEM);
|
return ret_errno(ENOMEM);
|
||||||
@ -2189,8 +2172,8 @@ static int set_config_sysctl(const char *key, const char *value,
|
|||||||
if (!sysctl_elem->value)
|
if (!sysctl_elem->value)
|
||||||
return ret_errno(ENOMEM);
|
return ret_errno(ENOMEM);
|
||||||
|
|
||||||
lxc_list_add_elem(sysctl_list, move_ptr(sysctl_elem));
|
list_add_tail(&sysctl_elem->head, &lxc_conf->sysctls);
|
||||||
lxc_list_add_tail(&lxc_conf->sysctls, move_ptr(sysctl_list));
|
move_ptr(sysctl_elem);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -2198,8 +2181,7 @@ static int set_config_sysctl(const char *key, const char *value,
|
|||||||
static int set_config_proc(const char *key, const char *value,
|
static int set_config_proc(const char *key, const char *value,
|
||||||
struct lxc_conf *lxc_conf, void *data)
|
struct lxc_conf *lxc_conf, void *data)
|
||||||
{
|
{
|
||||||
__do_free struct lxc_list *proclist = NULL;
|
call_cleaner(free_lxc_proc) struct lxc_proc *new_proc = NULL;
|
||||||
call_cleaner(free_lxc_proc) struct lxc_proc *procelem = NULL;
|
|
||||||
const char *subkey;
|
const char *subkey;
|
||||||
|
|
||||||
if (lxc_config_value_empty(value))
|
if (lxc_config_value_empty(value))
|
||||||
@ -2212,24 +2194,20 @@ static int set_config_proc(const char *key, const char *value,
|
|||||||
if (*subkey == '\0')
|
if (*subkey == '\0')
|
||||||
return ret_errno(EINVAL);
|
return ret_errno(EINVAL);
|
||||||
|
|
||||||
proclist = lxc_list_new();
|
new_proc = zalloc(sizeof(*new_proc));
|
||||||
if (!proclist)
|
if (!new_proc)
|
||||||
return ret_errno(ENOMEM);
|
return ret_errno(ENOMEM);
|
||||||
|
|
||||||
procelem = zalloc(sizeof(*procelem));
|
new_proc->filename = strdup(subkey);
|
||||||
if (!procelem)
|
if (!new_proc->filename)
|
||||||
return ret_errno(ENOMEM);
|
return ret_errno(ENOMEM);
|
||||||
|
|
||||||
procelem->filename = strdup(subkey);
|
new_proc->value = strdup(value);
|
||||||
if (!procelem->filename)
|
if (!new_proc->value)
|
||||||
return ret_errno(ENOMEM);
|
return ret_errno(ENOMEM);
|
||||||
|
|
||||||
procelem->value = strdup(value);
|
list_add_tail(&new_proc->head, &lxc_conf->procs);
|
||||||
if (!procelem->value)
|
move_ptr(new_proc);
|
||||||
return ret_errno(ENOMEM);
|
|
||||||
|
|
||||||
proclist->elem = move_ptr(procelem);
|
|
||||||
lxc_list_add_tail(&lxc_conf->procs, move_ptr(proclist));
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -2237,7 +2215,6 @@ static int set_config_proc(const char *key, const char *value,
|
|||||||
static int set_config_idmaps(const char *key, const char *value,
|
static int set_config_idmaps(const char *key, const char *value,
|
||||||
struct lxc_conf *lxc_conf, void *data)
|
struct lxc_conf *lxc_conf, void *data)
|
||||||
{
|
{
|
||||||
__do_free struct lxc_list *idmaplist = NULL;
|
|
||||||
__do_free struct id_map *idmap = NULL;
|
__do_free struct id_map *idmap = NULL;
|
||||||
unsigned long hostid, nsid, range;
|
unsigned long hostid, nsid, range;
|
||||||
char type;
|
char type;
|
||||||
@ -2246,10 +2223,6 @@ static int set_config_idmaps(const char *key, const char *value,
|
|||||||
if (lxc_config_value_empty(value))
|
if (lxc_config_value_empty(value))
|
||||||
return lxc_clear_idmaps(lxc_conf);
|
return lxc_clear_idmaps(lxc_conf);
|
||||||
|
|
||||||
idmaplist = lxc_list_new();
|
|
||||||
if (!idmaplist)
|
|
||||||
return ret_errno(ENOMEM);
|
|
||||||
|
|
||||||
idmap = zalloc(sizeof(*idmap));
|
idmap = zalloc(sizeof(*idmap));
|
||||||
if (!idmap)
|
if (!idmap)
|
||||||
return ret_errno(ENOMEM);
|
return ret_errno(ENOMEM);
|
||||||
@ -2269,8 +2242,7 @@ static int set_config_idmaps(const char *key, const char *value,
|
|||||||
idmap->hostid = hostid;
|
idmap->hostid = hostid;
|
||||||
idmap->nsid = nsid;
|
idmap->nsid = nsid;
|
||||||
idmap->range = range;
|
idmap->range = range;
|
||||||
idmaplist->elem = idmap;
|
list_add_tail(&idmap->head, &lxc_conf->id_map);
|
||||||
lxc_list_add_tail(&lxc_conf->id_map, idmaplist);
|
|
||||||
|
|
||||||
if (!lxc_conf->root_nsuid_map && idmap->idtype == ID_TYPE_UID)
|
if (!lxc_conf->root_nsuid_map && idmap->idtype == ID_TYPE_UID)
|
||||||
if (idmap->nsid == 0)
|
if (idmap->nsid == 0)
|
||||||
@ -2281,7 +2253,6 @@ static int set_config_idmaps(const char *key, const char *value,
|
|||||||
lxc_conf->root_nsgid_map = idmap;
|
lxc_conf->root_nsgid_map = idmap;
|
||||||
|
|
||||||
move_ptr(idmap);
|
move_ptr(idmap);
|
||||||
move_ptr(idmaplist);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -2429,70 +2400,96 @@ int add_elem_to_mount_list(const char *value, struct lxc_conf *lxc_conf) {
|
|||||||
return set_config_mount(NULL, value, lxc_conf, NULL);
|
return set_config_mount(NULL, value, lxc_conf, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int add_cap_entry(struct lxc_conf *conf, char *caps, bool keep)
|
||||||
|
{
|
||||||
|
char *token;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* In case several capability keep is specified in a single line split
|
||||||
|
* these caps in a single element for the list.
|
||||||
|
*/
|
||||||
|
lxc_iterate_parts(token, caps, " \t") {
|
||||||
|
__do_free struct cap_entry *new_cap = NULL;
|
||||||
|
int cap;
|
||||||
|
|
||||||
|
if (strequal(token, "none")) {
|
||||||
|
if (!keep)
|
||||||
|
return syserror_set(-EINVAL, "The \"none\" keyword is only valid when keeping caps");
|
||||||
|
|
||||||
|
lxc_clear_config_caps(conf);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
cap = parse_cap(token);
|
||||||
|
if (cap < 0) {
|
||||||
|
if (cap != -2)
|
||||||
|
return syserror_set(-EINVAL, "Invalid capability specified");
|
||||||
|
|
||||||
|
INFO("Ignoring unknown capability \"%s\"", token);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
new_cap = zalloc(sizeof(struct cap_entry));
|
||||||
|
if (!new_cap)
|
||||||
|
return ret_errno(ENOMEM);
|
||||||
|
|
||||||
|
new_cap->cap_name = strdup(token);
|
||||||
|
if (!new_cap->cap_name)
|
||||||
|
return ret_errno(ENOMEM);
|
||||||
|
new_cap->cap = cap;
|
||||||
|
|
||||||
|
list_add_tail(&new_cap->head, &conf->caps.list);
|
||||||
|
move_ptr(new_cap);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int set_config_cap_keep(const char *key, const char *value,
|
static int set_config_cap_keep(const char *key, const char *value,
|
||||||
struct lxc_conf *lxc_conf, void *data)
|
struct lxc_conf *lxc_conf, void *data)
|
||||||
{
|
{
|
||||||
__do_free char *keepcaps = NULL;
|
__do_free char *caps = NULL;
|
||||||
__do_free struct lxc_list *keeplist = NULL;
|
int ret;
|
||||||
char *token;
|
|
||||||
|
|
||||||
if (lxc_config_value_empty(value))
|
if (lxc_config_value_empty(value))
|
||||||
return lxc_clear_config_keepcaps(lxc_conf);
|
return lxc_clear_config_caps(lxc_conf);
|
||||||
|
|
||||||
keepcaps = strdup(value);
|
caps = strdup(value);
|
||||||
if (!keepcaps)
|
if (!caps)
|
||||||
return ret_errno(ENOMEM);
|
return ret_errno(ENOMEM);
|
||||||
|
|
||||||
/* In case several capability keep is specified in a single line
|
if (!lxc_conf->caps.keep && !list_empty(&lxc_conf->caps.list))
|
||||||
* split these caps in a single element for the list.
|
return syserror_set(-EINVAL, "Keeping and dropping capabilities are mutually exclusive");
|
||||||
*/
|
|
||||||
lxc_iterate_parts(token, keepcaps, " \t") {
|
|
||||||
if (strequal(token, "none"))
|
|
||||||
lxc_clear_config_keepcaps(lxc_conf);
|
|
||||||
|
|
||||||
keeplist = lxc_list_new();
|
ret = add_cap_entry(lxc_conf, caps, true);
|
||||||
if (!keeplist)
|
if (ret < 0)
|
||||||
return ret_errno(ENOMEM);
|
return ret;
|
||||||
|
|
||||||
keeplist->elem = strdup(token);
|
|
||||||
if (!keeplist->elem)
|
|
||||||
return ret_errno(ENOMEM);
|
|
||||||
|
|
||||||
lxc_list_add_tail(&lxc_conf->keepcaps, move_ptr(keeplist));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
lxc_conf->caps.keep = true;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int set_config_cap_drop(const char *key, const char *value,
|
static int set_config_cap_drop(const char *key, const char *value,
|
||||||
struct lxc_conf *lxc_conf, void *data)
|
struct lxc_conf *lxc_conf, void *data)
|
||||||
{
|
{
|
||||||
__do_free char *dropcaps = NULL;
|
__do_free char *caps = NULL;
|
||||||
__do_free struct lxc_list *droplist = NULL;
|
int ret;
|
||||||
char *token;
|
|
||||||
|
|
||||||
if (lxc_config_value_empty(value))
|
if (lxc_config_value_empty(value))
|
||||||
return lxc_clear_config_caps(lxc_conf);
|
return lxc_clear_config_caps(lxc_conf);
|
||||||
|
|
||||||
dropcaps = strdup(value);
|
if (lxc_conf->caps.keep)
|
||||||
if (!dropcaps)
|
return syserror_set(-EINVAL, "Keeping and dropping capabilities are mutually exclusive");
|
||||||
|
|
||||||
|
caps = strdup(value);
|
||||||
|
if (!caps)
|
||||||
return ret_errno(ENOMEM);
|
return ret_errno(ENOMEM);
|
||||||
|
|
||||||
/* In case several capability drop is specified in a single line
|
ret = add_cap_entry(lxc_conf, caps, false);
|
||||||
* split these caps in a single element for the list.
|
if (ret < 0)
|
||||||
*/
|
return ret;
|
||||||
lxc_iterate_parts(token, dropcaps, " \t") {
|
|
||||||
droplist = lxc_list_new();
|
|
||||||
if (!droplist)
|
|
||||||
return ret_errno(ENOMEM);
|
|
||||||
|
|
||||||
droplist->elem = strdup(token);
|
|
||||||
if (!droplist->elem)
|
|
||||||
return ret_errno(ENOMEM);
|
|
||||||
|
|
||||||
lxc_list_add_tail(&lxc_conf->caps, move_ptr(droplist));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
lxc_conf->caps.keep = false;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2818,7 +2815,7 @@ static int set_config_rootfs_options(const char *key, const char *value,
|
|||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret_errno(EINVAL);
|
return ret_errno(EINVAL);
|
||||||
|
|
||||||
rootfs->options = move_ptr(raw_options);
|
rootfs->mnt_opts.raw_options = move_ptr(raw_options);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3862,12 +3859,13 @@ static int __get_config_cgroup_controller(const char *key, char *retv,
|
|||||||
int inlen, struct lxc_conf *c,
|
int inlen, struct lxc_conf *c,
|
||||||
int version)
|
int version)
|
||||||
{
|
{
|
||||||
|
int fulllen = 0;
|
||||||
|
bool get_all = false;
|
||||||
int len;
|
int len;
|
||||||
size_t namespaced_token_len;
|
size_t namespaced_token_len;
|
||||||
char *global_token, *namespaced_token;
|
char *global_token, *namespaced_token;
|
||||||
struct lxc_list *it;
|
struct list_head *list;
|
||||||
int fulllen = 0;
|
struct lxc_cgroup *cgroup;
|
||||||
bool get_all = false;
|
|
||||||
|
|
||||||
if (!retv)
|
if (!retv)
|
||||||
inlen = 0;
|
inlen = 0;
|
||||||
@ -3878,10 +3876,12 @@ static int __get_config_cgroup_controller(const char *key, char *retv,
|
|||||||
global_token = "lxc.cgroup2";
|
global_token = "lxc.cgroup2";
|
||||||
namespaced_token = "lxc.cgroup2.";
|
namespaced_token = "lxc.cgroup2.";
|
||||||
namespaced_token_len = STRLITERALLEN("lxc.cgroup2.");
|
namespaced_token_len = STRLITERALLEN("lxc.cgroup2.");
|
||||||
|
list = &c->cgroup2;
|
||||||
} else if (version == CGROUP_SUPER_MAGIC) {
|
} else if (version == CGROUP_SUPER_MAGIC) {
|
||||||
global_token = "lxc.cgroup";
|
global_token = "lxc.cgroup";
|
||||||
namespaced_token = "lxc.cgroup.";
|
namespaced_token = "lxc.cgroup.";
|
||||||
namespaced_token_len = STRLITERALLEN("lxc.cgroup.");
|
namespaced_token_len = STRLITERALLEN("lxc.cgroup.");
|
||||||
|
list = &c->cgroup;
|
||||||
} else {
|
} else {
|
||||||
return ret_errno(EINVAL);
|
return ret_errno(EINVAL);
|
||||||
}
|
}
|
||||||
@ -3893,17 +3893,15 @@ static int __get_config_cgroup_controller(const char *key, char *retv,
|
|||||||
else
|
else
|
||||||
return ret_errno(EINVAL);
|
return ret_errno(EINVAL);
|
||||||
|
|
||||||
lxc_list_for_each(it, &c->cgroup) {
|
list_for_each_entry(cgroup, list, head) {
|
||||||
struct lxc_cgroup *cg = it->elem;
|
|
||||||
|
|
||||||
if (get_all) {
|
if (get_all) {
|
||||||
if (version != cg->version)
|
if (version != cgroup->version)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
strprint(retv, inlen, "%s.%s = %s\n", global_token,
|
strprint(retv, inlen, "%s.%s = %s\n", global_token,
|
||||||
cg->subsystem, cg->value);
|
cgroup->subsystem, cgroup->value);
|
||||||
} else if (strequal(cg->subsystem, key)) {
|
} else if (strequal(cgroup->subsystem, key)) {
|
||||||
strprint(retv, inlen, "%s\n", cg->value);
|
strprint(retv, inlen, "%s\n", cgroup->value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4022,7 +4020,7 @@ static inline int get_config_cgroup_relative(const char *key, char *retv,
|
|||||||
static int get_config_idmaps(const char *key, char *retv, int inlen,
|
static int get_config_idmaps(const char *key, char *retv, int inlen,
|
||||||
struct lxc_conf *c, void *data)
|
struct lxc_conf *c, void *data)
|
||||||
{
|
{
|
||||||
struct lxc_list *it;
|
struct id_map *map;
|
||||||
int len, listlen, ret;
|
int len, listlen, ret;
|
||||||
int fulllen = 0;
|
int fulllen = 0;
|
||||||
/* "u 1000 1000000 65536"
|
/* "u 1000 1000000 65536"
|
||||||
@ -4053,9 +4051,8 @@ static int get_config_idmaps(const char *key, char *retv, int inlen,
|
|||||||
else
|
else
|
||||||
memset(retv, 0, inlen);
|
memset(retv, 0, inlen);
|
||||||
|
|
||||||
listlen = lxc_list_len(&c->id_map);
|
listlen = list_len(&c->id_map);
|
||||||
lxc_list_for_each(it, &c->id_map) {
|
list_for_each_entry(map, &c->id_map, head) {
|
||||||
struct id_map *map = it->elem;
|
|
||||||
ret = strnprintf(buf, sizeof(buf), "%c %lu %lu %lu",
|
ret = strnprintf(buf, sizeof(buf), "%c %lu %lu %lu",
|
||||||
(map->idtype == ID_TYPE_UID) ? 'u' : 'g',
|
(map->idtype == ID_TYPE_UID) ? 'u' : 'g',
|
||||||
map->nsid, map->hostid, map->range);
|
map->nsid, map->hostid, map->range);
|
||||||
@ -4203,7 +4200,7 @@ static int get_config_rootfs_mount(const char *key, char *retv, int inlen,
|
|||||||
static int get_config_rootfs_options(const char *key, char *retv, int inlen,
|
static int get_config_rootfs_options(const char *key, char *retv, int inlen,
|
||||||
struct lxc_conf *c, void *data)
|
struct lxc_conf *c, void *data)
|
||||||
{
|
{
|
||||||
return lxc_get_conf_str(retv, inlen, c->rootfs.options);
|
return lxc_get_conf_str(retv, inlen, c->rootfs.mnt_opts.raw_options);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int get_config_uts_name(const char *key, char *retv, int inlen,
|
static int get_config_uts_name(const char *key, char *retv, int inlen,
|
||||||
@ -4284,15 +4281,15 @@ static int get_config_cap_drop(const char *key, char *retv, int inlen,
|
|||||||
struct lxc_conf *c, void *data)
|
struct lxc_conf *c, void *data)
|
||||||
{
|
{
|
||||||
int len, fulllen = 0;
|
int len, fulllen = 0;
|
||||||
struct lxc_list *it;
|
struct cap_entry *cap;
|
||||||
|
|
||||||
if (!retv)
|
if (!retv)
|
||||||
inlen = 0;
|
inlen = 0;
|
||||||
else
|
else
|
||||||
memset(retv, 0, inlen);
|
memset(retv, 0, inlen);
|
||||||
|
|
||||||
lxc_list_for_each(it, &c->caps) {
|
list_for_each_entry(cap, &c->caps.list, head) {
|
||||||
strprint(retv, inlen, "%s\n", (char *)it->elem);
|
strprint(retv, inlen, "%s\n", cap->cap_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
return fulllen;
|
return fulllen;
|
||||||
@ -4302,15 +4299,15 @@ static int get_config_cap_keep(const char *key, char *retv, int inlen,
|
|||||||
struct lxc_conf *c, void *data)
|
struct lxc_conf *c, void *data)
|
||||||
{
|
{
|
||||||
int len, fulllen = 0;
|
int len, fulllen = 0;
|
||||||
struct lxc_list *it;
|
struct cap_entry *cap;
|
||||||
|
|
||||||
if (!retv)
|
if (!retv)
|
||||||
inlen = 0;
|
inlen = 0;
|
||||||
else
|
else
|
||||||
memset(retv, 0, inlen);
|
memset(retv, 0, inlen);
|
||||||
|
|
||||||
lxc_list_for_each(it, &c->keepcaps) {
|
list_for_each_entry(cap, &c->caps.list, head) {
|
||||||
strprint(retv, inlen, "%s\n", (char *)it->elem);
|
strprint(retv, inlen, "%s\n", cap->cap_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
return fulllen;
|
return fulllen;
|
||||||
@ -4476,15 +4473,15 @@ static int get_config_environment(const char *key, char *retv, int inlen,
|
|||||||
struct lxc_conf *c, void *data)
|
struct lxc_conf *c, void *data)
|
||||||
{
|
{
|
||||||
int len, fulllen = 0;
|
int len, fulllen = 0;
|
||||||
struct lxc_list *it;
|
struct environment_entry *env;
|
||||||
|
|
||||||
if (!retv)
|
if (!retv)
|
||||||
inlen = 0;
|
inlen = 0;
|
||||||
else
|
else
|
||||||
memset(retv, 0, inlen);
|
memset(retv, 0, inlen);
|
||||||
|
|
||||||
lxc_list_for_each(it, &c->environment) {
|
list_for_each_entry(env, &c->environment, head) {
|
||||||
strprint(retv, inlen, "%s\n", (char *)it->elem);
|
strprint(retv, inlen, "%s=%s\n", env->key, env->val);
|
||||||
}
|
}
|
||||||
|
|
||||||
return fulllen;
|
return fulllen;
|
||||||
@ -4561,7 +4558,7 @@ static int get_config_prlimit(const char *key, char *retv, int inlen,
|
|||||||
{
|
{
|
||||||
int fulllen = 0, len;
|
int fulllen = 0, len;
|
||||||
bool get_all = false;
|
bool get_all = false;
|
||||||
struct lxc_list *it;
|
struct lxc_limit *lim;
|
||||||
|
|
||||||
if (!retv)
|
if (!retv)
|
||||||
inlen = 0;
|
inlen = 0;
|
||||||
@ -4575,11 +4572,10 @@ static int get_config_prlimit(const char *key, char *retv, int inlen,
|
|||||||
else
|
else
|
||||||
return ret_errno(EINVAL);
|
return ret_errno(EINVAL);
|
||||||
|
|
||||||
lxc_list_for_each(it, &c->limits) {
|
list_for_each_entry(lim, &c->limits, head) {
|
||||||
/* 2 colon separated 64 bit integers or the word 'unlimited' */
|
/* 2 colon separated 64 bit integers or the word 'unlimited' */
|
||||||
char buf[INTTYPE_TO_STRLEN(uint64_t) * 2 + 2];
|
char buf[INTTYPE_TO_STRLEN(uint64_t) * 2 + 2];
|
||||||
int partlen;
|
int partlen;
|
||||||
struct lxc_limit *lim = it->elem;
|
|
||||||
|
|
||||||
if (lim->limit.rlim_cur == RLIM_INFINITY) {
|
if (lim->limit.rlim_cur == RLIM_INFINITY) {
|
||||||
memcpy(buf, "unlimited", STRLITERALLEN("unlimited") + 1);
|
memcpy(buf, "unlimited", STRLITERALLEN("unlimited") + 1);
|
||||||
@ -4616,10 +4612,10 @@ static int get_config_prlimit(const char *key, char *retv, int inlen,
|
|||||||
static int get_config_sysctl(const char *key, char *retv, int inlen,
|
static int get_config_sysctl(const char *key, char *retv, int inlen,
|
||||||
struct lxc_conf *c, void *data)
|
struct lxc_conf *c, void *data)
|
||||||
{
|
{
|
||||||
int len;
|
|
||||||
struct lxc_list *it;
|
|
||||||
int fulllen = 0;
|
int fulllen = 0;
|
||||||
bool get_all = false;
|
bool get_all = false;
|
||||||
|
int len;
|
||||||
|
struct lxc_sysctl *sysctl;
|
||||||
|
|
||||||
if (!retv)
|
if (!retv)
|
||||||
inlen = 0;
|
inlen = 0;
|
||||||
@ -4633,13 +4629,12 @@ static int get_config_sysctl(const char *key, char *retv, int inlen,
|
|||||||
else
|
else
|
||||||
return ret_errno(EINVAL);
|
return ret_errno(EINVAL);
|
||||||
|
|
||||||
lxc_list_for_each(it, &c->sysctls) {
|
list_for_each_entry(sysctl, &c->sysctls, head) {
|
||||||
struct lxc_sysctl *elem = it->elem;
|
|
||||||
if (get_all) {
|
if (get_all) {
|
||||||
strprint(retv, inlen, "lxc.sysctl.%s = %s\n", elem->key,
|
strprint(retv, inlen, "lxc.sysctl.%s = %s\n", sysctl->key,
|
||||||
elem->value);
|
sysctl->value);
|
||||||
} else if (strequal(elem->key, key)) {
|
} else if (strequal(sysctl->key, key)) {
|
||||||
strprint(retv, inlen, "%s", elem->value);
|
strprint(retv, inlen, "%s", sysctl->value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4649,10 +4644,10 @@ static int get_config_sysctl(const char *key, char *retv, int inlen,
|
|||||||
static int get_config_proc(const char *key, char *retv, int inlen,
|
static int get_config_proc(const char *key, char *retv, int inlen,
|
||||||
struct lxc_conf *c, void *data)
|
struct lxc_conf *c, void *data)
|
||||||
{
|
{
|
||||||
struct lxc_list *it;
|
|
||||||
int len;
|
|
||||||
int fulllen = 0;
|
int fulllen = 0;
|
||||||
bool get_all = false;
|
bool get_all = false;
|
||||||
|
int len;
|
||||||
|
struct lxc_proc *proc;
|
||||||
|
|
||||||
if (!retv)
|
if (!retv)
|
||||||
inlen = 0;
|
inlen = 0;
|
||||||
@ -4666,9 +4661,7 @@ static int get_config_proc(const char *key, char *retv, int inlen,
|
|||||||
else
|
else
|
||||||
return ret_errno(EINVAL);
|
return ret_errno(EINVAL);
|
||||||
|
|
||||||
lxc_list_for_each(it, &c->procs) {
|
list_for_each_entry(proc, &c->procs, head) {
|
||||||
struct lxc_proc *proc = it->elem;
|
|
||||||
|
|
||||||
if (get_all) {
|
if (get_all) {
|
||||||
strprint(retv, inlen, "lxc.proc.%s = %s\n",
|
strprint(retv, inlen, "lxc.proc.%s = %s\n",
|
||||||
proc->filename, proc->value);
|
proc->filename, proc->value);
|
||||||
@ -5014,7 +5007,6 @@ static inline int clr_config_rootfs_mount(const char *key, struct lxc_conf *c,
|
|||||||
static inline int clr_config_rootfs_options(const char *key, struct lxc_conf *c,
|
static inline int clr_config_rootfs_options(const char *key, struct lxc_conf *c,
|
||||||
void *data)
|
void *data)
|
||||||
{
|
{
|
||||||
free_disarm(c->rootfs.options);
|
|
||||||
put_lxc_mount_options(&c->rootfs.mnt_opts);
|
put_lxc_mount_options(&c->rootfs.mnt_opts);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -5058,7 +5050,7 @@ static inline int clr_config_cap_drop(const char *key, struct lxc_conf *c,
|
|||||||
static inline int clr_config_cap_keep(const char *key, struct lxc_conf *c,
|
static inline int clr_config_cap_keep(const char *key, struct lxc_conf *c,
|
||||||
void *data)
|
void *data)
|
||||||
{
|
{
|
||||||
return lxc_clear_config_keepcaps(c);
|
return lxc_clear_config_caps(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int clr_config_console_path(const char *key, struct lxc_conf *c,
|
static inline int clr_config_console_path(const char *key, struct lxc_conf *c,
|
||||||
@ -5296,7 +5288,6 @@ static inline int clr_config_proc(const char *key, struct lxc_conf *c,
|
|||||||
static inline int clr_config_includefiles(const char *key, struct lxc_conf *c,
|
static inline int clr_config_includefiles(const char *key, struct lxc_conf *c,
|
||||||
void *data)
|
void *data)
|
||||||
{
|
{
|
||||||
lxc_clear_includes(c);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -668,7 +668,7 @@ static void must_append_sized(char **buf, size_t *bufsz, const char *data, size_
|
|||||||
|
|
||||||
static bool is_privileged(struct lxc_conf *conf)
|
static bool is_privileged(struct lxc_conf *conf)
|
||||||
{
|
{
|
||||||
return lxc_list_empty(&conf->id_map);
|
return list_empty(&conf->id_map);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char* AA_ALL_DEST_PATH_LIST[] = {
|
static const char* AA_ALL_DEST_PATH_LIST[] = {
|
||||||
|
@ -1219,7 +1219,7 @@ static int do_create_container_dir(const char *path, struct lxc_conf *conf)
|
|||||||
ret = 0;
|
ret = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!lxc_list_empty(&conf->id_map)) {
|
if (!list_empty(&conf->id_map)) {
|
||||||
ret = chown_mapped_root(path, conf);
|
ret = chown_mapped_root(path, conf);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
ret = -1;
|
ret = -1;
|
||||||
@ -1290,7 +1290,7 @@ static struct lxc_storage *do_storage_create(struct lxc_container *c,
|
|||||||
/* If we are not root, chown the rootfs dir to root in the target user
|
/* If we are not root, chown the rootfs dir to root in the target user
|
||||||
* namespace.
|
* namespace.
|
||||||
*/
|
*/
|
||||||
if (am_guest_unpriv() || !lxc_list_empty(&c->lxc_conf->id_map)) {
|
if (am_guest_unpriv() || !list_empty(&c->lxc_conf->id_map)) {
|
||||||
ret = chown_mapped_root(bdev->dest, c->lxc_conf);
|
ret = chown_mapped_root(bdev->dest, c->lxc_conf);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
ERROR("Error chowning \"%s\" to container root", bdev->dest);
|
ERROR("Error chowning \"%s\" to container root", bdev->dest);
|
||||||
@ -1482,11 +1482,10 @@ static bool create_run_template(struct lxc_container *c, char *tpath,
|
|||||||
* ... <-m mapn> -- and we append "--mapped-uid x", where x is
|
* ... <-m mapn> -- and we append "--mapped-uid x", where x is
|
||||||
* the mapped uid for our geteuid()
|
* the mapped uid for our geteuid()
|
||||||
*/
|
*/
|
||||||
if (!lxc_list_empty(&conf->id_map)) {
|
if (!list_empty(&conf->id_map)) {
|
||||||
int extraargs, hostuid_mapped, hostgid_mapped;
|
int extraargs, hostuid_mapped, hostgid_mapped;
|
||||||
char **n2;
|
char **n2;
|
||||||
char txtuid[20], txtgid[20];
|
char txtuid[20], txtgid[20];
|
||||||
struct lxc_list *it;
|
|
||||||
struct id_map *map;
|
struct id_map *map;
|
||||||
int n2args = 1;
|
int n2args = 1;
|
||||||
|
|
||||||
@ -1498,8 +1497,7 @@ static bool create_run_template(struct lxc_container *c, char *tpath,
|
|||||||
tpath = "lxc-usernsexec";
|
tpath = "lxc-usernsexec";
|
||||||
n2[0] = "lxc-usernsexec";
|
n2[0] = "lxc-usernsexec";
|
||||||
|
|
||||||
lxc_list_for_each(it, &conf->id_map) {
|
list_for_each_entry(map, &conf->id_map, head) {
|
||||||
map = it->elem;
|
|
||||||
n2args += 2;
|
n2args += 2;
|
||||||
n2 = realloc(n2, n2args * sizeof(char *));
|
n2 = realloc(n2, n2args * sizeof(char *));
|
||||||
if (!n2)
|
if (!n2)
|
||||||
@ -2239,7 +2237,7 @@ static inline bool enter_net_ns(struct lxc_container *c)
|
|||||||
if (pid < 0)
|
if (pid < 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if ((geteuid() != 0 || (c->lxc_conf && !lxc_list_empty(&c->lxc_conf->id_map))) &&
|
if ((geteuid() != 0 || (c->lxc_conf && !list_empty(&c->lxc_conf->id_map))) &&
|
||||||
(access("/proc/self/ns/user", F_OK) == 0))
|
(access("/proc/self/ns/user", F_OK) == 0))
|
||||||
if (!switch_to_ns(pid, "user"))
|
if (!switch_to_ns(pid, "user"))
|
||||||
return false;
|
return false;
|
||||||
@ -5077,7 +5075,7 @@ static int do_lxcapi_mount(struct lxc_container *c, const char *source,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Enter the container namespaces */
|
/* Enter the container namespaces */
|
||||||
if (!lxc_list_empty(&c->lxc_conf->id_map)) {
|
if (!list_empty(&c->lxc_conf->id_map)) {
|
||||||
if (!switch_to_ns(init_pid, "user")) {
|
if (!switch_to_ns(init_pid, "user")) {
|
||||||
ERROR("Failed to enter user namespace");
|
ERROR("Failed to enter user namespace");
|
||||||
_exit(EXIT_FAILURE);
|
_exit(EXIT_FAILURE);
|
||||||
@ -5170,7 +5168,7 @@ static int do_lxcapi_umount(struct lxc_container *c, const char *target,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Enter the container namespaces */
|
/* Enter the container namespaces */
|
||||||
if (!lxc_list_empty(&c->lxc_conf->id_map)) {
|
if (!list_empty(&c->lxc_conf->id_map)) {
|
||||||
if (!switch_to_ns(init_pid, "user")) {
|
if (!switch_to_ns(init_pid, "user")) {
|
||||||
ERROR("Failed to enter user namespace");
|
ERROR("Failed to enter user namespace");
|
||||||
_exit(EXIT_FAILURE);
|
_exit(EXIT_FAILURE);
|
||||||
|
@ -1052,12 +1052,11 @@ static int do_start(void *data)
|
|||||||
{
|
{
|
||||||
struct lxc_handler *handler = data;
|
struct lxc_handler *handler = data;
|
||||||
__lxc_unused __do_close int data_sock0 = handler->data_sock[0],
|
__lxc_unused __do_close int data_sock0 = handler->data_sock[0],
|
||||||
data_sock1 = handler->data_sock[1];
|
data_sock1 = handler->data_sock[1];
|
||||||
__do_close int devnull_fd = -EBADF, status_fd = -EBADF;
|
__do_close int devnull_fd = -EBADF, status_fd = -EBADF;
|
||||||
int ret;
|
int ret;
|
||||||
uid_t new_uid;
|
uid_t new_uid;
|
||||||
gid_t new_gid;
|
gid_t new_gid;
|
||||||
struct lxc_list *iterator;
|
|
||||||
uid_t nsuid = 0;
|
uid_t nsuid = 0;
|
||||||
gid_t nsgid = 0;
|
gid_t nsgid = 0;
|
||||||
|
|
||||||
@ -1110,7 +1109,7 @@ static int do_start(void *data)
|
|||||||
/* If we are in a new user namespace, become root there to have
|
/* If we are in a new user namespace, become root there to have
|
||||||
* privilege over our namespace.
|
* privilege over our namespace.
|
||||||
*/
|
*/
|
||||||
if (!lxc_list_empty(&handler->conf->id_map)) {
|
if (!list_empty(&handler->conf->id_map)) {
|
||||||
if (!handler->conf->root_nsuid_map)
|
if (!handler->conf->root_nsuid_map)
|
||||||
nsuid = handler->conf->init_uid;
|
nsuid = handler->conf->init_uid;
|
||||||
|
|
||||||
@ -1257,18 +1256,14 @@ static int do_start(void *data)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Add the requested environment variables to the current environment to
|
/*
|
||||||
* allow them to be used by the various hooks, such as the start hook
|
* Add the requested environment variables to the current environment
|
||||||
* below.
|
* to allow them to be used by the various hooks, such as the start
|
||||||
|
* hook below.
|
||||||
*/
|
*/
|
||||||
lxc_list_for_each(iterator, &handler->conf->environment) {
|
ret = lxc_set_environment(handler->conf);
|
||||||
ret = putenv((char *)iterator->elem);
|
if (ret < 0)
|
||||||
if (ret < 0) {
|
goto out_warn_father;
|
||||||
SYSERROR("Failed to set environment variable: %s",
|
|
||||||
(char *)iterator->elem);
|
|
||||||
goto out_warn_father;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!lxc_sync_wait_parent(handler, START_SYNC_POST_CONFIGURE))
|
if (!lxc_sync_wait_parent(handler, START_SYNC_POST_CONFIGURE))
|
||||||
goto out_warn_father;
|
goto out_warn_father;
|
||||||
@ -1361,14 +1356,9 @@ static int do_start(void *data)
|
|||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
SYSERROR("Failed to clear environment.");
|
SYSERROR("Failed to clear environment.");
|
||||||
|
|
||||||
lxc_list_for_each(iterator, &handler->conf->environment) {
|
ret = lxc_set_environment(handler->conf);
|
||||||
ret = putenv((char *)iterator->elem);
|
if (ret < 0)
|
||||||
if (ret < 0) {
|
goto out_warn_father;
|
||||||
SYSERROR("Failed to set environment variable: %s",
|
|
||||||
(char *)iterator->elem);
|
|
||||||
goto out_warn_father;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = putenv("container=lxc");
|
ret = putenv("container=lxc");
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
@ -1406,7 +1396,7 @@ static int do_start(void *data)
|
|||||||
* we switched to root in the new user namespace further above. Only
|
* we switched to root in the new user namespace further above. Only
|
||||||
* drop groups if we can, so ensure that we have necessary privilege.
|
* drop groups if we can, so ensure that we have necessary privilege.
|
||||||
*/
|
*/
|
||||||
if (lxc_list_empty(&handler->conf->id_map)) {
|
if (list_empty(&handler->conf->id_map)) {
|
||||||
#if HAVE_LIBCAP
|
#if HAVE_LIBCAP
|
||||||
if (lxc_proc_cap_is_set(CAP_SETGID, CAP_EFFECTIVE))
|
if (lxc_proc_cap_is_set(CAP_SETGID, CAP_EFFECTIVE))
|
||||||
#endif
|
#endif
|
||||||
@ -1473,7 +1463,7 @@ int resolve_clone_flags(struct lxc_handler *handler)
|
|||||||
if ((conf->ns_clone & ns_info[i].clone_flag))
|
if ((conf->ns_clone & ns_info[i].clone_flag))
|
||||||
handler->ns_clone_flags |= ns_info[i].clone_flag;
|
handler->ns_clone_flags |= ns_info[i].clone_flag;
|
||||||
} else {
|
} else {
|
||||||
if (i == LXC_NS_USER && lxc_list_empty(&handler->conf->id_map))
|
if (i == LXC_NS_USER && list_empty(&handler->conf->id_map))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (i == LXC_NS_NET && lxc_requests_empty_network(handler))
|
if (i == LXC_NS_NET && lxc_requests_empty_network(handler))
|
||||||
@ -1576,7 +1566,7 @@ static int lxc_spawn(struct lxc_handler *handler)
|
|||||||
int i, ret;
|
int i, ret;
|
||||||
char pidstr[20];
|
char pidstr[20];
|
||||||
bool wants_to_map_ids;
|
bool wants_to_map_ids;
|
||||||
struct lxc_list *id_map;
|
struct list_head *id_map;
|
||||||
const char *name = handler->name;
|
const char *name = handler->name;
|
||||||
const char *lxcpath = handler->lxcpath;
|
const char *lxcpath = handler->lxcpath;
|
||||||
bool share_ns = false;
|
bool share_ns = false;
|
||||||
@ -1584,7 +1574,7 @@ static int lxc_spawn(struct lxc_handler *handler)
|
|||||||
struct cgroup_ops *cgroup_ops = handler->cgroup_ops;
|
struct cgroup_ops *cgroup_ops = handler->cgroup_ops;
|
||||||
|
|
||||||
id_map = &conf->id_map;
|
id_map = &conf->id_map;
|
||||||
wants_to_map_ids = !lxc_list_empty(id_map);
|
wants_to_map_ids = !list_empty(id_map);
|
||||||
|
|
||||||
for (i = 0; i < LXC_NS_MAX; i++) {
|
for (i = 0; i < LXC_NS_MAX; i++) {
|
||||||
if (!conf->ns_share[i])
|
if (!conf->ns_share[i])
|
||||||
@ -1816,18 +1806,16 @@ static int lxc_spawn(struct lxc_handler *handler)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!lxc_list_empty(&conf->procs)) {
|
ret = setup_proc_filesystem(conf, handler->pid);
|
||||||
ret = setup_proc_filesystem(&conf->procs, handler->pid);
|
if (ret < 0) {
|
||||||
if (ret < 0)
|
ERROR("Failed to setup procfs limits");
|
||||||
goto out_delete_net;
|
goto out_delete_net;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!lxc_list_empty(&conf->limits)) {
|
ret = setup_resource_limits(conf, handler->pid);
|
||||||
ret = setup_resource_limits(&conf->limits, handler->pid);
|
if (ret < 0) {
|
||||||
if (ret < 0) {
|
ERROR("Failed to setup resource limits");
|
||||||
ERROR("Failed to setup resource limits");
|
goto out_delete_net;
|
||||||
goto out_delete_net;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Tell the child to continue its initialization. */
|
/* Tell the child to continue its initialization. */
|
||||||
@ -2014,14 +2002,14 @@ int __lxc_start(struct lxc_handler *handler, struct lxc_operations *ops,
|
|||||||
* it readonly.
|
* it readonly.
|
||||||
* If the container is unprivileged then skip rootfs pinning.
|
* If the container is unprivileged then skip rootfs pinning.
|
||||||
*/
|
*/
|
||||||
ret = lxc_rootfs_init(conf, !lxc_list_empty(&conf->id_map));
|
ret = lxc_rootfs_init(conf, !list_empty(&conf->id_map));
|
||||||
if (ret) {
|
if (ret) {
|
||||||
ERROR("Failed to handle rootfs pinning for container \"%s\"", handler->name);
|
ERROR("Failed to handle rootfs pinning for container \"%s\"", handler->name);
|
||||||
ret = -1;
|
ret = -1;
|
||||||
goto out_abort;
|
goto out_abort;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (geteuid() == 0 && !lxc_list_empty(&conf->id_map)) {
|
if (geteuid() == 0 && !list_empty(&conf->id_map)) {
|
||||||
/*
|
/*
|
||||||
* Most filesystems can't be mounted inside a userns so handle them here.
|
* Most filesystems can't be mounted inside a userns so handle them here.
|
||||||
*/
|
*/
|
||||||
|
@ -57,7 +57,7 @@ int ovl_clonepaths(struct lxc_storage *orig, struct lxc_storage *new, const char
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (am_guest_unpriv() || !lxc_list_empty(&conf->id_map)) {
|
if (am_guest_unpriv() || !list_empty(&conf->id_map)) {
|
||||||
ret = chown_mapped_root(new->dest, conf);
|
ret = chown_mapped_root(new->dest, conf);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
WARN("Failed to update ownership of %s", new->dest);
|
WARN("Failed to update ownership of %s", new->dest);
|
||||||
@ -88,7 +88,7 @@ int ovl_clonepaths(struct lxc_storage *orig, struct lxc_storage *new, const char
|
|||||||
if (ret < 0 && errno != EEXIST)
|
if (ret < 0 && errno != EEXIST)
|
||||||
return log_error_errno(-errno, errno, "Failed to create directory \"%s\"", work);
|
return log_error_errno(-errno, errno, "Failed to create directory \"%s\"", work);
|
||||||
|
|
||||||
if (am_guest_unpriv() || !lxc_list_empty(&conf->id_map)) {
|
if (am_guest_unpriv() || !list_empty(&conf->id_map)) {
|
||||||
__do_free char *lxc_overlay_delta_dir = NULL,
|
__do_free char *lxc_overlay_delta_dir = NULL,
|
||||||
*lxc_overlay_private_dir = NULL;
|
*lxc_overlay_private_dir = NULL;
|
||||||
|
|
||||||
@ -155,7 +155,7 @@ int ovl_clonepaths(struct lxc_storage *orig, struct lxc_storage *new, const char
|
|||||||
if (ret < 0 && errno != EEXIST)
|
if (ret < 0 && errno != EEXIST)
|
||||||
return log_error_errno(-errno, errno, "Failed to create directory \"%s\"", ndelta);
|
return log_error_errno(-errno, errno, "Failed to create directory \"%s\"", ndelta);
|
||||||
|
|
||||||
if (am_guest_unpriv() || !lxc_list_empty(&conf->id_map)) {
|
if (am_guest_unpriv() || !list_empty(&conf->id_map)) {
|
||||||
__do_free char *lxc_overlay_delta_dir = NULL,
|
__do_free char *lxc_overlay_delta_dir = NULL,
|
||||||
*lxc_overlay_private_dir = NULL;
|
*lxc_overlay_private_dir = NULL;
|
||||||
|
|
||||||
@ -276,7 +276,7 @@ int ovl_create(struct lxc_storage *bdev, const char *dest, const char *n,
|
|||||||
if (ret < 0 && errno != EEXIST)
|
if (ret < 0 && errno != EEXIST)
|
||||||
return log_error_errno(-errno, errno, "Failed to create directory \"%s\"", delta);
|
return log_error_errno(-errno, errno, "Failed to create directory \"%s\"", delta);
|
||||||
|
|
||||||
if (am_guest_unpriv() || !lxc_list_empty(&conf->id_map)) {
|
if (am_guest_unpriv() || !list_empty(&conf->id_map)) {
|
||||||
__do_free char *lxc_overlay_private_dir = NULL;
|
__do_free char *lxc_overlay_private_dir = NULL;
|
||||||
|
|
||||||
lxc_overlay_private_dir = must_make_path(tmp, LXC_OVERLAY_PRIVATE_DIR, NULL);
|
lxc_overlay_private_dir = must_make_path(tmp, LXC_OVERLAY_PRIVATE_DIR, NULL);
|
||||||
|
@ -606,7 +606,7 @@ struct lxc_storage *storage_init(struct lxc_conf *conf)
|
|||||||
const struct lxc_storage_type *q;
|
const struct lxc_storage_type *q;
|
||||||
const char *src = conf->rootfs.path;
|
const char *src = conf->rootfs.path;
|
||||||
const char *dst = conf->rootfs.mount;
|
const char *dst = conf->rootfs.mount;
|
||||||
const char *mntopts = conf->rootfs.options;
|
const char *mntopts = conf->rootfs.mnt_opts.raw_options;
|
||||||
|
|
||||||
BUILD_BUG_ON(LXC_STORAGE_INTERNAL_OVERLAY_RESTORE <= LXC_CLONE_MAXFLAGS);
|
BUILD_BUG_ON(LXC_STORAGE_INTERNAL_OVERLAY_RESTORE <= LXC_CLONE_MAXFLAGS);
|
||||||
|
|
||||||
|
@ -876,7 +876,7 @@ static int lxc_terminal_map_ids(struct lxc_conf *c, struct lxc_terminal *termina
|
|||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (lxc_list_empty(&c->id_map))
|
if (list_empty(&c->id_map))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (is_empty_string(terminal->name) && terminal->pty < 0)
|
if (is_empty_string(terminal->name) && terminal->pty < 0)
|
||||||
|
@ -30,7 +30,6 @@ struct lxc_terminal_info {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct lxc_terminal_state {
|
struct lxc_terminal_state {
|
||||||
struct lxc_list node;
|
|
||||||
int stdinfd;
|
int stdinfd;
|
||||||
int stdoutfd;
|
int stdoutfd;
|
||||||
int ptxfd;
|
int ptxfd;
|
||||||
|
Loading…
Reference in New Issue
Block a user