]>
git.proxmox.com Git - mirror_lxc.git/blob - src/lxc/criu.c
9b0ccacb6af7a136603a3d4e569dd223e9e74e91
2 * lxc: linux Container library
4 * Copyright © 2014-2015 Canonical Ltd.
7 * Tycho Andersen <tycho.andersen@canonical.com>
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
25 #include <linux/limits.h>
30 #include <sys/mount.h>
31 #include <sys/types.h>
49 #include <../include/lxcmntent.h>
54 #define CRIU_VERSION "2.0"
56 #define CRIU_GITID_VERSION "2.0"
57 #define CRIU_GITID_PATCHLEVEL 0
59 #define CRIU_IN_FLIGHT_SUPPORT "2.4"
60 #define CRIU_EXTERNAL_NOT_VETH "2.8"
62 lxc_log_define(lxc_criu
, lxc
);
65 /* the thing to hook to stdout and stderr for logging */
68 /* The type of criu invocation, one of "dump" or "restore" */
71 /* the user-provided migrate options relevant to this action */
72 struct migrate_opts
*user
;
74 /* The container to dump */
75 struct lxc_container
*c
;
77 /* dump: stop the container or not after dumping? */
78 char tty_id
[32]; /* the criu tty id for /dev/console, i.e. "tty[${rdev}:${dev}]" */
80 /* restore: the file to write the init process' pid into */
81 struct lxc_handler
*handler
;
83 /* The path that is bind mounted from /dev/console, if any. We don't
84 * want to use `--ext-mount-map auto`'s result here because the pts
85 * device may have a different path (e.g. if the pty number is
86 * different) on the target host. NULL if lxc.console = "none".
90 /* The detected version of criu */
94 static int load_tty_major_minor(char *directory
, char *output
, int len
)
100 ret
= snprintf(path
, sizeof(path
), "%s/tty.info", directory
);
101 if (ret
< 0 || ret
>= sizeof(path
)) {
102 ERROR("snprintf'd too many chacters: %d", ret
);
106 f
= fopen(path
, "r");
108 /* This means we're coming from a liblxc which didn't export
109 * the tty info. In this case they had to have lxc.console =
110 * none, so there's no problem restoring.
115 SYSERROR("couldn't open %s", path
);
119 if (!fgets(output
, len
, f
)) {
121 SYSERROR("couldn't read %s", path
);
129 static void exec_criu(struct criu_opts
*opts
)
131 char **argv
, log
[PATH_MAX
];
132 int static_args
= 23, argc
= 0, i
, ret
;
136 struct mntent mntent
;
138 char buf
[4096], tty_info
[32];
141 /* If we are currently in a cgroup /foo/bar, and the container is in a
142 * cgroup /lxc/foo, lxcfs will give us an ENOENT if some task in the
143 * container has an open fd that points to one of the cgroup files
144 * (systemd always opens its "root" cgroup). So, let's escape to the
145 * /actual/ root cgroup so that lxcfs thinks criu has enough rights to
148 if (!cgroup_escape()) {
149 ERROR("failed to escape cgroups");
153 /* The command line always looks like:
154 * criu $(action) --tcp-established --file-locks --link-remap \
155 * --manage-cgroups=full --action-script foo.sh -D $(directory) \
156 * -o $(directory)/$(action).log --ext-mount-map auto
157 * --enable-external-sharing --enable-external-masters
158 * --enable-fs hugetlbfs --enable-fs tracefs --ext-mount-map console:/dev/pts/n
159 * +1 for final NULL */
161 if (strcmp(opts
->action
, "dump") == 0 || strcmp(opts
->action
, "pre-dump") == 0) {
162 /* -t pid --freeze-cgroup /lxc/ct */
165 /* --prev-images-dir <path-to-directory-A-relative-to-B> */
166 if (opts
->user
->predump_dir
)
169 /* --page-server --address <address> --port <port> */
170 if (opts
->user
->pageserver_address
&& opts
->user
->pageserver_port
)
173 /* --leave-running (only for final dump) */
174 if (strcmp(opts
->action
, "dump") == 0 && !opts
->user
->stop
)
177 /* --external tty[88,4] */
182 if (!opts
->user
->preserves_inodes
)
185 /* --ghost-limit 1024 */
186 if (opts
->user
->ghost_limit
)
188 } else if (strcmp(opts
->action
, "restore") == 0) {
189 /* --root $(lxc_mount_point) --restore-detached
191 * --lsm-profile apparmor:whatever
196 if (load_tty_major_minor(opts
->user
->directory
, tty_info
, sizeof(tty_info
)))
199 /* --inherit-fd fd[%d]:tty[%s] */
206 if (cgroup_num_hierarchies() > 0)
207 static_args
+= 2 * cgroup_num_hierarchies();
209 if (opts
->user
->verbose
)
212 if (opts
->user
->action_script
)
215 static_args
+= 2 * lxc_list_len(&opts
->c
->lxc_conf
->mount_list
);
217 ret
= snprintf(log
, PATH_MAX
, "%s/%s.log", opts
->user
->directory
, opts
->action
);
218 if (ret
< 0 || ret
>= PATH_MAX
) {
219 ERROR("logfile name too long");
223 argv
= malloc(static_args
* sizeof(*argv
));
227 memset(argv
, 0, static_args
* sizeof(*argv
));
229 #define DECLARE_ARG(arg) \
232 ERROR("Got NULL argument for criu"); \
235 argv[argc++] = strdup(arg); \
240 argv
[argc
++] = on_path("criu", NULL
);
242 ERROR("Couldn't find criu binary");
246 DECLARE_ARG(opts
->action
);
247 DECLARE_ARG("--tcp-established");
248 DECLARE_ARG("--file-locks");
249 DECLARE_ARG("--link-remap");
250 DECLARE_ARG("--manage-cgroups=full");
251 DECLARE_ARG("--ext-mount-map");
253 DECLARE_ARG("--enable-external-sharing");
254 DECLARE_ARG("--enable-external-masters");
255 DECLARE_ARG("--enable-fs");
256 DECLARE_ARG("hugetlbfs");
257 DECLARE_ARG("--enable-fs");
258 DECLARE_ARG("tracefs");
260 DECLARE_ARG(opts
->user
->directory
);
264 for (i
= 0; i
< cgroup_num_hierarchies(); i
++) {
265 char **controllers
= NULL
, *fullname
;
268 if (!cgroup_get_hierarchies(i
, &controllers
)) {
269 ERROR("failed to get hierarchy %d", i
);
273 /* if we are in a dump, we have to ask the monitor process what
274 * the right cgroup is. if this is a restore, we can just use
275 * the handler the restore task created.
277 if (!strcmp(opts
->action
, "dump") || !strcmp(opts
->action
, "pre-dump")) {
278 path
= lxc_cmd_get_cgroup_path(opts
->c
->name
, opts
->c
->config_path
, controllers
[0]);
280 ERROR("failed to get cgroup path for %s", controllers
[0]);
286 p
= cgroup_get_cgroup(opts
->handler
, controllers
[0]);
288 ERROR("failed to get cgroup path for %s", controllers
[0]);
294 ERROR("strdup failed");
299 if (!lxc_deslashify(&path
)) {
300 ERROR("failed to deslashify %s", path
);
305 fullname
= lxc_string_join(",", (const char **) controllers
, false);
307 ERROR("failed to join controllers");
312 ret
= sprintf(buf
, "%s:%s", fullname
, path
);
315 if (ret
< 0 || ret
>= sizeof(buf
)) {
316 ERROR("sprintf of cgroup root arg failed");
320 DECLARE_ARG("--cgroup-root");
324 if (opts
->user
->verbose
)
325 DECLARE_ARG("-vvvvvv");
327 if (opts
->user
->action_script
) {
328 DECLARE_ARG("--action-script");
329 DECLARE_ARG(opts
->user
->action_script
);
332 mnts
= make_anonymous_mount_file(&opts
->c
->lxc_conf
->mount_list
);
336 while (getmntent_r(mnts
, &mntent
, buf
, sizeof(buf
))) {
337 char *fmt
, *key
, *val
, *mntdata
;
338 char arg
[2 * PATH_MAX
+ 2];
341 if (parse_mntopts(mntent
.mnt_opts
, &flags
, &mntdata
) < 0)
346 /* only add --ext-mount-map for actual bind mounts */
347 if (!(flags
& MS_BIND
))
350 if (strcmp(opts
->action
, "dump") == 0) {
352 key
= mntent
.mnt_dir
;
353 val
= mntent
.mnt_dir
;
356 key
= mntent
.mnt_dir
;
357 val
= mntent
.mnt_fsname
;
360 ret
= snprintf(arg
, sizeof(arg
), fmt
, key
, val
);
361 if (ret
< 0 || ret
>= sizeof(arg
)) {
363 ERROR("snprintf failed");
367 DECLARE_ARG("--ext-mount-map");
372 if (strcmp(opts
->action
, "dump") == 0 || strcmp(opts
->action
, "pre-dump") == 0) {
373 char pid
[32], *freezer_relative
;
375 if (sprintf(pid
, "%d", opts
->c
->init_pid(opts
->c
)) < 0)
381 freezer_relative
= lxc_cmd_get_cgroup_path(opts
->c
->name
,
382 opts
->c
->config_path
,
384 if (!freezer_relative
) {
385 ERROR("failed getting freezer path");
389 ret
= snprintf(log
, sizeof(log
), "/sys/fs/cgroup/freezer/%s", freezer_relative
);
390 if (ret
< 0 || ret
>= sizeof(log
))
393 if (!opts
->user
->disable_skip_in_flight
&&
394 strcmp(opts
->criu_version
, CRIU_IN_FLIGHT_SUPPORT
) >= 0)
395 DECLARE_ARG("--skip-in-flight");
397 DECLARE_ARG("--freeze-cgroup");
400 if (opts
->tty_id
[0]) {
401 DECLARE_ARG("--ext-mount-map");
402 DECLARE_ARG("/dev/console:console");
404 DECLARE_ARG("--external");
405 DECLARE_ARG(opts
->tty_id
);
408 if (opts
->user
->predump_dir
) {
409 DECLARE_ARG("--prev-images-dir");
410 DECLARE_ARG(opts
->user
->predump_dir
);
411 DECLARE_ARG("--track-mem");
414 if (opts
->user
->pageserver_address
&& opts
->user
->pageserver_port
) {
415 DECLARE_ARG("--page-server");
416 DECLARE_ARG("--address");
417 DECLARE_ARG(opts
->user
->pageserver_address
);
418 DECLARE_ARG("--port");
419 DECLARE_ARG(opts
->user
->pageserver_port
);
422 if (!opts
->user
->preserves_inodes
)
423 DECLARE_ARG("--force-irmap");
425 if (opts
->user
->ghost_limit
) {
426 char ghost_limit
[32];
428 ret
= sprintf(ghost_limit
, "%"PRIu64
, opts
->user
->ghost_limit
);
429 if (ret
< 0 || ret
>= sizeof(ghost_limit
)) {
430 ERROR("failed to print ghost limit %"PRIu64
, opts
->user
->ghost_limit
);
434 DECLARE_ARG("--ghost-limit");
435 DECLARE_ARG(ghost_limit
);
438 /* only for final dump */
439 if (strcmp(opts
->action
, "dump") == 0 && !opts
->user
->stop
)
440 DECLARE_ARG("--leave-running");
441 } else if (strcmp(opts
->action
, "restore") == 0) {
444 struct lxc_conf
*lxc_conf
= opts
->c
->lxc_conf
;
446 DECLARE_ARG("--root");
447 DECLARE_ARG(opts
->c
->lxc_conf
->rootfs
.mount
);
448 DECLARE_ARG("--restore-detached");
449 DECLARE_ARG("--restore-sibling");
452 if (opts
->console_fd
< 0) {
453 ERROR("lxc.console configured on source host but not target");
457 ret
= snprintf(buf
, sizeof(buf
), "fd[%d]:%s", opts
->console_fd
, tty_info
);
458 if (ret
< 0 || ret
>= sizeof(buf
))
461 DECLARE_ARG("--inherit-fd");
464 if (opts
->console_name
) {
465 if (snprintf(buf
, sizeof(buf
), "console:%s", opts
->console_name
) < 0) {
466 SYSERROR("sprintf'd too many bytes");
468 DECLARE_ARG("--ext-mount-map");
472 if (lxc_conf
->lsm_aa_profile
|| lxc_conf
->lsm_se_context
) {
474 if (lxc_conf
->lsm_aa_profile
)
475 ret
= snprintf(buf
, sizeof(buf
), "apparmor:%s", lxc_conf
->lsm_aa_profile
);
477 ret
= snprintf(buf
, sizeof(buf
), "selinux:%s", lxc_conf
->lsm_se_context
);
479 if (ret
< 0 || ret
>= sizeof(buf
))
482 DECLARE_ARG("--lsm-profile");
486 additional
= lxc_list_len(&opts
->c
->lxc_conf
->network
) * 2;
488 m
= realloc(argv
, (argc
+ additional
+ 1) * sizeof(*argv
));
493 lxc_list_for_each(it
, &opts
->c
->lxc_conf
->network
) {
494 char eth
[128], *veth
;
496 struct lxc_netdev
*n
= it
->elem
;
497 bool external_not_veth
;
499 if (strcmp(opts
->criu_version
, CRIU_EXTERNAL_NOT_VETH
) >= 0) {
500 /* Since criu version 2.8 the usage of --veth-pair
501 * has been deprecated:
502 * git tag --contains f2037e6d3445fc400
504 external_not_veth
= true;
506 external_not_veth
= false;
510 if (strlen(n
->name
) >= sizeof(eth
))
512 strncpy(eth
, n
->name
, sizeof(eth
));
514 ret
= snprintf(eth
, sizeof(eth
), "eth%d", netnr
);
515 if (ret
< 0 || ret
>= sizeof(eth
))
521 veth
= n
->priv
.veth_attr
.pair
;
524 if (external_not_veth
)
525 fmt
= "veth[%s]:%s@%s";
529 ret
= snprintf(buf
, sizeof(buf
), fmt
, eth
, veth
, n
->link
);
531 if (external_not_veth
)
536 ret
= snprintf(buf
, sizeof(buf
), fmt
, eth
, veth
);
538 if (ret
< 0 || ret
>= sizeof(buf
))
541 case LXC_NET_MACVLAN
:
543 ERROR("no host interface for macvlan %s", n
->name
);
547 ret
= snprintf(buf
, sizeof(buf
), "macvlan[%s]:%s", eth
, n
->link
);
548 if (ret
< 0 || ret
>= sizeof(buf
))
555 /* we have screened for this earlier... */
556 ERROR("unexpected network type %d", n
->type
);
560 if (external_not_veth
)
561 DECLARE_ARG("--external");
563 DECLARE_ARG("--veth-pair");
575 for (i
= 0; argv
[i
]; i
++) {
576 ret
= snprintf(buf
+ pos
, sizeof(buf
) - pos
, "%s ", argv
[i
]);
577 if (ret
< 0 || ret
>= sizeof(buf
) - pos
)
583 INFO("execing: %s", buf
);
585 /* before criu inits its log, it sometimes prints things to stdout/err;
586 * let's be sure we capture that.
588 if (dup2(opts
->pipefd
, STDOUT_FILENO
) < 0) {
589 SYSERROR("dup2 stdout failed");
593 if (dup2(opts
->pipefd
, STDERR_FILENO
) < 0) {
594 SYSERROR("dup2 stderr failed");
601 execv(argv
[0], argv
);
603 for (i
= 0; argv
[i
]; i
++)
609 * Check to see if the criu version is recent enough for all the features we
610 * use. This version allows either CRIU_VERSION or (CRIU_GITID_VERSION and
611 * CRIU_GITID_PATCHLEVEL) to work, enabling users building from git to c/r
612 * things potentially before a version is released with a particular feature.
614 * The intent is that when criu development slows down, we can drop this, but
615 * for now we shouldn't attempt to c/r with versions that we know won't work.
617 * Note: If version != NULL criu_version() stores the detected criu version in
618 * version. Allocates memory for version which must be freed by caller.
620 static bool criu_version_ok(char **version
)
625 if (pipe(pipes
) < 0) {
626 SYSERROR("pipe() failed");
632 SYSERROR("fork() failed");
637 char *args
[] = { "criu", "--version", NULL
};
641 close(STDERR_FILENO
);
642 if (dup2(pipes
[1], STDOUT_FILENO
) < 0)
645 path
= on_path("criu", NULL
);
657 if (wait_for_pid(pid
) < 0) {
659 SYSERROR("execing criu failed, is it installed?");
663 f
= fdopen(pipes
[0], "r");
675 if (fscanf(f
, "Version: %1023[^\n]s", tmp
) != 1)
678 if (fgetc(f
) != '\n')
681 if (strcmp(tmp
, CRIU_VERSION
) >= 0)
684 if (fscanf(f
, "GitID: v%1023[^-]s", tmp
) != 1)
690 if (fscanf(f
, "%d", &patch
) != 1)
693 if (strcmp(tmp
, CRIU_GITID_VERSION
) < 0)
696 if (patch
< CRIU_GITID_PATCHLEVEL
)
710 ERROR("must have criu " CRIU_VERSION
" or greater to checkpoint/restore");
715 /* Check and make sure the container has a configuration that we know CRIU can
717 static bool criu_ok(struct lxc_container
*c
, char **criu_version
)
721 if (!criu_version_ok(criu_version
))
725 ERROR("Must be root to checkpoint");
729 /* We only know how to restore containers with veth networks. */
730 lxc_list_for_each(it
, &c
->lxc_conf
->network
) {
731 struct lxc_netdev
*n
= it
->elem
;
736 case LXC_NET_MACVLAN
:
739 ERROR("Found un-dumpable network: %s (%s)", lxc_net_type_to_str(n
->type
), n
->name
);
747 static bool restore_net_info(struct lxc_container
*c
)
750 bool has_error
= true;
752 if (container_mem_lock(c
))
755 lxc_list_for_each(it
, &c
->lxc_conf
->network
) {
756 struct lxc_netdev
*netdev
= it
->elem
;
757 char template[IFNAMSIZ
];
759 if (netdev
->type
!= LXC_NET_VETH
)
762 snprintf(template, sizeof(template), "vethXXXXXX");
764 if (!netdev
->priv
.veth_attr
.pair
)
765 netdev
->priv
.veth_attr
.pair
= lxc_mkifname(template);
767 if (!netdev
->priv
.veth_attr
.pair
)
774 container_mem_unlock(c
);
778 // do_restore never returns, the calling process is used as the
779 // monitor process. do_restore calls exit() if it fails.
780 static void do_restore(struct lxc_container
*c
, int status_pipe
, struct migrate_opts
*opts
, char *criu_version
)
783 struct lxc_handler
*handler
;
785 int pipes
[2] = {-1, -1};
787 /* Try to detach from the current controlling tty if it exists.
788 * Othwerise, lxc_init (via lxc_console) will attach the container's
789 * console output to the current tty, which is probably not what any
790 * library user wants, and if they do, they can just manually configure
793 fd
= open("/dev/tty", O_RDWR
);
795 if (ioctl(fd
, TIOCNOTTY
, NULL
) < 0)
796 SYSERROR("couldn't detach from tty");
800 handler
= lxc_init(c
->name
, c
->lxc_conf
, c
->config_path
);
804 if (!cgroup_init(handler
)) {
805 ERROR("failed initing cgroups");
806 goto out_fini_handler
;
809 if (!cgroup_create(handler
)) {
810 ERROR("failed creating groups");
811 goto out_fini_handler
;
814 if (!restore_net_info(c
)) {
815 ERROR("failed restoring network info");
816 goto out_fini_handler
;
819 resolve_clone_flags(handler
);
821 if (pipe(pipes
) < 0) {
822 SYSERROR("pipe() failed");
823 goto out_fini_handler
;
828 goto out_fini_handler
;
832 struct lxc_rootfs
*rootfs
;
841 if (unshare(CLONE_NEWNS
))
842 goto out_fini_handler
;
844 /* CRIU needs the lxc root bind mounted so that it is the root of some
846 rootfs
= &c
->lxc_conf
->rootfs
;
848 if (rootfs_is_blockdev(c
->lxc_conf
)) {
849 if (do_rootfs_setup(c
->lxc_conf
, c
->name
, c
->config_path
) < 0)
850 goto out_fini_handler
;
852 if (mkdir(rootfs
->mount
, 0755) < 0 && errno
!= EEXIST
)
853 goto out_fini_handler
;
855 if (mount(NULL
, "/", NULL
, MS_SLAVE
| MS_REC
, NULL
) < 0) {
856 SYSERROR("remount / to private failed");
857 goto out_fini_handler
;
860 if (mount(rootfs
->path
, rootfs
->mount
, NULL
, MS_BIND
, NULL
) < 0) {
861 rmdir(rootfs
->mount
);
862 goto out_fini_handler
;
866 os
.pipefd
= pipes
[1];
867 os
.action
= "restore";
870 os
.console_fd
= c
->lxc_conf
->console
.slave
;
871 os
.criu_version
= criu_version
;
872 os
.handler
= handler
;
874 if (os
.console_fd
>= 0) {
875 /* Twiddle the FD_CLOEXEC bit. We want to pass this FD to criu
876 * via --inherit-fd, so we don't want it to close.
878 flags
= fcntl(os
.console_fd
, F_GETFD
);
880 SYSERROR("F_GETFD failed: %d", os
.console_fd
);
881 goto out_fini_handler
;
884 flags
&= ~FD_CLOEXEC
;
886 if (fcntl(os
.console_fd
, F_SETFD
, flags
) < 0) {
887 SYSERROR("F_SETFD failed");
888 goto out_fini_handler
;
891 os
.console_name
= c
->lxc_conf
->console
.name
;
893 /* exec_criu() returning is an error */
895 umount(rootfs
->mount
);
896 rmdir(rootfs
->mount
);
897 goto out_fini_handler
;
905 pid_t w
= waitpid(pid
, &status
, 0);
908 goto out_fini_handler
;
911 if (WIFEXITED(status
)) {
914 if (WEXITSTATUS(status
)) {
917 n
= read(pipes
[0], buf
, sizeof(buf
));
919 SYSERROR("failed reading from criu stderr");
920 goto out_fini_handler
;
923 if (n
== sizeof(buf
))
927 ERROR("criu process exited %d, output:\n%s", WEXITSTATUS(status
), buf
);
928 goto out_fini_handler
;
930 ret
= snprintf(buf
, sizeof(buf
), "/proc/self/task/%lu/children", (unsigned long)syscall(__NR_gettid
));
931 if (ret
< 0 || ret
>= sizeof(buf
)) {
932 ERROR("snprintf'd too many characters: %d", ret
);
933 goto out_fini_handler
;
936 FILE *f
= fopen(buf
, "r");
938 SYSERROR("couldn't read restore's children file %s", buf
);
939 goto out_fini_handler
;
942 ret
= fscanf(f
, "%d", (int*) &handler
->pid
);
945 ERROR("reading restore pid failed");
946 goto out_fini_handler
;
949 if (lxc_set_state(c
->name
, handler
, RUNNING
)) {
950 ERROR("error setting running state after restore");
951 goto out_fini_handler
;
955 ERROR("CRIU was killed with signal %d", WTERMSIG(status
));
956 goto out_fini_handler
;
961 ret
= write(status_pipe
, &status
, sizeof(status
));
965 if (sizeof(status
) != ret
) {
966 SYSERROR("failed to write all of status");
967 goto out_fini_handler
;
971 * See comment in lxcapi_start; we don't care if these
972 * fail because it's just a beauty thing. We just
973 * assign the return here to silence potential.
975 ret
= snprintf(title
, sizeof(title
), "[lxc monitor] %s %s", c
->config_path
, c
->name
);
976 ret
= setproctitle(title
);
978 ret
= lxc_poll(c
->name
, handler
);
980 lxc_abort(c
->name
, handler
);
981 lxc_fini(c
->name
, handler
);
991 lxc_fini(c
->name
, handler
);
994 if (status_pipe
>= 0) {
995 /* ensure getting here was a failure, e.g. if we failed to
996 * parse the child pid or something, even after a successful
1001 if (write(status_pipe
, &status
, sizeof(status
)) != sizeof(status
)) {
1002 SYSERROR("writing status failed");
1010 static int save_tty_major_minor(char *directory
, struct lxc_container
*c
, char *tty_id
, int len
)
1013 char path
[PATH_MAX
];
1017 if (c
->lxc_conf
->console
.path
&& !strcmp(c
->lxc_conf
->console
.path
, "none")) {
1022 ret
= snprintf(path
, sizeof(path
), "/proc/%d/root/dev/console", c
->init_pid(c
));
1023 if (ret
< 0 || ret
>= sizeof(path
)) {
1024 ERROR("snprintf'd too many chacters: %d", ret
);
1028 ret
= stat(path
, &sb
);
1030 SYSERROR("stat of %s failed", path
);
1034 ret
= snprintf(path
, sizeof(path
), "%s/tty.info", directory
);
1035 if (ret
< 0 || ret
>= sizeof(path
)) {
1036 ERROR("snprintf'd too many characters: %d", ret
);
1040 ret
= snprintf(tty_id
, len
, "tty[%llx:%llx]",
1041 (long long unsigned) sb
.st_rdev
,
1042 (long long unsigned) sb
.st_dev
);
1043 if (ret
< 0 || ret
>= sizeof(path
)) {
1044 ERROR("snprintf'd too many characters: %d", ret
);
1048 f
= fopen(path
, "w");
1050 SYSERROR("failed to open %s", path
);
1054 ret
= fprintf(f
, "%s", tty_id
);
1057 SYSERROR("failed to write to %s", path
);
1061 /* do one of either predump or a regular dump */
1062 static bool do_dump(struct lxc_container
*c
, char *mode
, struct migrate_opts
*opts
)
1065 char *criu_version
= NULL
;
1068 if (!criu_ok(c
, &criu_version
))
1071 if (pipe(criuout
) < 0) {
1072 SYSERROR("pipe() failed");
1076 if (mkdir_p(opts
->directory
, 0700) < 0)
1081 SYSERROR("fork failed");
1086 struct criu_opts os
;
1087 struct lxc_handler h
;
1092 if (!cgroup_init(&h
)) {
1093 ERROR("failed to cgroup_init()");
1097 os
.pipefd
= criuout
[1];
1101 os
.console_name
= c
->lxc_conf
->console
.path
;
1102 os
.criu_version
= criu_version
;
1104 if (save_tty_major_minor(opts
->directory
, c
, os
.tty_id
, sizeof(os
.tty_id
)) < 0)
1107 /* exec_criu() returning is an error */
1118 pid_t w
= waitpid(pid
, &status
, 0);
1120 SYSERROR("waitpid");
1125 n
= read(criuout
[0], buf
, sizeof(buf
));
1133 if (WIFEXITED(status
)) {
1134 if (WEXITSTATUS(status
)) {
1135 ERROR("dump failed with %d", WEXITSTATUS(status
));
1140 } else if (WIFSIGNALED(status
)) {
1141 ERROR("dump signaled with %d", WTERMSIG(status
));
1144 ERROR("unknown dump exit %d", status
);
1149 ERROR("criu output: %s", buf
);
1155 rmdir(opts
->directory
);
1159 bool __criu_pre_dump(struct lxc_container
*c
, struct migrate_opts
*opts
)
1161 return do_dump(c
, "pre-dump", opts
);
1164 bool __criu_dump(struct lxc_container
*c
, struct migrate_opts
*opts
)
1166 char path
[PATH_MAX
];
1169 ret
= snprintf(path
, sizeof(path
), "%s/inventory.img", opts
->directory
);
1170 if (ret
< 0 || ret
>= sizeof(path
))
1173 if (access(path
, F_OK
) == 0) {
1174 ERROR("please use a fresh directory for the dump directory");
1178 return do_dump(c
, "dump", opts
);
1181 bool __criu_restore(struct lxc_container
*c
, struct migrate_opts
*opts
)
1186 char *criu_version
= NULL
;
1188 if (!criu_ok(c
, &criu_version
))
1192 ERROR("Must be root to restore");
1197 ERROR("failed to create pipe");
1210 // this never returns
1211 do_restore(c
, pipefd
[1], opts
, criu_version
);
1216 nread
= read(pipefd
[0], &status
, sizeof(status
));
1218 if (sizeof(status
) != nread
) {
1219 ERROR("reading status from pipe failed");
1223 // If the criu process was killed or exited nonzero, wait() for the
1224 // handler, since the restore process died. Otherwise, we don't need to
1225 // wait, since the child becomes the monitor process.
1226 if (!WIFEXITED(status
) || WEXITSTATUS(status
))
1231 if (wait_for_pid(pid
))
1232 ERROR("restore process died");