573 lines
16 KiB
HTML
573 lines
16 KiB
HTML
|
|
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
|
<HTML><HEAD><TITLE>Man page of PIVOT_ROOT</TITLE>
|
|
</HEAD><BODY>
|
|
<H1>PIVOT_ROOT</H1>
|
|
Section: Linux Programmer's Manual (2)<BR>Updated: 2019-11-19<BR><A HREF="#index">Index</A>
|
|
<A HREF="/cgi-bin/man/man2html">Return to Main Contents</A><HR>
|
|
|
|
<A NAME="lbAB"> </A>
|
|
<H2>NAME</H2>
|
|
|
|
pivot_root - change the root mount
|
|
<A NAME="lbAC"> </A>
|
|
<H2>SYNOPSIS</H2>
|
|
|
|
<B>int pivot_root(const char *</B><I>new_root</I><B>, const char *</B><I>put_old</I><B>);</B>
|
|
|
|
<P>
|
|
|
|
<I>Note</I>:
|
|
|
|
There is no glibc wrapper for this system call; see NOTES.
|
|
<A NAME="lbAD"> </A>
|
|
<H2>DESCRIPTION</H2>
|
|
|
|
<B>pivot_root</B>()
|
|
|
|
changes the root mount in the mount namespace of the calling process.
|
|
More precisely, it moves the root mount to the
|
|
directory <I>put_old</I> and makes <I>new_root</I> the new root mount.
|
|
The calling process must have the
|
|
<B>CAP_SYS_ADMIN</B>
|
|
|
|
capability in the user namespace that owns the caller's mount namespace.
|
|
<P>
|
|
|
|
<B>pivot_root</B>()
|
|
|
|
changes the root directory and the current working directory
|
|
of each process or thread in the same mount namespace to
|
|
<I>new_root</I>
|
|
|
|
if they point to the old root directory.
|
|
(See also NOTES.)
|
|
On the other hand,
|
|
<B>pivot_root</B>()
|
|
|
|
does not change the caller's current working directory
|
|
(unless it is on the old root directory),
|
|
and thus it should be followed by a
|
|
<B>chdir("/")</B> call.
|
|
<P>
|
|
|
|
The following restrictions apply:
|
|
<DL COMPACT>
|
|
<DT id="1">-<DD>
|
|
<I>new_root</I>
|
|
|
|
and
|
|
<I>put_old</I>
|
|
|
|
must be directories.
|
|
<DT id="2">-<DD>
|
|
<I>new_root</I>
|
|
|
|
and
|
|
<I>put_old</I>
|
|
|
|
must not be on the same mount as the current root.
|
|
<DT id="3">-<DD>
|
|
<I>put_old</I> must be at or underneath <I>new_root</I>;
|
|
that is, adding some nonnegative
|
|
number of "<I>/..</I>" prefixes to the pathname pointed to by
|
|
<I>put_old</I>
|
|
|
|
must yield the same directory as <I>new_root</I>.
|
|
<DT id="4">-<DD>
|
|
<I>new_root</I>
|
|
|
|
must be a path to a mount point, but can't be
|
|
<I>"/"</I>.
|
|
|
|
A path that is not already a mount point can be converted into one by
|
|
bind mounting the path onto itself.
|
|
<DT id="5">-<DD>
|
|
The propagation type of the parent mount of
|
|
<I>new_root</I>
|
|
|
|
and the parent mount of the current root directory must not be
|
|
<B>MS_SHARED</B>;
|
|
|
|
similarly, if
|
|
<I>put_old</I>
|
|
|
|
is an existing mount point, its propagation type must not be
|
|
<B>MS_SHARED</B>.
|
|
|
|
These restrictions ensure that
|
|
<B>pivot_root</B>()
|
|
|
|
never propagates any changes to another mount namespace.
|
|
<DT id="6">-<DD>
|
|
The current root directory must be a mount point.
|
|
</DL>
|
|
<A NAME="lbAE"> </A>
|
|
<H2>RETURN VALUE</H2>
|
|
|
|
On success, zero is returned.
|
|
On error, -1 is returned, and
|
|
<I>errno</I> is set appropriately.
|
|
<A NAME="lbAF"> </A>
|
|
<H2>ERRORS</H2>
|
|
|
|
<B>pivot_root</B>()
|
|
|
|
may fail with any of the same errors as
|
|
<B><A HREF="/cgi-bin/man/man2html?2+stat">stat</A></B>(2).
|
|
|
|
Additionally, it may fail with the following errors:
|
|
<DL COMPACT>
|
|
<DT id="7"><B>EBUSY</B>
|
|
|
|
<DD>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<I>new_root</I>
|
|
|
|
or
|
|
<I>put_old</I>
|
|
|
|
is on the current root mount.
|
|
(This error covers the pathological case where
|
|
<I>new_root</I>
|
|
|
|
is
|
|
<I>"/"</I>.)
|
|
|
|
<DT id="8"><B>EINVAL</B>
|
|
|
|
<DD>
|
|
<I>new_root</I>
|
|
|
|
is not a mount point.
|
|
<DT id="9"><B>EINVAL</B>
|
|
|
|
<DD>
|
|
<I>put_old</I> is not at or underneath <I>new_root</I>.
|
|
<DT id="10"><B>EINVAL</B>
|
|
|
|
<DD>
|
|
The current root directory is not a mount point
|
|
(because of an earlier
|
|
<B><A HREF="/cgi-bin/man/man2html?2+chroot">chroot</A></B>(2)).
|
|
|
|
<DT id="11"><B>EINVAL</B>
|
|
|
|
<DD>
|
|
The current root is on the rootfs (initial ramfs) mount; see NOTES.
|
|
<DT id="12"><B>EINVAL</B>
|
|
|
|
<DD>
|
|
Either the mount point at
|
|
<I>new_root</I>,
|
|
|
|
or the parent mount of that mount point,
|
|
has propagation type
|
|
<B>MS_SHARED</B>.
|
|
|
|
<DT id="13"><B>EINVAL</B>
|
|
|
|
<DD>
|
|
<I>put_old</I>
|
|
|
|
is a mount point and has the propagation type
|
|
<B>MS_SHARED</B>.
|
|
|
|
<DT id="14"><B>ENOTDIR</B>
|
|
|
|
<DD>
|
|
<I>new_root</I> or <I>put_old</I> is not a directory.
|
|
<DT id="15"><B>EPERM</B>
|
|
|
|
<DD>
|
|
The calling process does not have the
|
|
<B>CAP_SYS_ADMIN</B>
|
|
|
|
capability.
|
|
</DL>
|
|
<A NAME="lbAG"> </A>
|
|
<H2>VERSIONS</H2>
|
|
|
|
<B>pivot_root</B>()
|
|
|
|
was introduced in Linux 2.3.41.
|
|
<A NAME="lbAH"> </A>
|
|
<H2>CONFORMING TO</H2>
|
|
|
|
<B>pivot_root</B>()
|
|
|
|
is Linux-specific and hence is not portable.
|
|
<A NAME="lbAI"> </A>
|
|
<H2>NOTES</H2>
|
|
|
|
Glibc does not provide a wrapper for this system call; call it using
|
|
<B><A HREF="/cgi-bin/man/man2html?2+syscall">syscall</A></B>(2).
|
|
|
|
<P>
|
|
|
|
A command-line interface for this system call is provided by
|
|
<B><A HREF="/cgi-bin/man/man2html?8+pivot_root">pivot_root</A></B>(8).
|
|
|
|
<P>
|
|
|
|
<B>pivot_root</B>()
|
|
|
|
allows the caller to switch to a new root filesystem while at the same time
|
|
placing the old root mount at a location under
|
|
<I>new_root</I>
|
|
|
|
from where it can subsequently be unmounted.
|
|
(The fact that it moves all processes that have a root directory
|
|
or current working directory on the old root directory to the
|
|
new root frees the old root directory of users,
|
|
allowing the old root mount to be unmounted more easily.)
|
|
<P>
|
|
|
|
One use of
|
|
<B>pivot_root</B>()
|
|
|
|
is during system startup, when the
|
|
system mounts a temporary root filesystem (e.g., an
|
|
<B><A HREF="/cgi-bin/man/man2html?4+initrd">initrd</A></B>(4)),
|
|
|
|
then mounts the real root filesystem, and eventually turns the latter into
|
|
the root directory of all relevant processes and threads.
|
|
A modern use is to set up a root filesystem during
|
|
the creation of a container.
|
|
<P>
|
|
|
|
The fact that
|
|
<B>pivot_root</B>()
|
|
|
|
modifies process root and current working directories in the
|
|
manner noted in DESCRIPTION
|
|
is necessary in order to prevent kernel threads from keeping the old
|
|
root mount busy with their root and current working directories,
|
|
even if they never access
|
|
the filesystem in any way.
|
|
<P>
|
|
|
|
The rootfs (initial ramfs) cannot be
|
|
<B>pivot_root</B>()ed.
|
|
|
|
The recommended method of changing the root filesystem in this case is
|
|
to delete everything in rootfs, overmount rootfs with the new root, attach
|
|
<I>stdin</I>/<I>stdout</I>/<I>stderr</I>
|
|
|
|
to the new
|
|
<I>/dev/console</I>,
|
|
|
|
and exec the new
|
|
<B><A HREF="/cgi-bin/man/man2html?1+init">init</A></B>(1).
|
|
|
|
Helper programs for this process exist; see
|
|
<B><A HREF="/cgi-bin/man/man2html?8+switch_root">switch_root</A></B>(8).
|
|
|
|
|
|
<A NAME="lbAJ"> </A>
|
|
<H3>pivot_root(".", ".")</H3>
|
|
|
|
<P>
|
|
|
|
<I>new_root</I>
|
|
|
|
and
|
|
<I>put_old</I>
|
|
|
|
may be the same directory.
|
|
In particular, the following sequence allows a pivot-root operation
|
|
without needing to create and remove a temporary directory:
|
|
<P>
|
|
|
|
|
|
|
|
chdir(new_root);
|
|
pivot_root(".", ".");
|
|
umount2(".", MNT_DETACH);
|
|
|
|
|
|
<P>
|
|
|
|
This sequence succeeds because the
|
|
<B>pivot_root</B>()
|
|
|
|
call stacks the old root mount point
|
|
on top of the new root mount point at
|
|
<I>/</I>.
|
|
|
|
At that point, the calling process's root directory and current
|
|
working directory refer to the new root mount point
|
|
(<I>new_root</I>).
|
|
|
|
During the subsequent
|
|
<B>umount</B>()
|
|
|
|
call, resolution of
|
|
<I>"."</I>
|
|
|
|
starts with
|
|
<I>new_root</I>
|
|
|
|
and then moves up the list of mounts stacked at
|
|
<I>/</I>,
|
|
|
|
with the result that old root mount point is unmounted.
|
|
|
|
<A NAME="lbAK"> </A>
|
|
<H3>Historical notes</H3>
|
|
|
|
For many years, this manual page carried the following text:
|
|
<DL COMPACT><DT id="16"><DD>
|
|
<P>
|
|
|
|
<B>pivot_root</B>()
|
|
|
|
may or may not change the current root and the current
|
|
working directory of any processes or threads which use the old
|
|
root directory.
|
|
The caller of
|
|
<B>pivot_root</B>()
|
|
|
|
must ensure that processes with root or current working directory
|
|
at the old root operate correctly in either case.
|
|
An easy way to ensure this is to change their
|
|
root and current working directory to <I>new_root</I> before invoking
|
|
<B>pivot_root</B>().
|
|
|
|
</DL>
|
|
|
|
<P>
|
|
|
|
This text, written before the system call implementation was
|
|
even finalized in the kernel, was probably intended to warn users
|
|
at that time that the implementation might change before final release.
|
|
However, the behavior stated in DESCRIPTION
|
|
has remained consistent since this system call
|
|
was first implemented and will not change now.
|
|
<A NAME="lbAL"> </A>
|
|
<H2>EXAMPLE</H2>
|
|
|
|
|
|
|
|
|
|
<P>
|
|
|
|
The program below demonstrates the use of
|
|
<B>pivot_root</B>()
|
|
|
|
inside a mount namespace that is created using
|
|
<B><A HREF="/cgi-bin/man/man2html?2+clone">clone</A></B>(2).
|
|
|
|
After pivoting to the root directory named in the program's
|
|
first command-line argument, the child created by
|
|
<B><A HREF="/cgi-bin/man/man2html?2+clone">clone</A></B>(2)
|
|
|
|
then executes the program named in the remaining command-line arguments.
|
|
<P>
|
|
|
|
We demonstrate the program by creating a directory that will serve as
|
|
the new root filesystem and placing a copy of the (statically linked)
|
|
<B><A HREF="/cgi-bin/man/man2html?1+busybox">busybox</A></B>(1)
|
|
|
|
executable in that directory.
|
|
<P>
|
|
|
|
|
|
|
|
$ <B>mkdir /tmp/rootfs</B>
|
|
$ <B>ls -id /tmp/rootfs</B> # Show inode number of new root directory
|
|
319459 /tmp/rootfs
|
|
$ <B>cp $(which busybox) /tmp/rootfs</B>
|
|
$ <B>PS1='bbsh$ ' sudo ./pivot_root_demo /tmp/rootfs /busybox sh</B>
|
|
bbsh$ <B>PATH=/</B>
|
|
bbsh$ <B>busybox ln busybox ln</B>
|
|
bbsh$ <B>ln busybox echo</B>
|
|
bbsh$ <B>ln busybox ls</B>
|
|
bbsh$ <B>ls</B>
|
|
busybox echo ln ls
|
|
bbsh$ <B>ls -id /</B> # Compare with inode number above
|
|
319459 /
|
|
bbsh$ <B>echo 'hello world'</B>
|
|
hello world
|
|
|
|
|
|
<A NAME="lbAM"> </A>
|
|
<H3>Program source</H3>
|
|
|
|
|
|
<P>
|
|
|
|
|
|
/* pivot_root_demo.c */
|
|
<P>
|
|
#define _GNU_SOURCE
|
|
#include <<A HREF="file:///usr/include/sched.h">sched.h</A>>
|
|
#include <<A HREF="file:///usr/include/stdio.h">stdio.h</A>>
|
|
#include <<A HREF="file:///usr/include/stdlib.h">stdlib.h</A>>
|
|
#include <<A HREF="file:///usr/include/unistd.h">unistd.h</A>>
|
|
#include <<A HREF="file:///usr/include/sys/wait.h">sys/wait.h</A>>
|
|
#include <<A HREF="file:///usr/include/sys/syscall.h">sys/syscall.h</A>>
|
|
#include <<A HREF="file:///usr/include/sys/mount.h">sys/mount.h</A>>
|
|
#include <<A HREF="file:///usr/include/sys/stat.h">sys/stat.h</A>>
|
|
#include <<A HREF="file:///usr/include/limits.h">limits.h</A>>
|
|
#include <<A HREF="file:///usr/include/sys/mman.h">sys/mman.h</A>>
|
|
<P>
|
|
#define errExit(msg) do { perror(msg); exit(EXIT_FAILURE); \
|
|
<BR> } while (0)
|
|
<P>
|
|
static int
|
|
pivot_root(const char *new_root, const char *put_old)
|
|
{
|
|
<BR> return syscall(SYS_pivot_root, new_root, put_old);
|
|
}
|
|
<P>
|
|
#define STACK_SIZE (1024 * 1024)
|
|
<P>
|
|
static int /* Startup function for cloned child */
|
|
child(void *arg)
|
|
{
|
|
<BR> char **args = arg;
|
|
<BR> char *new_root = args[0];
|
|
<BR> const char *put_old = "/oldrootfs";
|
|
<BR> char path[PATH_MAX];
|
|
<P>
|
|
<BR> /* Ensure that 'new_root' and its parent mount don't have
|
|
<BR> shared propagation (which would cause pivot_root() to
|
|
<BR> return an error), and prevent propagation of mount
|
|
<BR> events to the initial mount namespace */
|
|
<P>
|
|
<BR> if (mount(NULL, "/", NULL, MS_REC | MS_PRIVATE, NULL) == 1)
|
|
<BR> errExit("mount-MS_PRIVATE");
|
|
<P>
|
|
<BR> /* Ensure that 'new_root' is a mount point */
|
|
<P>
|
|
<BR> if (mount(new_root, new_root, NULL, MS_BIND, NULL) == -1)
|
|
<BR> errExit("mount-MS_BIND");
|
|
<P>
|
|
<BR> /* Create directory to which old root will be pivoted */
|
|
<P>
|
|
<BR> snprintf(path, sizeof(path), "%s/%s", new_root, put_old);
|
|
<BR> if (mkdir(path, 0777) == -1)
|
|
<BR> errExit("mkdir");
|
|
<P>
|
|
<BR> /* And pivot the root filesystem */
|
|
<P>
|
|
<BR> if (pivot_root(new_root, path) == -1)
|
|
<BR> errExit("pivot_root");
|
|
<P>
|
|
<BR> /* Switch the current working directory to "/" */
|
|
<P>
|
|
<BR> if (chdir("/") == -1)
|
|
<BR> errExit("chdir");
|
|
<P>
|
|
<BR> /* Unmount old root and remove mount point */
|
|
<P>
|
|
<BR> if (umount2(put_old, MNT_DETACH) == -1)
|
|
<BR> perror("umount2");
|
|
<BR> if (rmdir(put_old) == -1)
|
|
<BR> perror("rmdir");
|
|
<P>
|
|
<BR> /* Execute the command specified in argv[1]... */
|
|
<P>
|
|
<BR> execv(args[1], &args[1]);
|
|
<BR> errExit("execv");
|
|
}
|
|
<P>
|
|
int
|
|
main(int argc, char *argv[])
|
|
{
|
|
<BR> /* Create a child process in a new mount namespace */
|
|
<P>
|
|
<BR> char *stack = mmap(NULL, STACK_SIZE, PROT_READ | PROT_WRITE,
|
|
<BR> MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, -1, 0);
|
|
<BR> if (stack == MAP_FAILED)
|
|
<BR> errExit("mmap");
|
|
<P>
|
|
<BR> if (clone(child, stack + STACK_SIZE,
|
|
<BR> CLONE_NEWNS | SIGCHLD, &argv[1]) == -1)
|
|
<BR> errExit("clone");
|
|
<P>
|
|
<BR> /* Parent falls through to here; wait for child */
|
|
<P>
|
|
<BR> if (wait(NULL) == -1)
|
|
<BR> errExit("wait");
|
|
<P>
|
|
<BR> exit(EXIT_SUCCESS);
|
|
}
|
|
|
|
<A NAME="lbAN"> </A>
|
|
<H2>SEE ALSO</H2>
|
|
|
|
<B><A HREF="/cgi-bin/man/man2html?2+chdir">chdir</A></B>(2),
|
|
|
|
<B><A HREF="/cgi-bin/man/man2html?2+chroot">chroot</A></B>(2),
|
|
|
|
<B><A HREF="/cgi-bin/man/man2html?2+mount">mount</A></B>(2),
|
|
|
|
<B><A HREF="/cgi-bin/man/man2html?2+stat">stat</A></B>(2),
|
|
|
|
<B><A HREF="/cgi-bin/man/man2html?4+initrd">initrd</A></B>(4),
|
|
|
|
<B><A HREF="/cgi-bin/man/man2html?7+mount_namespaces">mount_namespaces</A></B>(7),
|
|
|
|
<B><A HREF="/cgi-bin/man/man2html?8+pivot_root">pivot_root</A></B>(8),
|
|
|
|
<B><A HREF="/cgi-bin/man/man2html?8+switch_root">switch_root</A></B>(8)
|
|
|
|
<A NAME="lbAO"> </A>
|
|
<H2>COLOPHON</H2>
|
|
|
|
This page is part of release 5.05 of the Linux
|
|
<I>man-pages</I>
|
|
|
|
project.
|
|
A description of the project,
|
|
information about reporting bugs,
|
|
and the latest version of this page,
|
|
can be found at
|
|
<A HREF="https://www.kernel.org/doc/man-pages/.">https://www.kernel.org/doc/man-pages/.</A>
|
|
<P>
|
|
|
|
<HR>
|
|
<A NAME="index"> </A><H2>Index</H2>
|
|
<DL>
|
|
<DT id="17"><A HREF="#lbAB">NAME</A><DD>
|
|
<DT id="18"><A HREF="#lbAC">SYNOPSIS</A><DD>
|
|
<DT id="19"><A HREF="#lbAD">DESCRIPTION</A><DD>
|
|
<DT id="20"><A HREF="#lbAE">RETURN VALUE</A><DD>
|
|
<DT id="21"><A HREF="#lbAF">ERRORS</A><DD>
|
|
<DT id="22"><A HREF="#lbAG">VERSIONS</A><DD>
|
|
<DT id="23"><A HREF="#lbAH">CONFORMING TO</A><DD>
|
|
<DT id="24"><A HREF="#lbAI">NOTES</A><DD>
|
|
<DL>
|
|
<DT id="25"><A HREF="#lbAJ">pivot_root(".", ".")</A><DD>
|
|
<DT id="26"><A HREF="#lbAK">Historical notes</A><DD>
|
|
</DL>
|
|
<DT id="27"><A HREF="#lbAL">EXAMPLE</A><DD>
|
|
<DL>
|
|
<DT id="28"><A HREF="#lbAM">Program source</A><DD>
|
|
</DL>
|
|
<DT id="29"><A HREF="#lbAN">SEE ALSO</A><DD>
|
|
<DT id="30"><A HREF="#lbAO">COLOPHON</A><DD>
|
|
</DL>
|
|
<HR>
|
|
This document was created by
|
|
<A HREF="/cgi-bin/man/man2html">man2html</A>,
|
|
using the manual pages.<BR>
|
|
Time: 00:05:33 GMT, March 31, 2021
|
|
</BODY>
|
|
</HTML>
|