ostree-prepare-root: Use pivot_root if real sysroot is already mounted at /

This allows ostree-prepare-root outside of the initramfs context where the
real rootfs is already mounted at /.  We can't use `mount --move` in this
case because we would be trying to move / into a subdirectory of itself.

Closes: #403
Approved by: cgwalters
This commit is contained in:
William Manley 2016-07-19 19:48:23 +01:00 committed by Atomic Bot
parent 83c0fdc352
commit 485a374b21
2 changed files with 76 additions and 31 deletions

View File

@ -33,6 +33,7 @@
#include <sys/types.h> #include <sys/types.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/param.h> #include <sys/param.h>
#include <sys/syscall.h>
#include <fcntl.h> #include <fcntl.h>
#include <stdio.h> #include <stdio.h>
#include <stdarg.h> #include <stdarg.h>
@ -184,6 +185,12 @@ resolve_deploy_path (const char * root_mountpoint)
return deploy_path; return deploy_path;
} }
static int
pivot_root(const char * new_root, const char * put_old)
{
return syscall(__NR_pivot_root, new_root, put_old);
}
int int
main(int argc, char *argv[]) main(int argc, char *argv[])
{ {
@ -197,6 +204,7 @@ main(int argc, char *argv[])
else else
root_mountpoint = argv[1]; root_mountpoint = argv[1];
root_mountpoint = realpath (root_mountpoint, NULL);
deploy_path = resolve_deploy_path (root_mountpoint); deploy_path = resolve_deploy_path (root_mountpoint);
/* Work-around for a kernel bug: for some reason the kernel /* Work-around for a kernel bug: for some reason the kernel
@ -292,6 +300,22 @@ main(int argc, char *argv[])
touch_run_ostree (); touch_run_ostree ();
if (strcmp(root_mountpoint, "/") == 0)
{
/* pivot_root rotates two mount points around. In this instance . (the
* deploy location) becomes / and the existing / becomes /sysroot. We
* have to use pivot_root rather than mount --move in this instance
* because our deploy location is mounted as a subdirectory of the real
* sysroot, so moving sysroot would also move the deploy location. In
* reality attempting mount --move would fail with EBUSY. */
if (pivot_root (".", "sysroot") < 0)
{
perrorv ("failed to pivot_root to deployment");
exit (EXIT_FAILURE);
}
}
else
{
/* In this instance typically we have our ready made-up up root at /* In this instance typically we have our ready made-up up root at
* /sysroot/ostree/deploy/.../ (deploy_path) and the real rootfs at * /sysroot/ostree/deploy/.../ (deploy_path) and the real rootfs at
* /sysroot (root_mountpoint). We want to end up with our made-up root at * /sysroot (root_mountpoint). We want to end up with our made-up root at
@ -328,6 +352,7 @@ main(int argc, char *argv[])
perrorv ("failed to MS_MOVE %s to %s", deploy_path, root_mountpoint); perrorv ("failed to MS_MOVE %s to %s", deploy_path, root_mountpoint);
exit (EXIT_FAILURE); exit (EXIT_FAILURE);
} }
}
if (getpid() == 1) if (getpid() == 1)
{ {

View File

@ -76,12 +76,32 @@ test_that_prepare_root_sets_sysroot_up_correctly_with_initrd() {
echo "ok ostree-prepare-root sets sysroot up correctly with initrd" echo "ok ostree-prepare-root sets sysroot up correctly with initrd"
} }
setup_no_initrd_env() {
mount --bind "$1" "$1"
setup_rootfs "$1"
setup_bootfs "$1"
}
test_that_prepare_root_sets_root_up_correctly_with_no_initrd() {
find_in_env setup_no_initrd_env >files
grep -qx "/this_is_ostree_root" files
grep -qx "/sysroot/this_is_bootfs" files
grep -qx "/sysroot/this_is_real_root" files
grep -qx "/var/this_is_ostree_var" files
grep -qx "/usr/this_is_ostree_usr" files
grep -qx "/usr is not writable" files
echo "ok ostree-prepare-root sets root up correctly with no initrd"
}
# This script sources itself so we only want to run tests if we're the parent: # This script sources itself so we only want to run tests if we're the parent:
if [ "${BASH_SOURCE[0]}" = "${0}" ]; then if [ "${BASH_SOURCE[0]}" = "${0}" ]; then
. $(dirname $0)/libtest.sh . $(dirname $0)/libtest.sh
unshare -m true || \ unshare -m true || \
skip "this test needs to set up mount namespaces, rerun as root" skip "this test needs to set up mount namespaces, rerun as root"
echo "1..1" echo "1..2"
test_that_prepare_root_sets_sysroot_up_correctly_with_initrd test_that_prepare_root_sets_sysroot_up_correctly_with_initrd
test_that_prepare_root_sets_root_up_correctly_with_no_initrd
fi fi