2 * Copyright (C) 2014 John Crispin <blogic@openwrt.org>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser General Public License version 2.1
6 * as published by the Free Software Foundation
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
14 #include <sys/types.h>
16 #include <sys/mount.h>
23 #include "libfstools.h"
25 /* this is a raw syscall - man 2 pivot_root */
26 extern int pivot_root(const char *new_root, const char *put_old);
29 mount_move(char *oldroot, char *newroot, char *dir)
32 #define MS_MOVE (1 << 13)
39 snprintf(olddir, sizeof(olddir), "%s%s", oldroot, dir);
40 snprintf(newdir, sizeof(newdir), "%s%s", newroot, dir);
42 if (stat(olddir, &s) || !S_ISDIR(s.st_mode))
45 if (stat(newdir, &s) || !S_ISDIR(s.st_mode))
48 ret = mount(olddir, newdir, NULL, MS_NOATIME | MS_MOVE, NULL);
51 fprintf(stderr, "failed %s %s: %s\n", olddir, newdir, strerror(errno));*/
57 pivot(char *new, char *old)
62 if (mount_move("", new, "/proc"))
65 snprintf(pivotdir, sizeof(pivotdir), "%s%s", new, old);
67 ret = pivot_root(new, pivotdir);
70 fprintf(stderr, "pivot_root failed %s %s: %s\n", new, pivotdir, strerror(errno));
74 mount_move(old, "", "/dev");
75 mount_move(old, "", "/tmp");
76 mount_move(old, "", "/sys");
77 mount_move(old, "", "/overlay");
83 fopivot(char *rw_root, char *ro_root)
85 char overlay[64], lowerdir[64];
87 if (find_filesystem("overlay")) {
88 fprintf(stderr, "BUG: no suitable fs found\n");
92 snprintf(overlay, sizeof(overlay), "overlayfs:%s", rw_root);
95 * First, try to mount without a workdir, for overlayfs v22 and before.
96 * If it fails, it means that we are probably using a v23 and
97 * later versions that require a workdir
99 snprintf(lowerdir, sizeof(lowerdir), "lowerdir=/,upperdir=%s", rw_root);
100 if (mount(overlay, "/mnt", "overlayfs", MS_NOATIME, lowerdir)) {
101 char upperdir[64], workdir[64], upgrade[64], upgrade_dest[64];
104 snprintf(upperdir, sizeof(upperdir), "%s/upper", rw_root);
105 snprintf(workdir, sizeof(workdir), "%s/work", rw_root);
106 snprintf(upgrade, sizeof(upgrade), "%s/sysupgrade.tgz", rw_root);
107 snprintf(upgrade_dest, sizeof(upgrade_dest), "%s/sysupgrade.tgz", upperdir);
108 snprintf(lowerdir, sizeof(lowerdir), "lowerdir=/,upperdir=%s,workdir=%s",
112 * Overlay FS v23 and later requires both a upper and
113 * a work directory, both on the same filesystem, but
114 * not part of the same subtree.
115 * We can't really deal with these constraints without
116 * creating two new subdirectories in /overlay.
118 mkdir(upperdir, 0755);
119 mkdir(workdir, 0755);
121 if (stat(upgrade, &st) == 0)
122 rename(upgrade, upgrade_dest);
124 /* Mainlined overlayfs has been renamed to "overlay", try that first */
125 if (mount(overlay, "/mnt", "overlay", MS_NOATIME, lowerdir)) {
126 if (mount(overlay, "/mnt", "overlayfs", MS_NOATIME, lowerdir)) {
127 fprintf(stderr, "mount failed: %s, options %s\n",
128 strerror(errno), lowerdir);
134 return pivot("/mnt", ro_root);
140 mkdir("/tmp/root", 0755);
141 mount("tmpfs", "/tmp/root", "tmpfs", MS_NOATIME, "mode=0755");
143 return fopivot("/tmp/root", "/rom");