diff --git a/.gitignore b/.gitignore index 9f34f9b1e..cd78e21cd 100644 --- a/.gitignore +++ b/.gitignore @@ -97,6 +97,7 @@ src/tests/lxc-test-utils* src/tests/lxc-usernic-test src/tests/lxc-test-config-jump-table src/tests/lxc-test-parse-config-file +src/tests/lxc-test-proc-pid src/tests/lxc-test-shortlived src/tests/lxc-test-api-reboot src/tests/lxc-test-criu-check-feature @@ -106,6 +107,7 @@ src/tests/lxc-test-state-server src/tests/lxc-test-basic src/tests/lxc-test-cve-2019-5736 src/tests/lxc-test-mount-injection +src/tests/lxc-test-sysctls src/tests/lxc-test-sys-mixed src/tests/lxc-test-rootfs-options src/tests/lxc-test-capabilities diff --git a/meson.build b/meson.build index f038fe4c5..8f8331a3d 100644 --- a/meson.build +++ b/meson.build @@ -284,8 +284,10 @@ endforeach if wants_io_uring == true liburing = dependency('liburing') - have = cc.get_define('IORING_POLL_ADD_MULTI', prefix : '#include ', dependencies: liburing) - conf.set10('HAVE_LIBURING', have) + if cc.has_function('io_uring_prep_poll_add', prefix : '#include ', dependencies: liburing) == false + error('liburing version does not support IORING_POLL_ADD_MULTI') + endif + conf.set10('HAVE_LIBURING', true) endif sh = find_program('sh') diff --git a/src/lxc/conf.c b/src/lxc/conf.c index 8e068b8ac..8bad08bd2 100644 --- a/src/lxc/conf.c +++ b/src/lxc/conf.c @@ -3288,7 +3288,7 @@ int setup_sysctl_parameters(struct lxc_conf *conf) char filename[PATH_MAX] = {0}; struct lxc_sysctl *sysctl, *nsysctl; - if (!list_empty(&conf->sysctls)) + if (list_empty(&conf->sysctls)) return 0; list_for_each_entry_safe(sysctl, nsysctl, &conf->sysctls, head) { @@ -3305,8 +3305,11 @@ int setup_sysctl_parameters(struct lxc_conf *conf) if (ret < 0) return log_error_errno(-1, errno, "Failed to setup sysctl parameters %s to %s", sysctl->key, sysctl->value); + + TRACE("Setting %s to %s", filename, sysctl->value); } + TRACE("Setup /proc/sys settings"); return 0; } @@ -3317,7 +3320,7 @@ int setup_proc_filesystem(struct lxc_conf *conf, pid_t pid) char filename[PATH_MAX] = {0}; struct lxc_proc *proc; - if (!list_empty(&conf->procs)) + if (list_empty(&conf->procs)) return 0; list_for_each_entry(proc, &conf->procs, head) { @@ -3334,6 +3337,8 @@ int setup_proc_filesystem(struct lxc_conf *conf, pid_t pid) if (ret < 0) return log_error_errno(-1, errno, "Failed to setup proc filesystem %s to %s", proc->filename, proc->value); + + TRACE("Setting %s to %s", filename, proc->value); } TRACE("Setup /proc/%d settings", pid); diff --git a/src/tests/Makefile.am b/src/tests/Makefile.am index 48d39bcb4..4e0314d16 100644 --- a/src/tests/Makefile.am +++ b/src/tests/Makefile.am @@ -1357,6 +1357,168 @@ lxc_test_capabilities_SOURCES += ../include/prlimit.c ../include/prlimit.h endif endif +lxc_test_sysctls_SOURCES = sysctls.c \ + ../lxc/af_unix.c ../lxc/af_unix.h \ + ../lxc/caps.c ../lxc/caps.h \ + ../lxc/cgroups/cgfsng.c \ + ../lxc/cgroups/cgroup.c ../lxc/cgroups/cgroup.h \ + ../lxc/cgroups/cgroup2_devices.c ../lxc/cgroups/cgroup2_devices.h \ + ../lxc/cgroups/cgroup_utils.c ../lxc/cgroups/cgroup_utils.h \ + ../lxc/commands.c ../lxc/commands.h \ + ../lxc/commands_utils.c ../lxc/commands_utils.h \ + ../lxc/conf.c ../lxc/conf.h \ + ../lxc/confile.c ../lxc/confile.h \ + ../lxc/confile_utils.c ../lxc/confile_utils.h \ + ../lxc/error.c ../lxc/error.h \ + ../lxc/file_utils.c ../lxc/file_utils.h \ + ../include/netns_ifaddrs.c ../include/netns_ifaddrs.h \ + ../lxc/initutils.c ../lxc/initutils.h \ + ../lxc/log.c ../lxc/log.h \ + ../lxc/lxclock.c ../lxc/lxclock.h \ + ../lxc/mainloop.c ../lxc/mainloop.h \ + ../lxc/monitor.c ../lxc/monitor.h \ + ../lxc/mount_utils.c ../lxc/mount_utils.h \ + ../lxc/namespace.c ../lxc/namespace.h \ + ../lxc/network.c ../lxc/network.h \ + ../lxc/nl.c ../lxc/nl.h \ + ../lxc/parse.c ../lxc/parse.h \ + ../lxc/process_utils.c ../lxc/process_utils.h \ + ../lxc/ringbuf.c ../lxc/ringbuf.h \ + ../lxc/start.c ../lxc/start.h \ + ../lxc/state.c ../lxc/state.h \ + ../lxc/storage/btrfs.c ../lxc/storage/btrfs.h \ + ../lxc/storage/dir.c ../lxc/storage/dir.h \ + ../lxc/storage/loop.c ../lxc/storage/loop.h \ + ../lxc/storage/lvm.c ../lxc/storage/lvm.h \ + ../lxc/storage/nbd.c ../lxc/storage/nbd.h \ + ../lxc/storage/overlay.c ../lxc/storage/overlay.h \ + ../lxc/storage/rbd.c ../lxc/storage/rbd.h \ + ../lxc/storage/rsync.c ../lxc/storage/rsync.h \ + ../lxc/storage/storage.c ../lxc/storage/storage.h \ + ../lxc/storage/storage_utils.c ../lxc/storage/storage_utils.h \ + ../lxc/storage/zfs.c ../lxc/storage/zfs.h \ + ../lxc/sync.c ../lxc/sync.h \ + ../lxc/string_utils.c ../lxc/string_utils.h \ + ../lxc/terminal.c ../lxc/terminal.h \ + ../lxc/utils.c ../lxc/utils.h \ + ../lxc/uuid.c ../lxc/uuid.h \ + $(LSM_SOURCES) +if ENABLE_SECCOMP +lxc_test_sysctls_SOURCES += ../lxc/seccomp.c ../lxc/lxcseccomp.h +endif + +if !HAVE_STRCHRNUL +lxc_test_sysctls_SOURCES += ../include/strchrnul.c ../include/strchrnul.h +endif + +if !HAVE_STRLCPY +lxc_test_sysctls_SOURCES += ../include/strlcpy.c ../include/strlcpy.h +endif + +if !HAVE_STRLCAT +lxc_test_sysctls_SOURCES += ../include/strlcat.c ../include/strlcat.h +endif + +if !HAVE_OPENPTY +lxc_test_sysctls_SOURCES += ../include/openpty.c ../include/openpty.h +endif + +if IS_BIONIC +lxc_test_sysctls_SOURCES += ../include/fexecve.c ../include/fexecve.h \ + ../include/lxcmntent.c ../include/lxcmntent.h +endif + +if !HAVE_GETGRGID_R +lxc_test_sysctls_SOURCES += ../include/getgrgid_r.c ../include/getgrgid_r.h +endif + +if !HAVE_PRLIMIT +if HAVE_PRLIMIT64 +lxc_test_sysctls_SOURCES += ../include/prlimit.c ../include/prlimit.h +endif +endif + +lxc_test_proc_pid_SOURCES = proc_pid.c \ + ../lxc/af_unix.c ../lxc/af_unix.h \ + ../lxc/caps.c ../lxc/caps.h \ + ../lxc/cgroups/cgfsng.c \ + ../lxc/cgroups/cgroup.c ../lxc/cgroups/cgroup.h \ + ../lxc/cgroups/cgroup2_devices.c ../lxc/cgroups/cgroup2_devices.h \ + ../lxc/cgroups/cgroup_utils.c ../lxc/cgroups/cgroup_utils.h \ + ../lxc/commands.c ../lxc/commands.h \ + ../lxc/commands_utils.c ../lxc/commands_utils.h \ + ../lxc/conf.c ../lxc/conf.h \ + ../lxc/confile.c ../lxc/confile.h \ + ../lxc/confile_utils.c ../lxc/confile_utils.h \ + ../lxc/error.c ../lxc/error.h \ + ../lxc/file_utils.c ../lxc/file_utils.h \ + ../include/netns_ifaddrs.c ../include/netns_ifaddrs.h \ + ../lxc/initutils.c ../lxc/initutils.h \ + ../lxc/log.c ../lxc/log.h \ + ../lxc/lxclock.c ../lxc/lxclock.h \ + ../lxc/mainloop.c ../lxc/mainloop.h \ + ../lxc/monitor.c ../lxc/monitor.h \ + ../lxc/mount_utils.c ../lxc/mount_utils.h \ + ../lxc/namespace.c ../lxc/namespace.h \ + ../lxc/network.c ../lxc/network.h \ + ../lxc/nl.c ../lxc/nl.h \ + ../lxc/parse.c ../lxc/parse.h \ + ../lxc/process_utils.c ../lxc/process_utils.h \ + ../lxc/ringbuf.c ../lxc/ringbuf.h \ + ../lxc/start.c ../lxc/start.h \ + ../lxc/state.c ../lxc/state.h \ + ../lxc/storage/btrfs.c ../lxc/storage/btrfs.h \ + ../lxc/storage/dir.c ../lxc/storage/dir.h \ + ../lxc/storage/loop.c ../lxc/storage/loop.h \ + ../lxc/storage/lvm.c ../lxc/storage/lvm.h \ + ../lxc/storage/nbd.c ../lxc/storage/nbd.h \ + ../lxc/storage/overlay.c ../lxc/storage/overlay.h \ + ../lxc/storage/rbd.c ../lxc/storage/rbd.h \ + ../lxc/storage/rsync.c ../lxc/storage/rsync.h \ + ../lxc/storage/storage.c ../lxc/storage/storage.h \ + ../lxc/storage/storage_utils.c ../lxc/storage/storage_utils.h \ + ../lxc/storage/zfs.c ../lxc/storage/zfs.h \ + ../lxc/sync.c ../lxc/sync.h \ + ../lxc/string_utils.c ../lxc/string_utils.h \ + ../lxc/terminal.c ../lxc/terminal.h \ + ../lxc/utils.c ../lxc/utils.h \ + ../lxc/uuid.c ../lxc/uuid.h \ + $(LSM_SOURCES) +if ENABLE_SECCOMP +lxc_test_proc_pid_SOURCES += ../lxc/seccomp.c ../lxc/lxcseccomp.h +endif + +if !HAVE_STRCHRNUL +lxc_test_proc_pid_SOURCES += ../include/strchrnul.c ../include/strchrnul.h +endif + +if !HAVE_STRLCPY +lxc_test_proc_pid_SOURCES += ../include/strlcpy.c ../include/strlcpy.h +endif + +if !HAVE_STRLCAT +lxc_test_proc_pid_SOURCES += ../include/strlcat.c ../include/strlcat.h +endif + +if !HAVE_OPENPTY +lxc_test_proc_pid_SOURCES += ../include/openpty.c ../include/openpty.h +endif + +if IS_BIONIC +lxc_test_proc_pid_SOURCES += ../include/fexecve.c ../include/fexecve.h \ + ../include/lxcmntent.c ../include/lxcmntent.h +endif + +if !HAVE_GETGRGID_R +lxc_test_proc_pid_SOURCES += ../include/getgrgid_r.c ../include/getgrgid_r.h +endif + +if !HAVE_PRLIMIT +if HAVE_PRLIMIT64 +lxc_test_proc_pid_SOURCES += ../include/prlimit.c ../include/prlimit.h +endif +endif + AM_CFLAGS += -DLXCROOTFSMOUNT=\"$(LXCROOTFSMOUNT)\" \ -DLXCPATH=\"$(LXCPATH)\" \ -DLXC_GLOBAL_CONF=\"$(LXC_GLOBAL_CONF)\" \ @@ -1416,6 +1578,7 @@ bin_PROGRAMS = lxc-test-api-reboot \ lxc-test-may-control \ lxc-test-mount-injection \ lxc-test-parse-config-file \ + lxc-test-proc-pid \ lxc-test-raw-clone \ lxc-test-reboot \ lxc-test-rootfs-options \ @@ -1426,6 +1589,7 @@ bin_PROGRAMS = lxc-test-api-reboot \ lxc-test-snapshot \ lxc-test-startone \ lxc-test-state-server \ + lxc-test-sysctls \ lxc-test-sys-mixed \ lxc-test-utils @@ -1527,6 +1691,7 @@ EXTRA_DIST = arch_parse.c \ may_control.c \ mount_injection.c \ parse_config_file.c \ + proc_pid.c \ rootfs_options.c \ saveconfig.c \ shortlived.c \ @@ -1535,6 +1700,7 @@ EXTRA_DIST = arch_parse.c \ startone.c \ state_server.c \ share_ns.c \ + sysctls.c \ sys_mixed.c clean-local: diff --git a/src/tests/capabilities.c b/src/tests/capabilities.c index 211c3ce42..57049423a 100644 --- a/src/tests/capabilities.c +++ b/src/tests/capabilities.c @@ -85,8 +85,7 @@ static int capabilities_deny(void *payload) static int run(int (*test)(void *), bool allow) { - __do_close int fd_log = -EBADF; - int fret = -1; + int fd_log = -EBADF, fret = -1; lxc_attach_options_t attach_options = LXC_ATTACH_OPTIONS_DEFAULT; int ret; pid_t pid; diff --git a/src/tests/lxctest.h b/src/tests/lxctest.h index e63936d5f..fda2821e6 100644 --- a/src/tests/lxctest.h +++ b/src/tests/lxctest.h @@ -30,14 +30,14 @@ #include #include -#define lxc_debug_stream(stream, format, ...) \ - do { \ - fprintf(stream, "%s: %d: %s: " format "\n", __FILE__, __LINE__, \ - __func__, __VA_ARGS__); \ +#define lxc_debug_stream(stream, format, ...) \ + do { \ + fprintf(stream, "%s: %d: %s: " format "\n", __FILE__, \ + __LINE__, __func__, ##__VA_ARGS__); \ } while (false) -#define lxc_error(format, ...) lxc_debug_stream(stderr, format, __VA_ARGS__) -#define lxc_debug(format, ...) lxc_debug_stream(stdout, format, __VA_ARGS__) +#define lxc_error(format, ...) lxc_debug_stream(stderr, format, ##__VA_ARGS__) +#define lxc_debug(format, ...) lxc_debug_stream(stdout, format, ##__VA_ARGS__) #define lxc_test_assert_stringify(expression, stringify_expression) \ do { \ diff --git a/src/tests/proc_pid.c b/src/tests/proc_pid.c new file mode 100644 index 000000000..9531ec2e2 --- /dev/null +++ b/src/tests/proc_pid.c @@ -0,0 +1,170 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ + +#include "config.h" + +#include +#include + +#include "lxccontainer.h" +#include "attach_options.h" + +#include "lxctest.h" +#include "utils.h" + +#define CONTAINER_NAME "test-proc-pid" +#define PROC_INIT_PATH "/proc/1/oom_score_adj" +#define PROC_SELF_PATH "/proc/self/oom_score_adj" + +static int check_oom_score_adj(void *payload) +{ + __do_close int fd = -EBADF; + char buf[INTTYPE_TO_STRLEN(__s64)]; + ssize_t ret; + + fd = open(PROC_INIT_PATH, O_RDONLY | O_CLOEXEC | O_NOFOLLOW); + if (fd < 0) { + lxc_error("Failed to open " PROC_INIT_PATH); + return EXIT_FAILURE; + } + + ret = lxc_read_nointr(fd, buf, sizeof(buf)); + if (ret < 0 || (size_t)ret >= sizeof(buf)) { + lxc_error("Failed to read " PROC_INIT_PATH); + return EXIT_FAILURE; + } + + buf[ret] = '\0'; + remove_trailing_newlines(buf); + + if (!strequal(buf, "-1000")) { + lxc_error("Unexpected value %s for " PROC_INIT_PATH, buf); + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} + +int main(int argc, char *argv[]) +{ + int fd_log = -EBADF, fret = EXIT_FAILURE; + lxc_attach_options_t attach_options = LXC_ATTACH_OPTIONS_DEFAULT; + int ret; + pid_t pid; + struct lxc_container *c; + struct lxc_log log; + char template[sizeof(P_tmpdir "/" CONTAINER_NAME "_XXXXXX")]; + + if (!file_exists(PROC_SELF_PATH)) { + lxc_debug("The sysctl path \"" PROC_SELF_PATH "\" needed for this test does not exist. Skipping"); + exit(EXIT_SUCCESS); + } + + (void)strlcpy(template, P_tmpdir "/" CONTAINER_NAME "_XXXXXX", sizeof(template)); + + fd_log = lxc_make_tmpfile(template, false); + if (fd_log < 0) { + lxc_error("%s", "Failed to create temporary log file for container \"capabilities\""); + return fret; + } + + log.name = CONTAINER_NAME; + log.file = template; + log.level = "TRACE"; + log.prefix = CONTAINER_NAME; + log.quiet = false; + log.lxcpath = NULL; + + if (lxc_log_init(&log)) + exit(fret); + + c = lxc_container_new(CONTAINER_NAME, NULL); + if (!c) { + lxc_error("%s", "Failed to create container " CONTAINER_NAME); + exit(fret); + } + + if (c->is_defined(c)) { + lxc_error("%s\n", "Container " CONTAINER_NAME " is defined"); + goto on_error_put; + } + + if (!c->createl(c, "busybox", NULL, NULL, 0, NULL)) { + lxc_error("%s\n", "Failed to create busybox container " CONTAINER_NAME); + goto on_error_put; + } + + if (!c->is_defined(c)) { + lxc_error("%s\n", "Container " CONTAINER_NAME " is not defined"); + goto on_error_destroy; + } + + if (!c->set_config_item(c, "lxc.mount.auto", "proc:rw")) { + lxc_error("%s\n", "Failed to set config item \"lxc.mount.auto=proc:rw\""); + goto on_error_destroy; + } + + if (!c->clear_config_item(c, "lxc.proc.oom_score_adj")) { + lxc_error("%s\n", "Failed to clear config item \"lxc.proc.oom_score_adj\""); + goto on_error_destroy; + } + + if (!c->set_config_item(c, "lxc.proc.oom_score_adj", "-1000")) { + lxc_error("%s\n", "Failed to set config item \"lxc.proc.oom_score_adj=-1000\""); + goto on_error_destroy; + } + + if (!c->want_daemonize(c, true)) { + lxc_error("%s\n", "Failed to mark container " CONTAINER_NAME " daemonized"); + goto on_error_destroy; + } + + if (!c->startl(c, 0, NULL)) { + lxc_error("%s\n", "Failed to start container " CONTAINER_NAME " daemonized"); + goto on_error_destroy; + } + + /* Leave some time for the container to write something to the log. */ + sleep(2); + + ret = c->attach(c, check_oom_score_adj, NULL, &attach_options, &pid); + if (ret < 0) { + lxc_error("%s\n", "Failed to run function in container " CONTAINER_NAME); + goto on_error_stop; + } + + ret = wait_for_pid(pid); + if (ret < 0) { + lxc_error("%s\n", "Function "CONTAINER_NAME" failed"); + goto on_error_stop; + } + + fret = 0; + +on_error_stop: + if (c->is_running(c) && !c->stop(c)) + lxc_error("%s\n", "Failed to stop container " CONTAINER_NAME); + +on_error_destroy: + if (!c->destroy(c)) + lxc_error("%s\n", "Failed to destroy container " CONTAINER_NAME); + +on_error_put: + lxc_container_put(c); + + if (fret == EXIT_SUCCESS) { + lxc_debug("All \"/proc/\" tests passed\n"); + } else { + char buf[4096]; + ssize_t buflen; + + while ((buflen = read(fd_log, buf, 1024)) > 0) { + buflen = write(STDERR_FILENO, buf, buflen); + if (buflen <= 0) + break; + } + } + close_prot_errno_disarm(fd_log); + (void)unlink(template); + + exit(fret); +} diff --git a/src/tests/sysctls.c b/src/tests/sysctls.c new file mode 100644 index 000000000..da4538fd7 --- /dev/null +++ b/src/tests/sysctls.c @@ -0,0 +1,171 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ + +#include "config.h" + +#include +#include + +#include "lxccontainer.h" +#include "attach_options.h" + +#include "lxctest.h" +#include "utils.h" + +#define CONTAINER_NAME "test-proc-sys" +#define SYSCTL_PATH "/proc/sys/net/ipv4/ip_forward" +#define SYSCTL_CONFIG_KEY "lxc.sysctl.net.ipv4.ip_forward" +#define SYSCTL_CONFIG_VALUE "1" + +static int check_sysctls(void *payload) +{ + __do_close int fd = -EBADF; + char buf[INTTYPE_TO_STRLEN(__u64)]; + ssize_t ret; + + fd = open(SYSCTL_PATH, O_RDONLY | O_CLOEXEC | O_NOFOLLOW); + if (fd < 0) { + lxc_error("Failed to open " SYSCTL_PATH); + return EXIT_FAILURE; + } + + ret = lxc_read_nointr(fd, buf, sizeof(buf)); + if (ret < 0 || (size_t)ret >= sizeof(buf)) { + lxc_error("Failed to read " SYSCTL_PATH); + return EXIT_FAILURE; + } + + buf[ret] = '\0'; + remove_trailing_newlines(buf); + + if (!strequal(buf, SYSCTL_CONFIG_VALUE)) { + lxc_error("Unexpected value %s for " SYSCTL_PATH, buf); + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} + +int main(int argc, char *argv[]) +{ + int fd_log = -EBADF, fret = EXIT_FAILURE; + lxc_attach_options_t attach_options = LXC_ATTACH_OPTIONS_DEFAULT; + int ret; + pid_t pid; + struct lxc_container *c; + struct lxc_log log; + char template[sizeof(P_tmpdir "/" CONTAINER_NAME "_XXXXXX")]; + + if (!file_exists(SYSCTL_PATH)) { + lxc_debug("The sysctl path \"" SYSCTL_PATH "\" needed for this test does not exist. Skipping"); + exit(EXIT_SUCCESS); + } + + (void)strlcpy(template, P_tmpdir "/" CONTAINER_NAME "_XXXXXX", sizeof(template)); + + fd_log = lxc_make_tmpfile(template, false); + if (fd_log < 0) { + lxc_error("%s", "Failed to create temporary log file for container \"capabilities\""); + return fret; + } + + log.name = CONTAINER_NAME; + log.file = template; + log.level = "TRACE"; + log.prefix = CONTAINER_NAME; + log.quiet = false; + log.lxcpath = NULL; + + if (lxc_log_init(&log)) + exit(fret); + + c = lxc_container_new(CONTAINER_NAME, NULL); + if (!c) { + lxc_error("%s", "Failed to create container " CONTAINER_NAME); + exit(fret); + } + + if (c->is_defined(c)) { + lxc_error("%s\n", "Container " CONTAINER_NAME " is defined"); + goto on_error_put; + } + + if (!c->createl(c, "busybox", NULL, NULL, 0, NULL)) { + lxc_error("%s\n", "Failed to create busybox container " CONTAINER_NAME); + goto on_error_put; + } + + if (!c->is_defined(c)) { + lxc_error("%s\n", "Container " CONTAINER_NAME " is not defined"); + goto on_error_destroy; + } + + if (!c->set_config_item(c, "lxc.mount.auto", "proc:rw")) { + lxc_error("%s\n", "Failed to set config item \"lxc.mount.auto=proc:rw\""); + goto on_error_destroy; + } + + if (!c->clear_config_item(c, SYSCTL_CONFIG_KEY)) { + lxc_error("%s\n", "Failed to clear config item \"" SYSCTL_CONFIG_KEY "\""); + goto on_error_destroy; + } + + if (!c->set_config_item(c, SYSCTL_CONFIG_KEY, SYSCTL_CONFIG_VALUE)) { + lxc_error("%s\n", "Failed to set config item \"" SYSCTL_CONFIG_KEY "\""); + goto on_error_destroy; + } + + if (!c->want_daemonize(c, true)) { + lxc_error("%s\n", "Failed to mark container " CONTAINER_NAME " daemonized"); + goto on_error_destroy; + } + + if (!c->startl(c, 0, NULL)) { + lxc_error("%s\n", "Failed to start container " CONTAINER_NAME " daemonized"); + goto on_error_destroy; + } + + /* Leave some time for the container to write something to the log. */ + sleep(2); + + ret = c->attach(c, check_sysctls, NULL, &attach_options, &pid); + if (ret < 0) { + lxc_error("%s\n", "Failed to run function in container " CONTAINER_NAME); + goto on_error_stop; + } + + ret = wait_for_pid(pid); + if (ret < 0) { + lxc_error("%s\n", "Function "CONTAINER_NAME" failed"); + goto on_error_stop; + } + + fret = 0; + +on_error_stop: + if (c->is_running(c) && !c->stop(c)) + lxc_error("%s\n", "Failed to stop container " CONTAINER_NAME); + +on_error_destroy: + if (!c->destroy(c)) + lxc_error("%s\n", "Failed to destroy container " CONTAINER_NAME); + +on_error_put: + lxc_container_put(c); + + if (fret == EXIT_SUCCESS) { + lxc_debug("All sysctl tests passed\n"); + } else { + char buf[4096]; + ssize_t buflen; + + while ((buflen = read(fd_log, buf, 1024)) > 0) { + buflen = write(STDERR_FILENO, buf, buflen); + if (buflen <= 0) + break; + } + } + close_prot_errno_disarm(fd_log); + (void)unlink(template); + + exit(fret); +}