aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Kerrisk <mtk.manpages@gmail.com>2019-07-28 09:11:29 +0200
committerMichael Kerrisk <mtk.manpages@gmail.com>2019-09-23 13:11:19 +0200
commit2f2e1a22968523829da906abd0f0660901897380 (patch)
tree73012567e0aef92c8659023290c4293f9611974b
parent0c2329cdbee7c707888d32ebccee53978417db21 (diff)
downloadman-pages-2f2e1a22968523829da906abd0f0660901897380.tar.gz
pivot_root.2: Add an example program
Signed-off-by: Michael Kerrisk <mtk.manpages@gmail.com>
-rw-r--r--man2/pivot_root.2134
1 files changed, 134 insertions, 0 deletions
diff --git a/man2/pivot_root.2 b/man2/pivot_root.2
index 9506dc7d1e..a11a31a031 100644
--- a/man2/pivot_root.2
+++ b/man2/pivot_root.2
@@ -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),