libfstools: skip JFFS2 padding when BLOCKSIZE was given
[project/fstools.git] / libfstools / mount.c
index 81176ce399b4cd8e2d347c0008c13dec92407f55..3d4111fe6b58c7d46ba96038c7fc571005f308cd 100644 (file)
@@ -14,6 +14,7 @@
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <sys/mount.h>
+#include <sys/wait.h>
 
 #include <errno.h>
 #include <stdio.h>
 /* this is a raw syscall - man 2 pivot_root */
 extern int pivot_root(const char *new_root, const char *put_old);
 
+/**
+ * mount_move - move mounted point to the new location
+ *
+ * @oldroot: directory that is current location of mount point
+ * @newroot: new directory for the mount point
+ */
 int
-mount_move(char *oldroot, char *newroot, char *dir)
+mount_move(const char *oldroot, const char *newroot, const char *dir)
 {
 #ifndef MS_MOVE
 #define MS_MOVE        (1 << 13)
@@ -48,7 +55,7 @@ mount_move(char *oldroot, char *newroot, char *dir)
        ret = mount(olddir, newdir, NULL, MS_NOATIME | MS_MOVE, NULL);
 
 /*     if (ret)
-               ULOG_ERR("failed %s %s: %s\n", olddir, newdir, strerror(errno));*/
+               ULOG_ERR("failed %s %s: %m\n", olddir, newdir);*/
 
        return ret;
 }
@@ -67,7 +74,7 @@ pivot(char *new, char *old)
        ret = pivot_root(new, pivotdir);
 
        if (ret < 0) {
-               ULOG_ERR("pivot_root failed %s %s: %s\n", new, pivotdir, strerror(errno));
+               ULOG_ERR("pivot_root failed %s %s: %m\n", new, pivotdir);
                return -1;
        }
 
@@ -79,10 +86,35 @@ pivot(char *new, char *old)
        return 0;
 }
 
+void
+selinux_restorecon(char *overlaydir)
+{
+       struct stat s;
+       pid_t restorecon_pid;
+       int status;
+
+       /* on non-SELinux system we don't have /sbin/restorecon, return */
+       if (stat("/sbin/restorecon", &s))
+               return;
+
+       restorecon_pid = fork();
+       if (!restorecon_pid)
+               exit(execl("/sbin/restorecon", "restorecon", overlaydir, (char *) NULL));
+       else if (restorecon_pid > 0)
+               waitpid(restorecon_pid, &status, 0);
+}
+
+/**
+ * fopivot - switch to overlay using passed dir as upper one
+ *
+ * @rw_root: writable directory that will be used as upper dir
+ * @ro_root: directory where old root will be put
+ */
 int
 fopivot(char *rw_root, char *ro_root)
 {
-       char overlay[64], lowerdir[64];
+       char overlay[64], mount_options[64], upperdir[64], workdir[64], upgrade[64], upgrade_dest[64];
+       struct stat st;
 
        if (find_filesystem("overlay")) {
                ULOG_ERR("BUG: no suitable fs found\n");
@@ -90,50 +122,47 @@ fopivot(char *rw_root, char *ro_root)
        }
 
        snprintf(overlay, sizeof(overlay), "overlayfs:%s", rw_root);
+       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(mount_options, sizeof(mount_options), "lowerdir=/,upperdir=%s,workdir=%s",
+                upperdir, workdir);
+
+       /*
+        * Initialize SELinux security label on newly created overlay
+        * filesystem where /upper doesn't yet exist
+        */
+       if (stat(upperdir, &st))
+               selinux_restorecon(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
+        * 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.
         */
-       snprintf(lowerdir, sizeof(lowerdir), "lowerdir=/,upperdir=%s", rw_root);
-       if (mount(overlay, "/mnt", "overlayfs", MS_NOATIME, lowerdir)) {
-               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)) {
-                               ULOG_ERR("mount failed: %s, options %s\n",
-                                        strerror(errno), lowerdir);
-                               return -1;
-                       }
-               }
+       if (mkdir(upperdir, 0755) == -1 && errno != EEXIST)
+               return -1;
+
+       if (mkdir(workdir, 0755) == -1 && errno != EEXIST)
+               return -1;
+
+       if (stat(upgrade, &st) == 0)
+               rename(upgrade, upgrade_dest);
+
+       if (mount(overlay, "/mnt", "overlay", MS_NOATIME, mount_options)) {
+               ULOG_ERR("mount failed: %m, options %s\n", mount_options);
+               return -1;
        }
 
        return pivot("/mnt", ro_root);
 }
 
+/**
+ * ramoverlay - use RAM to store filesystem changes on top of RO root
+ */
 int
 ramoverlay(void)
 {