#include <unistd.h>
#include <string.h>
-#include "../fs-state.h"
+#include "libfstools.h"
/* this is a raw syscall - man 2 pivot_root */
extern int pivot_root(const char *new_root, const char *put_old);
}
snprintf(overlay, sizeof(overlay), "overlayfs:%s", rw_root);
- snprintf(lowerdir, sizeof(lowerdir), "lowerdir=/,upperdir=%s", rw_root);
+ /*
+ * First, try to mount without a workdir, for overlayfs v22 and before.
+ * If it fails, it means that we are probably using a v23 and
+ * later versions that require a workdir
+ */
+ snprintf(lowerdir, sizeof(lowerdir), "lowerdir=/,upperdir=%s", rw_root);
if (mount(overlay, "/mnt", "overlayfs", MS_NOATIME, lowerdir)) {
- fprintf(stderr, "mount failed: %s\n", strerror(errno));
- return -1;
+ char upperdir[64], workdir[64], upgrade[64], upgrade_dest[64];
+ struct stat st;
+
+ snprintf(upperdir, sizeof(upperdir), "%s/upper", rw_root);
+ snprintf(workdir, sizeof(workdir), "%s/work", rw_root);
+ snprintf(upgrade, sizeof(upgrade), "%s/sysupgrade.tgz", rw_root);
+ snprintf(upgrade_dest, sizeof(upgrade_dest), "%s/sysupgrade.tgz", upperdir);
+ snprintf(lowerdir, sizeof(lowerdir), "lowerdir=/,upperdir=%s,workdir=%s",
+ upperdir, workdir);
+
+ /*
+ * Overlay FS v23 and later requires both a upper and
+ * a work directory, both on the same filesystem, but
+ * not part of the same subtree.
+ * We can't really deal with these constraints without
+ * creating two new subdirectories in /overlay.
+ */
+ mkdir(upperdir, 0755);
+ mkdir(workdir, 0755);
+
+ if (stat(upgrade, &st) == 0)
+ rename(upgrade, upgrade_dest);
+
+ /* Mainlined overlayfs has been renamed to "overlay", try that first */
+ if (mount(overlay, "/mnt", "overlay", MS_NOATIME, lowerdir)) {
+ if (mount(overlay, "/mnt", "overlayfs", MS_NOATIME, lowerdir)) {
+ fprintf(stderr, "mount failed: %s, options %s\n",
+ strerror(errno), lowerdir);
+ return -1;
+ }
+ }
}
return pivot("/mnt", ro_root);