TODO(idownes): Add unit test.
| 661 | |
| 662 | // TODO(idownes): Add unit test. |
| 663 | Try<Nothing> enter(const string& root) |
| 664 | { |
| 665 | // Prepare /tmp in the new root. Note that we cannot assume that the |
| 666 | // new root is writable (i.e., it could be a read only filesystem). |
| 667 | // Therefore, we always mount a tmpfs on /tmp in the new root so |
| 668 | // that we can create the mount point for the old root. |
| 669 | // |
| 670 | // NOTE: If the new root is a read-only filesystem (e.g., using bind |
| 671 | // backend), the 'tmpfs' mount point '/tmp' must already exist in the |
| 672 | // new root. Otherwise, mkdir would return an error because of unable |
| 673 | // to create it in read-only filesystem. |
| 674 | Try<Nothing> mkdir = os::mkdir(path::join(root, "tmp")); |
| 675 | if (mkdir.isError()) { |
| 676 | return Error("Failed to create 'tmpfs' mount point at '" + |
| 677 | path::join(root, "tmp") + "': " + mkdir.error()); |
| 678 | } |
| 679 | |
| 680 | // TODO(jieyu): Consider limiting the size of the tmpfs. |
| 681 | Try<Nothing> mount = fs::mount( |
| 682 | "tmpfs", |
| 683 | path::join(root, "tmp"), |
| 684 | "tmpfs", |
| 685 | MS_NOSUID | MS_NOEXEC | MS_NODEV, |
| 686 | "mode=1777"); |
| 687 | |
| 688 | if (mount.isError()) { |
| 689 | return Error("Failed to mount the temporary tmpfs at /tmp in new root: " + |
| 690 | mount.error()); |
| 691 | } |
| 692 | |
| 693 | // Create a mount point for the old root. |
| 694 | Try<string> old = os::mkdtemp(path::join(root, "tmp", "._old_root_.XXXXXX")); |
| 695 | if (old.isError()) { |
| 696 | return Error("Failed to create mount point for old root: " + old.error()); |
| 697 | } |
| 698 | |
| 699 | // Chroot to the new root. This is done by a particular sequence of |
| 700 | // operations, each of which is necessary: chdir, pivot_root, |
| 701 | // chroot, chdir. After these operations, the process will be |
| 702 | // chrooted to the new root. |
| 703 | |
| 704 | // Chdir to the new root. |
| 705 | Try<Nothing> chdir = os::chdir(root); |
| 706 | if (chdir.isError()) { |
| 707 | return Error("Failed to chdir to new root: " + chdir.error()); |
| 708 | } |
| 709 | |
| 710 | // Pivot the root to the cwd. |
| 711 | Try<Nothing> pivot = fs::pivot_root(root, old.get()); |
| 712 | if (pivot.isError()) { |
| 713 | return Error("Failed to pivot to new root: " + pivot.error()); |
| 714 | } |
| 715 | |
| 716 | // Chroot to the new "/". This is necessary to correctly set the |
| 717 | // base for all paths. |
| 718 | Try<Nothing> chroot = os::chroot("."); |
| 719 | if (chroot.isError()) { |
| 720 | return Error("Failed to chroot to new root: " + chroot.error()); |
no test coverage detected