diff --git a/crtools.c b/crtools.c index 7a9f9281e..eeb502c7d 100644 --- a/crtools.c +++ b/crtools.c @@ -59,7 +59,7 @@ int main(int argc, char *argv[]) int log_inited = 0; int log_level = 0; - static const char short_opts[] = "dsf:t:hcD:o:n:vxV"; + static const char short_opts[] = "dsf:t:hcD:o:n:vxVr:"; BUILD_BUG_ON(PAGE_SIZE != PAGE_IMAGE_SIZE); @@ -79,6 +79,7 @@ int main(int argc, char *argv[]) { "images-dir", required_argument, 0, 'D' }, { "log-file", required_argument, 0, 'o' }, { "namespaces", required_argument, 0, 'n' }, + { "root", required_argument, 0, 'r' }, { "ext-unix-sk", no_argument, 0, 'x' }, { "help", no_argument, 0, 'h' }, { SK_EST_PARAM, no_argument, 0, 42 }, @@ -108,6 +109,9 @@ int main(int argc, char *argv[]) case 'f': opts.show_dump_file = optarg; break; + case 'r': + opts.root = optarg; + break; case 'd': opts.restore_detach = true; break; @@ -245,6 +249,7 @@ usage: pr_msg(" supported: uts, ipc, pid\n"); pr_msg(" -x|--ext-unix-sk allow external unix connections\n"); pr_msg(" --%s checkpoint/restore established TCP connections\n", SK_EST_PARAM); + pr_msg(" -r|--root [PATH] change the root filesystem (when run in mount namespace)\n"); pr_msg("\n* Logging:\n"); pr_msg(" -o|--log-file [NAME] log file name (relative path is relative to --images-dir)\n"); diff --git a/include/crtools.h b/include/crtools.h index d346a03c1..df1899179 100644 --- a/include/crtools.h +++ b/include/crtools.h @@ -87,6 +87,7 @@ struct cr_options { unsigned int namespaces_flags; bool log_file_per_pid; char *output; + char *root; }; extern struct cr_options opts; diff --git a/include/mount.h b/include/mount.h index eaeca4339..45e6858ff 100644 --- a/include/mount.h +++ b/include/mount.h @@ -15,4 +15,5 @@ struct cr_options; extern void show_mountpoints(int fd, struct cr_options *); int prepare_mnt_ns(int pid); +extern int pivot_root(const char *new_root, const char *put_old); #endif /* MOUNT_H__ */ diff --git a/mount.c b/mount.c index 74634900f..ca12899b6 100644 --- a/mount.c +++ b/mount.c @@ -378,6 +378,13 @@ static int do_umount_one(struct mount_info *mi) if (!mi->parent) return 0; + /* + * Don't umount the future root. It can be a mountpoint only, + * otherwise pivot_root() fails. + */ + if (opts.root && !strcmp(opts.root, mi->mountpoint)) + return 0; + if (umount(mi->mountpoint)) { pr_perror("Can't umount at %s", mi->mountpoint); return -1; @@ -421,6 +428,33 @@ static int populate_mnt_ns(int ns_pid) pr_info("Populating mount namespace\n"); + if (opts.root) { + char put_root[PATH_MAX] = "crtools-put-root.XXXXXX"; + + if (chdir(opts.root)) { + pr_perror("chdir(%s) failed", opts.root); + return -1; + } + if (mkdtemp(put_root) == NULL) { + pr_perror("Can't create a temparary directory"); + return -1; + } + if (pivot_root(".", put_root)) { + pr_perror("pivot_root(., %s) failed", put_root); + if (rmdir(put_root)) + pr_perror("Can't remove the directory %s", put_root); + return -1; + } + if (umount2(put_root, MNT_DETACH)) { + pr_perror("Can't umount %s", put_root); + return -1; + } + if (rmdir(put_root)) { + pr_perror("Can't remove the directory %s", put_root); + return -1; + } + } + img = open_image_ro(CR_FD_MOUNTPOINTS, ns_pid); if (img < 0) return -1;