aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSerge Hallyn <serge.hallyn@canonical.com>2012-02-09 10:48:18 -0600
committerDaniel Lezcano <daniel.lezcano@free.fr>2012-02-26 10:44:40 +0100
commite2fa15201393a956df74919ce85bf6a4eec13862 (patch)
tree8aa2852237b2075d270146526619a2b78af20ebe
parentif lxc-init can't mount /dev/shm, don't fail. (diff)
downloadlxc-e2fa15201393a956df74919ce85bf6a4eec13862.tar.gz
lxc-e2fa15201393a956df74919ce85bf6a4eec13862.tar.bz2
lxc-e2fa15201393a956df74919ce85bf6a4eec13862.zip
fix reboot support detection
In order for reboot(LINUX_REBOOT_CMD_CADON) to detect whether container reboot is supported, it must be done in a non-init pid namespace. Fix that. Signed-off-by: Serge Hallyn <serge.hallyn@canonical.com> Signed-off-by: Daniel Lezcano <dlezcano@fr.ibm.com>
-rw-r--r--src/lxc/start.c66
1 files changed, 52 insertions, 14 deletions
diff --git a/src/lxc/start.c b/src/lxc/start.c
index 4e631b2..f3a47a3 100644
--- a/src/lxc/start.c
+++ b/src/lxc/start.c
@@ -414,22 +414,57 @@ void lxc_abort(const char *name, struct lxc_handler *handler)
#include <sys/reboot.h>
#include <linux/reboot.h>
-static int must_drop_cap_sys_boot(void)
+/*
+ * reboot(LINUX_REBOOT_CMD_CAD_ON) will return -EINVAL
+ * in a child pid namespace if container reboot support exists.
+ * Otherwise, it will either succeed or return -EPERM.
+ */
+static int container_reboot_supported(void *arg)
{
- FILE *f = fopen("/proc/sys/kernel/ctrl-alt-del", "r");
+ int *cmd = arg;
int ret;
- int v;
- if (!f)
+ ret = reboot(*cmd);
+ if (ret == -1 && errno == EINVAL)
+ return 1;
+ return 0;
+}
+
+static int must_drop_cap_sys_boot(void)
+{
+ FILE *f = fopen("/proc/sys/kernel/ctrl-alt-del", "r");
+ int ret, cmd, v;
+ long stack_size = 4096;
+ void *stack = alloca(stack_size) + stack_size;
+ int status;
+ pid_t pid;
+
+ if (!f) {
+ DEBUG("failed to open /proc/sys/kernel/ctrl-alt-del");
return 1;
+ }
ret = fscanf(f, "%d", &v);
fclose(f);
- if (ret != 1)
+ if (ret != 1) {
+ DEBUG("Failed to read /proc/sys/kernel/ctrl-alt-del");
return 1;
- ret = reboot(v ? LINUX_REBOOT_CMD_CAD_ON : LINUX_REBOOT_CMD_CAD_OFF);
- if (ret != -1)
+ }
+ cmd = v ? LINUX_REBOOT_CMD_CAD_ON : LINUX_REBOOT_CMD_CAD_OFF;
+
+ pid = clone(container_reboot_supported, stack, CLONE_NEWPID | SIGCHLD, &cmd);
+ if (pid < 0) {
+ SYSERROR("failed to clone\n");
+ return -1;
+ }
+ if (wait(&status) < 0) {
+ SYSERROR("unexpected wait error: %m\n");
+ return -1;
+ }
+
+ if (WEXITSTATUS(status) != 1)
return 1;
+
return 0;
}
@@ -461,20 +496,23 @@ static int do_start(void *data)
if (lxc_sync_barrier_parent(handler, LXC_SYNC_CONFIGURE))
return -1;
- /* Setup the container, ip, names, utsname, ... */
- if (lxc_setup(handler->name, handler->conf)) {
- ERROR("failed to setup the container");
- goto out_warn_father;
- }
-
if (must_drop_cap_sys_boot()) {
if (prctl(PR_CAPBSET_DROP, CAP_SYS_BOOT, 0, 0, 0)) {
SYSERROR("failed to remove CAP_SYS_BOOT capability");
return -1;
}
handler->conf->need_utmp_watch = 1;
- } else
+ DEBUG("Dropped cap_sys_boot\n");
+ } else {
+ DEBUG("Not dropping cap_sys_boot or watching utmp\n");
handler->conf->need_utmp_watch = 0;
+ }
+
+ /* Setup the container, ip, names, utsname, ... */
+ if (lxc_setup(handler->name, handler->conf)) {
+ ERROR("failed to setup the container");
+ goto out_warn_father;
+ }
close(handler->sigfd);