* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "../config.h"
+#include "config.h"
+
#include <stdio.h>
#undef _GNU_SOURCE
#include <string.h>
#include <signal.h>
#include <fcntl.h>
#include <termios.h>
-#include <namespace.h>
#include <sys/param.h>
#include <sys/file.h>
#include <sys/mount.h>
#include "start.h"
#include "conf.h"
-#include "cgroup.h"
#include "log.h"
#include "cgroup.h"
#include "error.h"
#include "commands.h"
#include "console.h"
#include "sync.h"
+#include "namespace.h"
lxc_log_define(lxc_start, lxc);
-LXC_TTY_HANDLER(SIGINT);
-LXC_TTY_HANDLER(SIGQUIT);
-
static int match_fd(int fd)
{
return (fd == 0 || fd == 1 || fd == 2);
struct dirent dirent, *direntp;
int fd, fddir;
DIR *dir;
- int ret = 0;
dir = opendir("/proc/self/fd");
if (!dir) {
fddir = dirfd(dir);
while (!readdir_r(dir, &dirent, &direntp)) {
- char procpath[64];
- char path[PATH_MAX];
-
if (!direntp)
break;
if (match_fd(fd))
continue;
- /*
- * found inherited fd
- */
- ret = -1;
-
- snprintf(procpath, sizeof(procpath), "/proc/self/fd/%d", fd);
- if (readlink(procpath, path, sizeof(path)) == -1)
- ERROR("readlink(%s) failed : %m", procpath);
- else
- ERROR("inherited fd %d on %s", fd, path);
+ WARN("inherited fd %d", fd);
}
- if (closedir(dir))
- ERROR("failed to close directory");
- return ret;
+ closedir(dir); /* cannot fail */
+ return 0;
}
-static int setup_sigchld_fd(sigset_t *oldmask)
+static int setup_signal_fd(sigset_t *oldmask)
{
sigset_t mask;
int fd;
return fd;
}
-static int sigchld_handler(int fd, void *data,
+static int signal_handler(int fd, void *data,
struct lxc_epoll_descr *descr)
{
struct signalfd_siginfo siginfo;
goto out_sigfd;
}
- if (lxc_mainloop_add_handler(&descr, sigfd, sigchld_handler, &pid)) {
+ if (lxc_mainloop_add_handler(&descr, sigfd, signal_handler, &pid)) {
ERROR("failed to add handler for the signal");
goto out_mainloop_open;
}
goto out_mainloop_open;
}
- if (lxc_utmp_mainloop_add(&descr, handler)) {
- ERROR("failed to add utmp handler to mainloop");
- goto out_mainloop_open;
+ if (handler->conf->need_utmp_watch) {
+ if (lxc_utmp_mainloop_add(&descr, handler)) {
+ ERROR("failed to add utmp handler to mainloop");
+ goto out_mainloop_open;
+ }
}
return lxc_mainloop(&descr);
return -1;
}
+extern int lxc_caps_check(void);
+
struct lxc_handler *lxc_init(const char *name, struct lxc_conf *conf)
{
struct lxc_handler *handler;
+ if (!lxc_caps_check()) {
+ ERROR("Not running with sufficient privilege");
+ return NULL;
+ }
+
handler = malloc(sizeof(*handler));
if (!handler)
return NULL;
/* the signal fd has to be created before forking otherwise
* if the child process exits before we setup the signal fd,
* the event will be lost and the command will be stuck */
- handler->sigfd = setup_sigchld_fd(&handler->oldmask);
+ handler->sigfd = setup_signal_fd(&handler->oldmask);
if (handler->sigfd < 0) {
ERROR("failed to set sigchild fd handler");
goto out_delete_console;
lxc_set_state(name, handler, STOPPING);
lxc_set_state(name, handler, STOPPED);
- /* reset mask set by setup_sigchld_fd */
+ /* reset mask set by setup_signal_fd */
if (sigprocmask(SIG_SETMASK, &handler->oldmask, NULL))
WARN("failed to restore sigprocmask");
kill(handler->pid, SIGKILL);
}
+#include <sys/reboot.h>
+#include <linux/reboot.h>
+
+static int must_drop_cap_sys_boot(void)
+{
+ FILE *f = fopen("/proc/sys/kernel/ctrl-alt-del", "r");
+ int ret;
+ int v;
+
+ if (!f)
+ return 1;
+
+ ret = fscanf(f, "%d", &v);
+ fclose(f);
+ if (ret != 1)
+ return 1;
+ ret = reboot(v ? LINUX_REBOOT_CMD_CAD_ON : LINUX_REBOOT_CMD_CAD_OFF);
+ if (ret != -1)
+ return 1;
+ return 0;
+}
+
static int do_start(void *data)
{
struct lxc_handler *handler = data;
goto out_warn_father;
}
- if (prctl(PR_CAPBSET_DROP, CAP_SYS_BOOT, 0, 0, 0)) {
- SYSERROR("failed to remove CAP_SYS_BOOT capability");
- return -1;
- }
+ 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
+ handler->conf->need_utmp_watch = 0;
close(handler->sigfd);
clone_flags |= CLONE_NEWNET;
+ /* Find gateway addresses from the link device, which is
+ * no longer accessible inside the container. Do this
+ * before creating network interfaces, since goto
+ * out_delete_net does not work before lxc_clone. */
+ if (lxc_find_gateway_addresses(handler)) {
+ ERROR("failed to find gateway addresses");
+ lxc_sync_fini(handler);
+ return -1;
+ }
+
/* that should be done before the clone because we will
* fill the netdev index and use them in the child
*/
- if (lxc_create_network(&handler->conf->network)) {
+ if (lxc_create_network(handler)) {
ERROR("failed to create the network");
lxc_sync_fini(handler);
return -1;
}
}
-
/* Create a process in a new set of namespaces */
handler->pid = lxc_clone(do_start, handler, clone_flags);
if (handler->pid < 0) {
if (lxc_sync_wait_child(handler, LXC_SYNC_CONFIGURE))
failed_before_rename = 1;
- if (lxc_rename_nsgroup(name, handler))
+ if (lxc_cgroup_create(name, handler->pid))
goto out_delete_net;
if (failed_before_rename)
goto out_fini;
}
- /* Avoid signals from terminal */
- LXC_TTY_ADD_HANDLER(SIGINT);
- LXC_TTY_ADD_HANDLER(SIGQUIT);
-
err = lxc_poll(name, handler);
if (err) {
ERROR("mainloop exited with an error");
while (waitpid(handler->pid, &status, 0) < 0 && errno == EINTR)
continue;
+ if (!WIFSIGNALED(status)) {
+ printf("child process exited but was not signaled\n");
+ return -1;
+ }
+
+ switch(WTERMSIG(status)) {
+ case SIGINT: /* halt */
+ DEBUG("Container halting");
+ break;
+ case SIGHUP: /* reboot */
+ DEBUG("Container rebooting");
+ handler->conf->reboot = 1;
+ break;
+ default:
+ DEBUG("unknown exit status for init: %d\n", WTERMSIG(status));
+ break;
+ }
+
err = lxc_error_set_and_log(handler->pid, status);
out_fini:
- LXC_TTY_DEL_HANDLER(SIGQUIT);
- LXC_TTY_DEL_HANDLER(SIGINT);
- lxc_unlink_nsgroup(name);
+ lxc_cgroup_destroy(name);
lxc_fini(name, handler);
return err;
if (lxc_check_inherited(-1))
return -1;
+ conf->need_utmp_watch = 1;
return __lxc_start(name, conf, &start_ops, &start_arg);
}