| 585 | |
| 586 | |
| 587 | Try<Nothing> pivot_root( |
| 588 | const string& newRoot, |
| 589 | const string& putOld) |
| 590 | { |
| 591 | // These checks are done in the syscall but we'll do them here to |
| 592 | // provide less cryptic error messages. See 'man 2 pivot_root'. |
| 593 | if (!os::stat::isdir(newRoot)) { |
| 594 | return Error("newRoot '" + newRoot + "' is not a directory"); |
| 595 | } |
| 596 | |
| 597 | if (!os::stat::isdir(putOld)) { |
| 598 | return Error("putOld '" + putOld + "' is not a directory"); |
| 599 | } |
| 600 | |
| 601 | // TODO(idownes): Verify that newRoot (and putOld) is on a different |
| 602 | // filesystem to the current root. st_dev distinguishes the device |
| 603 | // an inode is on, but bind mounts (which are acceptable to |
| 604 | // pivot_root) share the same st_dev as the source of the mount so |
| 605 | // st_dev is not generally sufficient. |
| 606 | |
| 607 | if (!strings::startsWith(putOld, newRoot)) { |
| 608 | return Error("putOld '" + putOld + |
| 609 | "' must be beneath newRoot '" + newRoot); |
| 610 | } |
| 611 | |
| 612 | #ifdef __NR_pivot_root |
| 613 | int ret = ::syscall(__NR_pivot_root, newRoot.c_str(), putOld.c_str()); |
| 614 | #else |
| 615 | #error "pivot_root is not available" |
| 616 | #endif |
| 617 | if (ret == -1) { |
| 618 | return ErrnoError(); |
| 619 | } |
| 620 | |
| 621 | return Nothing(); |
| 622 | } |
| 623 | |
| 624 | |
| 625 | namespace chroot { |
no test coverage detected