Commit 75d0c7b3 by Stéphane Graber

Merge pull request #893 from tych0/dont-require-dev-console-none

Dont require dev console none
parents f86f4161 4b54788e
...@@ -45,16 +45,88 @@ ...@@ -45,16 +45,88 @@
#include "network.h" #include "network.h"
#include "utils.h" #include "utils.h"
#define CRIU_VERSION "2.0"
#define CRIU_GITID_VERSION "2.0"
#define CRIU_GITID_PATCHLEVEL 0
lxc_log_define(lxc_criu, lxc); lxc_log_define(lxc_criu, lxc);
struct criu_opts {
/* The type of criu invocation, one of "dump" or "restore" */
char *action;
/* The directory to pass to criu */
char *directory;
/* The container to dump */
struct lxc_container *c;
/* Enable criu verbose mode? */
bool verbose;
/* (pre-)dump: a directory for the previous dump's images */
char *predump_dir;
/* dump: stop the container or not after dumping? */
bool stop;
char tty_id[32]; /* the criu tty id for /dev/console, i.e. "tty[${rdev}:${dev}]" */
/* restore: the file to write the init process' pid into */
char *pidfile;
const char *cgroup_path;
int console_fd;
/* The path that is bind mounted from /dev/console, if any. We don't
* want to use `--ext-mount-map auto`'s result here because the pts
* device may have a different path (e.g. if the pty number is
* different) on the target host. NULL if lxc.console = "none".
*/
char *console_name;
};
static int load_tty_major_minor(char *directory, char *output, int len)
{
FILE *f;
char path[PATH_MAX];
int ret;
ret = snprintf(path, sizeof(path), "%s/tty.info", directory);
if (ret < 0 || ret >= sizeof(path)) {
ERROR("snprintf'd too many chacters: %d", ret);
return -1;
}
f = fopen(path, "r");
if (!f) {
/* This means we're coming from a liblxc which didn't export
* the tty info. In this case they had to have lxc.console =
* none, so there's no problem restoring.
*/
if (errno == ENOENT)
return 0;
SYSERROR("couldn't open %s", path);
return -1;
}
if (!fgets(output, len, f)) {
fclose(f);
SYSERROR("couldn't read %s", path);
return -1;
}
fclose(f);
return 0;
}
static void exec_criu(struct criu_opts *opts) static void exec_criu(struct criu_opts *opts)
{ {
char **argv, log[PATH_MAX]; char **argv, log[PATH_MAX];
int static_args = 22, argc = 0, i, ret; int static_args = 24, argc = 0, i, ret;
int netnr = 0; int netnr = 0;
struct lxc_list *it; struct lxc_list *it;
char buf[4096]; char buf[4096], tty_info[32];
/* If we are currently in a cgroup /foo/bar, and the container is in a /* If we are currently in a cgroup /foo/bar, and the container is in a
* cgroup /lxc/foo, lxcfs will give us an ENOENT if some task in the * cgroup /lxc/foo, lxcfs will give us an ENOENT if some task in the
...@@ -73,7 +145,7 @@ static void exec_criu(struct criu_opts *opts) ...@@ -73,7 +145,7 @@ static void exec_criu(struct criu_opts *opts)
* --manage-cgroups action-script foo.sh -D $(directory) \ * --manage-cgroups action-script foo.sh -D $(directory) \
* -o $(directory)/$(action).log --ext-mount-map auto * -o $(directory)/$(action).log --ext-mount-map auto
* --enable-external-sharing --enable-external-masters * --enable-external-sharing --enable-external-masters
* --enable-fs hugetlbfs --enable-fs tracefs * --enable-fs hugetlbfs --enable-fs tracefs --ext-mount-map console:/dev/pts/n
* +1 for final NULL */ * +1 for final NULL */
if (strcmp(opts->action, "dump") == 0 || strcmp(opts->action, "pre-dump") == 0) { if (strcmp(opts->action, "dump") == 0 || strcmp(opts->action, "pre-dump") == 0) {
...@@ -87,12 +159,24 @@ static void exec_criu(struct criu_opts *opts) ...@@ -87,12 +159,24 @@ static void exec_criu(struct criu_opts *opts)
/* --leave-running (only for final dump) */ /* --leave-running (only for final dump) */
if (strcmp(opts->action, "dump") == 0 && !opts->stop) if (strcmp(opts->action, "dump") == 0 && !opts->stop)
static_args++; static_args++;
/* --external tty[88,4] */
if (opts->tty_id[0])
static_args += 2;
} else if (strcmp(opts->action, "restore") == 0) { } else if (strcmp(opts->action, "restore") == 0) {
/* --root $(lxc_mount_point) --restore-detached /* --root $(lxc_mount_point) --restore-detached
* --restore-sibling --pidfile $foo --cgroup-root $foo * --restore-sibling --pidfile $foo --cgroup-root $foo
* --lsm-profile apparmor:whatever * --lsm-profile apparmor:whatever
*/ */
static_args += 10; static_args += 10;
tty_info[0] = 0;
if (load_tty_major_minor(opts->directory, tty_info, sizeof(tty_info)))
return;
/* --inherit-fd fd[%d]:tty[%s] */
if (tty_info[0])
static_args += 2;
} else { } else {
return; return;
} }
...@@ -175,6 +259,13 @@ static void exec_criu(struct criu_opts *opts) ...@@ -175,6 +259,13 @@ static void exec_criu(struct criu_opts *opts)
DECLARE_ARG("--freeze-cgroup"); DECLARE_ARG("--freeze-cgroup");
DECLARE_ARG(log); DECLARE_ARG(log);
DECLARE_ARG("--ext-mount-map");
DECLARE_ARG("/dev/console:console");
if (opts->tty_id[0]) {
DECLARE_ARG("--external");
DECLARE_ARG(opts->tty_id);
}
if (opts->predump_dir) { if (opts->predump_dir) {
DECLARE_ARG("--prev-images-dir"); DECLARE_ARG("--prev-images-dir");
DECLARE_ARG(opts->predump_dir); DECLARE_ARG(opts->predump_dir);
...@@ -197,6 +288,22 @@ static void exec_criu(struct criu_opts *opts) ...@@ -197,6 +288,22 @@ static void exec_criu(struct criu_opts *opts)
DECLARE_ARG("--cgroup-root"); DECLARE_ARG("--cgroup-root");
DECLARE_ARG(opts->cgroup_path); DECLARE_ARG(opts->cgroup_path);
if (tty_info[0]) {
ret = snprintf(buf, sizeof(buf), "fd[%d]:%s", opts->console_fd, tty_info);
if (ret < 0 || ret >= sizeof(buf))
goto err;
DECLARE_ARG("--inherit-fd");
DECLARE_ARG(buf);
}
if (opts->console_name) {
if (snprintf(buf, sizeof(buf), "console:%s", opts->console_name) < 0) {
SYSERROR("sprintf'd too many bytes");
}
DECLARE_ARG("--ext-mount-map");
DECLARE_ARG(buf);
}
if (lxc_conf->lsm_aa_profile || lxc_conf->lsm_se_context) { if (lxc_conf->lsm_aa_profile || lxc_conf->lsm_se_context) {
if (lxc_conf->lsm_aa_profile) if (lxc_conf->lsm_aa_profile)
...@@ -352,10 +459,9 @@ version_error: ...@@ -352,10 +459,9 @@ version_error:
/* Check and make sure the container has a configuration that we know CRIU can /* Check and make sure the container has a configuration that we know CRIU can
* dump. */ * dump. */
bool criu_ok(struct lxc_container *c) static bool criu_ok(struct lxc_container *c)
{ {
struct lxc_list *it; struct lxc_list *it;
bool found_deny_rule = false;
if (!criu_version_ok()) if (!criu_version_ok())
return false; return false;
...@@ -379,33 +485,6 @@ bool criu_ok(struct lxc_container *c) ...@@ -379,33 +485,6 @@ bool criu_ok(struct lxc_container *c)
} }
} }
// These requirements come from http://criu.org/LXC
if (c->lxc_conf->console.path &&
strcmp(c->lxc_conf->console.path, "none") != 0) {
ERROR("lxc.console must be none\n");
return false;
}
if (c->lxc_conf->tty != 0) {
ERROR("lxc.tty must be 0\n");
return false;
}
lxc_list_for_each(it, &c->lxc_conf->cgroup) {
struct lxc_cgroup *cg = it->elem;
if (strcmp(cg->subsystem, "devices.deny") == 0 &&
strcmp(cg->value, "c 5:1 rwm") == 0) {
found_deny_rule = true;
break;
}
}
if (!found_deny_rule) {
ERROR("couldn't find devices.deny = c 5:1 rwm");
return false;
}
return true; return true;
} }
...@@ -480,6 +559,7 @@ void do_restore(struct lxc_container *c, int pipe, char *directory, bool verbose ...@@ -480,6 +559,7 @@ void do_restore(struct lxc_container *c, int pipe, char *directory, bool verbose
if (pid == 0) { if (pid == 0) {
struct criu_opts os; struct criu_opts os;
struct lxc_rootfs *rootfs; struct lxc_rootfs *rootfs;
int flags;
close(pipe); close(pipe);
pipe = -1; pipe = -1;
...@@ -515,6 +595,24 @@ void do_restore(struct lxc_container *c, int pipe, char *directory, bool verbose ...@@ -515,6 +595,24 @@ void do_restore(struct lxc_container *c, int pipe, char *directory, bool verbose
os.pidfile = pidfile; os.pidfile = pidfile;
os.verbose = verbose; os.verbose = verbose;
os.cgroup_path = cgroup_canonical_path(handler); os.cgroup_path = cgroup_canonical_path(handler);
os.console_fd = c->lxc_conf->console.slave;
/* Twiddle the FD_CLOEXEC bit. We want to pass this FD to criu
* via --inherit-fd, so we don't want it to close.
*/
flags = fcntl(os.console_fd, F_GETFD);
if (flags < 0) {
SYSERROR("F_GETFD failed");
goto out_fini_handler;
}
flags &= ~FD_CLOEXEC;
if (fcntl(os.console_fd, F_SETFD, flags) < 0) {
SYSERROR("F_SETFD failed");
goto out_fini_handler;
}
os.console_name = c->lxc_conf->console.name;
/* exec_criu() returning is an error */ /* exec_criu() returning is an error */
exec_criu(&os); exec_criu(&os);
...@@ -604,6 +702,55 @@ out: ...@@ -604,6 +702,55 @@ out:
exit(1); exit(1);
} }
static int save_tty_major_minor(char *directory, struct lxc_container *c, char *tty_id, int len)
{
FILE *f;
char path[PATH_MAX];
int ret;
struct stat sb;
if (c->lxc_conf->console.path && !strcmp(c->lxc_conf->console.path, "none")) {
tty_id[0] = 0;
return 0;
}
ret = snprintf(path, sizeof(path), "/proc/%d/root/dev/console", c->init_pid(c));
if (ret < 0 || ret >= sizeof(path)) {
ERROR("snprintf'd too many chacters: %d", ret);
return -1;
}
ret = stat(path, &sb);
if (ret < 0) {
SYSERROR("stat of %s failed", path);
return -1;
}
ret = snprintf(path, sizeof(path), "%s/tty.info", directory);
if (ret < 0 || ret >= sizeof(path)) {
ERROR("snprintf'd too many characters: %d", ret);
return -1;
}
ret = snprintf(tty_id, len, "tty[%lx:%lx]", sb.st_rdev, sb.st_dev);
if (ret < 0 || ret >= sizeof(path)) {
ERROR("snprintf'd too many characters: %d", ret);
return -1;
}
f = fopen(path, "w");
if (!f) {
SYSERROR("failed to open %s", path);
return -1;
}
ret = fprintf(f, "%s", tty_id);
fclose(f);
if (ret < 0)
SYSERROR("failed to write to %s", path);
return ret;
}
/* do one of either predump or a regular dump */ /* do one of either predump or a regular dump */
static bool do_dump(struct lxc_container *c, char *mode, char *directory, static bool do_dump(struct lxc_container *c, char *mode, char *directory,
bool stop, bool verbose, char *predump_dir) bool stop, bool verbose, char *predump_dir)
...@@ -631,6 +778,10 @@ static bool do_dump(struct lxc_container *c, char *mode, char *directory, ...@@ -631,6 +778,10 @@ static bool do_dump(struct lxc_container *c, char *mode, char *directory,
os.stop = stop; os.stop = stop;
os.verbose = verbose; os.verbose = verbose;
os.predump_dir = predump_dir; os.predump_dir = predump_dir;
os.console_name = c->lxc_conf->console.path;
if (save_tty_major_minor(directory, c, os.tty_id, sizeof(os.tty_id)) < 0)
exit(1);
/* exec_criu() returning is an error */ /* exec_criu() returning is an error */
exec_criu(&os); exec_criu(&os);
......
...@@ -27,41 +27,6 @@ ...@@ -27,41 +27,6 @@
#include <lxc/lxccontainer.h> #include <lxc/lxccontainer.h>
// We require either the criu major/minor version, or the criu GITID if criu
// was built from git.
#define CRIU_VERSION "1.9"
#define CRIU_GITID_VERSION "1.8"
#define CRIU_GITID_PATCHLEVEL 21
struct criu_opts {
/* The type of criu invocation, one of "dump" or "restore" */
char *action;
/* The directory to pass to criu */
char *directory;
/* The container to dump */
struct lxc_container *c;
/* Enable criu verbose mode? */
bool verbose;
/* (pre-)dump: a directory for the previous dump's images */
char *predump_dir;
/* dump: stop the container or not after dumping? */
bool stop;
/* restore: the file to write the init process' pid into */
char *pidfile;
const char *cgroup_path;
};
/* Check and make sure the container has a configuration that we know CRIU can
* dump. */
bool criu_ok(struct lxc_container *c);
bool pre_dump(struct lxc_container *c, char *directory, bool verbose, char *predump_dir); bool pre_dump(struct lxc_container *c, char *directory, bool verbose, char *predump_dir);
bool dump(struct lxc_container *c, char *directory, bool stop, bool verbose, char *predump_dir); bool dump(struct lxc_container *c, char *directory, bool stop, bool verbose, char *predump_dir);
bool restore(struct lxc_container *c, char *directory, bool verbose); bool restore(struct lxc_container *c, char *directory, bool verbose);
......
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