]> git.proxmox.com Git - mirror_lxc.git/blob - src/lxc/criu.c
Merge pull request #901 from stgraber/master
[mirror_lxc.git] / src / lxc / criu.c
1 /*
2 * lxc: linux Container library
3 *
4 * Copyright © 2014-2015 Canonical Ltd.
5 *
6 * Authors:
7 * Tycho Andersen <tycho.andersen@canonical.com>
8 *
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.
13 *
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.
18 *
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
22 */
23 #define _GNU_SOURCE
24 #include <assert.h>
25 #include <linux/limits.h>
26 #include <sched.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <sys/mount.h>
31 #include <sys/types.h>
32 #include <sys/wait.h>
33 #include <unistd.h>
34
35 #include "config.h"
36
37 #include "bdev/bdev.h"
38 #include "cgroup.h"
39 #include "conf.h"
40 #include "commands.h"
41 #include "criu.h"
42 #include "log.h"
43 #include "lxc.h"
44 #include "lxclock.h"
45 #include "network.h"
46 #include "utils.h"
47
48 #define CRIU_VERSION "2.0"
49
50 #define CRIU_GITID_VERSION "2.0"
51 #define CRIU_GITID_PATCHLEVEL 0
52
53 lxc_log_define(lxc_criu, lxc);
54
55 struct criu_opts {
56 /* The type of criu invocation, one of "dump" or "restore" */
57 char *action;
58
59 /* The directory to pass to criu */
60 char *directory;
61
62 /* The container to dump */
63 struct lxc_container *c;
64
65 /* Enable criu verbose mode? */
66 bool verbose;
67
68 /* (pre-)dump: a directory for the previous dump's images */
69 char *predump_dir;
70
71 /* dump: stop the container or not after dumping? */
72 bool stop;
73 char tty_id[32]; /* the criu tty id for /dev/console, i.e. "tty[${rdev}:${dev}]" */
74
75 /* restore: the file to write the init process' pid into */
76 char *pidfile;
77 const char *cgroup_path;
78 int console_fd;
79 /* The path that is bind mounted from /dev/console, if any. We don't
80 * want to use `--ext-mount-map auto`'s result here because the pts
81 * device may have a different path (e.g. if the pty number is
82 * different) on the target host. NULL if lxc.console = "none".
83 */
84 char *console_name;
85 };
86
87 static int load_tty_major_minor(char *directory, char *output, int len)
88 {
89 FILE *f;
90 char path[PATH_MAX];
91 int ret;
92
93 ret = snprintf(path, sizeof(path), "%s/tty.info", directory);
94 if (ret < 0 || ret >= sizeof(path)) {
95 ERROR("snprintf'd too many chacters: %d", ret);
96 return -1;
97 }
98
99 f = fopen(path, "r");
100 if (!f) {
101 /* This means we're coming from a liblxc which didn't export
102 * the tty info. In this case they had to have lxc.console =
103 * none, so there's no problem restoring.
104 */
105 if (errno == ENOENT)
106 return 0;
107
108 SYSERROR("couldn't open %s", path);
109 return -1;
110 }
111
112 if (!fgets(output, len, f)) {
113 fclose(f);
114 SYSERROR("couldn't read %s", path);
115 return -1;
116 }
117
118 fclose(f);
119 return 0;
120 }
121
122 static void exec_criu(struct criu_opts *opts)
123 {
124 char **argv, log[PATH_MAX];
125 int static_args = 24, argc = 0, i, ret;
126 int netnr = 0;
127 struct lxc_list *it;
128
129 char buf[4096], tty_info[32];
130
131 /* If we are currently in a cgroup /foo/bar, and the container is in a
132 * cgroup /lxc/foo, lxcfs will give us an ENOENT if some task in the
133 * container has an open fd that points to one of the cgroup files
134 * (systemd always opens its "root" cgroup). So, let's escape to the
135 * /actual/ root cgroup so that lxcfs thinks criu has enough rights to
136 * see all cgroups.
137 */
138 if (!cgroup_escape()) {
139 ERROR("failed to escape cgroups");
140 return;
141 }
142
143 /* The command line always looks like:
144 * criu $(action) --tcp-established --file-locks --link-remap --force-irmap \
145 * --manage-cgroups action-script foo.sh -D $(directory) \
146 * -o $(directory)/$(action).log --ext-mount-map auto
147 * --enable-external-sharing --enable-external-masters
148 * --enable-fs hugetlbfs --enable-fs tracefs --ext-mount-map console:/dev/pts/n
149 * +1 for final NULL */
150
151 if (strcmp(opts->action, "dump") == 0 || strcmp(opts->action, "pre-dump") == 0) {
152 /* -t pid --freeze-cgroup /lxc/ct */
153 static_args += 4;
154
155 /* --prev-images-dir <path-to-directory-A-relative-to-B> */
156 if (opts->predump_dir)
157 static_args += 2;
158
159 /* --leave-running (only for final dump) */
160 if (strcmp(opts->action, "dump") == 0 && !opts->stop)
161 static_args++;
162
163 /* --external tty[88,4] */
164 if (opts->tty_id[0])
165 static_args += 2;
166 } else if (strcmp(opts->action, "restore") == 0) {
167 /* --root $(lxc_mount_point) --restore-detached
168 * --restore-sibling --pidfile $foo --cgroup-root $foo
169 * --lsm-profile apparmor:whatever
170 */
171 static_args += 10;
172
173 tty_info[0] = 0;
174 if (load_tty_major_minor(opts->directory, tty_info, sizeof(tty_info)))
175 return;
176
177 /* --inherit-fd fd[%d]:tty[%s] */
178 if (tty_info[0])
179 static_args += 2;
180 } else {
181 return;
182 }
183
184 if (opts->verbose)
185 static_args++;
186
187 ret = snprintf(log, PATH_MAX, "%s/%s.log", opts->directory, opts->action);
188 if (ret < 0 || ret >= PATH_MAX) {
189 ERROR("logfile name too long\n");
190 return;
191 }
192
193 argv = malloc(static_args * sizeof(*argv));
194 if (!argv)
195 return;
196
197 memset(argv, 0, static_args * sizeof(*argv));
198
199 #define DECLARE_ARG(arg) \
200 do { \
201 if (arg == NULL) { \
202 ERROR("Got NULL argument for criu"); \
203 goto err; \
204 } \
205 argv[argc++] = strdup(arg); \
206 if (!argv[argc-1]) \
207 goto err; \
208 } while (0)
209
210 argv[argc++] = on_path("criu", NULL);
211 if (!argv[argc-1]) {
212 ERROR("Couldn't find criu binary\n");
213 goto err;
214 }
215
216 DECLARE_ARG(opts->action);
217 DECLARE_ARG("--tcp-established");
218 DECLARE_ARG("--file-locks");
219 DECLARE_ARG("--link-remap");
220 DECLARE_ARG("--force-irmap");
221 DECLARE_ARG("--manage-cgroups");
222 DECLARE_ARG("--ext-mount-map");
223 DECLARE_ARG("auto");
224 DECLARE_ARG("--enable-external-sharing");
225 DECLARE_ARG("--enable-external-masters");
226 DECLARE_ARG("--enable-fs");
227 DECLARE_ARG("hugetlbfs");
228 DECLARE_ARG("--enable-fs");
229 DECLARE_ARG("tracefs");
230 DECLARE_ARG("-D");
231 DECLARE_ARG(opts->directory);
232 DECLARE_ARG("-o");
233 DECLARE_ARG(log);
234
235 if (opts->verbose)
236 DECLARE_ARG("-vvvvvv");
237
238 if (strcmp(opts->action, "dump") == 0 || strcmp(opts->action, "pre-dump") == 0) {
239 char pid[32], *freezer_relative;
240
241 if (sprintf(pid, "%d", opts->c->init_pid(opts->c)) < 0)
242 goto err;
243
244 DECLARE_ARG("-t");
245 DECLARE_ARG(pid);
246
247 freezer_relative = lxc_cmd_get_cgroup_path(opts->c->name,
248 opts->c->config_path,
249 "freezer");
250 if (!freezer_relative) {
251 ERROR("failed getting freezer path");
252 goto err;
253 }
254
255 ret = snprintf(log, sizeof(log), "/sys/fs/cgroup/freezer/%s", freezer_relative);
256 if (ret < 0 || ret >= sizeof(log))
257 goto err;
258
259 DECLARE_ARG("--freeze-cgroup");
260 DECLARE_ARG(log);
261
262 DECLARE_ARG("--ext-mount-map");
263 DECLARE_ARG("/dev/console:console");
264 if (opts->tty_id[0]) {
265 DECLARE_ARG("--external");
266 DECLARE_ARG(opts->tty_id);
267 }
268
269 if (opts->predump_dir) {
270 DECLARE_ARG("--prev-images-dir");
271 DECLARE_ARG(opts->predump_dir);
272 }
273
274 /* only for final dump */
275 if (strcmp(opts->action, "dump") == 0 && !opts->stop)
276 DECLARE_ARG("--leave-running");
277 } else if (strcmp(opts->action, "restore") == 0) {
278 void *m;
279 int additional;
280 struct lxc_conf *lxc_conf = opts->c->lxc_conf;
281
282 DECLARE_ARG("--root");
283 DECLARE_ARG(opts->c->lxc_conf->rootfs.mount);
284 DECLARE_ARG("--restore-detached");
285 DECLARE_ARG("--restore-sibling");
286 DECLARE_ARG("--pidfile");
287 DECLARE_ARG(opts->pidfile);
288 DECLARE_ARG("--cgroup-root");
289 DECLARE_ARG(opts->cgroup_path);
290
291 if (tty_info[0]) {
292 ret = snprintf(buf, sizeof(buf), "fd[%d]:%s", opts->console_fd, tty_info);
293 if (ret < 0 || ret >= sizeof(buf))
294 goto err;
295
296 DECLARE_ARG("--inherit-fd");
297 DECLARE_ARG(buf);
298 }
299 if (opts->console_name) {
300 if (snprintf(buf, sizeof(buf), "console:%s", opts->console_name) < 0) {
301 SYSERROR("sprintf'd too many bytes");
302 }
303 DECLARE_ARG("--ext-mount-map");
304 DECLARE_ARG(buf);
305 }
306
307 if (lxc_conf->lsm_aa_profile || lxc_conf->lsm_se_context) {
308
309 if (lxc_conf->lsm_aa_profile)
310 ret = snprintf(buf, sizeof(buf), "apparmor:%s", lxc_conf->lsm_aa_profile);
311 else
312 ret = snprintf(buf, sizeof(buf), "selinux:%s", lxc_conf->lsm_se_context);
313
314 if (ret < 0 || ret >= sizeof(buf))
315 goto err;
316
317 DECLARE_ARG("--lsm-profile");
318 DECLARE_ARG(buf);
319 }
320
321 additional = lxc_list_len(&opts->c->lxc_conf->network) * 2;
322
323 m = realloc(argv, (argc + additional + 1) * sizeof(*argv));
324 if (!m)
325 goto err;
326 argv = m;
327
328 lxc_list_for_each(it, &opts->c->lxc_conf->network) {
329 char eth[128], *veth;
330 struct lxc_netdev *n = it->elem;
331
332 if (n->type != LXC_NET_VETH)
333 continue;
334
335 if (n->name) {
336 if (strlen(n->name) >= sizeof(eth))
337 goto err;
338 strncpy(eth, n->name, sizeof(eth));
339 } else
340 sprintf(eth, "eth%d", netnr);
341
342 veth = n->priv.veth_attr.pair;
343
344 if (n->link)
345 ret = snprintf(buf, sizeof(buf), "%s=%s@%s", eth, veth, n->link);
346 else
347 ret = snprintf(buf, sizeof(buf), "%s=%s", eth, veth);
348 if (ret < 0 || ret >= sizeof(buf))
349 goto err;
350
351 DECLARE_ARG("--veth-pair");
352 DECLARE_ARG(buf);
353 }
354
355 }
356
357 argv[argc] = NULL;
358
359 #undef DECLARE_ARG
360 execv(argv[0], argv);
361 err:
362 for (i = 0; argv[i]; i++)
363 free(argv[i]);
364 free(argv);
365 }
366
367 /*
368 * Check to see if the criu version is recent enough for all the features we
369 * use. This version allows either CRIU_VERSION or (CRIU_GITID_VERSION and
370 * CRIU_GITID_PATCHLEVEL) to work, enabling users building from git to c/r
371 * things potentially before a version is released with a particular feature.
372 *
373 * The intent is that when criu development slows down, we can drop this, but
374 * for now we shouldn't attempt to c/r with versions that we know won't work.
375 */
376 static bool criu_version_ok()
377 {
378 int pipes[2];
379 pid_t pid;
380
381 if (pipe(pipes) < 0) {
382 SYSERROR("pipe() failed");
383 return false;
384 }
385
386 pid = fork();
387 if (pid < 0) {
388 SYSERROR("fork() failed");
389 return false;
390 }
391
392 if (pid == 0) {
393 char *args[] = { "criu", "--version", NULL };
394 char *path;
395 close(pipes[0]);
396
397 close(STDERR_FILENO);
398 if (dup2(pipes[1], STDOUT_FILENO) < 0)
399 exit(1);
400
401 path = on_path("criu", NULL);
402 if (!path)
403 exit(1);
404
405 execv(path, args);
406 exit(1);
407 } else {
408 FILE *f;
409 char version[1024];
410 int patch;
411
412 close(pipes[1]);
413 if (wait_for_pid(pid) < 0) {
414 close(pipes[0]);
415 SYSERROR("execing criu failed, is it installed?");
416 return false;
417 }
418
419 f = fdopen(pipes[0], "r");
420 if (!f) {
421 close(pipes[0]);
422 return false;
423 }
424
425 if (fscanf(f, "Version: %1023[^\n]s", version) != 1)
426 goto version_error;
427
428 if (fgetc(f) != '\n')
429 goto version_error;
430
431 if (strcmp(version, CRIU_VERSION) >= 0)
432 goto version_match;
433
434 if (fscanf(f, "GitID: v%1023[^-]s", version) != 1)
435 goto version_error;
436
437 if (fgetc(f) != '-')
438 goto version_error;
439
440 if (fscanf(f, "%d", &patch) != 1)
441 goto version_error;
442
443 if (strcmp(version, CRIU_GITID_VERSION) < 0)
444 goto version_error;
445
446 if (patch < CRIU_GITID_PATCHLEVEL)
447 goto version_error;
448
449 version_match:
450 fclose(f);
451 return true;
452
453 version_error:
454 fclose(f);
455 ERROR("must have criu " CRIU_VERSION " or greater to checkpoint/restore\n");
456 return false;
457 }
458 }
459
460 /* Check and make sure the container has a configuration that we know CRIU can
461 * dump. */
462 static bool criu_ok(struct lxc_container *c)
463 {
464 struct lxc_list *it;
465
466 if (!criu_version_ok())
467 return false;
468
469 if (geteuid()) {
470 ERROR("Must be root to checkpoint\n");
471 return false;
472 }
473
474 /* We only know how to restore containers with veth networks. */
475 lxc_list_for_each(it, &c->lxc_conf->network) {
476 struct lxc_netdev *n = it->elem;
477 switch(n->type) {
478 case LXC_NET_VETH:
479 case LXC_NET_NONE:
480 case LXC_NET_EMPTY:
481 break;
482 default:
483 ERROR("Found network that is not VETH or NONE\n");
484 return false;
485 }
486 }
487
488 return true;
489 }
490
491 static bool restore_net_info(struct lxc_container *c)
492 {
493 struct lxc_list *it;
494 bool has_error = true;
495
496 if (container_mem_lock(c))
497 return false;
498
499 lxc_list_for_each(it, &c->lxc_conf->network) {
500 struct lxc_netdev *netdev = it->elem;
501 char template[IFNAMSIZ];
502
503 if (netdev->type != LXC_NET_VETH)
504 continue;
505
506 snprintf(template, sizeof(template), "vethXXXXXX");
507
508 if (!netdev->priv.veth_attr.pair)
509 netdev->priv.veth_attr.pair = lxc_mkifname(template);
510
511 if (!netdev->priv.veth_attr.pair)
512 goto out_unlock;
513 }
514
515 has_error = false;
516
517 out_unlock:
518 container_mem_unlock(c);
519 return !has_error;
520 }
521
522 // do_restore never returns, the calling process is used as the
523 // monitor process. do_restore calls exit() if it fails.
524 void do_restore(struct lxc_container *c, int pipe, char *directory, bool verbose)
525 {
526 pid_t pid;
527 char pidfile[L_tmpnam];
528 struct lxc_handler *handler;
529 int status;
530
531 if (!tmpnam(pidfile))
532 goto out;
533
534 handler = lxc_init(c->name, c->lxc_conf, c->config_path);
535 if (!handler)
536 goto out;
537
538 if (!cgroup_init(handler)) {
539 ERROR("failed initing cgroups");
540 goto out_fini_handler;
541 }
542
543 if (!cgroup_create(handler)) {
544 ERROR("failed creating groups");
545 goto out_fini_handler;
546 }
547
548 if (!restore_net_info(c)) {
549 ERROR("failed restoring network info");
550 goto out_fini_handler;
551 }
552
553 resolve_clone_flags(handler);
554
555 pid = fork();
556 if (pid < 0)
557 goto out_fini_handler;
558
559 if (pid == 0) {
560 struct criu_opts os;
561 struct lxc_rootfs *rootfs;
562 int flags;
563
564 close(pipe);
565 pipe = -1;
566
567 if (unshare(CLONE_NEWNS))
568 goto out_fini_handler;
569
570 /* CRIU needs the lxc root bind mounted so that it is the root of some
571 * mount. */
572 rootfs = &c->lxc_conf->rootfs;
573
574 if (rootfs_is_blockdev(c->lxc_conf)) {
575 if (do_rootfs_setup(c->lxc_conf, c->name, c->config_path) < 0)
576 goto out_fini_handler;
577 } else {
578 if (mkdir(rootfs->mount, 0755) < 0 && errno != EEXIST)
579 goto out_fini_handler;
580
581 if (mount(NULL, "/", NULL, MS_SLAVE | MS_REC, NULL) < 0) {
582 SYSERROR("remount / to private failed");
583 goto out_fini_handler;
584 }
585
586 if (mount(rootfs->path, rootfs->mount, NULL, MS_BIND, NULL) < 0) {
587 rmdir(rootfs->mount);
588 goto out_fini_handler;
589 }
590 }
591
592 os.action = "restore";
593 os.directory = directory;
594 os.c = c;
595 os.pidfile = pidfile;
596 os.verbose = verbose;
597 os.cgroup_path = cgroup_canonical_path(handler);
598 os.console_fd = c->lxc_conf->console.slave;
599
600 /* Twiddle the FD_CLOEXEC bit. We want to pass this FD to criu
601 * via --inherit-fd, so we don't want it to close.
602 */
603 flags = fcntl(os.console_fd, F_GETFD);
604 if (flags < 0) {
605 SYSERROR("F_GETFD failed");
606 goto out_fini_handler;
607 }
608
609 flags &= ~FD_CLOEXEC;
610
611 if (fcntl(os.console_fd, F_SETFD, flags) < 0) {
612 SYSERROR("F_SETFD failed");
613 goto out_fini_handler;
614 }
615 os.console_name = c->lxc_conf->console.name;
616
617 /* exec_criu() returning is an error */
618 exec_criu(&os);
619 umount(rootfs->mount);
620 rmdir(rootfs->mount);
621 goto out_fini_handler;
622 } else {
623 int ret;
624 char title[2048];
625
626 pid_t w = waitpid(pid, &status, 0);
627 if (w == -1) {
628 SYSERROR("waitpid");
629 goto out_fini_handler;
630 }
631
632 ret = write(pipe, &status, sizeof(status));
633 close(pipe);
634 pipe = -1;
635
636 if (sizeof(status) != ret) {
637 SYSERROR("failed to write all of status");
638 goto out_fini_handler;
639 }
640
641 if (WIFEXITED(status)) {
642 if (WEXITSTATUS(status)) {
643 ERROR("criu process exited %d\n", WEXITSTATUS(status));
644 goto out_fini_handler;
645 } else {
646 int ret;
647 FILE *f = fopen(pidfile, "r");
648 if (!f) {
649 SYSERROR("couldn't read restore's init pidfile %s\n", pidfile);
650 goto out_fini_handler;
651 }
652
653 ret = fscanf(f, "%d", (int*) &handler->pid);
654 fclose(f);
655 if (unlink(pidfile) < 0 && errno != ENOENT)
656 SYSERROR("unlinking pidfile failed");
657
658 if (ret != 1) {
659 ERROR("reading restore pid failed");
660 goto out_fini_handler;
661 }
662
663 if (lxc_set_state(c->name, handler, RUNNING)) {
664 ERROR("error setting running state after restore");
665 goto out_fini_handler;
666 }
667 }
668 } else {
669 ERROR("CRIU was killed with signal %d\n", WTERMSIG(status));
670 goto out_fini_handler;
671 }
672
673 /*
674 * See comment in lxcapi_start; we don't care if these
675 * fail because it's just a beauty thing. We just
676 * assign the return here to silence potential.
677 */
678 ret = snprintf(title, sizeof(title), "[lxc monitor] %s %s", c->config_path, c->name);
679 ret = setproctitle(title);
680
681 ret = lxc_poll(c->name, handler);
682 if (ret)
683 lxc_abort(c->name, handler);
684 lxc_fini(c->name, handler);
685 exit(ret);
686 }
687
688 out_fini_handler:
689 lxc_fini(c->name, handler);
690 if (unlink(pidfile) < 0 && errno != ENOENT)
691 SYSERROR("unlinking pidfile failed");
692
693 out:
694 if (pipe >= 0) {
695 status = 1;
696 if (write(pipe, &status, sizeof(status)) != sizeof(status)) {
697 SYSERROR("writing status failed");
698 }
699 close(pipe);
700 }
701
702 exit(1);
703 }
704
705 static int save_tty_major_minor(char *directory, struct lxc_container *c, char *tty_id, int len)
706 {
707 FILE *f;
708 char path[PATH_MAX];
709 int ret;
710 struct stat sb;
711
712 if (c->lxc_conf->console.path && !strcmp(c->lxc_conf->console.path, "none")) {
713 tty_id[0] = 0;
714 return 0;
715 }
716
717 ret = snprintf(path, sizeof(path), "/proc/%d/root/dev/console", c->init_pid(c));
718 if (ret < 0 || ret >= sizeof(path)) {
719 ERROR("snprintf'd too many chacters: %d", ret);
720 return -1;
721 }
722
723 ret = stat(path, &sb);
724 if (ret < 0) {
725 SYSERROR("stat of %s failed", path);
726 return -1;
727 }
728
729 ret = snprintf(path, sizeof(path), "%s/tty.info", directory);
730 if (ret < 0 || ret >= sizeof(path)) {
731 ERROR("snprintf'd too many characters: %d", ret);
732 return -1;
733 }
734
735 ret = snprintf(tty_id, len, "tty[%llx:%llx]",
736 (long long unsigned) sb.st_rdev,
737 (long long unsigned) sb.st_dev);
738 if (ret < 0 || ret >= sizeof(path)) {
739 ERROR("snprintf'd too many characters: %d", ret);
740 return -1;
741 }
742
743 f = fopen(path, "w");
744 if (!f) {
745 SYSERROR("failed to open %s", path);
746 return -1;
747 }
748
749 ret = fprintf(f, "%s", tty_id);
750 fclose(f);
751 if (ret < 0)
752 SYSERROR("failed to write to %s", path);
753 return ret;
754 }
755
756 /* do one of either predump or a regular dump */
757 static bool do_dump(struct lxc_container *c, char *mode, char *directory,
758 bool stop, bool verbose, char *predump_dir)
759 {
760 pid_t pid;
761
762 if (!criu_ok(c))
763 return false;
764
765 if (mkdir_p(directory, 0700) < 0)
766 return false;
767
768 pid = fork();
769 if (pid < 0) {
770 SYSERROR("fork failed");
771 return false;
772 }
773
774 if (pid == 0) {
775 struct criu_opts os;
776
777 os.action = mode;
778 os.directory = directory;
779 os.c = c;
780 os.stop = stop;
781 os.verbose = verbose;
782 os.predump_dir = predump_dir;
783 os.console_name = c->lxc_conf->console.path;
784
785 if (save_tty_major_minor(directory, c, os.tty_id, sizeof(os.tty_id)) < 0)
786 exit(1);
787
788 /* exec_criu() returning is an error */
789 exec_criu(&os);
790 exit(1);
791 } else {
792 int status;
793 pid_t w = waitpid(pid, &status, 0);
794 if (w == -1) {
795 SYSERROR("waitpid");
796 return false;
797 }
798
799 if (WIFEXITED(status)) {
800 if (WEXITSTATUS(status)) {
801 ERROR("dump failed with %d\n", WEXITSTATUS(status));
802 return false;
803 }
804
805 return true;
806 } else if (WIFSIGNALED(status)) {
807 ERROR("dump signaled with %d\n", WTERMSIG(status));
808 return false;
809 } else {
810 ERROR("unknown dump exit %d\n", status);
811 return false;
812 }
813 }
814 }
815
816 bool pre_dump(struct lxc_container *c, char *directory, bool verbose, char *predump_dir)
817 {
818 return do_dump(c, "pre-dump", directory, false, verbose, predump_dir);
819 }
820
821 bool dump(struct lxc_container *c, char *directory, bool stop, bool verbose, char *predump_dir)
822 {
823 char path[PATH_MAX];
824 int ret;
825
826 ret = snprintf(path, sizeof(path), "%s/inventory.img", directory);
827 if (ret < 0 || ret >= sizeof(path))
828 return false;
829
830 if (access(path, F_OK) == 0) {
831 ERROR("please use a fresh directory for the dump directory\n");
832 return false;
833 }
834
835 return do_dump(c, "dump", directory, stop, verbose, predump_dir);
836 }
837
838 bool restore(struct lxc_container *c, char *directory, bool verbose)
839 {
840 pid_t pid;
841 int status, nread;
842 int pipefd[2];
843
844 if (!criu_ok(c))
845 return false;
846
847 if (geteuid()) {
848 ERROR("Must be root to restore\n");
849 return false;
850 }
851
852 if (pipe(pipefd)) {
853 ERROR("failed to create pipe");
854 return false;
855 }
856
857 pid = fork();
858 if (pid < 0) {
859 close(pipefd[0]);
860 close(pipefd[1]);
861 return false;
862 }
863
864 if (pid == 0) {
865 close(pipefd[0]);
866 // this never returns
867 do_restore(c, pipefd[1], directory, verbose);
868 }
869
870 close(pipefd[1]);
871
872 nread = read(pipefd[0], &status, sizeof(status));
873 close(pipefd[0]);
874 if (sizeof(status) != nread) {
875 ERROR("reading status from pipe failed");
876 goto err_wait;
877 }
878
879 // If the criu process was killed or exited nonzero, wait() for the
880 // handler, since the restore process died. Otherwise, we don't need to
881 // wait, since the child becomes the monitor process.
882 if (!WIFEXITED(status) || WEXITSTATUS(status))
883 goto err_wait;
884 return true;
885
886 err_wait:
887 if (wait_for_pid(pid))
888 ERROR("restore process died");
889 return false;
890 }