diff options
author | Serge Hallyn <serge.hallyn@canonical.com> | 2012-02-09 10:48:18 -0600 |
---|---|---|
committer | Daniel Lezcano <daniel.lezcano@free.fr> | 2012-02-26 10:44:40 +0100 |
commit | e2fa15201393a956df74919ce85bf6a4eec13862 (patch) | |
tree | 8aa2852237b2075d270146526619a2b78af20ebe | |
parent | if lxc-init can't mount /dev/shm, don't fail. (diff) | |
download | lxc-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.c | 66 |
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); |