Unverified Commit 2ed90529 by Stéphane Graber Committed by GitHub

Merge pull request #3694 from brauner/2021-02-24/fixes_2

commands: rework and add LXC_CMD_GET_CGROUP_FD and LXC_CMD_GET_LIMIT_CGROUP_FD
parents 5dc90afd 7e85a2c4
...@@ -18,6 +18,7 @@ noinst_HEADERS = api_extensions.h \ ...@@ -18,6 +18,7 @@ noinst_HEADERS = api_extensions.h \
confile_utils.h \ confile_utils.h \
criu.h \ criu.h \
error.h \ error.h \
error_utils.h \
file_utils.h \ file_utils.h \
../include/netns_ifaddrs.h \ ../include/netns_ifaddrs.h \
initutils.h \ initutils.h \
...@@ -117,6 +118,7 @@ liblxc_la_SOURCES = af_unix.c af_unix.h \ ...@@ -117,6 +118,7 @@ liblxc_la_SOURCES = af_unix.c af_unix.h \
criu.c criu.h \ criu.c criu.h \
error.c error.h \ error.c error.h \
execute.c \ execute.c \
error_utils.h \
freezer.c \ freezer.c \
file_utils.c file_utils.h \ file_utils.c file_utils.h \
../include/netns_ifaddrs.c ../include/netns_ifaddrs.h \ ../include/netns_ifaddrs.c ../include/netns_ifaddrs.h \
......
...@@ -1641,7 +1641,7 @@ int lxc_attach(struct lxc_container *container, lxc_attach_exec_t exec_function, ...@@ -1641,7 +1641,7 @@ int lxc_attach(struct lxc_container *container, lxc_attach_exec_t exec_function,
ret = cgroup_attach(conf, name, lxcpath, pid); ret = cgroup_attach(conf, name, lxcpath, pid);
if (ret) { if (ret) {
call_cleaner(cgroup_exit) struct cgroup_ops *cgroup_ops = NULL; call_cleaner(cgroup_exit) struct cgroup_ops *cgroup_ops = NULL;
if (ret != -ENOCGROUP2 && ret != -ENOSYS) { if (!ERRNO_IS_NOT_SUPPORTED(ret)) {
SYSERROR("Failed to attach cgroup"); SYSERROR("Failed to attach cgroup");
goto on_error; goto on_error;
} }
......
...@@ -40,6 +40,7 @@ ...@@ -40,6 +40,7 @@
#include "commands_utils.h" #include "commands_utils.h"
#include "conf.h" #include "conf.h"
#include "config.h" #include "config.h"
#include "error_utils.h"
#include "log.h" #include "log.h"
#include "macro.h" #include "macro.h"
#include "mainloop.h" #include "mainloop.h"
...@@ -103,7 +104,7 @@ static bool string_in_list(char **list, const char *entry) ...@@ -103,7 +104,7 @@ static bool string_in_list(char **list, const char *entry)
/* Given a handler's cgroup data, return the struct hierarchy for the controller /* Given a handler's cgroup data, return the struct hierarchy for the controller
* @c, or NULL if there is none. * @c, or NULL if there is none.
*/ */
static struct hierarchy *get_hierarchy(struct cgroup_ops *ops, const char *controller) static struct hierarchy *get_hierarchy(const struct cgroup_ops *ops, const char *controller)
{ {
if (!ops->hierarchies) if (!ops->hierarchies)
return log_trace_errno(NULL, errno, "There are no useable cgroup controllers"); return log_trace_errno(NULL, errno, "There are no useable cgroup controllers");
...@@ -147,6 +148,38 @@ static struct hierarchy *get_hierarchy(struct cgroup_ops *ops, const char *contr ...@@ -147,6 +148,38 @@ static struct hierarchy *get_hierarchy(struct cgroup_ops *ops, const char *contr
return ret_set_errno(NULL, ENOENT); return ret_set_errno(NULL, ENOENT);
} }
int prepare_cgroup_fd(const struct cgroup_ops *ops, struct cgroup_fd *fd, bool limit)
{
int dfd;
const struct hierarchy *h;
h = get_hierarchy(ops, fd->controller);
if (!h)
return ret_errno(ENOENT);
/*
* The client requested that the controller must be in a specific
* cgroup version.
*/
if (fd->type != 0 && fd->type != h->fs_type)
return ret_errno(EINVAL);
if (limit)
dfd = h->dfd_con;
else
dfd = h->dfd_lim;
if (dfd < 0)
return ret_errno(EBADF);
fd->layout = ops->cgroup_layout;
fd->type = h->fs_type;
if (fd->type == UNIFIED_HIERARCHY)
fd->utilities = h->utilities;
fd->fd = dfd;
return 0;
}
/* Taken over modified from the kernel sources. */ /* Taken over modified from the kernel sources. */
#define NBITS 32 /* bits in uint32_t */ #define NBITS 32 /* bits in uint32_t */
#define DIV_ROUND_UP(n, d) (((n) + (d)-1) / (d)) #define DIV_ROUND_UP(n, d) (((n) + (d)-1) / (d))
...@@ -2057,7 +2090,7 @@ __cgfsng_ops static const char *cgfsng_get_cgroup(struct cgroup_ops *ops, ...@@ -2057,7 +2090,7 @@ __cgfsng_ops static const char *cgfsng_get_cgroup(struct cgroup_ops *ops,
return cgfsng_get_cgroup_do(ops, controller, false); return cgfsng_get_cgroup_do(ops, controller, false);
} }
__cgfsng_ops static const char *cgfsng_get_limiting_cgroup(struct cgroup_ops *ops, __cgfsng_ops static const char *cgfsng_get_limit_cgroup(struct cgroup_ops *ops,
const char *controller) const char *controller)
{ {
return cgfsng_get_cgroup_do(ops, controller, true); return cgfsng_get_cgroup_do(ops, controller, true);
...@@ -2369,7 +2402,7 @@ __cgfsng_ops static int cgfsng_get(struct cgroup_ops *ops, const char *filename, ...@@ -2369,7 +2402,7 @@ __cgfsng_ops static int cgfsng_get(struct cgroup_ops *ops, const char *filename,
if (p) if (p)
*p = '\0'; *p = '\0';
path = lxc_cmd_get_limiting_cgroup_path(name, lxcpath, controller); path = lxc_cmd_get_limit_cgroup_path(name, lxcpath, controller);
/* not running */ /* not running */
if (!path) if (!path)
return -1; return -1;
...@@ -2531,7 +2564,7 @@ __cgfsng_ops static int cgfsng_set(struct cgroup_ops *ops, ...@@ -2531,7 +2564,7 @@ __cgfsng_ops static int cgfsng_set(struct cgroup_ops *ops,
return 0; return 0;
} }
path = lxc_cmd_get_limiting_cgroup_path(name, lxcpath, controller); path = lxc_cmd_get_limit_cgroup_path(name, lxcpath, controller);
/* not running */ /* not running */
if (!path) if (!path)
return -1; return -1;
...@@ -3336,7 +3369,7 @@ struct cgroup_ops *cgroup_ops_init(struct lxc_conf *conf) ...@@ -3336,7 +3369,7 @@ struct cgroup_ops *cgroup_ops_init(struct lxc_conf *conf)
cgfsng_ops->chown = cgfsng_chown; cgfsng_ops->chown = cgfsng_chown;
cgfsng_ops->mount = cgfsng_mount; cgfsng_ops->mount = cgfsng_mount;
cgfsng_ops->devices_activate = cgfsng_devices_activate; cgfsng_ops->devices_activate = cgfsng_devices_activate;
cgfsng_ops->get_limiting_cgroup = cgfsng_get_limiting_cgroup; cgfsng_ops->get_limit_cgroup = cgfsng_get_limit_cgroup;
cgfsng_ops->criu_escape = cgfsng_criu_escape; cgfsng_ops->criu_escape = cgfsng_criu_escape;
cgfsng_ops->criu_num_hierarchies = cgfsng_criu_num_hierarchies; cgfsng_ops->criu_num_hierarchies = cgfsng_criu_num_hierarchies;
...@@ -3377,12 +3410,11 @@ static int __cgroup_attach_many(const struct lxc_conf *conf, const char *name, ...@@ -3377,12 +3410,11 @@ static int __cgroup_attach_many(const struct lxc_conf *conf, const char *name,
{ {
call_cleaner(put_cgroup_ctx) struct cgroup_ctx *ctx = &(struct cgroup_ctx){}; call_cleaner(put_cgroup_ctx) struct cgroup_ctx *ctx = &(struct cgroup_ctx){};
int ret; int ret;
char pidstr[INTTYPE_TO_STRLEN(pid_t)];
size_t idx; size_t idx;
ssize_t pidstr_len; ssize_t pidstr_len;
char pidstr[INTTYPE_TO_STRLEN(pid_t)];
ret = lxc_cmd_get_cgroup_ctx(name, lxcpath, NULL, true, ret = lxc_cmd_get_cgroup_ctx(name, lxcpath, sizeof(struct cgroup_ctx), ctx);
sizeof(struct cgroup_ctx), ctx);
if (ret < 0) if (ret < 0)
return ret_errno(ENOSYS); return ret_errno(ENOSYS);
...@@ -3406,7 +3438,7 @@ static int __cgroup_attach_many(const struct lxc_conf *conf, const char *name, ...@@ -3406,7 +3438,7 @@ static int __cgroup_attach_many(const struct lxc_conf *conf, const char *name,
if (idx == 0) if (idx == 0)
return syserrno_set(-ENOENT, "Failed to attach to cgroups"); return syserrno_set(-ENOENT, "Failed to attach to cgroups");
TRACE("Attached to %s cgroup layout", cgroup_layout_name(ctx->cgroup_layout)); TRACE("Attached to %s cgroup layout", cgroup_layout_name(ctx->layout));
return 0; return 0;
} }
...@@ -3420,7 +3452,7 @@ static int __cgroup_attach_unified(const struct lxc_conf *conf, const char *name ...@@ -3420,7 +3452,7 @@ static int __cgroup_attach_unified(const struct lxc_conf *conf, const char *name
dfd_unified = lxc_cmd_get_cgroup2_fd(name, lxcpath); dfd_unified = lxc_cmd_get_cgroup2_fd(name, lxcpath);
if (dfd_unified < 0) if (dfd_unified < 0)
return ret_errno(ENOCGROUP2); return ret_errno(ENOSYS);
return __unified_attach_fd(conf, dfd_unified, pid); return __unified_attach_fd(conf, dfd_unified, pid);
} }
...@@ -3432,65 +3464,117 @@ int cgroup_attach(const struct lxc_conf *conf, const char *name, ...@@ -3432,65 +3464,117 @@ int cgroup_attach(const struct lxc_conf *conf, const char *name,
ret = __cgroup_attach_many(conf, name, lxcpath, pid); ret = __cgroup_attach_many(conf, name, lxcpath, pid);
if (ret < 0) { if (ret < 0) {
if (ret != -ENOSYS) if (!ERRNO_IS_NOT_SUPPORTED(ret))
return ret; return ret;
ret = __cgroup_attach_unified(conf, name, lxcpath, pid); ret = __cgroup_attach_unified(conf, name, lxcpath, pid);
if (ret < 0 && ERRNO_IS_NOT_SUPPORTED(ret))
return ret_errno(ENOSYS);
} }
return ret; return ret;
} }
/* Connects to command socket therefore isn't callable from command handler. */ /* Connects to command socket therefore isn't callable from command handler. */
int cgroup_get(const char *name, const char *lxcpath, int cgroup_get(const char *name, const char *lxcpath, const char *key, char *buf, size_t len)
const char *filename, char *buf, size_t len)
{ {
__do_close int unified_fd = -EBADF; __do_close int dfd = -EBADF;
ssize_t ret; struct cgroup_fd fd = {
.fd = -EBADF,
};
size_t len_controller;
int ret;
if (is_empty_string(filename) || is_empty_string(name) || if (is_empty_string(name) || is_empty_string(lxcpath) ||
is_empty_string(lxcpath)) is_empty_string(key))
return ret_errno(EINVAL); return ret_errno(EINVAL);
if ((buf && !len) || (len && !buf)) if ((buf && !len) || (len && !buf))
return ret_errno(EINVAL); return ret_errno(EINVAL);
unified_fd = lxc_cmd_get_limiting_cgroup2_fd(name, lxcpath); len_controller = strcspn(key, ".");
if (unified_fd < 0) len_controller++; /* Don't forget the \0 byte. */
return ret_errno(ENOCGROUP2); if (len_controller >= MAX_CGROUP_ROOT_NAMELEN)
return ret_errno(EINVAL);
(void)strlcpy(fd.controller, key, len_controller);
ret = lxc_read_try_buf_at(unified_fd, filename, buf, len); ret = lxc_cmd_get_limit_cgroup_fd(name, lxcpath, sizeof(struct cgroup_fd), &fd);
if (ret < 0) if (ret < 0) {
SYSERROR("Failed to read cgroup value"); if (!ERRNO_IS_NOT_SUPPORTED(ret))
return ret;
dfd = lxc_cmd_get_limit_cgroup2_fd(name, lxcpath);
if (dfd < 0) {
if (!ERRNO_IS_NOT_SUPPORTED(ret))
return ret;
return ret_errno(ENOSYS);
}
fd.type = UNIFIED_HIERARCHY;
fd.fd = move_fd(dfd);
}
dfd = move_fd(fd.fd);
TRACE("Reading %s from %s cgroup hierarchy", key, cgroup_hierarchy_name(fd.type));
if (fd.type == UNIFIED_HIERARCHY && strequal(fd.controller, "devices"))
return ret_errno(EOPNOTSUPP);
else
ret = lxc_read_try_buf_at(dfd, key, buf, len);
return ret; return ret;
} }
/* Connects to command socket therefore isn't callable from command handler. */ /* Connects to command socket therefore isn't callable from command handler. */
int cgroup_set(const char *name, const char *lxcpath, int cgroup_set(const char *name, const char *lxcpath, const char *key, const char *value)
const char *filename, const char *value)
{ {
__do_close int unified_fd = -EBADF; __do_close int dfd = -EBADF;
ssize_t ret; struct cgroup_fd fd = {
.fd = -EBADF,
};
size_t len_controller;
int ret;
if (is_empty_string(filename) || is_empty_string(value) || if (is_empty_string(name) || is_empty_string(lxcpath) ||
is_empty_string(name) || is_empty_string(lxcpath)) is_empty_string(key) || is_empty_string(value))
return ret_errno(EINVAL); return ret_errno(EINVAL);
unified_fd = lxc_cmd_get_limiting_cgroup2_fd(name, lxcpath); len_controller = strcspn(key, ".");
if (unified_fd < 0) len_controller++; /* Don't forget the \0 byte. */
return ret_errno(ENOCGROUP2); if (len_controller >= MAX_CGROUP_ROOT_NAMELEN)
return ret_errno(EINVAL);
(void)strlcpy(fd.controller, key, len_controller);
ret = lxc_cmd_get_limit_cgroup_fd(name, lxcpath, sizeof(struct cgroup_fd), &fd);
if (ret < 0) {
if (!ERRNO_IS_NOT_SUPPORTED(ret))
return ret;
dfd = lxc_cmd_get_limit_cgroup2_fd(name, lxcpath);
if (dfd < 0) {
if (!ERRNO_IS_NOT_SUPPORTED(ret))
return ret;
if (strnequal(filename, "devices.", STRLITERALLEN("devices."))) { return ret_errno(ENOSYS);
}
fd.type = UNIFIED_HIERARCHY;
fd.fd = move_fd(dfd);
}
dfd = move_fd(fd.fd);
TRACE("Setting %s to %s in %s cgroup hierarchy", key, value, cgroup_hierarchy_name(fd.type));
if (fd.type == UNIFIED_HIERARCHY && strequal(fd.controller, "devices")) {
struct device_item device = {}; struct device_item device = {};
ret = device_cgroup_rule_parse(&device, filename, value); ret = device_cgroup_rule_parse(&device, key, value);
if (ret < 0) if (ret < 0)
return log_error_errno(-1, EINVAL, "Failed to parse device string %s=%s", filename, value); return log_error_errno(-1, EINVAL, "Failed to parse device string %s=%s",
key, value);
ret = lxc_cmd_add_bpf_device_cgroup(name, lxcpath, &device); ret = lxc_cmd_add_bpf_device_cgroup(name, lxcpath, &device);
} else { } else {
ret = lxc_writeat(unified_fd, filename, value, strlen(value)); ret = lxc_writeat(dfd, key, value, strlen(value));
} }
return ret; return ret;
...@@ -3553,7 +3637,7 @@ int cgroup_freeze(const char *name, const char *lxcpath, int timeout) ...@@ -3553,7 +3637,7 @@ int cgroup_freeze(const char *name, const char *lxcpath, int timeout)
if (is_empty_string(name) || is_empty_string(lxcpath)) if (is_empty_string(name) || is_empty_string(lxcpath))
return ret_errno(EINVAL); return ret_errno(EINVAL);
unified_fd = lxc_cmd_get_limiting_cgroup2_fd(name, lxcpath); unified_fd = lxc_cmd_get_limit_cgroup2_fd(name, lxcpath);
if (unified_fd < 0) if (unified_fd < 0)
return ret_errno(ENOCGROUP2); return ret_errno(ENOCGROUP2);
...@@ -3578,7 +3662,7 @@ int cgroup_unfreeze(const char *name, const char *lxcpath, int timeout) ...@@ -3578,7 +3662,7 @@ int cgroup_unfreeze(const char *name, const char *lxcpath, int timeout)
if (is_empty_string(name) || is_empty_string(lxcpath)) if (is_empty_string(name) || is_empty_string(lxcpath))
return ret_errno(EINVAL); return ret_errno(EINVAL);
unified_fd = lxc_cmd_get_limiting_cgroup2_fd(name, lxcpath); unified_fd = lxc_cmd_get_limit_cgroup2_fd(name, lxcpath);
if (unified_fd < 0) if (unified_fd < 0)
return ret_errno(ENOCGROUP2); return ret_errno(ENOCGROUP2);
......
...@@ -56,15 +56,40 @@ typedef enum { ...@@ -56,15 +56,40 @@ typedef enum {
UNIFIED_HIERARCHY = CGROUP2_SUPER_MAGIC, UNIFIED_HIERARCHY = CGROUP2_SUPER_MAGIC,
} cgroupfs_type_magic_t; } cgroupfs_type_magic_t;
static inline const char *cgroup_hierarchy_name(cgroupfs_type_magic_t type)
{
switch (type) {
case LEGACY_HIERARCHY:
return "legacy";
case UNIFIED_HIERARCHY:
return "unified";
}
return "unknown";
}
#define DEVICES_CONTROLLER (1U << 0) #define DEVICES_CONTROLLER (1U << 0)
#define FREEZER_CONTROLLER (1U << 1) #define FREEZER_CONTROLLER (1U << 1)
/*
* This is the maximum length of a cgroup controller in the kernel.
* This includes the \0 byte.
*/
#define MAX_CGROUP_ROOT_NAMELEN 64
/* That's plenty of hierarchies. */ /* That's plenty of hierarchies. */
#define CGROUP_CTX_MAX_FD 20 #define CGROUP_CTX_MAX_FD 20
// BUILD_BUG_ON(CGROUP_CTX_MAX_FD > KERNEL_SCM_MAX_FD);
struct cgroup_fd {
__s32 layout;
__u32 utilities;
__s32 type;
__s32 fd;
char controller[MAX_CGROUP_ROOT_NAMELEN];
} __attribute__((aligned(8)));
struct cgroup_ctx { struct cgroup_ctx {
__s32 cgroup_layout; __s32 layout;
__u32 utilities; __u32 utilities;
__u32 fd_len; __u32 fd_len;
__s32 fd[CGROUP_CTX_MAX_FD]; __s32 fd[CGROUP_CTX_MAX_FD];
...@@ -248,7 +273,7 @@ struct cgroup_ops { ...@@ -248,7 +273,7 @@ struct cgroup_ops {
bool (*monitor_delegate_controllers)(struct cgroup_ops *ops); bool (*monitor_delegate_controllers)(struct cgroup_ops *ops);
bool (*payload_delegate_controllers)(struct cgroup_ops *ops); bool (*payload_delegate_controllers)(struct cgroup_ops *ops);
void (*finalize)(struct cgroup_ops *ops); void (*finalize)(struct cgroup_ops *ops);
const char *(*get_limiting_cgroup)(struct cgroup_ops *ops, const char *controller); const char *(*get_limit_cgroup)(struct cgroup_ops *ops, const char *controller);
}; };
__hidden extern struct cgroup_ops *cgroup_init(struct lxc_conf *conf); __hidden extern struct cgroup_ops *cgroup_init(struct lxc_conf *conf);
...@@ -259,9 +284,9 @@ define_cleanup_function(struct cgroup_ops *, cgroup_exit); ...@@ -259,9 +284,9 @@ define_cleanup_function(struct cgroup_ops *, cgroup_exit);
__hidden extern int cgroup_attach(const struct lxc_conf *conf, const char *name, __hidden extern int cgroup_attach(const struct lxc_conf *conf, const char *name,
const char *lxcpath, pid_t pid); const char *lxcpath, pid_t pid);
__hidden extern int cgroup_get(const char *name, const char *lxcpath, __hidden extern int cgroup_get(const char *name, const char *lxcpath,
const char *filename, char *buf, size_t len); const char *key, char *buf, size_t len);
__hidden extern int cgroup_set(const char *name, const char *lxcpath, __hidden extern int cgroup_set(const char *name, const char *lxcpath,
const char *filename, const char *value); const char *key, const char *value);
__hidden extern int cgroup_freeze(const char *name, const char *lxcpath, int timeout); __hidden extern int cgroup_freeze(const char *name, const char *lxcpath, int timeout);
__hidden extern int cgroup_unfreeze(const char *name, const char *lxcpath, int timeout); __hidden extern int cgroup_unfreeze(const char *name, const char *lxcpath, int timeout);
__hidden extern int __cgroup_unfreeze(int unified_fd, int timeout); __hidden extern int __cgroup_unfreeze(int unified_fd, int timeout);
...@@ -311,11 +336,13 @@ static inline int prepare_cgroup_ctx(struct cgroup_ops *ops, ...@@ -311,11 +336,13 @@ static inline int prepare_cgroup_ctx(struct cgroup_ops *ops,
return ret_errno(ENOENT); return ret_errno(ENOENT);
ctx->fd_len = idx; ctx->fd_len = idx;
ctx->cgroup_layout = ops->cgroup_layout; ctx->layout = ops->cgroup_layout;
if (ops->unified && ops->unified->dfd_con > 0) if (ops->unified && ops->unified->dfd_con > 0)
ctx->utilities = ops->unified->utilities; ctx->utilities = ops->unified->utilities;
return 0; return 0;
} }
__hidden extern int prepare_cgroup_fd(const struct cgroup_ops *ops,
struct cgroup_fd *fd, bool limit);
#endif /* __LXC_CGROUP_H */ #endif /* __LXC_CGROUP_H */
...@@ -65,7 +65,7 @@ lxc_log_define(commands, lxc); ...@@ -65,7 +65,7 @@ lxc_log_define(commands, lxc);
static const char *lxc_cmd_str(lxc_cmd_t cmd) static const char *lxc_cmd_str(lxc_cmd_t cmd)
{ {
static const char *const cmdname[LXC_CMD_MAX] = { static const char *const cmdname[LXC_CMD_MAX] = {
[LXC_CMD_CONSOLE] = "console", [LXC_CMD_GET_TTY_FD] = "get_tty_fd",
[LXC_CMD_TERMINAL_WINCH] = "terminal_winch", [LXC_CMD_TERMINAL_WINCH] = "terminal_winch",
[LXC_CMD_STOP] = "stop", [LXC_CMD_STOP] = "stop",
[LXC_CMD_GET_STATE] = "get_state", [LXC_CMD_GET_STATE] = "get_state",
...@@ -84,11 +84,13 @@ static const char *lxc_cmd_str(lxc_cmd_t cmd) ...@@ -84,11 +84,13 @@ static const char *lxc_cmd_str(lxc_cmd_t cmd)
[LXC_CMD_UNFREEZE] = "unfreeze", [LXC_CMD_UNFREEZE] = "unfreeze",
[LXC_CMD_GET_CGROUP2_FD] = "get_cgroup2_fd", [LXC_CMD_GET_CGROUP2_FD] = "get_cgroup2_fd",
[LXC_CMD_GET_INIT_PIDFD] = "get_init_pidfd", [LXC_CMD_GET_INIT_PIDFD] = "get_init_pidfd",
[LXC_CMD_GET_LIMITING_CGROUP] = "get_limiting_cgroup", [LXC_CMD_GET_LIMIT_CGROUP] = "get_limit_cgroup",
[LXC_CMD_GET_LIMITING_CGROUP2_FD] = "get_limiting_cgroup2_fd", [LXC_CMD_GET_LIMIT_CGROUP2_FD] = "get_limit_cgroup2_fd",
[LXC_CMD_GET_DEVPTS_FD] = "get_devpts_fd", [LXC_CMD_GET_DEVPTS_FD] = "get_devpts_fd",
[LXC_CMD_GET_SECCOMP_NOTIFY_FD] = "get_seccomp_notify_fd", [LXC_CMD_GET_SECCOMP_NOTIFY_FD] = "get_seccomp_notify_fd",
[LXC_CMD_GET_CGROUP_CTX] = "get_cgroup_ctx", [LXC_CMD_GET_CGROUP_CTX] = "get_cgroup_ctx",
[LXC_CMD_GET_CGROUP_FD] = "get_cgroup_fd",
[LXC_CMD_GET_LIMIT_CGROUP_FD] = "get_limit_cgroup_fd",
}; };
if (cmd >= LXC_CMD_MAX) if (cmd >= LXC_CMD_MAX)
...@@ -110,6 +112,12 @@ static int __transfer_cgroup_ctx_fds(struct unix_fds *fds, struct cgroup_ctx *ct ...@@ -110,6 +112,12 @@ static int __transfer_cgroup_ctx_fds(struct unix_fds *fds, struct cgroup_ctx *ct
return 0; return 0;
} }
static int __transfer_cgroup_fd(struct unix_fds *fds, struct cgroup_fd *fd)
{
fd->fd = move_fd(fds->fd[0]);
return 0;
}
/* /*
* lxc_cmd_rsp_recv: Receive a response to a command * lxc_cmd_rsp_recv: Receive a response to a command
* *
...@@ -123,24 +131,32 @@ static int __transfer_cgroup_ctx_fds(struct unix_fds *fds, struct cgroup_ctx *ct ...@@ -123,24 +131,32 @@ static int __transfer_cgroup_ctx_fds(struct unix_fds *fds, struct cgroup_ctx *ct
* the response data is <= a void * worth of data, it will be * the response data is <= a void * worth of data, it will be
* stored directly in data and datalen will be 0. * stored directly in data and datalen will be 0.
* *
* As a special case, the response for LXC_CMD_CONSOLE is created * As a special case, the response for LXC_CMD_GET_TTY_FD is created here as
* here as it contains an fd for the ptx pty passed through the * it contains an fd for the ptx pty passed through the unix socket.
* unix socket.
*/ */
static int lxc_cmd_rsp_recv(int sock, struct lxc_cmd_rr *cmd) static int lxc_cmd_rsp_recv(int sock, struct lxc_cmd_rr *cmd)
{ {
__do_free void *__private_ptr = NULL;
struct lxc_cmd_tty_rsp_data *data_console = NULL;
call_cleaner(put_unix_fds) struct unix_fds *fds = &(struct unix_fds){}; call_cleaner(put_unix_fds) struct unix_fds *fds = &(struct unix_fds){};
struct lxc_cmd_rsp *rsp = &cmd->rsp; struct lxc_cmd_rsp *rsp = &cmd->rsp;
int cur_cmd = cmd->req.cmd; int cur_cmd = cmd->req.cmd, fret = 0;
const char *cur_cmdstr; const char *cur_cmdstr;
int fret = 0;
int ret; int ret;
/*
* Determine whether this command will receive file descriptors and how
* many at most.
*/
cur_cmdstr = lxc_cmd_str(cur_cmd); cur_cmdstr = lxc_cmd_str(cur_cmd);
switch (cur_cmd) { switch (cur_cmd) {
case LXC_CMD_GET_CGROUP_FD:
__fallthrough;
case LXC_CMD_GET_LIMIT_CGROUP_FD:
__fallthrough;
case LXC_CMD_GET_CGROUP2_FD: case LXC_CMD_GET_CGROUP2_FD:
__fallthrough; __fallthrough;
case LXC_CMD_GET_LIMITING_CGROUP2_FD: case LXC_CMD_GET_LIMIT_CGROUP2_FD:
__fallthrough; __fallthrough;
case LXC_CMD_GET_INIT_PIDFD: case LXC_CMD_GET_INIT_PIDFD:
__fallthrough; __fallthrough;
...@@ -148,7 +164,7 @@ static int lxc_cmd_rsp_recv(int sock, struct lxc_cmd_rr *cmd) ...@@ -148,7 +164,7 @@ static int lxc_cmd_rsp_recv(int sock, struct lxc_cmd_rr *cmd)
__fallthrough; __fallthrough;
case LXC_CMD_GET_DEVPTS_FD: case LXC_CMD_GET_DEVPTS_FD:
__fallthrough; __fallthrough;
case LXC_CMD_CONSOLE: case LXC_CMD_GET_TTY_FD:
fds->fd_count_max = 1; fds->fd_count_max = 1;
break; break;
case LXC_CMD_GET_CGROUP_CTX: case LXC_CMD_GET_CGROUP_CTX:
...@@ -158,83 +174,140 @@ static int lxc_cmd_rsp_recv(int sock, struct lxc_cmd_rr *cmd) ...@@ -158,83 +174,140 @@ static int lxc_cmd_rsp_recv(int sock, struct lxc_cmd_rr *cmd)
fds->fd_count_max = 0; fds->fd_count_max = 0;
break; break;
} }
/* Receive the first response including file descriptors if any. */
ret = lxc_abstract_unix_recv_fds(sock, fds, rsp, sizeof(*rsp)); ret = lxc_abstract_unix_recv_fds(sock, fds, rsp, sizeof(*rsp));
if (ret < 0) if (ret < 0)
return syserrno(ret, "Failed to receive response for command \"%s\"", cur_cmdstr); return syserrno(ret, "Failed to receive response for command \"%s\"", cur_cmdstr);
/*
* Verify that we actually received any file descriptors if the command
* expects to do so.
*/
if (fds->fd_count_max == 0) { if (fds->fd_count_max == 0) {
TRACE("Command \"%s\" received response with %u file descriptors", cur_cmdstr, fds->fd_count_ret); WARN("Command \"%s\" received response", cur_cmdstr);
} else if (fds->fd_count_ret == 0) { } else if (fds->fd_count_ret == 0) {
WARN("Command \"%s\" received response without expected file descriptors", cur_cmdstr); TRACE("Command \"%s\" received response without any of the expected %u file descriptors", cur_cmdstr, fds->fd_count_max);
fret = -EBADF; fret = -EBADF;
} else {
TRACE("Command \"%s\" received response with %u of %u expected file descriptors", cur_cmdstr, fds->fd_count_ret, fds->fd_count_max);
} }
if (cur_cmd == LXC_CMD_CONSOLE) { /*
struct lxc_cmd_console_rsp_data *rspdata; * Ensure that no excessive data is sent unless someone retrieves the
* console ringbuffer.
/* recv() returns 0 bytes when a tty cannot be allocated,
* rsp->ret is < 0 when the peer permission check failed
*/ */
if (ret == 0 || rsp->ret < 0) if ((rsp->datalen > LXC_CMD_DATA_MAX) &&
return 0; (cur_cmd != LXC_CMD_CONSOLE_LOG))
return syserrno_set(fret ?: -E2BIG, "Response data for command \"%s\" is too long: %d bytes > %d",
rspdata = malloc(sizeof(*rspdata)); cur_cmdstr, rsp->datalen, LXC_CMD_DATA_MAX);
if (!rspdata)
return syserrno_set(-ENOMEM, "Failed to receive response for command \"%s\"", cur_cmdstr);
rspdata->ptxfd = move_fd(fds->fd[0]);
rspdata->ttynum = PTR_TO_INT(rsp->data);
rsp->data = rspdata;
}
/*
* Prepare buffer for any command that expects to receive additional
* data. Note that some don't want any additional data.
*/
switch (cur_cmd) { switch (cur_cmd) {
case LXC_CMD_GET_CGROUP2_FD: case LXC_CMD_GET_CGROUP2_FD: /* no data */
__fallthrough; __fallthrough;
case LXC_CMD_GET_LIMITING_CGROUP2_FD: case LXC_CMD_GET_LIMIT_CGROUP2_FD: /* no data */
__fallthrough; __fallthrough;
case LXC_CMD_GET_INIT_PIDFD: case LXC_CMD_GET_INIT_PIDFD: /* no data */
__fallthrough; __fallthrough;
case LXC_CMD_GET_DEVPTS_FD: case LXC_CMD_GET_DEVPTS_FD: /* no data */
__fallthrough; __fallthrough;
case LXC_CMD_GET_SECCOMP_NOTIFY_FD: case LXC_CMD_GET_SECCOMP_NOTIFY_FD: /* no data */
if (!fret)
rsp->data = INT_TO_PTR(move_fd(fds->fd[0])); rsp->data = INT_TO_PTR(move_fd(fds->fd[0]));
return log_debug(fret ?: ret, "Finished processing \"%s\"", cur_cmdstr);
case LXC_CMD_GET_CGROUP_CTX: /* Return for any command that doesn't expect additional data. */
if ((rsp->datalen == 0) || (rsp->datalen > sizeof(struct cgroup_ctx))) return log_debug(fret ?: ret, "Finished processing \"%s\" with file descriptor %d", cur_cmdstr, PTR_TO_INT(rsp->data));
case LXC_CMD_GET_CGROUP_FD: /* data */
__fallthrough;
case LXC_CMD_GET_LIMIT_CGROUP_FD: /* data */
if (rsp->datalen > sizeof(struct cgroup_fd))
return syserrno_set(fret ?: -EINVAL, "Invalid response size from server for \"%s\"", cur_cmdstr); return syserrno_set(fret ?: -EINVAL, "Invalid response size from server for \"%s\"", cur_cmdstr);
/* Don't pointlessly allocate. */ /* Don't pointlessly allocate. */
rsp->data = (void *)cmd->req.data; rsp->data = (void *)cmd->req.data;
break; break;
default: case LXC_CMD_GET_CGROUP_CTX: /* data */
if (rsp->datalen > sizeof(struct cgroup_ctx))
return syserrno_set(fret ?: -EINVAL, "Invalid response size from server for \"%s\"", cur_cmdstr);
/* Don't pointlessly allocate. */
rsp->data = (void *)cmd->req.data;
break; break;
} case LXC_CMD_GET_TTY_FD: /* data */
/*
* recv() returns 0 bytes when a tty cannot be allocated,
* rsp->ret is < 0 when the peer permission check failed
*/
if (ret == 0 || rsp->ret < 0)
return 0;
if (rsp->datalen == 0) __private_ptr = malloc(sizeof(struct lxc_cmd_tty_rsp_data));
return log_debug(fret ?: ret, "Response data length for command \"%s\" is 0", cur_cmdstr); if (!__private_ptr)
return syserrno_set(fret ?: -ENOMEM, "Failed to receive response for command \"%s\"", cur_cmdstr);
data_console = (struct lxc_cmd_tty_rsp_data *)__private_ptr;
data_console->ptxfd = move_fd(fds->fd[0]);
data_console->ttynum = PTR_TO_INT(rsp->data);
if ((rsp->datalen > LXC_CMD_DATA_MAX) && rsp->datalen = 0;
(cur_cmd != LXC_CMD_CONSOLE_LOG)) rsp->data = data_console;
return syserrno_set(-E2BIG, "Response data for command \"%s\" is too long: %d bytes > %d", break;
cur_cmdstr, rsp->datalen, LXC_CMD_DATA_MAX); case LXC_CMD_CONSOLE_LOG: /* data */
__private_ptr = zalloc(rsp->datalen + 1);
rsp->data = __private_ptr;
break;
default: /* catch any additional command */
if (rsp->datalen > 0) {
__private_ptr = zalloc(rsp->datalen);
rsp->data = __private_ptr;
}
break;
}
if (rsp->datalen == 0) {
DEBUG("Command \"%s\" requested no additional data", cur_cmdstr);
/*
* Note that LXC_CMD_GET_TTY_FD historically allocates memory
* to return info to the caller. That's why we jump to no_data
* so we ensure that the allocated data is wiped if we return
* early here.
*/
goto no_data;
}
if (cur_cmd == LXC_CMD_CONSOLE_LOG) /*
rsp->data = zalloc(rsp->datalen + 1); * All commands ending up here expect data so rsp->data must be valid.
else if (cur_cmd != LXC_CMD_GET_CGROUP_CTX) * Either static or allocated memory.
rsp->data = malloc(rsp->datalen); */
if (!rsp->data) if (!rsp->data)
return syserrno_set(-ENOMEM, "Failed to allocate response buffer for command \"%s\"", cur_cmdstr); return syserrno_set(fret ?: -ENOMEM, "Failed to prepare response buffer for command \"%s\"", cur_cmdstr);
ret = lxc_recv_nointr(sock, rsp->data, rsp->datalen, 0); ret = lxc_recv_nointr(sock, rsp->data, rsp->datalen, 0);
if (ret != rsp->datalen) if (ret != rsp->datalen)
return syserrno(-errno, "Failed to receive response data for command \"%s\"", cur_cmdstr); return syserrno(-errno, "Failed to receive response data for command \"%s\": %d != %d", cur_cmdstr, ret, rsp->datalen);
if (cur_cmd == LXC_CMD_GET_CGROUP_CTX) { switch (cur_cmd) {
case LXC_CMD_GET_CGROUP_CTX:
if (!fret)
ret = __transfer_cgroup_ctx_fds(fds, rsp->data); ret = __transfer_cgroup_ctx_fds(fds, rsp->data);
if (ret < 0) /* Make sure any received fds are wiped by us. */
return syserrno(ret, "Failed to transfer file descriptors for \"%s\"", cur_cmdstr); break;
case LXC_CMD_GET_CGROUP_FD:
__fallthrough;
case LXC_CMD_GET_LIMIT_CGROUP_FD:
if (!fret)
ret = __transfer_cgroup_fd(fds, rsp->data);
/* Make sure any received fds are wiped by us. */
break;
} }
no_data:
if (!fret && ret >= 0)
move_ptr(__private_ptr);
return fret ?: ret; return fret ?: ret;
} }
...@@ -288,12 +361,18 @@ static inline int lxc_cmd_rsp_send_keep(int fd, struct lxc_cmd_rsp *rsp) ...@@ -288,12 +361,18 @@ static inline int lxc_cmd_rsp_send_keep(int fd, struct lxc_cmd_rsp *rsp)
static inline int rsp_one_fd(int fd, int fd_send, struct lxc_cmd_rsp *rsp) static inline int rsp_one_fd(int fd, int fd_send, struct lxc_cmd_rsp *rsp)
{ {
int ret; ssize_t ret;
ret = lxc_abstract_unix_send_fds(fd, &fd_send, 1, rsp, sizeof(*rsp)); ret = lxc_abstract_unix_send_fds(fd, &fd_send, 1, rsp, sizeof(*rsp));
if (ret < 0) if (ret < 0)
return ret; return ret;
if (rsp->data && rsp->datalen > 0) {
ret = lxc_send_nointr(fd, rsp->data, rsp->datalen, MSG_NOSIGNAL);
if (ret < 0 || ret != (ssize_t)rsp->datalen)
return syswarn(-errno, "Failed to send command response %zd", ret);
}
return LXC_CMD_REAP_CLIENT_FD; return LXC_CMD_REAP_CLIENT_FD;
} }
...@@ -369,13 +448,13 @@ static int lxc_cmd_send(const char *name, struct lxc_cmd_rr *cmd, ...@@ -369,13 +448,13 @@ static int lxc_cmd_send(const char *name, struct lxc_cmd_rr *cmd,
* *
* Returns the size of the response message on success, < 0 on failure * Returns the size of the response message on success, < 0 on failure
* *
* Note that there is a special case for LXC_CMD_CONSOLE. For this command * Note that there is a special case for LXC_CMD_GET_TTY_FD. For this command
* the fd cannot be closed because it is used as a placeholder to indicate * the fd cannot be closed because it is used as a placeholder to indicate that
* that a particular tty slot is in use. The fd is also used as a signal to * a particular tty slot is in use. The fd is also used as a signal to the
* the container that when the caller dies or closes the fd, the container * container that when the caller dies or closes the fd, the container will
* will notice the fd on its side of the socket in its mainloop select and * notice the fd on its side of the socket in its mainloop select and then free
* then free the slot with lxc_cmd_fd_cleanup(). The socket fd will be * the slot with lxc_cmd_fd_cleanup(). The socket fd will be returned in the
* returned in the cmd response structure. * cmd response structure.
*/ */
static int lxc_cmd(const char *name, struct lxc_cmd_rr *cmd, int *stopped, static int lxc_cmd(const char *name, struct lxc_cmd_rr *cmd, int *stopped,
const char *lxcpath, const char *hashed_sock_name) const char *lxcpath, const char *hashed_sock_name)
...@@ -384,7 +463,7 @@ static int lxc_cmd(const char *name, struct lxc_cmd_rr *cmd, int *stopped, ...@@ -384,7 +463,7 @@ static int lxc_cmd(const char *name, struct lxc_cmd_rr *cmd, int *stopped,
int ret = -1; int ret = -1;
bool stay_connected = false; bool stay_connected = false;
if (cmd->req.cmd == LXC_CMD_CONSOLE || if (cmd->req.cmd == LXC_CMD_GET_TTY_FD ||
cmd->req.cmd == LXC_CMD_ADD_STATE_CLIENT) cmd->req.cmd == LXC_CMD_ADD_STATE_CLIENT)
stay_connected = true; stay_connected = true;
...@@ -629,7 +708,6 @@ static int lxc_cmd_get_seccomp_notify_fd_callback(int fd, struct lxc_cmd_req *re ...@@ -629,7 +708,6 @@ static int lxc_cmd_get_seccomp_notify_fd_callback(int fd, struct lxc_cmd_req *re
} }
int lxc_cmd_get_cgroup_ctx(const char *name, const char *lxcpath, int lxc_cmd_get_cgroup_ctx(const char *name, const char *lxcpath,
const char *controller, bool batch,
size_t size_ret_ctx, struct cgroup_ctx *ret_ctx) size_t size_ret_ctx, struct cgroup_ctx *ret_ctx)
{ {
struct lxc_cmd_rr cmd = { struct lxc_cmd_rr cmd = {
...@@ -644,9 +722,6 @@ int lxc_cmd_get_cgroup_ctx(const char *name, const char *lxcpath, ...@@ -644,9 +722,6 @@ int lxc_cmd_get_cgroup_ctx(const char *name, const char *lxcpath,
}; };
int ret, stopped; int ret, stopped;
if (batch && !is_empty_string(controller))
return ret_errno(EINVAL);
ret = lxc_cmd(name, &cmd, &stopped, lxcpath, NULL); ret = lxc_cmd(name, &cmd, &stopped, lxcpath, NULL);
if (ret < 0) if (ret < 0)
return log_debug_errno(-1, errno, "Failed to process cgroup context command"); return log_debug_errno(-1, errno, "Failed to process cgroup context command");
...@@ -679,6 +754,7 @@ static int lxc_cmd_get_cgroup_ctx_callback(int fd, struct lxc_cmd_req *req, ...@@ -679,6 +754,7 @@ static int lxc_cmd_get_cgroup_ctx_callback(int fd, struct lxc_cmd_req *req,
return lxc_cmd_rsp_send_reap(fd, &rsp); return lxc_cmd_rsp_send_reap(fd, &rsp);
} }
rsp.ret = 0;
rsp.data = &ctx_server; rsp.data = &ctx_server;
rsp.datalen = min(sizeof(struct cgroup_ctx), (size_t)req->datalen); rsp.datalen = min(sizeof(struct cgroup_ctx), (size_t)req->datalen);
return rsp_many_fds(fd, ctx_server.fd_len, ctx_server.fd, &rsp); return rsp_many_fds(fd, ctx_server.fd_len, ctx_server.fd, &rsp);
...@@ -742,7 +818,7 @@ static char *lxc_cmd_get_cgroup_path_do(const char *name, const char *lxcpath, ...@@ -742,7 +818,7 @@ static char *lxc_cmd_get_cgroup_path_do(const char *name, const char *lxcpath,
return NULL; return NULL;
if (ret == 0) { if (ret == 0) {
if (command == LXC_CMD_GET_LIMITING_CGROUP) { if (command == LXC_CMD_GET_LIMIT_CGROUP) {
/* /*
* This may indicate that the container was started * This may indicate that the container was started
* under an ealier version before * under an ealier version before
...@@ -783,10 +859,10 @@ char *lxc_cmd_get_cgroup_path(const char *name, const char *lxcpath, ...@@ -783,10 +859,10 @@ char *lxc_cmd_get_cgroup_path(const char *name, const char *lxcpath,
} }
/* /*
* lxc_cmd_get_limiting_cgroup_path: Calculate a container's limiting cgroup * lxc_cmd_get_limit_cgroup_path: Calculate a container's limit cgroup
* path for a particular subsystem. This is the cgroup path relative to the * path for a particular subsystem. This is the cgroup path relative to the
* root of the cgroup filesystem. This may be the same as the path returned by * root of the cgroup filesystem. This may be the same as the path returned by
* lxc_cmd_get_cgroup_path if the container doesn't have a limiting path prefix * lxc_cmd_get_cgroup_path if the container doesn't have a limit path prefix
* set. * set.
* *
* @name : name of container to connect to * @name : name of container to connect to
...@@ -796,11 +872,11 @@ char *lxc_cmd_get_cgroup_path(const char *name, const char *lxcpath, ...@@ -796,11 +872,11 @@ char *lxc_cmd_get_cgroup_path(const char *name, const char *lxcpath,
* Returns the path on success, NULL on failure. The caller must free() the * Returns the path on success, NULL on failure. The caller must free() the
* returned path. * returned path.
*/ */
char *lxc_cmd_get_limiting_cgroup_path(const char *name, const char *lxcpath, char *lxc_cmd_get_limit_cgroup_path(const char *name, const char *lxcpath,
const char *subsystem) const char *subsystem)
{ {
return lxc_cmd_get_cgroup_path_do(name, lxcpath, subsystem, return lxc_cmd_get_cgroup_path_do(name, lxcpath, subsystem,
LXC_CMD_GET_LIMITING_CGROUP); LXC_CMD_GET_LIMIT_CGROUP);
} }
static int lxc_cmd_get_cgroup_callback_do(int fd, struct lxc_cmd_req *req, static int lxc_cmd_get_cgroup_callback_do(int fd, struct lxc_cmd_req *req,
...@@ -824,7 +900,7 @@ static int lxc_cmd_get_cgroup_callback_do(int fd, struct lxc_cmd_req *req, ...@@ -824,7 +900,7 @@ static int lxc_cmd_get_cgroup_callback_do(int fd, struct lxc_cmd_req *req,
reqdata = NULL; reqdata = NULL;
} }
get_fn = (limiting_cgroup ? cgroup_ops->get_limiting_cgroup get_fn = (limiting_cgroup ? cgroup_ops->get_limit_cgroup
: cgroup_ops->get_cgroup); : cgroup_ops->get_cgroup);
path = get_fn(cgroup_ops, reqdata); path = get_fn(cgroup_ops, reqdata);
...@@ -846,7 +922,7 @@ static int lxc_cmd_get_cgroup_callback(int fd, struct lxc_cmd_req *req, ...@@ -846,7 +922,7 @@ static int lxc_cmd_get_cgroup_callback(int fd, struct lxc_cmd_req *req,
return lxc_cmd_get_cgroup_callback_do(fd, req, handler, descr, false); return lxc_cmd_get_cgroup_callback_do(fd, req, handler, descr, false);
} }
static int lxc_cmd_get_limiting_cgroup_callback(int fd, struct lxc_cmd_req *req, static int lxc_cmd_get_limit_cgroup_callback(int fd, struct lxc_cmd_req *req,
struct lxc_handler *handler, struct lxc_handler *handler,
struct lxc_epoll_descr *descr) struct lxc_epoll_descr *descr)
{ {
...@@ -1056,7 +1132,7 @@ static int lxc_cmd_terminal_winch_callback(int fd, struct lxc_cmd_req *req, ...@@ -1056,7 +1132,7 @@ static int lxc_cmd_terminal_winch_callback(int fd, struct lxc_cmd_req *req,
} }
/* /*
* lxc_cmd_console: Open an fd to a tty in the container * lxc_cmd_get_tty_fd: Open an fd to a tty in the container
* *
* @name : name of container to connect to * @name : name of container to connect to
* @ttynum : in: the tty to open or -1 for next available * @ttynum : in: the tty to open or -1 for next available
...@@ -1066,13 +1142,13 @@ static int lxc_cmd_terminal_winch_callback(int fd, struct lxc_cmd_req *req, ...@@ -1066,13 +1142,13 @@ static int lxc_cmd_terminal_winch_callback(int fd, struct lxc_cmd_req *req,
* *
* Returns fd holding tty allocated on success, < 0 on failure * Returns fd holding tty allocated on success, < 0 on failure
*/ */
int lxc_cmd_console(const char *name, int *ttynum, int *fd, const char *lxcpath) int lxc_cmd_get_tty_fd(const char *name, int *ttynum, int *fd, const char *lxcpath)
{ {
__do_free struct lxc_cmd_console_rsp_data *rspdata = NULL; __do_free struct lxc_cmd_tty_rsp_data *rspdata = NULL;
int ret, stopped; int ret, stopped;
struct lxc_cmd_rr cmd = { struct lxc_cmd_rr cmd = {
.req = { .req = {
.cmd = LXC_CMD_CONSOLE, .cmd = LXC_CMD_GET_TTY_FD,
.data = INT_TO_PTR(*ttynum), .data = INT_TO_PTR(*ttynum),
}, },
}; };
...@@ -1098,7 +1174,7 @@ int lxc_cmd_console(const char *name, int *ttynum, int *fd, const char *lxcpath) ...@@ -1098,7 +1174,7 @@ int lxc_cmd_console(const char *name, int *ttynum, int *fd, const char *lxcpath)
return log_info(ret, "Alloced fd %d for tty %d via socket %d", *fd, rspdata->ttynum, ret); return log_info(ret, "Alloced fd %d for tty %d via socket %d", *fd, rspdata->ttynum, ret);
} }
static int lxc_cmd_console_callback(int fd, struct lxc_cmd_req *req, static int lxc_cmd_get_tty_fd_callback(int fd, struct lxc_cmd_req *req,
struct lxc_handler *handler, struct lxc_handler *handler,
struct lxc_epoll_descr *descr) struct lxc_epoll_descr *descr)
{ {
...@@ -1569,6 +1645,102 @@ static int lxc_cmd_unfreeze_callback(int fd, struct lxc_cmd_req *req, ...@@ -1569,6 +1645,102 @@ static int lxc_cmd_unfreeze_callback(int fd, struct lxc_cmd_req *req,
return lxc_cmd_rsp_send_reap(fd, &rsp); return lxc_cmd_rsp_send_reap(fd, &rsp);
} }
int lxc_cmd_get_cgroup_fd(const char *name, const char *lxcpath,
size_t size_ret_fd, struct cgroup_fd *ret_fd)
{
int ret, stopped;
struct lxc_cmd_rr cmd = {
.req = {
.cmd = LXC_CMD_GET_CGROUP_FD,
.datalen = sizeof(struct cgroup_fd),
.data = ret_fd,
},
.rsp = {
ret = -ENOSYS,
},
};
ret = lxc_cmd(name, &cmd, &stopped, lxcpath, NULL);
if (ret < 0)
return log_debug_errno(-1, errno, "Failed to process cgroup fd command");
if (cmd.rsp.ret < 0)
return log_debug_errno(-EBADF, errno, "Failed to receive cgroup fd");
return 0;
}
int lxc_cmd_get_limit_cgroup_fd(const char *name, const char *lxcpath,
size_t size_ret_fd, struct cgroup_fd *ret_fd)
{
int ret, stopped;
struct lxc_cmd_rr cmd = {
.req = {
.cmd = LXC_CMD_GET_LIMIT_CGROUP_FD,
.datalen = sizeof(struct cgroup_fd),
.data = ret_fd,
},
.rsp = {
ret = -ENOSYS,
},
};
ret = lxc_cmd(name, &cmd, &stopped, lxcpath, NULL);
if (ret < 0)
return log_debug_errno(-1, errno, "Failed to process limit cgroup fd command");
if (cmd.rsp.ret < 0)
return log_debug_errno(-EBADF, errno, "Failed to receive limit cgroup fd");
return 0;
}
static int __lxc_cmd_get_cgroup_fd_callback(int fd, struct lxc_cmd_req *req,
struct lxc_handler *handler,
struct lxc_epoll_descr *descr,
bool limit)
{
struct lxc_cmd_rsp rsp = {
.ret = -EINVAL,
};
struct cgroup_ops *ops = handler->cgroup_ops;
struct cgroup_fd fd_server = {};
int ret;
ret = copy_struct_from_client(sizeof(struct cgroup_fd), &fd_server,
req->datalen, req->data);
if (ret < 0)
return lxc_cmd_rsp_send_reap(fd, &rsp);
if (strnlen(fd_server.controller, MAX_CGROUP_ROOT_NAMELEN) == 0)
return lxc_cmd_rsp_send_reap(fd, &rsp);
ret = prepare_cgroup_fd(ops, &fd_server, limit);
if (ret < 0) {
rsp.ret = ret;
return lxc_cmd_rsp_send_reap(fd, &rsp);
}
rsp.ret = 0;
rsp.data = &fd_server;
rsp.datalen = min(sizeof(struct cgroup_fd), (size_t)req->datalen);
return rsp_one_fd(fd, fd_server.fd, &rsp);
}
static int lxc_cmd_get_cgroup_fd_callback(int fd, struct lxc_cmd_req *req,
struct lxc_handler *handler,
struct lxc_epoll_descr *descr)
{
return __lxc_cmd_get_cgroup_fd_callback(fd, req, handler, descr, false);
}
static int lxc_cmd_get_limit_cgroup_fd_callback(int fd, struct lxc_cmd_req *req,
struct lxc_handler *handler,
struct lxc_epoll_descr *descr)
{
return __lxc_cmd_get_cgroup_fd_callback(fd, req, handler, descr, true);
}
int lxc_cmd_get_cgroup2_fd(const char *name, const char *lxcpath) int lxc_cmd_get_cgroup2_fd(const char *name, const char *lxcpath)
{ {
int ret, stopped; int ret, stopped;
...@@ -1591,12 +1763,12 @@ int lxc_cmd_get_cgroup2_fd(const char *name, const char *lxcpath) ...@@ -1591,12 +1763,12 @@ int lxc_cmd_get_cgroup2_fd(const char *name, const char *lxcpath)
return PTR_TO_INT(cmd.rsp.data); return PTR_TO_INT(cmd.rsp.data);
} }
int lxc_cmd_get_limiting_cgroup2_fd(const char *name, const char *lxcpath) int lxc_cmd_get_limit_cgroup2_fd(const char *name, const char *lxcpath)
{ {
int ret, stopped; int ret, stopped;
struct lxc_cmd_rr cmd = { struct lxc_cmd_rr cmd = {
.req = { .req = {
.cmd = LXC_CMD_GET_LIMITING_CGROUP2_FD, .cmd = LXC_CMD_GET_LIMIT_CGROUP2_FD,
}, },
.rsp = { .rsp = {
.ret = -ENOSYS, .ret = -ENOSYS,
...@@ -1647,8 +1819,7 @@ static int lxc_cmd_get_cgroup2_fd_callback(int fd, struct lxc_cmd_req *req, ...@@ -1647,8 +1819,7 @@ static int lxc_cmd_get_cgroup2_fd_callback(int fd, struct lxc_cmd_req *req,
false); false);
} }
static int lxc_cmd_get_limiting_cgroup2_fd_callback(int fd, static int lxc_cmd_get_limit_cgroup2_fd_callback(int fd, struct lxc_cmd_req *req,
struct lxc_cmd_req *req,
struct lxc_handler *handler, struct lxc_handler *handler,
struct lxc_epoll_descr *descr) struct lxc_epoll_descr *descr)
{ {
...@@ -1674,7 +1845,7 @@ static int lxc_cmd_process(int fd, struct lxc_cmd_req *req, ...@@ -1674,7 +1845,7 @@ static int lxc_cmd_process(int fd, struct lxc_cmd_req *req,
struct lxc_epoll_descr *); struct lxc_epoll_descr *);
callback cb[LXC_CMD_MAX] = { callback cb[LXC_CMD_MAX] = {
[LXC_CMD_CONSOLE] = lxc_cmd_console_callback, [LXC_CMD_GET_TTY_FD] = lxc_cmd_get_tty_fd_callback,
[LXC_CMD_TERMINAL_WINCH] = lxc_cmd_terminal_winch_callback, [LXC_CMD_TERMINAL_WINCH] = lxc_cmd_terminal_winch_callback,
[LXC_CMD_STOP] = lxc_cmd_stop_callback, [LXC_CMD_STOP] = lxc_cmd_stop_callback,
[LXC_CMD_GET_STATE] = lxc_cmd_get_state_callback, [LXC_CMD_GET_STATE] = lxc_cmd_get_state_callback,
...@@ -1693,11 +1864,13 @@ static int lxc_cmd_process(int fd, struct lxc_cmd_req *req, ...@@ -1693,11 +1864,13 @@ static int lxc_cmd_process(int fd, struct lxc_cmd_req *req,
[LXC_CMD_UNFREEZE] = lxc_cmd_unfreeze_callback, [LXC_CMD_UNFREEZE] = lxc_cmd_unfreeze_callback,
[LXC_CMD_GET_CGROUP2_FD] = lxc_cmd_get_cgroup2_fd_callback, [LXC_CMD_GET_CGROUP2_FD] = lxc_cmd_get_cgroup2_fd_callback,
[LXC_CMD_GET_INIT_PIDFD] = lxc_cmd_get_init_pidfd_callback, [LXC_CMD_GET_INIT_PIDFD] = lxc_cmd_get_init_pidfd_callback,
[LXC_CMD_GET_LIMITING_CGROUP] = lxc_cmd_get_limiting_cgroup_callback, [LXC_CMD_GET_LIMIT_CGROUP] = lxc_cmd_get_limit_cgroup_callback,
[LXC_CMD_GET_LIMITING_CGROUP2_FD] = lxc_cmd_get_limiting_cgroup2_fd_callback, [LXC_CMD_GET_LIMIT_CGROUP2_FD] = lxc_cmd_get_limit_cgroup2_fd_callback,
[LXC_CMD_GET_DEVPTS_FD] = lxc_cmd_get_devpts_fd_callback, [LXC_CMD_GET_DEVPTS_FD] = lxc_cmd_get_devpts_fd_callback,
[LXC_CMD_GET_SECCOMP_NOTIFY_FD] = lxc_cmd_get_seccomp_notify_fd_callback, [LXC_CMD_GET_SECCOMP_NOTIFY_FD] = lxc_cmd_get_seccomp_notify_fd_callback,
[LXC_CMD_GET_CGROUP_CTX] = lxc_cmd_get_cgroup_ctx_callback, [LXC_CMD_GET_CGROUP_CTX] = lxc_cmd_get_cgroup_ctx_callback,
[LXC_CMD_GET_CGROUP_FD] = lxc_cmd_get_cgroup_fd_callback,
[LXC_CMD_GET_LIMIT_CGROUP_FD] = lxc_cmd_get_limit_cgroup_fd_callback,
}; };
if (req->cmd >= LXC_CMD_MAX) if (req->cmd >= LXC_CMD_MAX)
......
...@@ -21,7 +21,7 @@ ...@@ -21,7 +21,7 @@
#define LXC_CMD_REAP_CLIENT_FD 1 #define LXC_CMD_REAP_CLIENT_FD 1
typedef enum { typedef enum {
LXC_CMD_CONSOLE = 0, LXC_CMD_GET_TTY_FD = 0,
LXC_CMD_TERMINAL_WINCH = 1, LXC_CMD_TERMINAL_WINCH = 1,
LXC_CMD_STOP = 2, LXC_CMD_STOP = 2,
LXC_CMD_GET_STATE = 3, LXC_CMD_GET_STATE = 3,
...@@ -40,11 +40,13 @@ typedef enum { ...@@ -40,11 +40,13 @@ typedef enum {
LXC_CMD_UNFREEZE = 16, LXC_CMD_UNFREEZE = 16,
LXC_CMD_GET_CGROUP2_FD = 17, LXC_CMD_GET_CGROUP2_FD = 17,
LXC_CMD_GET_INIT_PIDFD = 18, LXC_CMD_GET_INIT_PIDFD = 18,
LXC_CMD_GET_LIMITING_CGROUP = 19, LXC_CMD_GET_LIMIT_CGROUP = 19,
LXC_CMD_GET_LIMITING_CGROUP2_FD = 20, LXC_CMD_GET_LIMIT_CGROUP2_FD = 20,
LXC_CMD_GET_DEVPTS_FD = 21, LXC_CMD_GET_DEVPTS_FD = 21,
LXC_CMD_GET_SECCOMP_NOTIFY_FD = 22, LXC_CMD_GET_SECCOMP_NOTIFY_FD = 22,
LXC_CMD_GET_CGROUP_CTX = 23, LXC_CMD_GET_CGROUP_CTX = 23,
LXC_CMD_GET_CGROUP_FD = 24,
LXC_CMD_GET_LIMIT_CGROUP_FD = 25,
LXC_CMD_MAX, LXC_CMD_MAX,
} lxc_cmd_t; } lxc_cmd_t;
...@@ -65,7 +67,7 @@ struct lxc_cmd_rr { ...@@ -65,7 +67,7 @@ struct lxc_cmd_rr {
struct lxc_cmd_rsp rsp; struct lxc_cmd_rsp rsp;
}; };
struct lxc_cmd_console_rsp_data { struct lxc_cmd_tty_rsp_data {
int ptxfd; int ptxfd;
int ttynum; int ttynum;
}; };
...@@ -79,7 +81,8 @@ struct lxc_cmd_console_log { ...@@ -79,7 +81,8 @@ struct lxc_cmd_console_log {
}; };
__hidden extern int lxc_cmd_terminal_winch(const char *name, const char *lxcpath); __hidden extern int lxc_cmd_terminal_winch(const char *name, const char *lxcpath);
__hidden extern int lxc_cmd_console(const char *name, int *ttynum, int *fd, const char *lxcpath); __hidden extern int lxc_cmd_get_tty_fd(const char *name, int *ttynum, int *fd,
const char *lxcpath);
/* /*
* Get the 'real' cgroup path (as seen in /proc/self/cgroup) for a container * Get the 'real' cgroup path (as seen in /proc/self/cgroup) for a container
* for a particular subsystem * for a particular subsystem
...@@ -125,7 +128,6 @@ __hidden extern int lxc_cmd_console_log(const char *name, const char *lxcpath, ...@@ -125,7 +128,6 @@ __hidden extern int lxc_cmd_console_log(const char *name, const char *lxcpath,
struct lxc_console_log *log); struct lxc_console_log *log);
__hidden extern int lxc_cmd_get_seccomp_notify_fd(const char *name, const char *lxcpath); __hidden extern int lxc_cmd_get_seccomp_notify_fd(const char *name, const char *lxcpath);
__hidden extern int lxc_cmd_get_cgroup_ctx(const char *name, const char *lxcpath, __hidden extern int lxc_cmd_get_cgroup_ctx(const char *name, const char *lxcpath,
const char *controller, bool batch,
size_t size_ret_ctx, size_t size_ret_ctx,
struct cgroup_ctx *ret_ctx); struct cgroup_ctx *ret_ctx);
__hidden extern int lxc_cmd_seccomp_notify_add_listener(const char *name, const char *lxcpath, int fd, __hidden extern int lxc_cmd_seccomp_notify_add_listener(const char *name, const char *lxcpath, int fd,
...@@ -138,9 +140,18 @@ __hidden extern int lxc_cmd_add_bpf_device_cgroup(const char *name, const char * ...@@ -138,9 +140,18 @@ __hidden extern int lxc_cmd_add_bpf_device_cgroup(const char *name, const char *
__hidden extern int lxc_cmd_freeze(const char *name, const char *lxcpath, int timeout); __hidden extern int lxc_cmd_freeze(const char *name, const char *lxcpath, int timeout);
__hidden extern int lxc_cmd_unfreeze(const char *name, const char *lxcpath, int timeout); __hidden extern int lxc_cmd_unfreeze(const char *name, const char *lxcpath, int timeout);
__hidden extern int lxc_cmd_get_cgroup2_fd(const char *name, const char *lxcpath); __hidden extern int lxc_cmd_get_cgroup2_fd(const char *name, const char *lxcpath);
__hidden extern char *lxc_cmd_get_limiting_cgroup_path(const char *name, const char *lxcpath, __hidden extern int lxc_cmd_get_cgroup_fd(const char *name, const char *lxcpath,
size_t size_ret_fd,
struct cgroup_fd *ret_fd);
__hidden extern char *lxc_cmd_get_limit_cgroup_path(const char *name,
const char *lxcpath,
const char *subsystem); const char *subsystem);
__hidden extern int lxc_cmd_get_limiting_cgroup2_fd(const char *name, const char *lxcpath); __hidden extern int lxc_cmd_get_limit_cgroup2_fd(const char *name,
const char *lxcpath);
__hidden extern int lxc_cmd_get_limit_cgroup_fd(const char *name,
const char *lxcpath,
size_t size_ret_fd,
struct cgroup_fd *ret_fd);
__hidden extern int lxc_cmd_get_devpts_fd(const char *name, const char *lxcpath); __hidden extern int lxc_cmd_get_devpts_fd(const char *name, const char *lxcpath);
#endif /* __commands_h */ #endif /* __commands_h */
...@@ -304,19 +304,19 @@ static int exec_criu(struct cgroup_ops *cgroup_ops, struct lxc_conf *conf, ...@@ -304,19 +304,19 @@ static int exec_criu(struct cgroup_ops *cgroup_ops, struct lxc_conf *conf,
* the handler the restore task created. * the handler the restore task created.
*/ */
if (strequal(opts->action, "dump") || strequal(opts->action, "pre-dump")) { if (strequal(opts->action, "dump") || strequal(opts->action, "pre-dump")) {
cgroup_base_path = lxc_cmd_get_limiting_cgroup_path(opts->c->name, opts->c->config_path, controllers_list[0]); cgroup_base_path = lxc_cmd_get_limit_cgroup_path(opts->c->name, opts->c->config_path, controllers_list[0]);
if (!cgroup_base_path) if (!cgroup_base_path)
return log_error_errno(-ENOENT, ENOENT, "Failed to retrieve limiting cgroup path for %s", controllers_list[0] ?: "(null)"); return log_error_errno(-ENOENT, ENOENT, "Failed to retrieve limit cgroup path for %s", controllers_list[0] ?: "(null)");
} else { } else {
const char *p; const char *p;
p = cgroup_ops->get_limiting_cgroup(cgroup_ops, controllers_list[0]); p = cgroup_ops->get_limit_cgroup(cgroup_ops, controllers_list[0]);
if (!p) if (!p)
return log_error_errno(-ENOENT, ENOENT, "Failed to retrieve limiting cgroup path for %s", controllers_list[0] ?: "(null)"); return log_error_errno(-ENOENT, ENOENT, "Failed to retrieve limit cgroup path for %s", controllers_list[0] ?: "(null)");
cgroup_base_path = strdup(p); cgroup_base_path = strdup(p);
if (!cgroup_base_path) if (!cgroup_base_path)
return log_error_errno(-ENOMEM, ENOMEM, "Failed to duplicate limiting cgroup path"); return log_error_errno(-ENOMEM, ENOMEM, "Failed to duplicate limit cgroup path");
} }
tmp = lxc_deslashify(cgroup_base_path); tmp = lxc_deslashify(cgroup_base_path);
...@@ -393,7 +393,7 @@ static int exec_criu(struct cgroup_ops *cgroup_ops, struct lxc_conf *conf, ...@@ -393,7 +393,7 @@ static int exec_criu(struct cgroup_ops *cgroup_ops, struct lxc_conf *conf,
DECLARE_ARG("-t"); DECLARE_ARG("-t");
DECLARE_ARG(init_pid_str); DECLARE_ARG(init_pid_str);
freezer_relative = lxc_cmd_get_limiting_cgroup_path(opts->c->name, freezer_relative = lxc_cmd_get_limit_cgroup_path(opts->c->name,
opts->c->config_path, opts->c->config_path,
"freezer"); "freezer");
if (!freezer_relative) if (!freezer_relative)
......
/* SPDX-License-Identifier: LGPL-2.1+ */
#ifndef __LXC_ERROR_UTILS_H
#define __LXC_ERROR_UTILS_H
#include <stdbool.h>
#define MAX_ERRNO 4095
#define IS_ERR_VALUE(x) unlikely((x) >= (unsigned long)-MAX_ERRNO)
static inline void *ERR_PTR(long error)
{
return (void *)error;
}
static inline long PTR_ERR(const void *ptr)
{
return (long)ptr;
}
static inline long IS_ERR(const void *ptr)
{
return IS_ERR_VALUE((unsigned long)ptr);
}
static inline long IS_ERR_OR_NULL(const void *ptr)
{
return !ptr || IS_ERR_VALUE((unsigned long)ptr);
}
static inline void *ERR_CAST(const void *ptr)
{
return (void *)ptr;
}
static inline int PTR_RET(const void *ptr)
{
if (IS_ERR(ptr))
return PTR_ERR(ptr);
else
return 0;
}
/* Taken from Lennart tyvm. */
#define CASE_F(X) case X:
#define CASE_F_1(CASE, X) CASE_F(X)
#define CASE_F_2(CASE, X, ...) CASE(X) CASE_F_1(CASE, __VA_ARGS__)
#define CASE_F_3(CASE, X, ...) CASE(X) CASE_F_2(CASE, __VA_ARGS__)
#define CASE_F_4(CASE, X, ...) CASE(X) CASE_F_3(CASE, __VA_ARGS__)
#define CASE_F_5(CASE, X, ...) CASE(X) CASE_F_4(CASE, __VA_ARGS__)
#define CASE_F_6(CASE, X, ...) CASE(X) CASE_F_5(CASE, __VA_ARGS__)
#define CASE_F_7(CASE, X, ...) CASE(X) CASE_F_6(CASE, __VA_ARGS__)
#define CASE_F_8(CASE, X, ...) CASE(X) CASE_F_7(CASE, __VA_ARGS__)
#define CASE_F_9(CASE, X, ...) CASE(X) CASE_F_8(CASE, __VA_ARGS__)
#define CASE_F_10(CASE, X, ...) CASE(X) CASE_F_9(CASE, __VA_ARGS__)
#define CASE_F_11(CASE, X, ...) CASE(X) CASE_F_10(CASE, __VA_ARGS__)
#define CASE_F_12(CASE, X, ...) CASE(X) CASE_F_11(CASE, __VA_ARGS__)
#define CASE_F_13(CASE, X, ...) CASE(X) CASE_F_12(CASE, __VA_ARGS__)
#define CASE_F_14(CASE, X, ...) CASE(X) CASE_F_13(CASE, __VA_ARGS__)
#define CASE_F_15(CASE, X, ...) CASE(X) CASE_F_14(CASE, __VA_ARGS__)
#define CASE_F_16(CASE, X, ...) CASE(X) CASE_F_15(CASE, __VA_ARGS__)
#define CASE_F_17(CASE, X, ...) CASE(X) CASE_F_16(CASE, __VA_ARGS__)
#define CASE_F_18(CASE, X, ...) CASE(X) CASE_F_17(CASE, __VA_ARGS__)
#define CASE_F_19(CASE, X, ...) CASE(X) CASE_F_18(CASE, __VA_ARGS__)
#define CASE_F_20(CASE, X, ...) CASE(X) CASE_F_19(CASE, __VA_ARGS__)
#define GET_CASE_F(_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15,_16,_17,_18,_19,_20,NAME,...) NAME
#define FOR_EACH_MAKE_CASE(...) \
GET_CASE_F(__VA_ARGS__,CASE_F_20,CASE_F_19,CASE_F_18,CASE_F_17,CASE_F_16,CASE_F_15,CASE_F_14,CASE_F_13,CASE_F_12,CASE_F_11, \
CASE_F_10,CASE_F_9,CASE_F_8,CASE_F_7,CASE_F_6,CASE_F_5,CASE_F_4,CASE_F_3,CASE_F_2,CASE_F_1) \
(CASE_F,__VA_ARGS__)
#define XCONCATENATE(x, y) x ## y
#define CONCATENATE(x, y) XCONCATENATE(x, y)
#define assert_static(expr) \
struct CONCATENATE(_assert_struct_, __COUNTER__) { \
char x[(expr) ? 0 : -1]; \
}
#define IN_SET(x, ...) \
({ \
bool _found = false; \
static const long double __assert_in_set[] __lxc_unused = { \
__VA_ARGS__}; \
assert_static(ARRAY_SIZE(__assert_in_set) <= 20); \
switch (x) { \
FOR_EACH_MAKE_CASE(__VA_ARGS__) \
_found = true; \
break; \
default: \
break; \
} \
_found; \
})
static inline bool ERRNO_IS_NOT_SUPPORTED(int r) {
return IN_SET(abs(r), EOPNOTSUPP, ENOSYS);
}
#endif /* __LXC_ERROR_UTILS_H */
...@@ -127,7 +127,7 @@ ssize_t lxc_read_try_buf_at(int dfd, const char *path, void *buf, size_t count) ...@@ -127,7 +127,7 @@ ssize_t lxc_read_try_buf_at(int dfd, const char *path, void *buf, size_t count)
__do_close int fd = -EBADF; __do_close int fd = -EBADF;
ssize_t ret; ssize_t ret;
fd = open_at(dfd, path, PROTECT_OPEN_W, PROTECT_LOOKUP_BENEATH, 0); fd = open_at(dfd, path, PROTECT_OPEN, PROTECT_LOOKUP_BENEATH, 0);
if (fd < 0) if (fd < 0)
return -errno; return -errno;
......
...@@ -3290,7 +3290,7 @@ static bool do_lxcapi_set_cgroup_item(struct lxc_container *c, const char *subsy ...@@ -3290,7 +3290,7 @@ static bool do_lxcapi_set_cgroup_item(struct lxc_container *c, const char *subsy
return false; return false;
ret = cgroup_set(c->name, c->config_path, subsys, value); ret = cgroup_set(c->name, c->config_path, subsys, value);
if (ret == -ENOCGROUP2) { if (ret < 0 && ERRNO_IS_NOT_SUPPORTED(ret)) {
cgroup_ops = cgroup_init(c->lxc_conf); cgroup_ops = cgroup_init(c->lxc_conf);
if (!cgroup_ops) if (!cgroup_ops)
return false; return false;
...@@ -3315,7 +3315,7 @@ static int do_lxcapi_get_cgroup_item(struct lxc_container *c, const char *subsys ...@@ -3315,7 +3315,7 @@ static int do_lxcapi_get_cgroup_item(struct lxc_container *c, const char *subsys
return -1; return -1;
ret = cgroup_get(c->name, c->config_path, subsys, retv, inlen); ret = cgroup_get(c->name, c->config_path, subsys, retv, inlen);
if (ret == -ENOCGROUP2) { if (ret < 0 && ERRNO_IS_NOT_SUPPORTED(ret)) {
cgroup_ops = cgroup_init(c->lxc_conf); cgroup_ops = cgroup_init(c->lxc_conf);
if (!cgroup_ops) if (!cgroup_ops)
return -1; return -1;
......
...@@ -700,43 +700,6 @@ enum { ...@@ -700,43 +700,6 @@ enum {
(b) = __tmp; \ (b) = __tmp; \
} while (0) } while (0)
#define MAX_ERRNO 4095
#define IS_ERR_VALUE(x) unlikely((x) >= (unsigned long)-MAX_ERRNO)
static inline void *ERR_PTR(long error)
{
return (void *)error;
}
static inline long PTR_ERR(const void *ptr)
{
return (long)ptr;
}
static inline long IS_ERR(const void *ptr)
{
return IS_ERR_VALUE((unsigned long)ptr);
}
static inline long IS_ERR_OR_NULL(const void *ptr)
{
return !ptr || IS_ERR_VALUE((unsigned long)ptr);
}
static inline void *ERR_CAST(const void *ptr)
{
return (void *)ptr;
}
static inline int PTR_RET(const void *ptr)
{
if (IS_ERR(ptr))
return PTR_ERR(ptr);
else
return 0;
}
#define min(x, y) \ #define min(x, y) \
({ \ ({ \
typeof(x) _min1 = (x); \ typeof(x) _min1 = (x); \
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include <unistd.h> #include <unistd.h>
#include "macro.h" #include "macro.h"
#include "error_utils.h"
#define define_cleanup_function(type, cleaner) \ #define define_cleanup_function(type, cleaner) \
static inline void cleaner##_function(type *ptr) \ static inline void cleaner##_function(type *ptr) \
......
...@@ -1078,7 +1078,7 @@ int lxc_terminal_ptx_cb(int fd, uint32_t events, void *cbdata, ...@@ -1078,7 +1078,7 @@ int lxc_terminal_ptx_cb(int fd, uint32_t events, void *cbdata,
int lxc_terminal_getfd(struct lxc_container *c, int *ttynum, int *ptxfd) int lxc_terminal_getfd(struct lxc_container *c, int *ttynum, int *ptxfd)
{ {
return lxc_cmd_console(c->name, ttynum, ptxfd, c->config_path); return lxc_cmd_get_tty_fd(c->name, ttynum, ptxfd, c->config_path);
} }
int lxc_console(struct lxc_container *c, int ttynum, int lxc_console(struct lxc_container *c, int ttynum,
...@@ -1094,7 +1094,7 @@ int lxc_console(struct lxc_container *c, int ttynum, ...@@ -1094,7 +1094,7 @@ int lxc_console(struct lxc_container *c, int ttynum,
}; };
int istty = 0; int istty = 0;
ttyfd = lxc_cmd_console(c->name, &ttynum, &ptxfd, c->config_path); ttyfd = lxc_cmd_get_tty_fd(c->name, &ttynum, &ptxfd, c->config_path);
if (ttyfd < 0) if (ttyfd < 0)
return -1; return -1;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment