Unverified Commit 7453799a by Stéphane Graber Committed by GitHub

Merge pull request #3217 from brauner/rework_cgroups

cgroups, logging: fixes and improvements
parents 0374aacd c04a6d4e
......@@ -335,14 +335,14 @@ int lxc_unix_sockaddr(struct sockaddr_un *ret, const char *path)
len = strlen(path);
if (len == 0)
return minus_one_set_errno(EINVAL);
return ret_set_errno(-1, EINVAL);
if (path[0] != '/' && path[0] != '@')
return minus_one_set_errno(EINVAL);
return ret_set_errno(-1, EINVAL);
if (path[1] == '\0')
return minus_one_set_errno(EINVAL);
return ret_set_errno(-1, EINVAL);
if (len + 1 > sizeof(ret->sun_path))
return minus_one_set_errno(EINVAL);
return ret_set_errno(-1, EINVAL);
*ret = (struct sockaddr_un){
.sun_family = AF_UNIX,
......
......@@ -104,9 +104,8 @@ static struct lxc_proc_context_info *lxc_proc_get_context_info(pid_t pid)
static inline void lxc_proc_close_ns_fd(struct lxc_proc_context_info *ctx)
{
for (int i = 0; i < LXC_NS_MAX; i++) {
__do_close_prot_errno int fd ATTR_UNUSED = move_fd(ctx->ns_fd[i]);
}
for (int i = 0; i < LXC_NS_MAX; i++)
close_prot_errno_disarm(ctx->ns_fd[i]);
}
static void lxc_proc_put_context_info(struct lxc_proc_context_info *ctx)
......@@ -668,9 +667,8 @@ struct attach_clone_payload {
static void lxc_put_attach_clone_payload(struct attach_clone_payload *p)
{
__do_close_prot_errno int ipc_socket ATTR_UNUSED = p->ipc_socket;
__do_close_prot_errno int terminal_slave_fd ATTR_UNUSED = p->terminal_slave_fd;
close_prot_errno_disarm(p->ipc_socket);
close_prot_errno_disarm(p->terminal_slave_fd);
if (p->init_ctx) {
lxc_proc_put_context_info(p->init_ctx);
p->init_ctx = NULL;
......@@ -1009,10 +1007,10 @@ int lxc_attach(struct lxc_container *container, lxc_attach_exec_t exec_function,
}
if (!container)
return minus_one_set_errno(EINVAL);
return ret_set_errno(-1, EINVAL);
if (!lxc_container_get(container))
return minus_one_set_errno(EINVAL);
return ret_set_errno(-1, EINVAL);
name = container->name;
lxcpath = container->config_path;
......
......@@ -500,13 +500,11 @@ static bool cg_legacy_filter_and_set_cpus(char *path, bool am_initialized)
copy_parent:
if (!am_initialized) {
fpath = must_make_path(path, "cpuset.cpus", NULL);
ret = lxc_write_to_file(fpath, cpulist, strlen(cpulist), false,
0666);
if (ret < 0) {
SYSERROR("Failed to write cpu list to \"%s\"", fpath);
return false;
}
ret = lxc_write_openat(path, "cpuset.cpus", cpulist, strlen(cpulist));
if (ret < 0)
return log_error_errno(false,
errno, "Failed to write cpu list to \"%s/cpuset.cpus\"",
path);
TRACE("Copied cpu settings of parent cgroup");
}
......@@ -517,7 +515,7 @@ copy_parent:
/* Copy contents of parent(@path)/@file to @path/@file */
static bool copy_parent_file(char *path, char *file)
{
__do_free char *child_path = NULL, *parent_path = NULL, *value = NULL;
__do_free char *parent_path = NULL, *value = NULL;
int ret;
char oldv;
int len = 0;
......@@ -545,13 +543,17 @@ static bool copy_parent_file(char *path, char *file)
}
*lastslash = oldv;
child_path = must_make_path(path, file, NULL);
ret = lxc_write_to_file(child_path, value, len, false, 0666);
ret = lxc_write_openat(path, file, value, len);
if (ret < 0)
SYSERROR("Failed to write \"%s\" to file \"%s\"", value, child_path);
SYSERROR("Failed to write \"%s\" to file \"%s/%s\"", value, path, file);
return ret >= 0;
}
static bool is_unified_hierarchy(const struct hierarchy *h)
{
return h->version == CGROUP2_SUPER_MAGIC;
}
/* Initialize the cpuset hierarchy in first directory of @gname and set
* cgroup.clone_children so that children inherit settings. Since the
* h->base_path is populated by init or ourselves, we know it is already
......@@ -559,11 +561,15 @@ static bool copy_parent_file(char *path, char *file)
*/
static bool cg_legacy_handle_cpuset_hierarchy(struct hierarchy *h, char *cgname)
{
__do_free char *cgpath = NULL, *clonechildrenpath = NULL;
__do_free char *cgpath = NULL;
__do_close_prot_errno int cgroup_fd = -EBADF;
int ret;
char v;
char *slash;
if (is_unified_hierarchy(h))
return true;
if (!string_in_list(h->controllers, "cpuset"))
return true;
......@@ -585,14 +591,13 @@ static bool cg_legacy_handle_cpuset_hierarchy(struct hierarchy *h, char *cgname)
}
}
clonechildrenpath = must_make_path(cgpath, "cgroup.clone_children", NULL);
/* unified hierarchy doesn't have clone_children */
if (!file_exists(clonechildrenpath))
return true;
cgroup_fd = lxc_open_dirfd(cgpath);
if (cgroup_fd < 0)
return false;
ret = lxc_read_from_file(clonechildrenpath, &v, 1);
ret = lxc_readat(cgroup_fd, "cgroup.clone_children", &v, 1);
if (ret < 0) {
SYSERROR("Failed to read file \"%s\"", clonechildrenpath);
SYSERROR("Failed to read file \"%s/cgroup.clone_children\"", cgpath);
return false;
}
......@@ -612,10 +617,10 @@ static bool cg_legacy_handle_cpuset_hierarchy(struct hierarchy *h, char *cgname)
return false;
}
ret = lxc_write_to_file(clonechildrenpath, "1", 1, false, 0666);
ret = lxc_writeat(cgroup_fd, "cgroup.clone_children", "1", 1);
if (ret < 0) {
/* Set clone_children so children inherit our settings */
SYSERROR("Failed to write 1 to \"%s\"", clonechildrenpath);
SYSERROR("Failed to write 1 to \"%s/cgroup.clone_children\"", cgpath);
return false;
}
......@@ -1086,9 +1091,18 @@ __cgfsng_ops static void cgfsng_payload_destroy(struct cgroup_ops *ops,
int ret;
struct generic_userns_exec_data wrap;
if (!ops)
log_error_errno(return, ENOENT, "Called with uninitialized cgroup operations");
if (!ops->hierarchies)
return;
if (!handler)
log_error_errno(return, EINVAL, "Called with uninitialized handler");
if (!handler->conf)
log_error_errno(return, EINVAL, "Called with uninitialized conf");
wrap.origuid = 0;
wrap.container_cgroup = ops->container_cgroup;
wrap.hierarchies = ops->hierarchies;
......@@ -1115,12 +1129,23 @@ __cgfsng_ops static void cgfsng_monitor_destroy(struct cgroup_ops *ops,
struct lxc_handler *handler)
{
int len;
struct lxc_conf *conf = handler->conf;
char pidstr[INTTYPE_TO_STRLEN(pid_t)];
struct lxc_conf *conf;
if (!ops)
log_error_errno(return, ENOENT, "Called with uninitialized cgroup operations");
if (!ops->hierarchies)
return;
if (!handler)
log_error_errno(return, EINVAL, "Called with uninitialized handler");
if (!handler->conf)
log_error_errno(return, EINVAL, "Called with uninitialized conf");
conf = handler->conf;
len = snprintf(pidstr, sizeof(pidstr), "%d", handler->monitor_pid);
if (len < 0 || (size_t)len >= sizeof(pidstr))
return;
......@@ -1155,16 +1180,15 @@ __cgfsng_ops static void cgfsng_monitor_destroy(struct cgroup_ops *ops,
* Make sure not to pass in the ro string literal PIVOT_CGROUP
* here.
*/
if (!cg_legacy_handle_cpuset_hierarchy(h, pivot_cgroup)) {
WARN("Failed to handle legacy cpuset controller");
continue;
}
if (!cg_legacy_handle_cpuset_hierarchy(h, pivot_cgroup))
log_warn_errno(continue,
errno, "Failed to handle legacy cpuset controller");
ret = mkdir_p(pivot_path, 0755);
if (ret < 0 && errno != EEXIST) {
SYSWARN("Failed to create cgroup \"%s\"\n", pivot_path);
continue;
}
if (ret < 0 && errno != EEXIST)
log_warn_errno(continue, errno,
"Failed to create cgroup \"%s\"\n",
pivot_path);
if (chop)
*chop = '/';
......@@ -1173,10 +1197,10 @@ __cgfsng_ops static void cgfsng_monitor_destroy(struct cgroup_ops *ops,
* cgroup.
*/
ret = lxc_write_to_file(pivot_path, pidstr, len, false, 0666);
if (ret != 0) {
SYSWARN("Failed to move monitor %s to \"%s\"\n", pidstr, pivot_path);
continue;
}
if (ret != 0)
log_warn_errno(continue, errno,
"Failed to move monitor %s to \"%s\"\n",
pidstr, pivot_path);
ret = recursive_destroy(h->monitor_full_path);
if (ret < 0)
......@@ -1284,14 +1308,22 @@ __cgfsng_ops static inline bool cgfsng_monitor_create(struct cgroup_ops *ops,
char *offset, *tmp;
int i, idx = 0;
size_t len;
struct lxc_conf *conf = handler->conf;
struct lxc_conf *conf;
if (!conf)
return false;
if (!ops)
return ret_set_errno(false, ENOENT);
if (!ops->hierarchies)
return true;
if (ops->monitor_cgroup)
return ret_set_errno(false, EEXIST);
if (!handler || !handler->conf)
return ret_set_errno(false, EINVAL);
conf = handler->conf;
if (conf->cgroup_meta.dir)
tmp = lxc_string_join("/",
(const char *[]){conf->cgroup_meta.dir,
......@@ -1301,7 +1333,7 @@ __cgfsng_ops static inline bool cgfsng_monitor_create(struct cgroup_ops *ops,
else
tmp = must_make_path(ops->monitor_pattern, handler->name, NULL);
if (!tmp)
return false;
return ret_set_errno(false, ENOMEM);
len = strlen(tmp) + 5; /* leave room for -NNN\0 */
monitor_cgroup = must_realloc(tmp, len);
......@@ -1309,11 +1341,8 @@ __cgfsng_ops static inline bool cgfsng_monitor_create(struct cgroup_ops *ops,
*offset = 0;
do {
if (idx) {
int ret = snprintf(offset, 5, "-%d", idx);
if (ret < 0 || (size_t)ret >= 5)
return false;
}
if (idx)
sprintf(offset, "-%d", idx);
for (i = 0; ops->hierarchies[i]; i++) {
if (!monitor_create_path_for_hierarchy(ops->hierarchies[i],
......@@ -1332,43 +1361,46 @@ __cgfsng_ops static inline bool cgfsng_monitor_create(struct cgroup_ops *ops,
} while (ops->hierarchies[i] && idx > 0 && idx < 1000);
if (idx == 1000)
return false;
return ret_set_errno(false, ERANGE);
INFO("The monitor process uses \"%s\" as cgroup", monitor_cgroup);
ops->monitor_cgroup = move_ptr(monitor_cgroup);
return true;
return log_info(true, "The monitor process uses \"%s\" as cgroup", ops->monitor_cgroup);
}
/* Try to create the same cgroup in all hierarchies. Start with cgroup_pattern;
* next cgroup_pattern-1, -2, ..., -999.
*/
__cgfsng_ops static inline bool cgfsng_payload_create(struct cgroup_ops *ops,
struct lxc_handler *handler)
struct lxc_handler *handler)
{
__do_free char *container_cgroup = NULL, *tmp = NULL;
int idx = 0;
int i, ret;
size_t len;
char *offset;
int idx = 0;
struct lxc_conf *conf = handler->conf;
if (ops->container_cgroup)
return false;
struct lxc_conf *conf;
if (!conf)
return false;
if (!ops)
return ret_set_errno(false, ENOENT);
if (!ops->hierarchies)
return true;
if (ops->container_cgroup)
return ret_set_errno(false, EEXIST);
if (!handler || !handler->conf)
return ret_set_errno(false, EINVAL);
conf = handler->conf;
if (conf->cgroup_meta.dir)
tmp = lxc_string_join("/", (const char *[]){conf->cgroup_meta.dir, handler->name, NULL}, false);
else
tmp = lxc_string_replace("%n", handler->name, ops->cgroup_pattern);
if (!tmp) {
ERROR("Failed expanding cgroup name pattern");
return false;
}
if (!tmp)
return log_error_errno(false, ENOMEM,
"Failed expanding cgroup name pattern");
len = strlen(tmp) + 5; /* leave room for -NNN\0 */
container_cgroup = must_realloc(NULL, len);
......@@ -1376,11 +1408,8 @@ __cgfsng_ops static inline bool cgfsng_payload_create(struct cgroup_ops *ops,
offset = container_cgroup + len - 5;
do {
if (idx) {
ret = snprintf(offset, 5, "-%d", idx);
if (ret < 0 || (size_t)ret >= 5)
return false;
}
if (idx)
sprintf(offset, "-%d", idx);
for (i = 0; ops->hierarchies[i]; i++) {
if (!container_create_path_for_hierarchy(ops->hierarchies[i],
......@@ -1398,7 +1427,7 @@ __cgfsng_ops static inline bool cgfsng_payload_create(struct cgroup_ops *ops,
} while (ops->hierarchies[i] && idx > 0 && idx < 1000);
if (idx == 1000)
return false;
return ret_set_errno(false, ERANGE);
INFO("The container process uses \"%s\" as cgroup", container_cgroup);
ops->container_cgroup = move_ptr(container_cgroup);
......@@ -1422,9 +1451,18 @@ __cgfsng_ops static bool cgfsng_monitor_enter(struct cgroup_ops *ops,
char monitor[INTTYPE_TO_STRLEN(pid_t)],
transient[INTTYPE_TO_STRLEN(pid_t)];
if (!ops)
return ret_set_errno(false, ENOENT);
if (!ops->hierarchies)
return true;
if (!ops->monitor_cgroup)
return ret_set_errno(false, ENOENT);
if (!handler || !handler->conf)
return ret_set_errno(false, EINVAL);
monitor_len = snprintf(monitor, sizeof(monitor), "%d", handler->monitor_pid);
if (handler->transient_pid > 0)
transient_len = snprintf(transient, sizeof(transient), "%d",
......@@ -1458,9 +1496,18 @@ __cgfsng_ops static bool cgfsng_payload_enter(struct cgroup_ops *ops,
int len;
char pidstr[INTTYPE_TO_STRLEN(pid_t)];
if (!ops)
return ret_set_errno(false, ENOENT);
if (!ops->hierarchies)
return true;
if (!ops->container_cgroup)
return ret_set_errno(false, ENOENT);
if (!handler || !handler->conf)
return ret_set_errno(false, EINVAL);
len = snprintf(pidstr, sizeof(pidstr), "%d", handler->pid);
for (int i = 0; ops->hierarchies[i]; i++) {
......@@ -1513,24 +1560,20 @@ static int chown_cgroup_wrapper(void *data)
gid_t nsgid = (arg->conf->root_nsgid_map != NULL) ? 0 : arg->conf->init_gid;
ret = setresgid(nsgid, nsgid, nsgid);
if (ret < 0) {
SYSERROR("Failed to setresgid(%d, %d, %d)",
(int)nsgid, (int)nsgid, (int)nsgid);
return -1;
}
if (ret < 0)
return log_error_errno(-1, errno,
"Failed to setresgid(%d, %d, %d)",
(int)nsgid, (int)nsgid, (int)nsgid);
ret = setresuid(nsuid, nsuid, nsuid);
if (ret < 0) {
SYSERROR("Failed to setresuid(%d, %d, %d)",
(int)nsuid, (int)nsuid, (int)nsuid);
return -1;
}
if (ret < 0)
return log_error_errno(-1, errno,
"Failed to setresuid(%d, %d, %d)",
(int)nsuid, (int)nsuid, (int)nsuid);
ret = setgroups(0, NULL);
if (ret < 0 && errno != EPERM) {
SYSERROR("Failed to setgroups(0, NULL)");
return -1;
}
if (ret < 0 && errno != EPERM)
return log_error_errno(-1, errno, "Failed to setgroups(0, NULL)");
destuid = get_ns_uid(arg->origuid);
if (destuid == LXC_INVALID_UID)
......@@ -1542,7 +1585,9 @@ static int chown_cgroup_wrapper(void *data)
ret = chowmod(path, destuid, nsgid, 0775);
if (ret < 0)
return -1;
log_info_errno(continue,
errno, "Failed to change %s to uid %d and gid %d and mode 0755",
path, destuid, nsgid);
/* Failures to chown() these are inconvenient but not
* detrimental We leave these owned by the container launcher,
......@@ -1553,18 +1598,27 @@ static int chown_cgroup_wrapper(void *data)
if (arg->hierarchies[i]->version == CGROUP_SUPER_MAGIC) {
fullpath = must_make_path(path, "tasks", NULL);
(void)chowmod(fullpath, destuid, nsgid, 0664);
ret = chowmod(fullpath, destuid, nsgid, 0664);
if (ret < 0)
SYSINFO("Failed to change %s to uid %d and gid %d and mode 0664",
fullpath, destuid, nsgid);
}
fullpath = must_make_path(path, "cgroup.procs", NULL);
(void)chowmod(fullpath, destuid, nsgid, 0664);
ret = chowmod(fullpath, destuid, nsgid, 0664);
if (ret < 0)
SYSINFO("Failed to change %s to uid %d and gid %d and mode 0664",
fullpath, destuid, nsgid);
if (arg->hierarchies[i]->version != CGROUP2_SUPER_MAGIC)
continue;
for (char **p = arg->hierarchies[i]->cgroup2_chown; p && *p; p++) {
fullpath = must_make_path(path, *p, NULL);
(void)chowmod(fullpath, destuid, nsgid, 0664);
ret = chowmod(fullpath, destuid, nsgid, 0664);
if (ret < 0)
SYSINFO("Failed to change %s to uid %d and gid %d and mode 0664",
fullpath, destuid, nsgid);
}
}
......@@ -1572,26 +1626,32 @@ static int chown_cgroup_wrapper(void *data)
}
__cgfsng_ops static bool cgfsng_chown(struct cgroup_ops *ops,
struct lxc_conf *conf)
struct lxc_conf *conf)
{
struct generic_userns_exec_data wrap;
if (lxc_list_empty(&conf->id_map))
return true;
if (!ops)
return ret_set_errno(false, ENOENT);
if (!ops->hierarchies)
return true;
if (!ops->container_cgroup)
return ret_set_errno(false, ENOENT);
if (!conf)
return ret_set_errno(false, EINVAL);
if (lxc_list_empty(&conf->id_map))
return true;
wrap.origuid = geteuid();
wrap.path = NULL;
wrap.hierarchies = ops->hierarchies;
wrap.conf = conf;
if (userns_exec_1(conf, chown_cgroup_wrapper, &wrap,
"chown_cgroup_wrapper") < 0) {
ERROR("Error requesting cgroup chown in new user namespace");
return false;
}
if (userns_exec_1(conf, chown_cgroup_wrapper, &wrap, "chown_cgroup_wrapper") < 0)
return log_error_errno(false, errno, "Error requesting cgroup chown in new user namespace");
return true;
}
......@@ -1728,9 +1788,15 @@ __cgfsng_ops static bool cgfsng_mount(struct cgroup_ops *ops,
int ret;
bool has_cgns = false, retval = false, wants_force_mount = false;
if (!ops)
return ret_set_errno(false, ENOENT);
if (!ops->hierarchies)
return true;
if (!handler || !handler->conf)
return ret_set_errno(false, EINVAL);
if ((type & LXC_AUTO_CGROUP_MASK) == 0)
return true;
......@@ -1790,10 +1856,10 @@ __cgfsng_ops static bool cgfsng_mount(struct cgroup_ops *ops,
continue;
ret = mkdir(controllerpath, 0755);
if (ret < 0) {
SYSERROR("Error creating cgroup path: %s", controllerpath);
goto on_error;
}
if (ret < 0)
log_error_errno(goto on_error, errno,
"Error creating cgroup path: %s",
controllerpath);
if (has_cgns && wants_force_mount) {
/* If cgroup namespaces are supported but the container
......@@ -1872,8 +1938,11 @@ __cgfsng_ops static int cgfsng_nrtasks(struct cgroup_ops *ops)
{
__do_free char *path = NULL;
if (!ops)
return ret_set_errno(-1, ENOENT);
if (!ops->container_cgroup || !ops->hierarchies)
return -1;
return ret_set_errno(-1, EINVAL);
path = must_make_path(ops->hierarchies[0]->container_full_path, NULL);
return recursive_count_nrtasks(path);
......@@ -1881,23 +1950,33 @@ __cgfsng_ops static int cgfsng_nrtasks(struct cgroup_ops *ops)
/* Only root needs to escape to the cgroup of its init. */
__cgfsng_ops static bool cgfsng_escape(const struct cgroup_ops *ops,
struct lxc_conf *conf)
struct lxc_conf *conf)
{
if (conf->cgroup_meta.relative || geteuid() || !ops->hierarchies)
if (!ops)
return ret_set_errno(false, ENOENT);
if (!ops->hierarchies)
return true;
if (!conf)
return ret_set_errno(false, EINVAL);
if (conf->cgroup_meta.relative || geteuid())
return true;
for (int i = 0; ops->hierarchies[i]; i++) {
int ret;
__do_free char *fullpath = NULL;
int ret;
fullpath = must_make_path(ops->hierarchies[i]->mountpoint,
ops->hierarchies[i]->container_base_path,
"cgroup.procs", NULL);
fullpath =
must_make_path(ops->hierarchies[i]->mountpoint,
ops->hierarchies[i]->container_base_path,
"cgroup.procs", NULL);
ret = lxc_write_to_file(fullpath, "0", 2, false, 0666);
if (ret != 0) {
SYSERROR("Failed to escape to cgroup \"%s\"", fullpath);
return false;
}
if (ret != 0)
return log_error_errno(false,
errno, "Failed to escape to cgroup \"%s\"",
fullpath);
}
return true;
......@@ -1907,6 +1986,9 @@ __cgfsng_ops static int cgfsng_num_hierarchies(struct cgroup_ops *ops)
{
int i = 0;
if (!ops)
return ret_set_errno(-1, ENOENT);
if (!ops->hierarchies)
return 0;
......@@ -1916,35 +1998,37 @@ __cgfsng_ops static int cgfsng_num_hierarchies(struct cgroup_ops *ops)
return i;
}
__cgfsng_ops static bool cgfsng_get_hierarchies(struct cgroup_ops *ops, int n, char ***out)
__cgfsng_ops static bool cgfsng_get_hierarchies(struct cgroup_ops *ops, int n,
char ***out)
{
int i;
if (!ops)
return ret_set_errno(false, ENOENT);
if (!ops->hierarchies)
return false;
/* sanity check n */
for (i = 0; i < n; i++)
if (!ops->hierarchies[i])
return false;
return ret_set_errno(false, ENOENT);
*out = ops->hierarchies[i]->controllers;
return true;
}
static bool cg_legacy_freeze(struct cgroup_ops *ops)
{
__do_free char *path = NULL;
struct hierarchy *h;
h = get_hierarchy(ops, "freezer");
if (!h)
return minus_one_set_errno(ENOENT);
return ret_set_errno(-1, ENOENT);
path = must_make_path(h->container_full_path, "freezer.state", NULL);
return lxc_write_to_file(path, "FROZEN", STRLITERALLEN("FROZEN"), false, 0666);
return lxc_write_openat(h->container_full_path, "freezer.state",
"FROZEN", STRLITERALLEN("FROZEN"));
}
static int freezer_cgroup_events_cb(int fd, uint32_t events, void *cbdata,
......@@ -1984,7 +2068,6 @@ static int freezer_cgroup_events_cb(int fd, uint32_t events, void *cbdata,
static int cg_unified_freeze(struct cgroup_ops *ops, int timeout)
{
__do_close_prot_errno int fd = -EBADF;
__do_free char *path = NULL;
__do_lxc_mainloop_close struct lxc_epoll_descr *descr_ptr = NULL;
int ret;
struct lxc_epoll_descr descr;
......@@ -1992,10 +2075,10 @@ static int cg_unified_freeze(struct cgroup_ops *ops, int timeout)
h = ops->unified;
if (!h)
return minus_one_set_errno(ENOENT);
return ret_set_errno(-1, ENOENT);
if (!h->container_full_path)
return minus_one_set_errno(EEXIST);
return ret_set_errno(-1, EEXIST);
if (timeout != 0) {
__do_free char *events_file = NULL;
......@@ -2003,27 +2086,26 @@ static int cg_unified_freeze(struct cgroup_ops *ops, int timeout)
events_file = must_make_path(h->container_full_path, "cgroup.events", NULL);
fd = open(events_file, O_RDONLY | O_CLOEXEC);
if (fd < 0)
return error_log_errno(errno, "Failed to open cgroup.events file");
return log_error_errno(-1, errno, "Failed to open cgroup.events file");
ret = lxc_mainloop_open(&descr);
if (ret)
return error_log_errno(errno, "Failed to create epoll instance to wait for container freeze");
return log_error_errno(-1, errno, "Failed to create epoll instance to wait for container freeze");
/* automatically cleaned up now */
descr_ptr = &descr;
ret = lxc_mainloop_add_handler(&descr, fd, freezer_cgroup_events_cb, INT_TO_PTR((int){1}));
if (ret < 0)
return error_log_errno(errno, "Failed to add cgroup.events fd handler to mainloop");
return log_error_errno(-1, errno, "Failed to add cgroup.events fd handler to mainloop");
}
path = must_make_path(h->container_full_path, "cgroup.freeze", NULL);
ret = lxc_write_to_file(path, "1", 1, false, 0666);
ret = lxc_write_openat(h->container_full_path, "cgroup.freeze", "1", 1);
if (ret < 0)
return error_log_errno(errno, "Failed to open cgroup.freeze file");
return log_error_errno(-1, errno, "Failed to open cgroup.freeze file");
if (timeout != 0 && lxc_mainloop(&descr, timeout))
return error_log_errno(errno, "Failed to wait for container to be frozen");
return log_error_errno(-1, errno, "Failed to wait for container to be frozen");
return 0;
}
......@@ -2031,7 +2113,7 @@ static int cg_unified_freeze(struct cgroup_ops *ops, int timeout)
__cgfsng_ops static int cgfsng_freeze(struct cgroup_ops *ops, int timeout)
{
if (!ops->hierarchies)
return minus_one_set_errno(ENOENT);
return ret_set_errno(-1, ENOENT);
if (ops->cgroup_layout != CGROUP_LAYOUT_UNIFIED)
return cg_legacy_freeze(ops);
......@@ -2041,21 +2123,19 @@ __cgfsng_ops static int cgfsng_freeze(struct cgroup_ops *ops, int timeout)
static int cg_legacy_unfreeze(struct cgroup_ops *ops)
{
__do_free char *path = NULL;
struct hierarchy *h;
h = get_hierarchy(ops, "freezer");
if (!h)
return minus_one_set_errno(ENOENT);
return ret_set_errno(-1, ENOENT);
path = must_make_path(h->container_full_path, "freezer.state", NULL);
return lxc_write_to_file(path, "THAWED", STRLITERALLEN("THAWED"), false, 0666);
return lxc_write_openat(h->container_full_path, "freezer.state",
"THAWED", STRLITERALLEN("THAWED"));
}
static int cg_unified_unfreeze(struct cgroup_ops *ops, int timeout)
{
__do_close_prot_errno int fd = -EBADF;
__do_free char *path = NULL;
__do_lxc_mainloop_close struct lxc_epoll_descr *descr_ptr = NULL;
int ret;
struct lxc_epoll_descr descr;
......@@ -2063,10 +2143,10 @@ static int cg_unified_unfreeze(struct cgroup_ops *ops, int timeout)
h = ops->unified;
if (!h)
return minus_one_set_errno(ENOENT);
return ret_set_errno(-1, ENOENT);
if (!h->container_full_path)
return minus_one_set_errno(EEXIST);
return ret_set_errno(-1, EEXIST);
if (timeout != 0) {
__do_free char *events_file = NULL;
......@@ -2074,27 +2154,26 @@ static int cg_unified_unfreeze(struct cgroup_ops *ops, int timeout)
events_file = must_make_path(h->container_full_path, "cgroup.events", NULL);
fd = open(events_file, O_RDONLY | O_CLOEXEC);
if (fd < 0)
return error_log_errno(errno, "Failed to open cgroup.events file");
return log_error_errno(-1, errno, "Failed to open cgroup.events file");
ret = lxc_mainloop_open(&descr);
if (ret)
return error_log_errno(errno, "Failed to create epoll instance to wait for container unfreeze");
return log_error_errno(-1, errno, "Failed to create epoll instance to wait for container unfreeze");
/* automatically cleaned up now */
descr_ptr = &descr;
ret = lxc_mainloop_add_handler(&descr, fd, freezer_cgroup_events_cb, INT_TO_PTR((int){0}));
if (ret < 0)
return error_log_errno(errno, "Failed to add cgroup.events fd handler to mainloop");
return log_error_errno(-1, errno, "Failed to add cgroup.events fd handler to mainloop");
}
path = must_make_path(h->container_full_path, "cgroup.freeze", NULL);
ret = lxc_write_to_file(path, "0", 1, false, 0666);
ret = lxc_write_openat(h->container_full_path, "cgroup.freeze", "0", 1);
if (ret < 0)
return error_log_errno(errno, "Failed to open cgroup.freeze file");
return log_error_errno(-1, errno, "Failed to open cgroup.freeze file");
if (timeout != 0 && lxc_mainloop(&descr, timeout))
return error_log_errno(errno, "Failed to wait for container to be unfrozen");
return log_error_errno(-1, errno, "Failed to wait for container to be unfrozen");
return 0;
}
......@@ -2102,7 +2181,7 @@ static int cg_unified_unfreeze(struct cgroup_ops *ops, int timeout)
__cgfsng_ops static int cgfsng_unfreeze(struct cgroup_ops *ops, int timeout)
{
if (!ops->hierarchies)
return minus_one_set_errno(ENOENT);
return ret_set_errno(-1, ENOENT);
if (ops->cgroup_layout != CGROUP_LAYOUT_UNIFIED)
return cg_legacy_unfreeze(ops);
......@@ -2111,18 +2190,19 @@ __cgfsng_ops static int cgfsng_unfreeze(struct cgroup_ops *ops, int timeout)
}
__cgfsng_ops static const char *cgfsng_get_cgroup(struct cgroup_ops *ops,
const char *controller)
const char *controller)
{
struct hierarchy *h;
h = get_hierarchy(ops, controller);
if (!h) {
WARN("Failed to find hierarchy for controller \"%s\"",
controller ? controller : "(null)");
return NULL;
}
if (!h)
return log_warn_errno(NULL,
ENOENT, "Failed to find hierarchy for controller \"%s\"",
controller ? controller : "(null)");
return h->container_full_path ? h->container_full_path + strlen(h->mountpoint) : NULL;
return h->container_full_path
? h->container_full_path + strlen(h->mountpoint)
: NULL;
}
/* Given a cgroup path returned from lxc_cmd_get_cgroup_path, build a full path,
......@@ -2137,51 +2217,53 @@ static inline char *build_full_cgpath_from_monitorpath(struct hierarchy *h,
static int cgroup_attach_leaf(int unified_fd, int64_t pid)
{
int idx = 0;
int idx = 1;
int ret;
char pidstr[INTTYPE_TO_STRLEN(int64_t) + 1];
char attach_cgroup[STRLITERALLEN("lxc-1000/cgroup.procs") + 1];
size_t pidstr_len;
/* Create leaf cgroup. */
ret = mkdirat(unified_fd, "lxc", 0755);
if (ret < 0 && errno != EEXIST)
return log_error_errno(-1, errno, "Failed to create leaf cgroup \"lxc\"");
pidstr_len = sprintf(pidstr, INT64_FMT, pid);
ret = lxc_writeat(unified_fd, "cgroup.procs", pidstr, pidstr_len);
ret = lxc_writeat(unified_fd, "lxc/cgroup.procs", pidstr, pidstr_len);
if (ret < 0)
ret = lxc_writeat(unified_fd, "cgroup.procs", pidstr, pidstr_len);
if (ret == 0)
return 0;
/* this is a non-leaf node */
if (errno != EBUSY)
return error_log_errno(errno, "Failed to attach to unified cgroup");
return log_error_errno(-1, errno, "Failed to attach to unified cgroup");
do {
char *slash;
char attach_cgroup[STRLITERALLEN("lxc-1000/cgroup.procs") + 1];
if (idx)
ret = snprintf(attach_cgroup, sizeof(attach_cgroup),
"lxc-%d/cgroup.procs", idx);
else
ret = snprintf(attach_cgroup, sizeof(attach_cgroup),
"lxc/cgroup.procs");
if (ret < 0 || (size_t)ret >= sizeof(attach_cgroup))
return -1;
sprintf(attach_cgroup, "lxc-%d/cgroup.procs", idx);
slash = &attach_cgroup[ret] - STRLITERALLEN("/cgroup.procs");
*slash = '\0';
ret = mkdirat(unified_fd, attach_cgroup, 0755);
if (ret < 0 && errno != EEXIST)
return error_log_errno(errno, "Failed to create cgroup %s", attach_cgroup);
return log_error_errno(-1, errno, "Failed to create cgroup %s", attach_cgroup);
*slash = '/';
ret = lxc_writeat(unified_fd, attach_cgroup, pidstr, pidstr_len);
if (ret == 0)
return 0;
/* this is a non-leaf node */
if (errno != EBUSY)
return error_log_errno(errno, "Failed to attach to unified cgroup");
return log_error_errno(-1, errno, "Failed to attach to unified cgroup");
idx++;
} while (idx < 1000);
return -1;
return log_error_errno(-1, errno, "Failed to attach to unified cgroup");
}
int cgroup_attach(const char *name, const char *lxcpath, int64_t pid)
......@@ -2235,6 +2317,9 @@ __cgfsng_ops static bool cgfsng_attach(struct cgroup_ops *ops, const char *name,
int len, ret;
char pidstr[INTTYPE_TO_STRLEN(pid_t)];
if (!ops)
return ret_set_errno(false, ENOENT);
if (!ops->hierarchies)
return true;
......@@ -2262,10 +2347,10 @@ __cgfsng_ops static bool cgfsng_attach(struct cgroup_ops *ops, const char *name,
fullpath = build_full_cgpath_from_monitorpath(h, path, "cgroup.procs");
ret = lxc_write_to_file(fullpath, pidstr, len, false, 0666);
if (ret < 0) {
SYSERROR("Failed to attach %d to %s", (int)pid, fullpath);
return false;
}
if (ret < 0)
return log_error_errno(false, errno,
"Failed to attach %d to %s",
(int)pid, fullpath);
}
return true;
......@@ -2285,6 +2370,9 @@ __cgfsng_ops static int cgfsng_get(struct cgroup_ops *ops, const char *filename,
struct hierarchy *h;
int ret = -1;
if (!ops)
return ret_set_errno(-1, ENOENT);
controller = must_copy_string(filename);
p = strchr(controller, '.');
if (p)
......@@ -2425,6 +2513,9 @@ __cgfsng_ops static int cgfsng_set(struct cgroup_ops *ops,
struct hierarchy *h;
int ret = -1;
if (!ops)
return ret_set_errno(-1, ENOENT);
controller = must_copy_string(key);
p = strchr(controller, '.');
if (p)
......@@ -2435,7 +2526,7 @@ __cgfsng_ops static int cgfsng_set(struct cgroup_ops *ops,
ret = device_cgroup_rule_parse(&device, key, value);
if (ret < 0)
return error_log_errno(EINVAL, "Failed to parse device string %s=%s",
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);
......@@ -2546,12 +2637,10 @@ static int cg_legacy_set_data(struct cgroup_ops *ops, const char *filename,
const char *value)
{
__do_free char *controller = NULL;
__do_free char *fullpath = NULL;
char *p;
/* "b|c <2^64-1>:<2^64-1> r|w|m" = 47 chars max */
char converted_value[50];
struct hierarchy *h;
int ret = 0;
controller = must_copy_string(filename);
p = strchr(controller, '.');
......@@ -2559,6 +2648,8 @@ static int cg_legacy_set_data(struct cgroup_ops *ops, const char *filename,
*p = '\0';
if (strcmp("devices.allow", filename) == 0 && value[0] == '/') {
int ret;
ret = convert_devpath(value, converted_value);
if (ret < 0)
return ret;
......@@ -2575,9 +2666,7 @@ static int cg_legacy_set_data(struct cgroup_ops *ops, const char *filename,
return -ENOENT;
}
fullpath = must_make_path(h->container_full_path, filename, NULL);
ret = lxc_write_to_file(fullpath, value, strlen(value), false, 0666);
return ret;
return lxc_write_openat(h->container_full_path, filename, value, strlen(value));
}
__cgfsng_ops static bool cgfsng_setup_limits_legacy(struct cgroup_ops *ops,
......@@ -2590,11 +2679,18 @@ __cgfsng_ops static bool cgfsng_setup_limits_legacy(struct cgroup_ops *ops,
struct lxc_cgroup *cg;
bool ret = false;
if (!ops)
return ret_set_errno(false, ENOENT);
if (!conf)
return ret_set_errno(false, EINVAL);
cgroup_settings = &conf->cgroup;
if (lxc_list_empty(cgroup_settings))
return true;
if (!ops->hierarchies)
return false;
return ret_set_errno(false, EINVAL);
sorted_cgroup_settings = sort_cgroup_settings(cgroup_settings);
if (!sorted_cgroup_settings)
......@@ -2605,14 +2701,13 @@ __cgfsng_ops static bool cgfsng_setup_limits_legacy(struct cgroup_ops *ops,
if (do_devices == !strncmp("devices", cg->subsystem, 7)) {
if (cg_legacy_set_data(ops, cg->subsystem, cg->value)) {
if (do_devices && (errno == EACCES || errno == EPERM)) {
WARN("Failed to set \"%s\" to \"%s\"",
cg->subsystem, cg->value);
continue;
}
WARN("Failed to set \"%s\" to \"%s\"",
cg->subsystem, cg->value);
goto out;
if (do_devices && (errno == EACCES || errno == EPERM))
log_warn_errno(continue,
errno, "Failed to set \"%s\" to \"%s\"",
cg->subsystem, cg->value);
log_warn_errno(goto out, errno,
"Failed to set \"%s\" to \"%s\"",
cg->subsystem, cg->value);
}
DEBUG("Set controller \"%s\" set to \"%s\"",
cg->subsystem, cg->value);
......@@ -2644,7 +2739,7 @@ static int bpf_device_cgroup_prepare(struct cgroup_ops *ops,
ret = device_cgroup_rule_parse(&device_item, key, val);
if (ret < 0)
return error_log_errno(EINVAL,
return log_error_errno(-1, EINVAL,
"Failed to parse device string %s=%s",
key, val);
......@@ -2658,41 +2753,51 @@ static int bpf_device_cgroup_prepare(struct cgroup_ops *ops,
__cgfsng_ops static bool cgfsng_setup_limits(struct cgroup_ops *ops,
struct lxc_handler *handler)
{
struct lxc_list *iterator;
struct hierarchy *h = ops->unified;
struct lxc_conf *conf = handler->conf;
struct lxc_list *cgroup_settings = &conf->cgroup2;
struct lxc_list *cgroup_settings, *iterator;
struct hierarchy *h;
struct lxc_conf *conf;
if (lxc_list_empty(cgroup_settings))
if (!ops)
return ret_set_errno(false, ENOENT);
if (!ops->hierarchies)
return true;
if (!h)
if (!ops->container_cgroup)
return ret_set_errno(false, EINVAL);
if (!handler || !handler->conf)
return ret_set_errno(false, EINVAL);
conf = handler->conf;
if (lxc_list_empty(&conf->cgroup2))
return true;
cgroup_settings = &conf->cgroup2;
if (!ops->unified)
return false;
h = ops->unified;
lxc_list_for_each (iterator, cgroup_settings) {
__do_free char *fullpath = NULL;
int ret;
struct lxc_cgroup *cg = iterator->elem;
int ret;
if (strncmp("devices", cg->subsystem, 7) == 0) {
ret = bpf_device_cgroup_prepare(ops, conf, cg->subsystem,
cg->value);
} else {
fullpath = must_make_path(h->container_full_path,
cg->subsystem, NULL);
ret = lxc_write_to_file(fullpath, cg->value,
strlen(cg->value), false, 0666);
if (ret < 0) {
SYSERROR("Failed to set \"%s\" to \"%s\"",
cg->subsystem, cg->value);
return false;
}
ret = lxc_write_openat(h->container_full_path,
cg->subsystem, cg->value,
strlen(cg->value));
if (ret < 0)
return log_error_errno(false,
errno, "Failed to set \"%s\" to \"%s\"",
cg->subsystem, cg->value);
}
TRACE("Set \"%s\" to \"%s\"", cg->subsystem, cg->value);
}
INFO("Limits for the unified cgroup hierarchy have been setup");
return true;
return log_info(true, "Limits for the unified cgroup hierarchy have been setup");
}
__cgfsng_ops bool cgfsng_devices_activate(struct cgroup_ops *ops,
......@@ -2700,12 +2805,26 @@ __cgfsng_ops bool cgfsng_devices_activate(struct cgroup_ops *ops,
{
#ifdef HAVE_STRUCT_BPF_CGROUP_DEV_CTX
__do_bpf_program_free struct bpf_program *devices = NULL;
struct lxc_conf *conf = handler->conf;
struct hierarchy *unified = ops->unified;
int ret;
struct lxc_conf *conf;
struct hierarchy *unified;
struct lxc_list *it;
struct bpf_program *devices_old;
if (!ops)
return ret_set_errno(false, ENOENT);
if (!ops->hierarchies)
return true;
if (!ops->container_cgroup)
return ret_set_errno(false, EEXIST);
if (!handler || !handler->conf)
return ret_set_errno(false, EINVAL);
conf = handler->conf;
unified = ops->unified;
if (!unified || !unified->bpf_device_controller ||
!unified->container_full_path || lxc_list_empty(&conf->devices))
return true;
......@@ -2806,10 +2925,10 @@ bool __cgfsng_delegate_controllers(struct cgroup_ops *ops, const char *cgroup)
base_path = must_append_path(base_path, parts[i], NULL);
target = must_make_path(base_path, "cgroup.subtree_control", NULL);
ret = lxc_writeat(-1, target, add_controllers, full_len);
if (ret < 0) {
SYSERROR("Could not enable \"%s\" controllers in the unified cgroup \"%s\"", add_controllers, target);
goto on_error;
}
if (ret < 0)
log_error_errno(goto on_error,
errno, "Could not enable \"%s\" controllers in the unified cgroup \"%s\"",
add_controllers, target);
TRACE("Enable \"%s\" controllers in the unified cgroup \"%s\"", add_controllers, target);
}
......@@ -2822,11 +2941,17 @@ on_error:
__cgfsng_ops bool cgfsng_monitor_delegate_controllers(struct cgroup_ops *ops)
{
if (!ops)
return ret_set_errno(false, ENOENT);
return __cgfsng_delegate_controllers(ops, ops->monitor_cgroup);
}
__cgfsng_ops bool cgfsng_payload_delegate_controllers(struct cgroup_ops *ops)
{
if (!ops)
return ret_set_errno(false, ENOENT);
return __cgfsng_delegate_controllers(ops, ops->container_cgroup);
}
......@@ -2858,37 +2983,37 @@ static bool cgroup_use_wants_controllers(const struct cgroup_ops *ops,
static void cg_unified_delegate(char ***delegate)
{
__do_free char *tmp = NULL;
int idx;
__do_free char *buf = NULL;
char *standard[] = {"cgroup.subtree_control", "cgroup.threads", NULL};
char *token;
int idx;
tmp = read_file("/sys/kernel/cgroup/delegate");
if (!tmp) {
buf = read_file("/sys/kernel/cgroup/delegate");
if (!buf) {
for (char **p = standard; p && *p; p++) {
idx = append_null_to_list((void ***)delegate);
(*delegate)[idx] = must_copy_string(*p);
}
} else {
char *token;
lxc_iterate_parts (token, tmp, " \t\n") {
/*
* We always need to chown this for both cgroup and
* cgroup2.
*/
if (strcmp(token, "cgroup.procs") == 0)
continue;
log_warn_errno(return, errno, "Failed to read /sys/kernel/cgroup/delegate");
}
idx = append_null_to_list((void ***)delegate);
(*delegate)[idx] = must_copy_string(token);
}
lxc_iterate_parts (token, buf, " \t\n") {
/*
* We always need to chown this for both cgroup and
* cgroup2.
*/
if (strcmp(token, "cgroup.procs") == 0)
continue;
idx = append_null_to_list((void ***)delegate);
(*delegate)[idx] = must_copy_string(token);
}
}
/* At startup, parse_hierarchies finds all the info we need about cgroup
* mountpoints and current cgroups, and stores it in @d.
*/
static bool cg_hybrid_init(struct cgroup_ops *ops, bool relative,
bool unprivileged)
static int cg_hybrid_init(struct cgroup_ops *ops, bool relative, bool unprivileged)
{
__do_free char *basecginfo = NULL;
__do_free char *line = NULL;
......@@ -2905,19 +3030,15 @@ static bool cg_hybrid_init(struct cgroup_ops *ops, bool relative,
else
basecginfo = read_file("/proc/self/cgroup");
if (!basecginfo)
return false;
return ret_set_errno(-1, ENOMEM);
ret = get_existing_subsystems(&klist, &nlist);
if (ret < 0) {
ERROR("Failed to retrieve available legacy cgroup controllers");
return false;
}
if (ret < 0)
return log_error_errno(-1, errno, "Failed to retrieve available legacy cgroup controllers");
f = fopen("/proc/self/mountinfo", "r");
if (!f) {
ERROR("Failed to open \"/proc/self/mountinfo\"");
return false;
}
if (!f)
return log_error_errno(-1, errno, "Failed to open \"/proc/self/mountinfo\"");
lxc_cgfsng_print_basecg_debuginfo(basecginfo, klist, nlist);
......@@ -2954,22 +3075,18 @@ static bool cg_hybrid_init(struct cgroup_ops *ops, bool relative,
if (type == CGROUP_SUPER_MAGIC)
if (controller_list_is_dup(ops->hierarchies, controller_list))
goto next;
log_trace_errno(goto next, EEXIST, "Skipping duplicating controller");
mountpoint = cg_hybrid_get_mountpoint(line);
if (!mountpoint) {
ERROR("Failed parsing mountpoint from \"%s\"", line);
goto next;
}
if (!mountpoint)
log_error_errno(goto next, EINVAL, "Failed parsing mountpoint from \"%s\"", line);
if (type == CGROUP_SUPER_MAGIC)
base_cgroup = cg_hybrid_get_current_cgroup(basecginfo, controller_list[0], CGROUP_SUPER_MAGIC);
else
base_cgroup = cg_hybrid_get_current_cgroup(basecginfo, NULL, CGROUP2_SUPER_MAGIC);
if (!base_cgroup) {
ERROR("Failed to find current cgroup");
goto next;
}
if (!base_cgroup)
log_error_errno(goto next, EINVAL, "Failed to find current cgroup");
trim(base_cgroup);
prune_init_scope(base_cgroup);
......@@ -2978,7 +3095,7 @@ static bool cg_hybrid_init(struct cgroup_ops *ops, bool relative,
else
writeable = test_writeable_v1(mountpoint, base_cgroup);
if (!writeable)
goto next;
log_trace_errno(goto next, EROFS, "The %s group is not writeable", base_cgroup);
if (type == CGROUP2_SUPER_MAGIC) {
char *cgv2_ctrl_path;
......@@ -2998,7 +3115,7 @@ static bool cg_hybrid_init(struct cgroup_ops *ops, bool relative,
/* Exclude all controllers that cgroup use does not want. */
if (!cgroup_use_wants_controllers(ops, controller_list))
goto next;
log_trace_errno(goto next, EINVAL, "Skipping controller");
new = add_hierarchy(&ops->hierarchies, controller_list, mountpoint, base_cgroup, type);
if (type == CGROUP2_SUPER_MAGIC && !ops->unified) {
......@@ -3025,9 +3142,9 @@ static bool cg_hybrid_init(struct cgroup_ops *ops, bool relative,
* controllers are accounted for
*/
if (!all_controllers_found(ops))
return false;
return log_error_errno(-1, ENOENT, "Failed to find all required controllers");
return true;
return 0;
}
/* Get current cgroup from /proc/self/cgroup for the cgroupfs v2 hierarchy. */
......@@ -3072,20 +3189,21 @@ static int cg_unified_init(struct cgroup_ops *ops, bool relative,
ret = unified_cgroup_hierarchy();
if (ret == -ENOMEDIUM)
return -ENOMEDIUM;
return ret_errno(ENOMEDIUM);
if (ret != CGROUP2_SUPER_MAGIC)
return 0;
base_cgroup = cg_unified_get_current_cgroup(relative);
if (!base_cgroup)
return -EINVAL;
return ret_errno(EINVAL);
if (!relative)
prune_init_scope(base_cgroup);
/* We assume that we have already been given controllers to delegate
* further down the hierarchy. If not it is up to the user to delegate
* them to us.
/*
* We assume that the cgroup we're currently in has been delegated to
* us and we are free to further delege all of the controllers listed
* in cgroup.controllers further down the hierarchy.
*/
mountpoint = must_copy_string(DEFAULT_CGROUP_MOUNTPOINT);
subtree_path = must_make_path(mountpoint, base_cgroup, "cgroup.controllers", NULL);
......@@ -3103,7 +3221,7 @@ static int cg_unified_init(struct cgroup_ops *ops, bool relative,
*/
new = add_hierarchy(&ops->hierarchies, delegatable, mountpoint, base_cgroup, CGROUP2_SUPER_MAGIC);
if (!unprivileged)
if (unprivileged)
cg_unified_delegate(&new->cgroup2_chown);
if (bpf_devices_cgroup_supported())
......@@ -3114,7 +3232,7 @@ static int cg_unified_init(struct cgroup_ops *ops, bool relative,
return CGROUP2_SUPER_MAGIC;
}
static bool cg_init(struct cgroup_ops *ops, struct lxc_conf *conf)
static int cg_init(struct cgroup_ops *ops, struct lxc_conf *conf)
{
int ret;
const char *tmp;
......@@ -3134,29 +3252,32 @@ static bool cg_init(struct cgroup_ops *ops, struct lxc_conf *conf)
ret = cg_unified_init(ops, relative, !lxc_list_empty(&conf->id_map));
if (ret < 0)
return false;
return -1;
if (ret == CGROUP2_SUPER_MAGIC)
return true;
return 0;
return cg_hybrid_init(ops, relative, !lxc_list_empty(&conf->id_map));
}
__cgfsng_ops static bool cgfsng_data_init(struct cgroup_ops *ops)
__cgfsng_ops static int cgfsng_data_init(struct cgroup_ops *ops)
{
const char *cgroup_pattern;
if (!ops)
return ret_set_errno(-1, ENOENT);
/* copy system-wide cgroup information */
cgroup_pattern = lxc_global_config_value("lxc.cgroup.pattern");
if (!cgroup_pattern) {
/* lxc.cgroup.pattern is only NULL on error. */
ERROR("Failed to retrieve cgroup pattern");
return false;
return ret_set_errno(-1, ENOMEM);
}
ops->cgroup_pattern = must_copy_string(cgroup_pattern);
ops->monitor_pattern = MONITOR_CGROUP;
return true;
return 0;
}
struct cgroup_ops *cgfsng_ops_init(struct lxc_conf *conf)
......@@ -3165,12 +3286,12 @@ struct cgroup_ops *cgfsng_ops_init(struct lxc_conf *conf)
cgfsng_ops = malloc(sizeof(struct cgroup_ops));
if (!cgfsng_ops)
return NULL;
return ret_set_errno(NULL, ENOMEM);
memset(cgfsng_ops, 0, sizeof(struct cgroup_ops));
cgfsng_ops->cgroup_layout = CGROUP_LAYOUT_UNKNOWN;
if (!cg_init(cgfsng_ops, conf))
if (cg_init(cgfsng_ops, conf))
return NULL;
cgfsng_ops->unified_fd = -EBADF;
......
......@@ -24,19 +24,16 @@ struct cgroup_ops *cgroup_init(struct lxc_conf *conf)
{
struct cgroup_ops *cgroup_ops;
if (!conf) {
ERROR("No valid conf given");
return NULL;
}
if (!conf)
return log_error_errno(NULL, EINVAL, "No valid conf given");
cgroup_ops = cgfsng_ops_init(conf);
if (!cgroup_ops) {
ERROR("Failed to initialize cgroup driver");
return NULL;
}
if (!cgroup_ops)
return log_error_errno(NULL, errno, "Failed to initialize cgroup driver");
if (!cgroup_ops->data_init(cgroup_ops))
return NULL;
if (cgroup_ops->data_init(cgroup_ops))
return log_error_errno(NULL, errno,
"Failed to initialize cgroup data");
TRACE("Initialized cgroup driver %s", cgroup_ops->driver);
......
......@@ -132,7 +132,7 @@ struct cgroup_ops {
*/
cgroup_layout_t cgroup_layout;
bool (*data_init)(struct cgroup_ops *ops);
int (*data_init)(struct cgroup_ops *ops);
void (*payload_destroy)(struct cgroup_ops *ops, struct lxc_handler *handler);
void (*monitor_destroy)(struct cgroup_ops *ops, struct lxc_handler *handler);
bool (*monitor_create)(struct cgroup_ops *ops, struct lxc_handler *handler);
......
......@@ -35,11 +35,11 @@ static int bpf_program_add_instructions(struct bpf_program *prog,
struct bpf_insn *new_insn;
if (prog->kernel_fd >= 0)
return error_log_errno(EBUSY, "Refusing to update bpf cgroup program that's already loaded");
return log_error_errno(-1, EBUSY, "Refusing to update bpf cgroup program that's already loaded");
new_insn = realloc(prog->instructions, sizeof(struct bpf_insn) * (count + prog->n_instructions));
if (!new_insn)
return error_log_errno(ENOMEM, "Failed to reallocate bpf cgroup program");
return log_error_errno(-1, ENOMEM, "Failed to reallocate bpf cgroup program");
prog->instructions = new_insn;
memcpy(prog->instructions + prog->n_instructions, instructions,
......@@ -184,7 +184,7 @@ struct bpf_program *bpf_program_new(uint32_t prog_type)
int bpf_program_init(struct bpf_program *prog)
{
if (!prog)
return minus_one_set_errno(EINVAL);
return ret_set_errno(-1, EINVAL);
const struct bpf_insn pre_insn[] = {
/* load device type to r2 */
......@@ -217,7 +217,7 @@ int bpf_program_append_device(struct bpf_program *prog, struct device_item *devi
int device_type;
if (!prog || !device)
return minus_one_set_errno(EINVAL);
return ret_set_errno(-1, EINVAL);
/* This is a global rule so no need to append anything. */
if (device->global_rule > LXC_BPF_DEVICE_CGROUP_LOCAL_RULE) {
......@@ -227,7 +227,7 @@ int bpf_program_append_device(struct bpf_program *prog, struct device_item *devi
device_type = bpf_device_type(device->type);
if (device_type < 0)
return error_log_errno(EINVAL, "Invalid bpf cgroup device type %c", device->type);
return log_error_errno(-1, EINVAL, "Invalid bpf cgroup device type %c", device->type);
if (device_type > 0)
jump_nr++;
......@@ -249,7 +249,7 @@ int bpf_program_append_device(struct bpf_program *prog, struct device_item *devi
ret = bpf_program_add_instructions(prog, ins, ARRAY_SIZE(ins));
if (ret)
return error_log_errno(errno, "Failed to add instructions to bpf cgroup program");
return log_error_errno(-1, errno, "Failed to add instructions to bpf cgroup program");
}
if (!bpf_device_all_access(access_mask)) {
......@@ -262,7 +262,7 @@ int bpf_program_append_device(struct bpf_program *prog, struct device_item *devi
jump_nr -= 3;
ret = bpf_program_add_instructions(prog, ins, ARRAY_SIZE(ins));
if (ret)
return error_log_errno(errno, "Failed to add instructions to bpf cgroup program");
return log_error_errno(-1, errno, "Failed to add instructions to bpf cgroup program");
}
if (device->major >= 0) {
......@@ -272,7 +272,7 @@ int bpf_program_append_device(struct bpf_program *prog, struct device_item *devi
ret = bpf_program_add_instructions(prog, ins, ARRAY_SIZE(ins));
if (ret)
return error_log_errno(errno, "Failed to add instructions to bpf cgroup program");
return log_error_errno(-1, errno, "Failed to add instructions to bpf cgroup program");
}
if (device->minor >= 0) {
......@@ -282,13 +282,13 @@ int bpf_program_append_device(struct bpf_program *prog, struct device_item *devi
ret = bpf_program_add_instructions(prog, ins, ARRAY_SIZE(ins));
if (ret)
return error_log_errno(errno, "Failed to add instructions to bpf cgroup program");
return log_error_errno(-1, errno, "Failed to add instructions to bpf cgroup program");
}
ret = bpf_program_add_instructions(prog, bpf_access_decision,
ARRAY_SIZE(bpf_access_decision));
if (ret)
return error_log_errno(errno, "Failed to add instructions to bpf cgroup program");
return log_error_errno(-1, errno, "Failed to add instructions to bpf cgroup program");
return 0;
}
......@@ -301,7 +301,7 @@ int bpf_program_finalize(struct bpf_program *prog)
};
if (!prog)
return minus_one_set_errno(EINVAL);
return ret_set_errno(-1, EINVAL);
TRACE("Implementing %s bpf device cgroup program",
prog->device_list_type == LXC_BPF_DEVICE_CGROUP_BLACKLIST
......@@ -332,7 +332,7 @@ static int bpf_program_load_kernel(struct bpf_program *prog, char *log_buf,
prog->kernel_fd = bpf(BPF_PROG_LOAD, &attr, sizeof(attr));
if (prog->kernel_fd < 0)
return error_log_errno(errno, "Failed to load bpf program");
return log_error_errno(-1, errno, "Failed to load bpf program");
return 0;
}
......@@ -346,17 +346,17 @@ int bpf_program_cgroup_attach(struct bpf_program *prog, int type,
int ret;
if (!prog)
return minus_one_set_errno(EINVAL);
return ret_set_errno(-1, EINVAL);
if (flags & ~(BPF_F_ALLOW_OVERRIDE, BPF_F_ALLOW_MULTI))
return error_log_errno(EINVAL, "Invalid flags for bpf program");
return log_error_errno(-1, EINVAL, "Invalid flags for bpf program");
if (prog->attached_path) {
if (prog->attached_type != type)
return error_log_errno(EBUSY, "Wrong type for bpf program");
return log_error_errno(-1, EBUSY, "Wrong type for bpf program");
if (prog->attached_flags != flags)
return error_log_errno(EBUSY, "Wrong flags for bpf program");
return log_error_errno(-1, EBUSY, "Wrong flags for bpf program");
if (flags != BPF_F_ALLOW_OVERRIDE)
return true;
......@@ -364,15 +364,15 @@ int bpf_program_cgroup_attach(struct bpf_program *prog, int type,
ret = bpf_program_load_kernel(prog, NULL, 0);
if (ret < 0)
return error_log_errno(ret, "Failed to load bpf program");
return log_error_errno(-1, ret, "Failed to load bpf program");
copy = strdup(path);
if (!copy)
return error_log_errno(ENOMEM, "Failed to duplicate cgroup path %s", path);
return log_error_errno(-1, ENOMEM, "Failed to duplicate cgroup path %s", path);
fd = open(path, O_DIRECTORY | O_RDONLY | O_CLOEXEC);
if (fd < 0)
return error_log_errno(errno, "Failed to open cgroup path %s", path);
return log_error_errno(-1, errno, "Failed to open cgroup path %s", path);
attr = (union bpf_attr){
.attach_type = type,
......@@ -383,7 +383,7 @@ int bpf_program_cgroup_attach(struct bpf_program *prog, int type,
ret = bpf(BPF_PROG_ATTACH, &attr, sizeof(attr));
if (ret < 0)
return error_log_errno(errno, "Failed to attach bpf program");
return log_error_errno(-1, errno, "Failed to attach bpf program");
free_replace_move_ptr(prog->attached_path, copy);
prog->attached_type = type;
......@@ -407,7 +407,7 @@ int bpf_program_cgroup_detach(struct bpf_program *prog)
fd = open(prog->attached_path, O_DIRECTORY | O_RDONLY | O_CLOEXEC);
if (fd < 0) {
if (errno != ENOENT)
return error_log_errno(errno, "Failed to open attach cgroup %s",
return log_error_errno(-1, errno, "Failed to open attach cgroup %s",
prog->attached_path);
} else {
union bpf_attr attr;
......@@ -420,7 +420,7 @@ int bpf_program_cgroup_detach(struct bpf_program *prog)
ret = bpf(BPF_PROG_DETACH, &attr, sizeof(attr));
if (ret < 0)
return error_log_errno(errno, "Failed to detach bpf program from cgroup %s",
return log_error_errno(-1, errno, "Failed to detach bpf program from cgroup %s",
prog->attached_path);
}
......@@ -488,11 +488,11 @@ int bpf_list_add_device(struct lxc_conf *conf, struct device_item *device)
list_elem = malloc(sizeof(*list_elem));
if (!list_elem)
return error_log_errno(ENOMEM, "Failed to allocate new device list");
return log_error_errno(-1, ENOMEM, "Failed to allocate new device list");
new_device = memdup(device, sizeof(struct device_item));
if (!new_device)
return error_log_errno(ENOMEM, "Failed to allocate new device item");
return log_error_errno(-1, ENOMEM, "Failed to allocate new device item");
lxc_list_add_elem(list_elem, move_ptr(new_device));
lxc_list_add_tail(&conf->devices, move_ptr(list_elem));
......
......@@ -913,16 +913,16 @@ int lxc_cmd_add_bpf_device_cgroup(const char *name, const char *lxcpath,
int ret;
if (strlen(device->access) > STRLITERALLEN("rwm"))
return error_log_errno(EINVAL, "Invalid access mode specified %s",
return log_error_errno(-1, EINVAL, "Invalid access mode specified %s",
device->access);
ret = lxc_cmd(name, &cmd, &stopped, lxcpath, NULL);
if (ret < 0 || cmd.rsp.ret < 0)
return error_log_errno(errno, "Failed to add new bpf device cgroup rule");
return log_error_errno(-1, errno, "Failed to add new bpf device cgroup rule");
return 0;
#else
return minus_one_set_errno(ENOSYS);
return ret_set_errno(-1, ENOSYS);
#endif
}
......@@ -1006,7 +1006,7 @@ reap_client_fd:
*/
return 1;
#else
return minus_one_set_errno(ENOSYS);
return ret_set_errno(-1, ENOSYS);
#endif
}
......@@ -1155,7 +1155,7 @@ int lxc_cmd_seccomp_notify_add_listener(const char *name, const char *lxcpath,
return cmd.rsp.ret;
#else
return minus_one_set_errno(ENOSYS);
return ret_set_errno(-1, ENOSYS);
#endif
}
......@@ -1211,7 +1211,7 @@ int lxc_cmd_freeze(const char *name, const char *lxcpath, int timeout)
ret = lxc_cmd(name, &cmd, &stopped, lxcpath, NULL);
if (ret <= 0 || cmd.rsp.ret < 0)
return error_log_errno(errno, "Failed to freeze container");
return log_error_errno(-1, errno, "Failed to freeze container");
return cmd.rsp.ret;
}
......@@ -1244,7 +1244,7 @@ int lxc_cmd_unfreeze(const char *name, const char *lxcpath, int timeout)
ret = lxc_cmd(name, &cmd, &stopped, lxcpath, NULL);
if (ret <= 0 || cmd.rsp.ret < 0)
return error_log_errno(errno, "Failed to unfreeze container");
return log_error_errno(-1, errno, "Failed to unfreeze container");
return cmd.rsp.ret;
}
......
......@@ -45,6 +45,13 @@
#define __returns_twice __attribute__((returns_twice))
#endif
/* This attribute is required to silence clang warnings */
#if defined(__GNUC__)
#define __lxc_unused __attribute__ ((unused))
#else
#define __lxc_unused
#endif
#define __cgfsng_ops
#endif /* __LXC_COMPILER_H */
......@@ -401,11 +401,11 @@ static int set_config_net_l2proxy(const char *key, const char *value,
return clr_config_net_l2proxy(key, lxc_conf, data);
if (!netdev)
return minus_one_set_errno(EINVAL);
return ret_set_errno(-1, EINVAL);
ret = lxc_safe_uint(value, &val);
if (ret < 0)
return minus_one_set_errno(-ret);
return ret_set_errno(-1, -ret);
switch (val) {
case 0:
......@@ -416,7 +416,7 @@ static int set_config_net_l2proxy(const char *key, const char *value,
return 0;
}
return minus_one_set_errno(EINVAL);
return ret_set_errno(-1, EINVAL);
}
static int set_config_net_name(const char *key, const char *value,
......@@ -485,11 +485,11 @@ static int set_config_net_ipvlan_mode(const char *key, const char *value,
return clr_config_net_ipvlan_mode(key, lxc_conf, data);
if (!netdev)
return minus_one_set_errno(EINVAL);
return ret_set_errno(-1, EINVAL);
if (netdev->type != LXC_NET_IPVLAN) {
SYSERROR("Invalid ipvlan mode \"%s\", can only be used with ipvlan network", value);
return minus_one_set_errno(EINVAL);
return ret_set_errno(-1, EINVAL);
}
return lxc_ipvlan_mode_to_flag(&netdev->priv.ipvlan_attr.mode, value);
......@@ -504,11 +504,11 @@ static int set_config_net_ipvlan_isolation(const char *key, const char *value,
return clr_config_net_ipvlan_isolation(key, lxc_conf, data);
if (!netdev)
return minus_one_set_errno(EINVAL);
return ret_set_errno(-1, EINVAL);
if (netdev->type != LXC_NET_IPVLAN) {
SYSERROR("Invalid ipvlan isolation \"%s\", can only be used with ipvlan network", value);
return minus_one_set_errno(EINVAL);
return ret_set_errno(-1, EINVAL);
}
return lxc_ipvlan_isolation_to_flag(&netdev->priv.ipvlan_attr.isolation, value);
......@@ -729,11 +729,11 @@ static int set_config_net_veth_ipv4_route(const char *key, const char *value,
return clr_config_net_veth_ipv4_route(key, lxc_conf, data);
if (!netdev)
return minus_one_set_errno(EINVAL);
return ret_set_errno(-1, EINVAL);
if (netdev->type != LXC_NET_VETH) {
SYSERROR("Invalid ipv4 route \"%s\", can only be used with veth network", value);
return minus_one_set_errno(EINVAL);
return ret_set_errno(-1, EINVAL);
}
inetdev = malloc(sizeof(*inetdev));
......@@ -754,22 +754,22 @@ static int set_config_net_veth_ipv4_route(const char *key, const char *value,
slash = strchr(valdup, '/');
if (!slash)
return minus_one_set_errno(EINVAL);
return ret_set_errno(-1, EINVAL);
*slash = '\0';
slash++;
if (*slash == '\0')
return minus_one_set_errno(EINVAL);
return ret_set_errno(-1, EINVAL);
netmask = slash;
ret = lxc_safe_uint(netmask, &inetdev->prefix);
if (ret < 0 || inetdev->prefix > 32)
return minus_one_set_errno(EINVAL);
return ret_set_errno(-1, EINVAL);
ret = inet_pton(AF_INET, valdup, &inetdev->addr);
if (!ret || ret < 0)
return minus_one_set_errno(EINVAL);
return ret_set_errno(-1, EINVAL);
lxc_list_add_tail(&netdev->priv.veth_attr.ipv4_routes, list);
move_ptr(inetdev);
......@@ -900,11 +900,11 @@ static int set_config_net_veth_ipv6_route(const char *key, const char *value,
return clr_config_net_veth_ipv6_route(key, lxc_conf, data);
if (!netdev)
return minus_one_set_errno(EINVAL);
return ret_set_errno(-1, EINVAL);
if (netdev->type != LXC_NET_VETH) {
SYSERROR("Invalid ipv6 route \"%s\", can only be used with veth network", value);
return minus_one_set_errno(EINVAL);
return ret_set_errno(-1, EINVAL);
}
inet6dev = malloc(sizeof(*inet6dev));
......@@ -925,22 +925,22 @@ static int set_config_net_veth_ipv6_route(const char *key, const char *value,
slash = strchr(valdup, '/');
if (!slash)
return minus_one_set_errno(EINVAL);
return ret_set_errno(-1, EINVAL);
*slash = '\0';
slash++;
if (*slash == '\0')
return minus_one_set_errno(EINVAL);
return ret_set_errno(-1, EINVAL);
netmask = slash;
ret = lxc_safe_uint(netmask, &inet6dev->prefix);
if (ret < 0 || inet6dev->prefix > 128)
return minus_one_set_errno(EINVAL);
return ret_set_errno(-1, EINVAL);
ret = inet_pton(AF_INET6, valdup, &inet6dev->addr);
if (!ret || ret < 0)
return minus_one_set_errno(EINVAL);
return ret_set_errno(-1, EINVAL);
lxc_list_add_tail(&netdev->priv.veth_attr.ipv6_routes, list);
move_ptr(inet6dev);
......@@ -1004,7 +1004,7 @@ static int set_config_seccomp_allow_nesting(const char *key, const char *value,
return -1;
if (lxc_conf->seccomp.allow_nesting > 1)
return minus_one_set_errno(EINVAL);
return ret_set_errno(-1, EINVAL);
return 0;
#else
......@@ -1019,7 +1019,7 @@ static int set_config_seccomp_notify_cookie(const char *key, const char *value,
#ifdef HAVE_SECCOMP_NOTIFY
return set_config_string_item(&lxc_conf->seccomp.notifier.cookie, value);
#else
return minus_one_set_errno(ENOSYS);
return ret_set_errno(-1, ENOSYS);
#endif
}
......@@ -1033,7 +1033,7 @@ static int set_config_seccomp_notify_proxy(const char *key, const char *value,
return clr_config_seccomp_notify_proxy(key, lxc_conf, NULL);
if (strncmp(value, "unix:", 5) != 0)
return minus_one_set_errno(EINVAL);
return ret_set_errno(-1, EINVAL);
offset = value + 5;
if (lxc_unix_sockaddr(&lxc_conf->seccomp.notifier.proxy_addr, offset) < 0)
......@@ -1041,7 +1041,7 @@ static int set_config_seccomp_notify_proxy(const char *key, const char *value,
return 0;
#else
return minus_one_set_errno(ENOSYS);
return ret_set_errno(-1, ENOSYS);
#endif
}
......@@ -3985,7 +3985,7 @@ static int get_config_seccomp_notify_cookie(const char *key, char *retv, int inl
#ifdef HAVE_SECCOMP_NOTIFY
return lxc_get_conf_str(retv, inlen, c->seccomp.notifier.cookie);
#else
return minus_one_set_errno(ENOSYS);
return ret_set_errno(-1, ENOSYS);
#endif
}
......@@ -3998,7 +3998,7 @@ static int get_config_seccomp_notify_proxy(const char *key, char *retv, int inle
? &c->seccomp.notifier.proxy_addr.sun_path[0]
: &c->seccomp.notifier.proxy_addr.sun_path[1]);
#else
return minus_one_set_errno(ENOSYS);
return ret_set_errno(-1, ENOSYS);
#endif
}
......@@ -4611,7 +4611,7 @@ static inline int clr_config_seccomp_notify_cookie(const char *key,
c->seccomp.notifier.cookie = NULL;
return 0;
#else
return minus_one_set_errno(ENOSYS);
return ret_set_errno(-1, ENOSYS);
#endif
}
......@@ -4623,7 +4623,7 @@ static inline int clr_config_seccomp_notify_proxy(const char *key,
sizeof(c->seccomp.notifier.proxy_addr));
return 0;
#else
return minus_one_set_errno(ENOSYS);
return ret_set_errno(-1, ENOSYS);
#endif
}
......@@ -5064,7 +5064,7 @@ static int clr_config_net_l2proxy(const char *key, struct lxc_conf *lxc_conf,
struct lxc_netdev *netdev = data;
if (!netdev)
return minus_one_set_errno(EINVAL);
return ret_set_errno(-1, EINVAL);
netdev->l2proxy = false;
......@@ -5093,7 +5093,7 @@ static int clr_config_net_ipvlan_mode(const char *key,
struct lxc_netdev *netdev = data;
if (!netdev)
return minus_one_set_errno(EINVAL);
return ret_set_errno(-1, EINVAL);
if (netdev->type != LXC_NET_IPVLAN)
return 0;
......@@ -5109,7 +5109,7 @@ static int clr_config_net_ipvlan_isolation(const char *key,
struct lxc_netdev *netdev = data;
if (!netdev)
return minus_one_set_errno(EINVAL);
return ret_set_errno(-1, EINVAL);
if (netdev->type != LXC_NET_IPVLAN)
return 0;
......@@ -5125,7 +5125,7 @@ static int clr_config_net_veth_mode(const char *key,
struct lxc_netdev *netdev = data;
if (!netdev)
return minus_one_set_errno(EINVAL);
return ret_set_errno(-1, EINVAL);
if (netdev->type != LXC_NET_VETH)
return 0;
......@@ -5493,7 +5493,7 @@ static int get_config_net_ipvlan_mode(const char *key, char *retv, int inlen,
memset(retv, 0, inlen);
if (!netdev)
return minus_one_set_errno(EINVAL);
return ret_set_errno(-1, EINVAL);
if (netdev->type != LXC_NET_IPVLAN)
return 0;
......@@ -5532,7 +5532,7 @@ static int get_config_net_ipvlan_isolation(const char *key, char *retv, int inle
memset(retv, 0, inlen);
if (!netdev)
return minus_one_set_errno(EINVAL);
return ret_set_errno(-1, EINVAL);
if (netdev->type != LXC_NET_IPVLAN)
return 0;
......@@ -5571,7 +5571,7 @@ static int get_config_net_veth_mode(const char *key, char *retv, int inlen,
memset(retv, 0, inlen);
if (!netdev)
return minus_one_set_errno(EINVAL);
return ret_set_errno(-1, EINVAL);
if (netdev->type != LXC_NET_VETH)
return 0;
......@@ -5800,7 +5800,7 @@ static int get_config_net_veth_ipv4_route(const char *key, char *retv, int inlen
memset(retv, 0, inlen);
if (!netdev)
return minus_one_set_errno(EINVAL);
return ret_set_errno(-1, EINVAL);
if (netdev->type != LXC_NET_VETH)
return 0;
......@@ -5891,7 +5891,7 @@ static int get_config_net_veth_ipv6_route(const char *key, char *retv, int inlen
memset(retv, 0, inlen);
if (!netdev)
return minus_one_set_errno(EINVAL);
return ret_set_errno(-1, EINVAL);
if (netdev->type != LXC_NET_VETH)
return 0;
......
......@@ -503,7 +503,7 @@ int lxc_veth_mode_to_flag(int *mode, const char *value)
return 0;
}
return minus_one_set_errno(EINVAL);
return ret_set_errno(-1, EINVAL);
}
static struct lxc_macvlan_mode {
......
......@@ -18,6 +18,27 @@
#include "string_utils.h"
#include "utils.h"
int lxc_open_dirfd(const char *dir)
{
return open(dir, O_DIRECTORY | O_RDONLY | O_CLOEXEC);
}
int lxc_readat(int dirfd, const char *filename, void *buf, size_t count)
{
__do_close_prot_errno int fd = -EBADF;
ssize_t ret;
fd = openat(dirfd, filename, O_RDONLY | O_CLOEXEC);
if (fd < 0)
return -1;
ret = lxc_read_nointr(fd, buf, count);
if (ret < 0 || (size_t)ret != count)
return -1;
return 0;
}
int lxc_writeat(int dirfd, const char *filename, const void *buf, size_t count)
{
__do_close_prot_errno int fd = -EBADF;
......@@ -34,6 +55,18 @@ int lxc_writeat(int dirfd, const char *filename, const void *buf, size_t count)
return 0;
}
int lxc_write_openat(const char *dir, const char *filename, const void *buf,
size_t count)
{
__do_close_prot_errno int dirfd = -EBADF;
dirfd = open(dir, O_DIRECTORY | O_RDONLY | O_CLOEXEC);
if (dirfd < 0)
return -1;
return lxc_writeat(dirfd, filename, buf, count);
}
int lxc_write_to_file(const char *filename, const void *buf, size_t count,
bool add_newline, mode_t mode)
{
......
......@@ -15,8 +15,11 @@
/* read and write whole files */
extern int lxc_write_to_file(const char *filename, const void *buf,
size_t count, bool add_newline, mode_t mode);
extern int lxc_readat(int dirfd, const char *filename, void *buf, size_t count);
extern int lxc_writeat(int dirfd, const char *filename, const void *buf,
size_t count);
extern int lxc_write_openat(const char *dir, const char *filename,
const void *buf, size_t count);
extern int lxc_read_from_file(const char *filename, void *buf, size_t count);
/* send and receive buffers completely */
......@@ -47,5 +50,6 @@ extern ssize_t lxc_sendfile_nointr(int out_fd, int in_fd, off_t *offset,
size_t count);
extern char *file_to_buf(char *path, size_t *length);
extern int fd_to_fd(int from, int to);
extern int lxc_open_dirfd(const char *dir);
#endif /* __LXC_FILE_UTILS_H */
......@@ -26,13 +26,6 @@
#define LXC_LOG_PREFIX_SIZE 32
#define LXC_LOG_BUFFER_SIZE 4096
/* This attribute is required to silence clang warnings */
#if defined(__GNUC__)
#define ATTR_UNUSED __attribute__ ((unused))
#else
#define ATTR_UNUSED
#endif
/* predefined lxc log priorities. */
enum lxc_loglevel {
LXC_LOG_LEVEL_TRACE,
......@@ -245,10 +238,10 @@ static inline void __lxc_log(const struct lxc_log_category *category,
*/
#define lxc_log_priority_define(acategory, LEVEL) \
\
ATTR_UNUSED __attribute__ ((format (printf, 2, 3))) \
__lxc_unused __attribute__ ((format (printf, 2, 3))) \
static inline void LXC_##LEVEL(struct lxc_log_locinfo *, const char *, ...); \
\
ATTR_UNUSED static inline void LXC_##LEVEL(struct lxc_log_locinfo* locinfo, \
__lxc_unused static inline void LXC_##LEVEL(struct lxc_log_locinfo* locinfo, \
const char* format, ...) \
{ \
if (lxc_log_priority_is_enabled(acategory, LXC_LOG_LEVEL_##LEVEL)) { \
......@@ -484,19 +477,6 @@ ATTR_UNUSED static inline void LXC_##LEVEL(struct lxc_log_locinfo* locinfo, \
} while (0)
#endif
#define error_log_errno(__errno__, format, ...) \
({ \
errno = __errno__; \
SYSERROR(format, ##__VA_ARGS__); \
-1; \
})
#define log_trace(__ret__, format, ...) \
({ \
TRACE(format, ##__VA_ARGS__); \
__ret__; \
})
#define log_error_errno(__ret__, __errno__, format, ...) \
({ \
errno = __errno__; \
......@@ -510,6 +490,19 @@ ATTR_UNUSED static inline void LXC_##LEVEL(struct lxc_log_locinfo* locinfo, \
__ret__; \
})
#define log_trace_errno(__ret__, __errno__, format, ...) \
({ \
errno = __errno__; \
SYSTRACE(format, ##__VA_ARGS__); \
__ret__; \
})
#define log_trace(__ret__, format, ...) \
({ \
TRACE(format, ##__VA_ARGS__); \
__ret__; \
})
#define log_warn_errno(__ret__, __errno__, format, ...) \
({ \
errno = __errno__; \
......@@ -517,16 +510,30 @@ ATTR_UNUSED static inline void LXC_##LEVEL(struct lxc_log_locinfo* locinfo, \
__ret__; \
})
#define log_debug_errno(__ret__, __errno__, format, ...) \
({ \
errno = __errno__; \
SYSDEBUG(format, ##__VA_ARGS__); \
__ret__; \
})
#define log_debug(__ret__, format, ...) \
({ \
DEBUG(format, ##__VA_ARGS__); \
__ret__; \
})
#define log_debug_errno(__ret__, __errno__, format, ...) \
({ \
SYSDEBUG(format, ##__VA_ARGS__); \
__ret__; \
#define log_info_errno(__ret__, __errno__, format, ...) \
({ \
errno = __errno__; \
SYSINFO(format, ##__VA_ARGS__); \
__ret__; \
})
#define log_info(__ret__, format, ...) \
({ \
INFO(format, ##__VA_ARGS__); \
__ret__; \
})
extern int lxc_log_fd;
......
......@@ -5262,7 +5262,7 @@ out:
static int do_lxcapi_seccomp_notify_fd(struct lxc_container *c)
{
if (!c || !c->lxc_conf)
return minus_one_set_errno(-EINVAL);
return ret_set_errno(-1, -EINVAL);
return lxc_seccomp_get_notify_fd(&c->lxc_conf->seccomp);
}
......
......@@ -442,18 +442,18 @@ enum {
__internal_fd__; \
})
#define minus_one_set_errno(__errno__) \
({ \
errno = __errno__; \
-1; \
})
#define ret_set_errno(__ret__, __errno__) \
({ \
errno = __errno__; \
__ret__; \
})
#define ret_errno(__errno__) \
({ \
errno = __errno__; \
-__errno__; \
})
#define free_replace_move_ptr(a, b) \
({ \
free(a); \
......
......@@ -131,7 +131,7 @@ static int lxc_setup_ipv4_routes(struct lxc_list *ip, int ifindex)
if (err) {
SYSERROR("Failed to setup ipv4 route for network device "
"with ifindex %d", ifindex);
return minus_one_set_errno(-err);
return ret_set_errno(-1, -err);
}
}
......@@ -150,7 +150,7 @@ static int lxc_setup_ipv6_routes(struct lxc_list *ip, int ifindex)
if (err) {
SYSERROR("Failed to setup ipv6 route for network device "
"with ifindex %d", ifindex);
return minus_one_set_errno(-err);
return ret_set_errno(-1, -err);
}
}
......@@ -168,7 +168,7 @@ static int setup_ipv4_addr_routes(struct lxc_list *ip, int ifindex)
err = lxc_ipv4_dest_add(ifindex, &inetdev->addr, 32);
if (err)
return error_log_errno(err,
return log_error_errno(-1, err,
"Failed to setup ipv4 address route for network device with eifindex %d",
ifindex);
}
......@@ -186,7 +186,7 @@ static int setup_ipv6_addr_routes(struct lxc_list *ip, int ifindex)
err = lxc_ipv6_dest_add(ifindex, &inet6dev->addr, 128);
if (err)
return error_log_errno(err,
return log_error_errno(-1, err,
"Failed to setup ipv6 address route for network device with eifindex %d",
ifindex);
}
......@@ -258,13 +258,13 @@ static int lxc_is_ip_forwarding_enabled(const char *ifname, int family)
char buf[1] = "";
if (family != AF_INET && family != AF_INET6)
return minus_one_set_errno(EINVAL);
return ret_set_errno(-1, EINVAL);
ret = snprintf(path, PATH_MAX, "/proc/sys/net/%s/conf/%s/%s",
family == AF_INET ? "ipv4" : "ipv6", ifname,
"forwarding");
if (ret < 0 || (size_t)ret >= PATH_MAX)
return minus_one_set_errno(E2BIG);
return ret_set_errno(-1, E2BIG);
return lxc_read_file_expect(path, buf, 1, "1");
}
......@@ -401,19 +401,19 @@ static int instantiate_veth(struct lxc_handler *handler, struct lxc_netdev *netd
if (netdev->ipv4_gateway) {
char bufinet4[INET_ADDRSTRLEN];
if (!inet_ntop(AF_INET, netdev->ipv4_gateway, bufinet4, sizeof(bufinet4))) {
error_log_errno(-errno, "Failed to convert gateway ipv4 address on \"%s\"", veth1);
log_error_errno(-1, -errno, "Failed to convert gateway ipv4 address on \"%s\"", veth1);
goto out_delete;
}
err = lxc_ip_forwarding_on(veth1, AF_INET);
if (err) {
error_log_errno(err, "Failed to activate ipv4 forwarding on \"%s\"", veth1);
log_error_errno(-1, err, "Failed to activate ipv4 forwarding on \"%s\"", veth1);
goto out_delete;
}
err = lxc_add_ip_neigh_proxy(bufinet4, veth1);
if (err) {
error_log_errno(err, "Failed to add gateway ipv4 proxy on \"%s\"", veth1);
log_error_errno(-1, err, "Failed to add gateway ipv4 proxy on \"%s\"", veth1);
goto out_delete;
}
}
......@@ -422,7 +422,7 @@ static int instantiate_veth(struct lxc_handler *handler, struct lxc_netdev *netd
char bufinet6[INET6_ADDRSTRLEN];
if (!inet_ntop(AF_INET6, netdev->ipv6_gateway, bufinet6, sizeof(bufinet6))) {
error_log_errno(-errno, "Failed to convert gateway ipv6 address on \"%s\"", veth1);
log_error_errno(-1, -errno, "Failed to convert gateway ipv6 address on \"%s\"", veth1);
goto out_delete;
}
......@@ -431,25 +431,25 @@ static int instantiate_veth(struct lxc_handler *handler, struct lxc_netdev *netd
*/
err = lxc_is_ip_forwarding_enabled("all", AF_INET6);
if (err) {
error_log_errno(err, "Requires sysctl net.ipv6.conf.all.forwarding=1");
log_error_errno(-1, err, "Requires sysctl net.ipv6.conf.all.forwarding=1");
goto out_delete;
}
err = lxc_ip_forwarding_on(veth1, AF_INET6);
if (err) {
error_log_errno(err, "Failed to activate ipv6 forwarding on \"%s\"", veth1);
log_error_errno(-1, err, "Failed to activate ipv6 forwarding on \"%s\"", veth1);
goto out_delete;
}
err = lxc_neigh_proxy_on(veth1, AF_INET6);
if (err) {
error_log_errno(err, "Failed to activate proxy ndp on \"%s\"", veth1);
log_error_errno(-1, err, "Failed to activate proxy ndp on \"%s\"", veth1);
goto out_delete;
}
err = lxc_add_ip_neigh_proxy(bufinet6, veth1);
if (err) {
error_log_errno(err, "Failed to add gateway ipv6 proxy on \"%s\"", veth1);
log_error_errno(-1, err, "Failed to add gateway ipv6 proxy on \"%s\"", veth1);
goto out_delete;
}
}
......@@ -457,14 +457,14 @@ static int instantiate_veth(struct lxc_handler *handler, struct lxc_netdev *netd
/* setup ipv4 address routes on the host interface */
err = setup_ipv4_addr_routes(&netdev->ipv4, netdev->priv.veth_attr.ifindex);
if (err) {
error_log_errno(err, "Failed to setup ip address routes for network device \"%s\"", veth1);
log_error_errno(-1, err, "Failed to setup ip address routes for network device \"%s\"", veth1);
goto out_delete;
}
/* setup ipv6 address routes on the host interface */
err = setup_ipv6_addr_routes(&netdev->ipv6, netdev->priv.veth_attr.ifindex);
if (err) {
error_log_errno(err, "Failed to setup ip address routes for network device \"%s\"", veth1);
log_error_errno(-1, err, "Failed to setup ip address routes for network device \"%s\"", veth1);
goto out_delete;
}
}
......@@ -580,19 +580,19 @@ static int lxc_ipvlan_create(const char *master, const char *name, int mode, int
len = strlen(master);
if (len == 1 || len >= IFNAMSIZ)
return minus_one_set_errno(EINVAL);
return ret_set_errno(-1, EINVAL);
len = strlen(name);
if (len == 1 || len >= IFNAMSIZ)
return minus_one_set_errno(EINVAL);
return ret_set_errno(-1, EINVAL);
index = if_nametoindex(master);
if (!index)
return minus_one_set_errno(EINVAL);
return ret_set_errno(-1, EINVAL);
err = netlink_open(&nlh, NETLINK_ROUTE);
if (err)
return minus_one_set_errno(-err);
return ret_set_errno(-1, -err);
err = -ENOMEM;
nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE);
......@@ -653,7 +653,7 @@ out:
nlmsg_free(answer);
nlmsg_free(nlmsg);
if (err < 0)
return minus_one_set_errno(-err);
return ret_set_errno(-1, -err);
return 0;
}
......@@ -846,7 +846,7 @@ static int instantiate_phys(struct lxc_handler *handler, struct lxc_netdev *netd
mtu_orig = netdev_get_mtu(netdev->ifindex);
if (mtu_orig < 0) {
SYSERROR("Failed to get original mtu for interface \"%s\"", netdev->link);
return minus_one_set_errno(-mtu_orig);
return ret_set_errno(-1, -mtu_orig);
}
netdev->priv.phys_attr.mtu = mtu_orig;
......@@ -2007,13 +2007,13 @@ static int lxc_is_ip_neigh_proxy_enabled(const char *ifname, int family)
char buf[1] = "";
if (family != AF_INET && family != AF_INET6)
return minus_one_set_errno(EINVAL);
return ret_set_errno(-1, EINVAL);
ret = snprintf(path, PATH_MAX, "/proc/sys/net/%s/conf/%s/%s",
family == AF_INET ? "ipv4" : "ipv6", ifname,
family == AF_INET ? "proxy_arp" : "proxy_ndp");
if (ret < 0 || (size_t)ret >= PATH_MAX)
return minus_one_set_errno(E2BIG);
return ret_set_errno(-1, E2BIG);
return lxc_read_file_expect(path, buf, 1, "1");
}
......@@ -3047,7 +3047,7 @@ static int lxc_setup_l2proxy(struct lxc_netdev *netdev) {
/* Check for net.ipv4.conf.[link].forwarding=1 */
if (lxc_is_ip_forwarding_enabled(netdev->link, AF_INET) < 0) {
ERROR("Requires sysctl net.ipv4.conf.%s.forwarding=1", netdev->link);
return minus_one_set_errno(EINVAL);
return ret_set_errno(-1, EINVAL);
}
}
......@@ -3056,13 +3056,13 @@ static int lxc_setup_l2proxy(struct lxc_netdev *netdev) {
/* Check for net.ipv6.conf.[link].proxy_ndp=1 */
if (lxc_is_ip_neigh_proxy_enabled(netdev->link, AF_INET6) < 0) {
ERROR("Requires sysctl net.ipv6.conf.%s.proxy_ndp=1", netdev->link);
return minus_one_set_errno(EINVAL);
return ret_set_errno(-1, EINVAL);
}
/* Check for net.ipv6.conf.[link].forwarding=1 */
if (lxc_is_ip_forwarding_enabled(netdev->link, AF_INET6) < 0) {
ERROR("Requires sysctl net.ipv6.conf.%s.forwarding=1", netdev->link);
return minus_one_set_errno(EINVAL);
return ret_set_errno(-1, EINVAL);
}
}
......@@ -3071,31 +3071,31 @@ static int lxc_setup_l2proxy(struct lxc_netdev *netdev) {
/* Check mode is l3s as other modes do not work with l2proxy. */
if (netdev->priv.ipvlan_attr.mode != IPVLAN_MODE_L3S) {
ERROR("Requires ipvlan mode on dev \"%s\" be l3s when used with l2proxy", netdev->link);
return minus_one_set_errno(EINVAL);
return ret_set_errno(-1, EINVAL);
}
/* Retrieve local-loopback interface index for use with IPVLAN static routes. */
lo_ifindex = if_nametoindex(loop_device);
if (lo_ifindex == 0) {
ERROR("Failed to retrieve ifindex for \"%s\" routing cleanup", loop_device);
return minus_one_set_errno(EINVAL);
return ret_set_errno(-1, EINVAL);
}
}
lxc_list_for_each_safe(cur, &netdev->ipv4, next) {
inet4dev = cur->elem;
if (!inet_ntop(AF_INET, &inet4dev->addr, bufinet4, sizeof(bufinet4)))
return minus_one_set_errno(-errno);
return ret_set_errno(-1, -errno);
if (lxc_add_ip_neigh_proxy(bufinet4, netdev->link) < 0)
return minus_one_set_errno(EINVAL);
return ret_set_errno(-1, EINVAL);
/* IPVLAN requires a route to local-loopback to trigger l2proxy. */
if (netdev->type == LXC_NET_IPVLAN) {
err = lxc_ipv4_dest_add(lo_ifindex, &inet4dev->addr, 32);
if (err < 0) {
ERROR("Failed to add ipv4 dest \"%s\" for network device \"%s\"", bufinet4, loop_device);
return minus_one_set_errno(-err);
return ret_set_errno(-1, -err);
}
}
}
......@@ -3103,17 +3103,17 @@ static int lxc_setup_l2proxy(struct lxc_netdev *netdev) {
lxc_list_for_each_safe(cur, &netdev->ipv6, next) {
inet6dev = cur->elem;
if (!inet_ntop(AF_INET6, &inet6dev->addr, bufinet6, sizeof(bufinet6)))
return minus_one_set_errno(-errno);
return ret_set_errno(-1, -errno);
if (lxc_add_ip_neigh_proxy(bufinet6, netdev->link) < 0)
return minus_one_set_errno(EINVAL);
return ret_set_errno(-1, EINVAL);
/* IPVLAN requires a route to local-loopback to trigger l2proxy. */
if (netdev->type == LXC_NET_IPVLAN) {
err = lxc_ipv6_dest_add(lo_ifindex, &inet6dev->addr, 128);
if (err < 0) {
ERROR("Failed to add ipv6 dest \"%s\" for network device \"%s\"", bufinet6, loop_device);
return minus_one_set_errno(-err);
return ret_set_errno(-1, -err);
}
}
}
......@@ -3127,7 +3127,7 @@ static int lxc_delete_ipv4_l2proxy(struct in_addr *ip, char *link, unsigned int
if (!inet_ntop(AF_INET, ip, bufinet4, sizeof(bufinet4))) {
SYSERROR("Failed to convert IP for l2proxy ipv4 removal on dev \"%s\"", link);
return minus_one_set_errno(EINVAL);
return ret_set_errno(-1, EINVAL);
}
/* If a local-loopback ifindex supplied remove the static route to the lo device. */
......@@ -3145,7 +3145,7 @@ static int lxc_delete_ipv4_l2proxy(struct in_addr *ip, char *link, unsigned int
}
if (errCount > 0)
return minus_one_set_errno(EINVAL);
return ret_set_errno(-1, EINVAL);
return 0;
}
......@@ -3156,7 +3156,7 @@ static int lxc_delete_ipv6_l2proxy(struct in6_addr *ip, char *link, unsigned int
if (!inet_ntop(AF_INET6, ip, bufinet6, sizeof(bufinet6))) {
SYSERROR("Failed to convert IP for l2proxy ipv6 removal on dev \"%s\"", link);
return minus_one_set_errno(EINVAL);
return ret_set_errno(-1, EINVAL);
}
/* If a local-loopback ifindex supplied remove the static route to the lo device. */
......@@ -3174,7 +3174,7 @@ static int lxc_delete_ipv6_l2proxy(struct in6_addr *ip, char *link, unsigned int
}
if (errCount > 0)
return minus_one_set_errno(EINVAL);
return ret_set_errno(-1, EINVAL);
return 0;
}
......@@ -3209,7 +3209,7 @@ static int lxc_delete_l2proxy(struct lxc_netdev *netdev) {
}
if (errCount > 0)
return minus_one_set_errno(EINVAL);
return ret_set_errno(-1, EINVAL);
return 0;
}
......@@ -3766,12 +3766,12 @@ static int lxc_setup_netdev_in_child_namespaces(struct lxc_netdev *netdev)
if (err < 0) {
SYSERROR("Failed to setup ipv4 gateway to network device \"%s\"",
current_ifname);
return minus_one_set_errno(-err);
return ret_set_errno(-1, -err);
}
} else {
/* Check the gateway address is valid */
if (!inet_ntop(AF_INET, netdev->ipv4_gateway, bufinet4, sizeof(bufinet4)))
return minus_one_set_errno(errno);
return ret_set_errno(-1, errno);
/* Try adding a default route to the gateway address */
err = lxc_ipv4_gateway_add(netdev->ifindex, netdev->ipv4_gateway);
......@@ -3820,12 +3820,12 @@ static int lxc_setup_netdev_in_child_namespaces(struct lxc_netdev *netdev)
if (err < 0) {
SYSERROR("Failed to setup ipv6 gateway to network device \"%s\"",
current_ifname);
return minus_one_set_errno(-err);
return ret_set_errno(-1, -err);
}
} else {
/* Check the gateway address is valid */
if (!inet_ntop(AF_INET6, netdev->ipv6_gateway, bufinet6, sizeof(bufinet6)))
return minus_one_set_errno(errno);
return ret_set_errno(-1, errno);
/* Try adding a default route to the gateway address */
err = lxc_ipv6_gateway_add(netdev->ifindex, netdev->ipv6_gateway);
......
......@@ -1119,8 +1119,8 @@ void lxc_abort(const char *name, struct lxc_handler *handler)
static int do_start(void *data)
{
struct lxc_handler *handler = data;
ATTR_UNUSED __do_close_prot_errno int data_sock0 = handler->data_sock[0],
data_sock1 = handler->data_sock[1];
__lxc_unused __do_close_prot_errno int data_sock0 = handler->data_sock[0],
data_sock1 = handler->data_sock[1];
__do_close_prot_errno int status_fd = -EBADF;
int ret;
uid_t new_uid;
......@@ -1132,7 +1132,7 @@ static int do_start(void *data)
lxc_sync_fini_parent(handler);
if (lxc_abstract_unix_recv_fds(handler->data_sock[1], &status_fd, 1, NULL, 0) < 0) {
if (lxc_abstract_unix_recv_fds(data_sock1, &status_fd, 1, NULL, 0) < 0) {
ERROR("Failed to receive status file descriptor to child process");
goto out_warn_father;
}
......
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