1PIVOT_ROOT(2) Linux Programmer's Manual PIVOT_ROOT(2)
2
3
4
6 pivot_root - change the root mount
7
9 int pivot_root(const char *new_root, const char *put_old);
10
11 Note: There is no glibc wrapper for this system call; see NOTES.
12
14 pivot_root() changes the root mount in the mount namespace of the call‐
15 ing process. More precisely, it moves the root mount to the directory
16 put_old and makes new_root the new root mount. The calling process
17 must have the CAP_SYS_ADMIN capability in the user namespace that owns
18 the caller's mount namespace.
19
20 pivot_root() changes the root directory and the current working direc‐
21 tory of each process or thread in the same mount namespace to new_root
22 if they point to the old root directory. (See also NOTES.) On the
23 other hand, pivot_root() does not change the caller's current working
24 directory (unless it is on the old root directory), and thus it should
25 be followed by a chdir("/") call.
26
27 The following restrictions apply:
28
29 - new_root and put_old must be directories.
30
31 - new_root and put_old must not be on the same mount as the current
32 root.
33
34 - put_old must be at or underneath new_root; that is, adding some non‐
35 negative number of "/.." prefixes to the pathname pointed to by
36 put_old must yield the same directory as new_root.
37
38 - new_root must be a path to a mount point, but can't be "/". A path
39 that is not already a mount point can be converted into one by bind
40 mounting the path onto itself.
41
42 - The propagation type of the parent mount of new_root and the parent
43 mount of the current root directory must not be MS_SHARED; simi‐
44 larly, if put_old is an existing mount point, its propagation type
45 must not be MS_SHARED. These restrictions ensure that pivot_root()
46 never propagates any changes to another mount namespace.
47
48 - The current root directory must be a mount point.
49
51 On success, zero is returned. On error, -1 is returned, and errno is
52 set appropriately.
53
55 pivot_root() may fail with any of the same errors as stat(2). Addi‐
56 tionally, it may fail with the following errors:
57
58 EBUSY new_root or put_old is on the current root mount. (This error
59 covers the pathological case where new_root is "/".)
60
61 EINVAL new_root is not a mount point.
62
63 EINVAL put_old is not at or underneath new_root.
64
65 EINVAL The current root directory is not a mount point (because of an
66 earlier chroot(2)).
67
68 EINVAL The current root is on the rootfs (initial ramfs) mount; see
69 NOTES.
70
71 EINVAL Either the mount point at new_root, or the parent mount of that
72 mount point, has propagation type MS_SHARED.
73
74 EINVAL put_old is a mount point and has the propagation type MS_SHARED.
75
76 ENOTDIR
77 new_root or put_old is not a directory.
78
79 EPERM The calling process does not have the CAP_SYS_ADMIN capability.
80
82 pivot_root() was introduced in Linux 2.3.41.
83
85 pivot_root() is Linux-specific and hence is not portable.
86
88 Glibc does not provide a wrapper for this system call; call it using
89 syscall(2).
90
91 A command-line interface for this system call is provided by
92 pivot_root(8).
93
94 pivot_root() allows the caller to switch to a new root filesystem while
95 at the same time placing the old root mount at a location under
96 new_root from where it can subsequently be unmounted. (The fact that
97 it moves all processes that have a root directory or current working
98 directory on the old root directory to the new root frees the old root
99 directory of users, allowing the old root mount to be unmounted more
100 easily.)
101
102 One use of pivot_root() is during system startup, when the system
103 mounts a temporary root filesystem (e.g., an initrd(4)), then mounts
104 the real root filesystem, and eventually turns the latter into the root
105 directory of all relevant processes and threads. A modern use is to
106 set up a root filesystem during the creation of a container.
107
108 The fact that pivot_root() modifies process root and current working
109 directories in the manner noted in DESCRIPTION is necessary in order to
110 prevent kernel threads from keeping the old root mount busy with their
111 root and current working directories, even if they never access the
112 filesystem in any way.
113
114 The rootfs (initial ramfs) cannot be pivot_root()ed. The recommended
115 method of changing the root filesystem in this case is to delete every‐
116 thing in rootfs, overmount rootfs with the new root, attach stdin/std‐
117 out/stderr to the new /dev/console, and exec the new init(1). Helper
118 programs for this process exist; see switch_root(8).
119
120 pivot_root(".", ".")
121 new_root and put_old may be the same directory. In particular, the
122 following sequence allows a pivot-root operation without needing to
123 create and remove a temporary directory:
124
125 chdir(new_root);
126 pivot_root(".", ".");
127 umount2(".", MNT_DETACH);
128
129 This sequence succeeds because the pivot_root() call stacks the old
130 root mount point on top of the new root mount point at /. At that
131 point, the calling process's root directory and current working direc‐
132 tory refer to the new root mount point (new_root). During the subse‐
133 quent umount() call, resolution of "." starts with new_root and then
134 moves up the list of mounts stacked at /, with the result that old root
135 mount point is unmounted.
136
137 Historical notes
138 For many years, this manual page carried the following text:
139
140 pivot_root() may or may not change the current root and the cur‐
141 rent working directory of any processes or threads which use the
142 old root directory. The caller of pivot_root() must ensure that
143 processes with root or current working directory at the old root
144 operate correctly in either case. An easy way to ensure this is
145 to change their root and current working directory to new_root
146 before invoking pivot_root().
147
148 This text, written before the system call implementation was even
149 finalized in the kernel, was probably intended to warn users at that
150 time that the implementation might change before final release. How‐
151 ever, the behavior stated in DESCRIPTION has remained consistent since
152 this system call was first implemented and will not change now.
153
155 The program below demonstrates the use of pivot_root() inside a mount
156 namespace that is created using clone(2). After pivoting to the root
157 directory named in the program's first command-line argument, the child
158 created by clone(2) then executes the program named in the remaining
159 command-line arguments.
160
161 We demonstrate the program by creating a directory that will serve as
162 the new root filesystem and placing a copy of the (statically linked)
163 busybox(1) executable in that directory.
164
165 $ mkdir /tmp/rootfs
166 $ ls -id /tmp/rootfs # Show inode number of new root directory
167 319459 /tmp/rootfs
168 $ cp $(which busybox) /tmp/rootfs
169 $ PS1='bbsh$ ' sudo ./pivot_root_demo /tmp/rootfs /busybox sh
170 bbsh$ PATH=/
171 bbsh$ busybox ln busybox ln
172 bbsh$ ln busybox echo
173 bbsh$ ln busybox ls
174 bbsh$ ls
175 busybox echo ln ls
176 bbsh$ ls -id / # Compare with inode number above
177 319459 /
178 bbsh$ echo 'hello world'
179 hello world
180
181 Program source
182
183
184 /* pivot_root_demo.c */
185
186 #define _GNU_SOURCE
187 #include <sched.h>
188 #include <stdio.h>
189 #include <stdlib.h>
190 #include <unistd.h>
191 #include <sys/wait.h>
192 #include <sys/syscall.h>
193 #include <sys/mount.h>
194 #include <sys/stat.h>
195 #include <limits.h>
196 #include <sys/mman.h>
197
198 #define errExit(msg) do { perror(msg); exit(EXIT_FAILURE); \
199 } while (0)
200
201 static int
202 pivot_root(const char *new_root, const char *put_old)
203 {
204 return syscall(SYS_pivot_root, new_root, put_old);
205 }
206
207 #define STACK_SIZE (1024 * 1024)
208
209 static int /* Startup function for cloned child */
210 child(void *arg)
211 {
212 char **args = arg;
213 char *new_root = args[0];
214 const char *put_old = "/oldrootfs";
215 char path[PATH_MAX];
216
217 /* Ensure that 'new_root' and its parent mount don't have
218 shared propagation (which would cause pivot_root() to
219 return an error), and prevent propagation of mount
220 events to the initial mount namespace */
221
222 if (mount(NULL, "/", NULL, MS_REC | MS_PRIVATE, NULL) == 1)
223 errExit("mount-MS_PRIVATE");
224
225 /* Ensure that 'new_root' is a mount point */
226
227 if (mount(new_root, new_root, NULL, MS_BIND, NULL) == -1)
228 errExit("mount-MS_BIND");
229
230 /* Create directory to which old root will be pivoted */
231
232 snprintf(path, sizeof(path), "%s/%s", new_root, put_old);
233 if (mkdir(path, 0777) == -1)
234 errExit("mkdir");
235
236 /* And pivot the root filesystem */
237
238 if (pivot_root(new_root, path) == -1)
239 errExit("pivot_root");
240
241 /* Switch the current working directory to "/" */
242
243 if (chdir("/") == -1)
244 errExit("chdir");
245
246 /* Unmount old root and remove mount point */
247
248 if (umount2(put_old, MNT_DETACH) == -1)
249 perror("umount2");
250 if (rmdir(put_old) == -1)
251 perror("rmdir");
252
253 /* Execute the command specified in argv[1]... */
254
255 execv(args[1], &args[1]);
256 errExit("execv");
257 }
258
259 int
260 main(int argc, char *argv[])
261 {
262 /* Create a child process in a new mount namespace */
263
264 char *stack = mmap(NULL, STACK_SIZE, PROT_READ | PROT_WRITE,
265 MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, -1, 0);
266 if (stack == MAP_FAILED)
267 errExit("mmap");
268
269 if (clone(child, stack + STACK_SIZE,
270 CLONE_NEWNS | SIGCHLD, &argv[1]) == -1)
271 errExit("clone");
272
273 /* Parent falls through to here; wait for child */
274
275 if (wait(NULL) == -1)
276 errExit("wait");
277
278 exit(EXIT_SUCCESS);
279 }
280
282 chdir(2), chroot(2), mount(2), stat(2), initrd(4), mount_namespaces(7),
283 pivot_root(8), switch_root(8)
284
286 This page is part of release 5.07 of the Linux man-pages project. A
287 description of the project, information about reporting bugs, and the
288 latest version of this page, can be found at
289 https://www.kernel.org/doc/man-pages/.
290
291
292
293Linux 2020-06-09 PIVOT_ROOT(2)