Change the root file system to /dev/hda1 from an interactive shell:mount /dev/hda1 /new-rootcd /new-rootpivot_root . old-rootexec chroot . sh <dev/console >dev/console 2>&1umount /old-root
因此执行pivot_root时,内部执行逻辑是:
- 第一步,把当前的rootfs mount到一个目录(比如old-root)
- 第二部,把进程的rootfs设置为新的
所以需要在pivot_root之后,umount old-root。
// pivotRoot will call pivot_root such that rootfs becomes the new root// filesystem, and everything else is cleaned up.func pivotRoot(rootfs string) error {// While the documentation may claim otherwise, pivot_root(".", ".") is// actually valid. What this results in is / being the new root but// /proc/self/cwd being the old root. Since we can play around with the cwd// with pivot_root this allows us to pivot without creating directories in// the rootfs. Shout-outs to the LXC developers for giving us this idea.oldroot, err := unix.Open("/", unix.O_DIRECTORY|unix.O_RDONLY, 0)if err != nil {return err}defer unix.Close(oldroot) //nolint: errchecknewroot, err := unix.Open(rootfs, unix.O_DIRECTORY|unix.O_RDONLY, 0)if err != nil {return err}defer unix.Close(newroot) //nolint: errcheck// Change to the new root so that the pivot_root actually acts on it.if err := unix.Fchdir(newroot); err != nil {return err}// "/" being the new root , /proc/self/cwd being the old root// https://unix.stackexchange.com/questions/571823/strange-behaviour-of-pivot-root-in-mount-namespace// You can call pivot_root(".", ".") which avoids the need for a directory to put the old root into.if err := unix.PivotRoot(".", "."); err != nil {return fmt.Errorf("pivot_root %s", err)}// Currently our "." is oldroot (according to the current kernel code).// However, purely for safety, we will fchdir(oldroot) since there isn't// really any guarantee from the kernel what /proc/self/cwd will be after a// pivot_root(2).if err := unix.Fchdir(oldroot); err != nil {return err}// Make oldroot rslave to make sure our unmounts don't propagate to the// host (and thus bork the machine). We don't use rprivate because this is// known to cause issues due to races where we still have a reference to a// mount while a process in the host namespace are trying to operate on// something they think has no mounts (devicemapper in particular).// 修改oldroot的mount属性if err := unix.Mount("", ".", "", unix.MS_SLAVE|unix.MS_REC, ""); err != nil {return err}// Preform the unmount. MNT_DETACH allows us to unmount /proc/self/cwd.if err := unix.Unmount(".", unix.MNT_DETACH); err != nil {return err}// Switch back to our shiny new root.if err := unix.Chdir("/"); err != nil {return fmt.Errorf("chdir / %s", err)}return nil}
