mirror of https://github.com/mkerrisk/man-pages
pivot_root.2: Add an example program
Signed-off-by: Michael Kerrisk <mtk.manpages@gmail.com>
This commit is contained in:
parent
0c2329cdbe
commit
2f2e1a2296
|
@ -195,6 +195,140 @@ Some of the more obscure uses of
|
|||
.BR pivot_root ()
|
||||
may quickly lead to
|
||||
insanity.
|
||||
.SH EXAMPLE
|
||||
.PP
|
||||
The program below demonstrates the use of
|
||||
.BR pivot_root ()
|
||||
inside a mount namespace that is created using
|
||||
.BR clone (2).
|
||||
After pivoting to the root directory named in the program's
|
||||
first command-line argument, the child created by
|
||||
.BR clone (2)
|
||||
then executes the program named in the remaining command-line arguments.
|
||||
.PP
|
||||
We demonstrate the program by creating a directory that will serve as
|
||||
the new root filesystem and placing a copy of the (statically linked)
|
||||
.BR busybox (1)
|
||||
executable in that directory.
|
||||
.PP
|
||||
.in +4n
|
||||
.EX
|
||||
$ \fBmkdir /tmp/rootfs\fP
|
||||
$ \fBls \-id /tmp/rootfs\fP # Show inode number of new root directory
|
||||
319459 /tmp/rootfs
|
||||
$ \fBcp $(which busybox) /tmp/rootfs\fP
|
||||
$ \fBPS1='bbsh$ ' sudo ./pivot_root_demo /tmp/rootfs /busybox sh\fP
|
||||
bbsh$ \fBPATH=/\fP
|
||||
bbsh$ \fBbusybox ln busybox ln\fP
|
||||
bbsh$ \fBln busybox echo\fP
|
||||
bbsh$ \fBln busybox ls\fP
|
||||
bbsh$ \fBls\fP
|
||||
busybox echo ln ls
|
||||
bbsh$ \fBls \-id /\fP # Compare with inode number above
|
||||
319459 /
|
||||
bbsh$ \fBecho \(aqhello world\(aq\fP
|
||||
hello world
|
||||
.EE
|
||||
.in
|
||||
.SS Program source
|
||||
\&
|
||||
.PP
|
||||
.EX
|
||||
/* pivot_root_demo.c */
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <sched.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/stat.h>
|
||||
#include <limits.h>
|
||||
|
||||
#define errExit(msg) do { perror(msg); exit(EXIT_FAILURE); \e
|
||||
} while (0)
|
||||
|
||||
static int
|
||||
pivot_root(const char *new_root, const char *put_old)
|
||||
{
|
||||
return syscall(SYS_pivot_root, new_root, put_old);
|
||||
}
|
||||
|
||||
#define STACK_SIZE (1024 * 1024)
|
||||
|
||||
static int /* Startup function for cloned child */
|
||||
child(void *arg)
|
||||
{
|
||||
char **args = arg;
|
||||
char *new_root = args[0];
|
||||
const char *put_old = "/oldrootfs";
|
||||
char path[PATH_MAX];
|
||||
|
||||
/* Ensure that \(aqnew_root\(aq and its parent mount don\(aqt have
|
||||
shared propagation (which would cause pivot_root() to
|
||||
return an error), and prevent propagation of mount
|
||||
events to the initial mount namespace */
|
||||
|
||||
if (mount(NULL, "/", NULL, MS_REC | MS_PRIVATE, NULL) == 1)
|
||||
errExit("mount\-MS_PRIVATE");
|
||||
|
||||
/* Ensure that \(aqnew_root\(aq is a mount point */
|
||||
|
||||
if (mount(new_root, new_root, NULL, MS_BIND, NULL) == \-1)
|
||||
errExit("mount\-MS_BIND");
|
||||
|
||||
/* Create directory to which old root will be pivoted */
|
||||
|
||||
snprintf(path, sizeof(path), "%s/%s", new_root, put_old);
|
||||
if (mkdir(path, 0777) == \-1)
|
||||
errExit("mkdir");
|
||||
|
||||
/* And pivot the root filesystem */
|
||||
|
||||
if (pivot_root(new_root, path) == \-1)
|
||||
errExit("pivot_root");
|
||||
|
||||
/* Switch the current working working directory to "/" */
|
||||
|
||||
if (chdir("/") == \-1)
|
||||
errExit("chdir");
|
||||
|
||||
/* Unmount old root and remove mount point */
|
||||
|
||||
if (umount2(put_old, MNT_DETACH) == \-1)
|
||||
perror("umount2");
|
||||
if (rmdir(put_old) == \-1)
|
||||
perror("rmdir");
|
||||
|
||||
/* Execute the command specified in argv[1]... */
|
||||
|
||||
execv(args[1], &args[1]);
|
||||
errExit("execv");
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
/* Create a child process in a new mount namespace */
|
||||
|
||||
char *stack = malloc(STACK_SIZE);
|
||||
if (stack == NULL)
|
||||
errExit("malloc");
|
||||
|
||||
if (clone(child, stack + STACK_SIZE,
|
||||
CLONE_NEWNS | SIGCHLD, &argv[1]) == \-1)
|
||||
errExit("clone");
|
||||
|
||||
/* Parent falls through to here; wait for child */
|
||||
|
||||
if (wait(NULL) == \-1)
|
||||
errExit("wait");
|
||||
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
.EE
|
||||
.SH SEE ALSO
|
||||
.BR chdir (2),
|
||||
.BR chroot (2),
|
||||
|
|
Loading…
Reference in New Issue