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:
parent
83c0fdc352
commit
485a374b21
|
|
@ -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,41 +300,58 @@ main(int argc, char *argv[])
|
||||||
|
|
||||||
touch_run_ostree ();
|
touch_run_ostree ();
|
||||||
|
|
||||||
/* In this instance typically we have our ready made-up up root at
|
if (strcmp(root_mountpoint, "/") == 0)
|
||||||
* /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/ and the real rootfs under /sysroot/sysroot as systemd will be
|
|
||||||
* responsible for moving /sysroot to /.
|
|
||||||
*
|
|
||||||
* We need to do this in 3 moves to avoid trying to move /sysroot under
|
|
||||||
* itself:
|
|
||||||
*
|
|
||||||
* 1. /sysroot/ostree/deploy/... -> /sysroot.tmp
|
|
||||||
* 2. /sysroot -> /sysroot.tmp/sysroot
|
|
||||||
* 3. /sysroot.tmp -> /sysroot
|
|
||||||
*/
|
|
||||||
if (mkdir ("/sysroot.tmp", 0755) < 0)
|
|
||||||
{
|
{
|
||||||
perrorv ("couldn't create temporary sysroot /sysroot.tmp: ");
|
/* pivot_root rotates two mount points around. In this instance . (the
|
||||||
exit (EXIT_FAILURE);
|
* 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
|
||||||
if (mount (deploy_path, "/sysroot.tmp", NULL, MS_MOVE, NULL) < 0)
|
|
||||||
{
|
{
|
||||||
perrorv ("failed to MS_MOVE '%s' to '/sysroot.tmp'", deploy_path);
|
/* In this instance typically we have our ready made-up up root at
|
||||||
exit (EXIT_FAILURE);
|
* /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/ and the real rootfs under /sysroot/sysroot as systemd will be
|
||||||
|
* responsible for moving /sysroot to /.
|
||||||
|
*
|
||||||
|
* We need to do this in 3 moves to avoid trying to move /sysroot under
|
||||||
|
* itself:
|
||||||
|
*
|
||||||
|
* 1. /sysroot/ostree/deploy/... -> /sysroot.tmp
|
||||||
|
* 2. /sysroot -> /sysroot.tmp/sysroot
|
||||||
|
* 3. /sysroot.tmp -> /sysroot
|
||||||
|
*/
|
||||||
|
if (mkdir ("/sysroot.tmp", 0755) < 0)
|
||||||
|
{
|
||||||
|
perrorv ("couldn't create temporary sysroot /sysroot.tmp: ");
|
||||||
|
exit (EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
if (mount (root_mountpoint, "sysroot", NULL, MS_MOVE, NULL) < 0)
|
if (mount (deploy_path, "/sysroot.tmp", NULL, MS_MOVE, NULL) < 0)
|
||||||
{
|
{
|
||||||
perrorv ("failed to MS_MOVE '%s' to 'sysroot'", root_mountpoint);
|
perrorv ("failed to MS_MOVE '%s' to '/sysroot.tmp'", deploy_path);
|
||||||
exit (EXIT_FAILURE);
|
exit (EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mount (".", root_mountpoint, NULL, MS_MOVE, NULL) < 0)
|
if (mount (root_mountpoint, "sysroot", NULL, MS_MOVE, NULL) < 0)
|
||||||
{
|
{
|
||||||
perrorv ("failed to MS_MOVE %s to %s", deploy_path, root_mountpoint);
|
perrorv ("failed to MS_MOVE '%s' to 'sysroot'", root_mountpoint);
|
||||||
exit (EXIT_FAILURE);
|
exit (EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mount (".", root_mountpoint, NULL, MS_MOVE, NULL) < 0)
|
||||||
|
{
|
||||||
|
perrorv ("failed to MS_MOVE %s to %s", deploy_path, root_mountpoint);
|
||||||
|
exit (EXIT_FAILURE);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (getpid() == 1)
|
if (getpid() == 1)
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue