]> git.proxmox.com Git - mirror_lxc.git/blob - src/lxc/criu.c
c/r: print criu's stdout when it fails
[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], *pos, 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 buf[0] = 0;
360 pos = buf;
361 for (i = 0; argv[i]; i++) {
362 pos = strncat(buf, argv[i], buf + sizeof(buf) - pos);
363 pos = strncat(buf, " ", buf + sizeof(buf) - pos);
364 }
365
366 INFO("execing: %s", buf);
367
368 #undef DECLARE_ARG
369 execv(argv[0], argv);
370 err:
371 for (i = 0; argv[i]; i++)
372 free(argv[i]);
373 free(argv);
374 }
375
376 /*
377 * Check to see if the criu version is recent enough for all the features we
378 * use. This version allows either CRIU_VERSION or (CRIU_GITID_VERSION and
379 * CRIU_GITID_PATCHLEVEL) to work, enabling users building from git to c/r
380 * things potentially before a version is released with a particular feature.
381 *
382 * The intent is that when criu development slows down, we can drop this, but
383 * for now we shouldn't attempt to c/r with versions that we know won't work.
384 */
385 static bool criu_version_ok()
386 {
387 int pipes[2];
388 pid_t pid;
389
390 if (pipe(pipes) < 0) {
391 SYSERROR("pipe() failed");
392 return false;
393 }
394
395 pid = fork();
396 if (pid < 0) {
397 SYSERROR("fork() failed");
398 return false;
399 }
400
401 if (pid == 0) {
402 char *args[] = { "criu", "--version", NULL };
403 char *path;
404 close(pipes[0]);
405
406 close(STDERR_FILENO);
407 if (dup2(pipes[1], STDOUT_FILENO) < 0)
408 exit(1);
409
410 path = on_path("criu", NULL);
411 if (!path)
412 exit(1);
413
414 execv(path, args);
415 exit(1);
416 } else {
417 FILE *f;
418 char version[1024];
419 int patch;
420
421 close(pipes[1]);
422 if (wait_for_pid(pid) < 0) {
423 close(pipes[0]);
424 SYSERROR("execing criu failed, is it installed?");
425 return false;
426 }
427
428 f = fdopen(pipes[0], "r");
429 if (!f) {
430 close(pipes[0]);
431 return false;
432 }
433
434 if (fscanf(f, "Version: %1023[^\n]s", version) != 1)
435 goto version_error;
436
437 if (fgetc(f) != '\n')
438 goto version_error;
439
440 if (strcmp(version, CRIU_VERSION) >= 0)
441 goto version_match;
442
443 if (fscanf(f, "GitID: v%1023[^-]s", version) != 1)
444 goto version_error;
445
446 if (fgetc(f) != '-')
447 goto version_error;
448
449 if (fscanf(f, "%d", &patch) != 1)
450 goto version_error;
451
452 if (strcmp(version, CRIU_GITID_VERSION) < 0)
453 goto version_error;
454
455 if (patch < CRIU_GITID_PATCHLEVEL)
456 goto version_error;
457
458 version_match:
459 fclose(f);
460 return true;
461
462 version_error:
463 fclose(f);
464 ERROR("must have criu " CRIU_VERSION " or greater to checkpoint/restore\n");
465 return false;
466 }
467 }
468
469 /* Check and make sure the container has a configuration that we know CRIU can
470 * dump. */
471 static bool criu_ok(struct lxc_container *c)
472 {
473 struct lxc_list *it;
474
475 if (!criu_version_ok())
476 return false;
477
478 if (geteuid()) {
479 ERROR("Must be root to checkpoint\n");
480 return false;
481 }
482
483 /* We only know how to restore containers with veth networks. */
484 lxc_list_for_each(it, &c->lxc_conf->network) {
485 struct lxc_netdev *n = it->elem;
486 switch(n->type) {
487 case LXC_NET_VETH:
488 case LXC_NET_NONE:
489 case LXC_NET_EMPTY:
490 break;
491 default:
492 ERROR("Found network that is not VETH or NONE\n");
493 return false;
494 }
495 }
496
497 return true;
498 }
499
500 static bool restore_net_info(struct lxc_container *c)
501 {
502 struct lxc_list *it;
503 bool has_error = true;
504
505 if (container_mem_lock(c))
506 return false;
507
508 lxc_list_for_each(it, &c->lxc_conf->network) {
509 struct lxc_netdev *netdev = it->elem;
510 char template[IFNAMSIZ];
511
512 if (netdev->type != LXC_NET_VETH)
513 continue;
514
515 snprintf(template, sizeof(template), "vethXXXXXX");
516
517 if (!netdev->priv.veth_attr.pair)
518 netdev->priv.veth_attr.pair = lxc_mkifname(template);
519
520 if (!netdev->priv.veth_attr.pair)
521 goto out_unlock;
522 }
523
524 has_error = false;
525
526 out_unlock:
527 container_mem_unlock(c);
528 return !has_error;
529 }
530
531 // do_restore never returns, the calling process is used as the
532 // monitor process. do_restore calls exit() if it fails.
533 void do_restore(struct lxc_container *c, int status_pipe, char *directory, bool verbose)
534 {
535 pid_t pid;
536 char pidfile[L_tmpnam];
537 struct lxc_handler *handler;
538 int status, pipes[2] = {-1, -1};
539
540 if (!tmpnam(pidfile))
541 goto out;
542
543 handler = lxc_init(c->name, c->lxc_conf, c->config_path);
544 if (!handler)
545 goto out;
546
547 if (!cgroup_init(handler)) {
548 ERROR("failed initing cgroups");
549 goto out_fini_handler;
550 }
551
552 if (!cgroup_create(handler)) {
553 ERROR("failed creating groups");
554 goto out_fini_handler;
555 }
556
557 if (!restore_net_info(c)) {
558 ERROR("failed restoring network info");
559 goto out_fini_handler;
560 }
561
562 resolve_clone_flags(handler);
563
564 if (pipe(pipes) < 0) {
565 SYSERROR("pipe() failed");
566 goto out_fini_handler;
567 }
568
569 pid = fork();
570 if (pid < 0)
571 goto out_fini_handler;
572
573 if (pid == 0) {
574 struct criu_opts os;
575 struct lxc_rootfs *rootfs;
576 int flags;
577
578 close(status_pipe);
579 status_pipe = -1;
580
581 close(pipes[0]);
582 pipes[0] = -1;
583 if (dup2(pipes[1], STDERR_FILENO) < 0) {
584 SYSERROR("dup2 failed");
585 goto out_fini_handler;
586 }
587
588 if (dup2(pipes[1], STDOUT_FILENO) < 0) {
589 SYSERROR("dup2 failed");
590 goto out_fini_handler;
591 }
592
593 if (unshare(CLONE_NEWNS))
594 goto out_fini_handler;
595
596 /* CRIU needs the lxc root bind mounted so that it is the root of some
597 * mount. */
598 rootfs = &c->lxc_conf->rootfs;
599
600 if (rootfs_is_blockdev(c->lxc_conf)) {
601 if (do_rootfs_setup(c->lxc_conf, c->name, c->config_path) < 0)
602 goto out_fini_handler;
603 } else {
604 if (mkdir(rootfs->mount, 0755) < 0 && errno != EEXIST)
605 goto out_fini_handler;
606
607 if (mount(NULL, "/", NULL, MS_SLAVE | MS_REC, NULL) < 0) {
608 SYSERROR("remount / to private failed");
609 goto out_fini_handler;
610 }
611
612 if (mount(rootfs->path, rootfs->mount, NULL, MS_BIND, NULL) < 0) {
613 rmdir(rootfs->mount);
614 goto out_fini_handler;
615 }
616 }
617
618 os.action = "restore";
619 os.directory = directory;
620 os.c = c;
621 os.pidfile = pidfile;
622 os.verbose = verbose;
623 os.cgroup_path = cgroup_canonical_path(handler);
624 os.console_fd = c->lxc_conf->console.slave;
625
626 /* Twiddle the FD_CLOEXEC bit. We want to pass this FD to criu
627 * via --inherit-fd, so we don't want it to close.
628 */
629 flags = fcntl(os.console_fd, F_GETFD);
630 if (flags < 0) {
631 SYSERROR("F_GETFD failed");
632 goto out_fini_handler;
633 }
634
635 flags &= ~FD_CLOEXEC;
636
637 if (fcntl(os.console_fd, F_SETFD, flags) < 0) {
638 SYSERROR("F_SETFD failed");
639 goto out_fini_handler;
640 }
641 os.console_name = c->lxc_conf->console.name;
642
643 /* exec_criu() returning is an error */
644 exec_criu(&os);
645 umount(rootfs->mount);
646 rmdir(rootfs->mount);
647 goto out_fini_handler;
648 } else {
649 int ret;
650 char title[2048];
651
652 close(pipes[1]);
653 pipes[1] = -1;
654
655 pid_t w = waitpid(pid, &status, 0);
656 if (w == -1) {
657 SYSERROR("waitpid");
658 goto out_fini_handler;
659 }
660
661 ret = write(status_pipe, &status, sizeof(status));
662 close(status_pipe);
663 status_pipe = -1;
664
665 if (sizeof(status) != ret) {
666 SYSERROR("failed to write all of status");
667 goto out_fini_handler;
668 }
669
670 if (WIFEXITED(status)) {
671 if (WEXITSTATUS(status)) {
672 char buf[4096];
673 int n;
674
675 n = read(pipes[0], buf, sizeof(buf));
676 if (n < 0) {
677 SYSERROR("failed reading from criu stderr");
678 goto out_fini_handler;
679 }
680
681 buf[n] = 0;
682
683 ERROR("criu process exited %d, output:\n%s\n", WEXITSTATUS(status), buf);
684 goto out_fini_handler;
685 } else {
686 int ret;
687 FILE *f = fopen(pidfile, "r");
688 if (!f) {
689 SYSERROR("couldn't read restore's init pidfile %s\n", pidfile);
690 goto out_fini_handler;
691 }
692
693 ret = fscanf(f, "%d", (int*) &handler->pid);
694 fclose(f);
695 if (unlink(pidfile) < 0 && errno != ENOENT)
696 SYSERROR("unlinking pidfile failed");
697
698 if (ret != 1) {
699 ERROR("reading restore pid failed");
700 goto out_fini_handler;
701 }
702
703 if (lxc_set_state(c->name, handler, RUNNING)) {
704 ERROR("error setting running state after restore");
705 goto out_fini_handler;
706 }
707 }
708 } else {
709 ERROR("CRIU was killed with signal %d\n", WTERMSIG(status));
710 goto out_fini_handler;
711 }
712
713 close(pipes[0]);
714
715 /*
716 * See comment in lxcapi_start; we don't care if these
717 * fail because it's just a beauty thing. We just
718 * assign the return here to silence potential.
719 */
720 ret = snprintf(title, sizeof(title), "[lxc monitor] %s %s", c->config_path, c->name);
721 ret = setproctitle(title);
722
723 ret = lxc_poll(c->name, handler);
724 if (ret)
725 lxc_abort(c->name, handler);
726 lxc_fini(c->name, handler);
727 exit(ret);
728 }
729
730 out_fini_handler:
731 if (pipes[0] >= 0)
732 close(pipes[0]);
733 if (pipes[1] >= 0)
734 close(pipes[1]);
735
736 lxc_fini(c->name, handler);
737 if (unlink(pidfile) < 0 && errno != ENOENT)
738 SYSERROR("unlinking pidfile failed");
739
740 out:
741 if (status_pipe >= 0) {
742 status = 1;
743 if (write(status_pipe, &status, sizeof(status)) != sizeof(status)) {
744 SYSERROR("writing status failed");
745 }
746 close(status_pipe);
747 }
748
749 exit(1);
750 }
751
752 static int save_tty_major_minor(char *directory, struct lxc_container *c, char *tty_id, int len)
753 {
754 FILE *f;
755 char path[PATH_MAX];
756 int ret;
757 struct stat sb;
758
759 if (c->lxc_conf->console.path && !strcmp(c->lxc_conf->console.path, "none")) {
760 tty_id[0] = 0;
761 return 0;
762 }
763
764 ret = snprintf(path, sizeof(path), "/proc/%d/root/dev/console", c->init_pid(c));
765 if (ret < 0 || ret >= sizeof(path)) {
766 ERROR("snprintf'd too many chacters: %d", ret);
767 return -1;
768 }
769
770 ret = stat(path, &sb);
771 if (ret < 0) {
772 SYSERROR("stat of %s failed", path);
773 return -1;
774 }
775
776 ret = snprintf(path, sizeof(path), "%s/tty.info", directory);
777 if (ret < 0 || ret >= sizeof(path)) {
778 ERROR("snprintf'd too many characters: %d", ret);
779 return -1;
780 }
781
782 ret = snprintf(tty_id, len, "tty[%llx:%llx]",
783 (long long unsigned) sb.st_rdev,
784 (long long unsigned) sb.st_dev);
785 if (ret < 0 || ret >= sizeof(path)) {
786 ERROR("snprintf'd too many characters: %d", ret);
787 return -1;
788 }
789
790 f = fopen(path, "w");
791 if (!f) {
792 SYSERROR("failed to open %s", path);
793 return -1;
794 }
795
796 ret = fprintf(f, "%s", tty_id);
797 fclose(f);
798 if (ret < 0)
799 SYSERROR("failed to write to %s", path);
800 return ret;
801 }
802
803 /* do one of either predump or a regular dump */
804 static bool do_dump(struct lxc_container *c, char *mode, char *directory,
805 bool stop, bool verbose, char *predump_dir)
806 {
807 pid_t pid;
808
809 if (!criu_ok(c))
810 return false;
811
812 if (mkdir_p(directory, 0700) < 0)
813 return false;
814
815 pid = fork();
816 if (pid < 0) {
817 SYSERROR("fork failed");
818 return false;
819 }
820
821 if (pid == 0) {
822 struct criu_opts os;
823
824 os.action = mode;
825 os.directory = directory;
826 os.c = c;
827 os.stop = stop;
828 os.verbose = verbose;
829 os.predump_dir = predump_dir;
830 os.console_name = c->lxc_conf->console.path;
831
832 if (save_tty_major_minor(directory, c, os.tty_id, sizeof(os.tty_id)) < 0)
833 exit(1);
834
835 /* exec_criu() returning is an error */
836 exec_criu(&os);
837 exit(1);
838 } else {
839 int status;
840 pid_t w = waitpid(pid, &status, 0);
841 if (w == -1) {
842 SYSERROR("waitpid");
843 return false;
844 }
845
846 if (WIFEXITED(status)) {
847 if (WEXITSTATUS(status)) {
848 ERROR("dump failed with %d\n", WEXITSTATUS(status));
849 return false;
850 }
851
852 return true;
853 } else if (WIFSIGNALED(status)) {
854 ERROR("dump signaled with %d\n", WTERMSIG(status));
855 return false;
856 } else {
857 ERROR("unknown dump exit %d\n", status);
858 return false;
859 }
860 }
861 }
862
863 bool pre_dump(struct lxc_container *c, char *directory, bool verbose, char *predump_dir)
864 {
865 return do_dump(c, "pre-dump", directory, false, verbose, predump_dir);
866 }
867
868 bool dump(struct lxc_container *c, char *directory, bool stop, bool verbose, char *predump_dir)
869 {
870 char path[PATH_MAX];
871 int ret;
872
873 ret = snprintf(path, sizeof(path), "%s/inventory.img", directory);
874 if (ret < 0 || ret >= sizeof(path))
875 return false;
876
877 if (access(path, F_OK) == 0) {
878 ERROR("please use a fresh directory for the dump directory\n");
879 return false;
880 }
881
882 return do_dump(c, "dump", directory, stop, verbose, predump_dir);
883 }
884
885 bool restore(struct lxc_container *c, char *directory, bool verbose)
886 {
887 pid_t pid;
888 int status, nread;
889 int pipefd[2];
890
891 if (!criu_ok(c))
892 return false;
893
894 if (geteuid()) {
895 ERROR("Must be root to restore\n");
896 return false;
897 }
898
899 if (pipe(pipefd)) {
900 ERROR("failed to create pipe");
901 return false;
902 }
903
904 pid = fork();
905 if (pid < 0) {
906 close(pipefd[0]);
907 close(pipefd[1]);
908 return false;
909 }
910
911 if (pid == 0) {
912 close(pipefd[0]);
913 // this never returns
914 do_restore(c, pipefd[1], directory, verbose);
915 }
916
917 close(pipefd[1]);
918
919 nread = read(pipefd[0], &status, sizeof(status));
920 close(pipefd[0]);
921 if (sizeof(status) != nread) {
922 ERROR("reading status from pipe failed");
923 goto err_wait;
924 }
925
926 // If the criu process was killed or exited nonzero, wait() for the
927 // handler, since the restore process died. Otherwise, we don't need to
928 // wait, since the child becomes the monitor process.
929 if (!WIFEXITED(status) || WEXITSTATUS(status))
930 goto err_wait;
931 return true;
932
933 err_wait:
934 if (wait_for_pid(pid))
935 ERROR("restore process died");
936 return false;
937 }