Merge "fs_mgr: Create a C++ Fstab struct"
diff --git a/adb/NOTICE b/adb/NOTICE
index ff47c95..9ffcc08 100644
--- a/adb/NOTICE
+++ b/adb/NOTICE
@@ -189,63 +189,3 @@
 
    END OF TERMS AND CONDITIONS
 
-------------------------------------------------------------
-libwinpthread license:
-------------------------------------------------------------
-Copyright (c) 2011 mingw-w64 project
-
-Permission is hereby granted, free of charge, to any person obtaining a
-copy of this software and associated documentation files (the "Software"),
-to deal in the Software without restriction, including without limitation
-the rights to use, copy, modify, merge, publish, distribute, sublicense,
-and/or sell copies of the Software, and to permit persons to whom the
-Software is furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-DEALINGS IN THE SOFTWARE.
-
-
-/*
- * Parts of this library are derived by:
- *
- * Posix Threads library for Microsoft Windows
- *
- * Use at own risk, there is no implied warranty to this code.
- * It uses undocumented features of Microsoft Windows that can change
- * at any time in the future.
- *
- * (C) 2010 Lockless Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification,
- * are permitted provided that the following conditions are met:
- *
- *
- *  * Redistributions of source code must retain the above copyright notice,
- *    this list of conditions and the following disclaimer.
- *  * Redistributions in binary form must reproduce the above copyright notice,
- *    this list of conditions and the following disclaimer in the documentation
- *    and/or other materials provided with the distribution.
- *  * Neither the name of Lockless Inc. nor the names of its contributors may be
- *    used to endorse or promote products derived from this software without
- *    specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AN
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
- * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
- * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
- * OF THE POSSIBILITY OF SUCH DAMAGE.
- */
diff --git a/base/include/android-base/unique_fd.h b/base/include/android-base/unique_fd.h
index 4e3879b..4e6c879 100644
--- a/base/include/android-base/unique_fd.h
+++ b/base/include/android-base/unique_fd.h
@@ -16,6 +16,7 @@
 
 #pragma once
 
+#include <dirent.h>
 #include <fcntl.h>
 
 #if !defined(_WIN32)
@@ -231,3 +232,13 @@
 template <typename T>
 int close(const android::base::unique_fd_impl<T>&)
     __attribute__((__unavailable__("close called on unique_fd")));
+
+template <typename T>
+FILE* fdopen(const android::base::unique_fd_impl<T>&, const char* mode)
+    __attribute__((__unavailable__("fdopen takes ownership of the fd passed in; either dup the "
+                                   "unique_fd, or use android::base::Fdopen to pass ownership")));
+
+template <typename T>
+DIR* fdopendir(const android::base::unique_fd_impl<T>&) __attribute__((
+    __unavailable__("fdopendir takes ownership of the fd passed in; either dup the "
+                    "unique_fd, or use android::base::Fdopendir to pass ownership")));
diff --git a/fastboot/device/flashing.cpp b/fastboot/device/flashing.cpp
index 7b99884..fbba631 100644
--- a/fastboot/device/flashing.cpp
+++ b/fastboot/device/flashing.cpp
@@ -153,6 +153,7 @@
         if (!FlashPartitionTable(super_name, *new_metadata.get())) {
             return device->WriteFail("Unable to flash new partition table");
         }
+        fs_mgr_overlayfs_teardown();
         return device->WriteOkay("Successfully flashed partition table");
     }
 
@@ -186,5 +187,6 @@
     if (!UpdateAllPartitionMetadata(super_name, *new_metadata.get())) {
         return device->WriteFail("Unable to write new partition table");
     }
+    fs_mgr_overlayfs_teardown();
     return device->WriteOkay("Successfully updated partition table");
 }
diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp
index 820ff31..6f863ad 100644
--- a/fs_mgr/fs_mgr.cpp
+++ b/fs_mgr/fs_mgr.cpp
@@ -82,6 +82,7 @@
 
 #define ARRAY_SIZE(a) (sizeof(a) / sizeof(*(a)))
 
+using android::base::Realpath;
 using android::dm::DeviceMapper;
 using android::dm::DmDeviceState;
 using android::fs_mgr::AvbHandle;
@@ -100,7 +101,7 @@
     FS_STAT_FULL_MOUNT_FAILED = 0x0100,
     FS_STAT_E2FSCK_FAILED = 0x0200,
     FS_STAT_E2FSCK_FS_FIXED = 0x0400,
-    FS_STAT_EXT4_INVALID_MAGIC = 0x0800,
+    FS_STAT_INVALID_MAGIC = 0x0800,
     FS_STAT_TOGGLE_QUOTAS_FAILED = 0x10000,
     FS_STAT_SET_RESERVED_BLOCKS_FAILED = 0x20000,
     FS_STAT_ENABLE_ENCRYPTION_FAILED = 0x40000,
@@ -143,6 +144,18 @@
     return fs_type == "ext4" || fs_type == "ext3" || fs_type == "ext2";
 }
 
+static bool is_f2fs(const std::string& fs_type) {
+    return fs_type == "f2fs";
+}
+
+static std::string realpath(const char* blk_device) {
+    std::string real_path;
+    if (!Realpath(blk_device, &real_path)) {
+        real_path = blk_device;
+    }
+    return real_path;
+}
+
 static bool should_force_check(int fs_stat) {
     return fs_stat &
            (FS_STAT_E2FSCK_F_ALWAYS | FS_STAT_UNCLEAN_SHUTDOWN | FS_STAT_QUOTA_ENABLED |
@@ -160,11 +173,12 @@
     const char* e2fsck_argv[] = {E2FSCK_BIN, "-y", blk_device};
     const char* e2fsck_forced_argv[] = {E2FSCK_BIN, "-f", "-y", blk_device};
 
+    if (*fs_stat & FS_STAT_INVALID_MAGIC) {  // will fail, so do not try
+        return;
+    }
+
     /* Check for the types of filesystems we know how to check */
     if (is_extfs(fs_type)) {
-        if (*fs_stat & FS_STAT_EXT4_INVALID_MAGIC) {  // will fail, so do not try
-            return;
-        }
         /*
          * First try to mount and unmount the filesystem.  We do this because
          * the kernel is more efficient than e2fsck in running the journal and
@@ -214,10 +228,10 @@
          * (e.g. recent SDK system images). Detect these and skip the check.
          */
         if (access(E2FSCK_BIN, X_OK)) {
-            LINFO << "Not running " << E2FSCK_BIN << " on " << blk_device
+            LINFO << "Not running " << E2FSCK_BIN << " on " << realpath(blk_device)
                   << " (executable not in system image)";
         } else {
-            LINFO << "Running " << E2FSCK_BIN << " on " << blk_device;
+            LINFO << "Running " << E2FSCK_BIN << " on " << realpath(blk_device);
             if (should_force_check(*fs_stat)) {
                 ret = android_fork_execvp_ext(
                     ARRAY_SIZE(e2fsck_forced_argv), const_cast<char**>(e2fsck_forced_argv), &status,
@@ -237,13 +251,9 @@
                 *fs_stat |= FS_STAT_E2FSCK_FS_FIXED;
             }
         }
-    } else if (!strcmp(fs_type, "f2fs")) {
-            const char *f2fs_fsck_argv[] = {
-                    F2FS_FSCK_BIN,
-                    "-a",
-                    blk_device
-            };
-        LINFO << "Running " << F2FS_FSCK_BIN << " -a " << blk_device;
+    } else if (is_f2fs(fs_type)) {
+        const char* f2fs_fsck_argv[] = {F2FS_FSCK_BIN, "-a", blk_device};
+        LINFO << "Running " << F2FS_FSCK_BIN << " -a " << realpath(blk_device);
 
         ret = android_fork_execvp_ext(ARRAY_SIZE(f2fs_fsck_argv),
                                       const_cast<char **>(f2fs_fsck_argv),
@@ -277,7 +287,7 @@
 }
 
 // Read the primary superblock from an ext4 filesystem.  On failure return
-// false.  If it's not an ext4 filesystem, also set FS_STAT_EXT4_INVALID_MAGIC.
+// false.  If it's not an ext4 filesystem, also set FS_STAT_INVALID_MAGIC.
 static bool read_ext4_superblock(const char* blk_device, struct ext4_super_block* sb, int* fs_stat) {
     android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(blk_device, O_RDONLY | O_CLOEXEC)));
 
@@ -294,7 +304,7 @@
     if (!is_ext4_superblock_valid(sb)) {
         LINFO << "Invalid ext4 superblock on '" << blk_device << "'";
         // not a valid fs, tune2fs, fsck, and mount  will all fail.
-        *fs_stat |= FS_STAT_EXT4_INVALID_MAGIC;
+        *fs_stat |= FS_STAT_INVALID_MAGIC;
         return false;
     }
     *fs_stat |= FS_STAT_IS_EXT4;
@@ -422,6 +432,36 @@
     }
 }
 
+// Read the primary superblock from an f2fs filesystem.  On failure return
+// false.  If it's not an f2fs filesystem, also set FS_STAT_INVALID_MAGIC.
+#define F2FS_BLKSIZE 4096
+#define F2FS_SUPER_OFFSET 1024
+static bool read_f2fs_superblock(const char* blk_device, int* fs_stat) {
+    android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(blk_device, O_RDONLY | O_CLOEXEC)));
+    __le32 sb1, sb2;
+
+    if (fd < 0) {
+        PERROR << "Failed to open '" << blk_device << "'";
+        return false;
+    }
+
+    if (pread(fd, &sb1, sizeof(sb1), F2FS_SUPER_OFFSET) != sizeof(sb1)) {
+        PERROR << "Can't read '" << blk_device << "' superblock1";
+        return false;
+    }
+    if (pread(fd, &sb2, sizeof(sb2), F2FS_BLKSIZE + F2FS_SUPER_OFFSET) != sizeof(sb2)) {
+        PERROR << "Can't read '" << blk_device << "' superblock2";
+        return false;
+    }
+
+    if (sb1 != cpu_to_le32(F2FS_SUPER_MAGIC) && sb2 != cpu_to_le32(F2FS_SUPER_MAGIC)) {
+        LINFO << "Invalid f2fs superblock on '" << blk_device << "'";
+        *fs_stat |= FS_STAT_INVALID_MAGIC;
+        return false;
+    }
+    return true;
+}
+
 //
 // Prepare the filesystem on the given block device to be mounted.
 //
@@ -451,6 +491,10 @@
         } else {
             return fs_stat;
         }
+    } else if (is_f2fs(rec->fs_type)) {
+        if (!read_f2fs_superblock(blk_device, &fs_stat)) {
+            return fs_stat;
+        }
     }
 
     if ((rec->fs_mgr_flags & MF_CHECK) ||
@@ -617,9 +661,10 @@
             }
 
             int fs_stat = prepare_fs_for_mount(fstab->recs[i].blk_device, &fstab->recs[i]);
-            if (fs_stat & FS_STAT_EXT4_INVALID_MAGIC) {
-                LERROR << __FUNCTION__ << "(): skipping mount, invalid ext4, mountpoint="
-                       << fstab->recs[i].mount_point << " rec[" << i
+            if (fs_stat & FS_STAT_INVALID_MAGIC) {
+                LERROR << __FUNCTION__ << "(): skipping mount due to invalid magic, mountpoint="
+                       << fstab->recs[i].mount_point
+                       << " blk_dev=" << realpath(fstab->recs[i].blk_device) << " rec[" << i
                        << "].fs_type=" << fstab->recs[i].fs_type;
                 mount_errno = EINVAL;  // continue bootup for FDE
                 continue;
@@ -911,7 +956,7 @@
   private:
     bool UpdateCheckpointPartition(struct fstab_rec* rec) {
         if (fs_mgr_is_checkpoint_fs(rec)) {
-            if (!strcmp(rec->fs_type, "f2fs")) {
+            if (is_f2fs(rec->fs_type)) {
                 std::string opts(rec->fs_options);
 
                 opts += ",checkpoint=disable";
@@ -1002,7 +1047,7 @@
         /* Skip mounting the root partition, as it will already have been mounted */
         if (!strcmp(fstab->recs[i].mount_point, "/") ||
             !strcmp(fstab->recs[i].mount_point, "/system")) {
-            if ((fstab->recs[i].fs_mgr_flags & MS_RDONLY) != 0) {
+            if ((fstab->recs[i].flags & MS_RDONLY) != 0) {
                 fs_mgr_set_blk_ro(fstab->recs[i].blk_device);
             }
             continue;
@@ -1104,10 +1149,9 @@
              * at two different lines in the fstab.  Use the top one for formatting
              * as that is the preferred one.
              */
-            LERROR << __FUNCTION__ << "(): " << fstab->recs[top_idx].blk_device
-                   << " is wiped and " << fstab->recs[top_idx].mount_point
-                   << " " << fstab->recs[top_idx].fs_type
-                   << " is formattable. Format it.";
+            LERROR << __FUNCTION__ << "(): " << realpath(fstab->recs[top_idx].blk_device)
+                   << " is wiped and " << fstab->recs[top_idx].mount_point << " "
+                   << fstab->recs[top_idx].fs_type << " is formattable. Format it.";
 
             checkpoint_manager.Revert(&fstab->recs[top_idx]);
 
diff --git a/fs_mgr/fs_mgr_overlayfs.cpp b/fs_mgr/fs_mgr_overlayfs.cpp
index bef46e1..20652ad 100644
--- a/fs_mgr/fs_mgr_overlayfs.cpp
+++ b/fs_mgr/fs_mgr_overlayfs.cpp
@@ -395,6 +395,18 @@
     return false;
 }
 
+void fs_mgr_overlayfs_umount_scratch() {
+    // Lazy umount will allow us to move on and possibly later
+    // establish a new fresh mount without requiring a reboot should
+    // the developer wish to restart.  Old references should melt
+    // away or have no data.  Main goal is to shut the door on the
+    // current overrides with an expectation of a subsequent reboot,
+    // thus any errors here are ignored.
+    umount2(kScratchMountPoint.c_str(), MNT_DETACH);
+    LINFO << "umount(" << kScratchMountPoint << ")";
+    rmdir(kScratchMountPoint.c_str());
+}
+
 // reduce 'DM_DEV_STATUS failed for scratch: No such device or address' noise
 std::string scratch_device_cache;
 
@@ -408,13 +420,7 @@
 
     auto save_errno = errno;
     if (fs_mgr_overlayfs_already_mounted(kScratchMountPoint, false)) {
-        // Lazy umount will allow us to move on and possibly later
-        // establish a new fresh mount without requiring a reboot should
-        // the developer wish to restart.  Old references should melt
-        // away or have no data.  Main goal is to shut the door on the
-        // current overrides with an expectation of a subsequent reboot,
-        // thus any errors here are ignored.
-        umount2(kScratchMountPoint.c_str(), MNT_DETACH);
+        fs_mgr_overlayfs_umount_scratch();
     }
     auto builder = MetadataBuilder::New(super_device, slot_number);
     if (!builder) {
@@ -753,14 +759,20 @@
     return builder->FindPartition(android::base::Basename(kScratchMountPoint)) != nullptr;
 }
 
+bool fs_mgr_overlayfs_invalid(const fstab* fstab) {
+    if (fs_mgr_overlayfs_valid() == OverlayfsValidResult::kNotSupported) return true;
+
+    // in recovery or fastbootd mode, not allowed!
+    if (fs_mgr_access("/system/bin/recovery")) return true;
+
+    return !fstab;
+}
+
 }  // namespace
 
 bool fs_mgr_overlayfs_mount_all(fstab* fstab) {
     auto ret = false;
-
-    if (fs_mgr_overlayfs_valid() == OverlayfsValidResult::kNotSupported) return ret;
-
-    if (!fstab) return ret;
+    if (fs_mgr_overlayfs_invalid(fstab)) return ret;
 
     auto scratch_can_be_mounted = true;
     for (const auto& mount_point : fs_mgr_candidate_list(fstab)) {
@@ -773,8 +785,7 @@
                 fs_mgr_overlayfs_mount_scratch(scratch_device,
                                                fs_mgr_overlayfs_scratch_mount_type()) &&
                 !fs_mgr_access(kScratchMountPoint + kOverlayTopDir)) {
-                umount2(kScratchMountPoint.c_str(), MNT_DETACH);
-                rmdir(kScratchMountPoint.c_str());
+                fs_mgr_overlayfs_umount_scratch();
             }
         }
         if (fs_mgr_overlayfs_mount(mount_point)) ret = true;
@@ -790,9 +801,9 @@
 }
 
 std::vector<std::string> fs_mgr_overlayfs_required_devices(fstab* fstab) {
-    if (fs_mgr_overlayfs_valid() == OverlayfsValidResult::kNotSupported) return {};
+    if (fs_mgr_overlayfs_invalid(fstab)) return {};
 
-    if (fs_mgr_get_entry_for_mount_point(const_cast<struct fstab*>(fstab), kScratchMountPoint)) {
+    if (fs_mgr_get_entry_for_mount_point(fstab, kScratchMountPoint)) {
         return {};
     }
 
@@ -867,6 +878,7 @@
     auto ret = true;
     // If scratch exists, but is not mounted, lets gain access to clean
     // specific override entries.
+    auto mount_scratch = false;
     if ((mount_point != nullptr) && !fs_mgr_overlayfs_already_mounted(kScratchMountPoint, false)) {
         auto scratch_device = fs_mgr_overlayfs_scratch_device();
         if (scratch_device.empty()) {
@@ -876,7 +888,8 @@
             CreateLogicalPartition(super_device, slot_number, partition_name, true, 0s,
                                    &scratch_device);
         }
-        fs_mgr_overlayfs_mount_scratch(scratch_device, fs_mgr_overlayfs_scratch_mount_type());
+        mount_scratch = fs_mgr_overlayfs_mount_scratch(scratch_device,
+                                                       fs_mgr_overlayfs_scratch_mount_type());
     }
     for (const auto& overlay_mount_point : kOverlayMountPoints) {
         ret &= fs_mgr_overlayfs_teardown_one(overlay_mount_point, mount_point ?: "", change);
@@ -894,6 +907,8 @@
         PERROR << "teardown";
         ret = false;
     }
+    if (mount_scratch) fs_mgr_overlayfs_umount_scratch();
+
     return ret;
 }
 
diff --git a/init/first_stage_mount.cpp b/init/first_stage_mount.cpp
index 8644dae..d35329e 100644
--- a/init/first_stage_mount.cpp
+++ b/init/first_stage_mount.cpp
@@ -413,7 +413,14 @@
     // heads up for instantiating required device(s) for overlayfs logic
     const auto devices = fs_mgr_overlayfs_required_devices(device_tree_fstab_.get());
     for (auto const& device : devices) {
-        InitMappedDevice(device);
+        if (android::base::StartsWith(device, "/dev/block/by-name/")) {
+            required_devices_partition_names_.emplace(basename(device.c_str()));
+            auto uevent_callback = [this](const Uevent& uevent) { return UeventCallback(uevent); };
+            uevent_listener_.RegenerateUevents(uevent_callback);
+            uevent_listener_.Poll(uevent_callback, 10s);
+        } else {
+            InitMappedDevice(device);
+        }
     }
 
     fs_mgr_overlayfs_mount_all(device_tree_fstab_.get());
diff --git a/init/uevent_listener.cpp b/init/uevent_listener.cpp
index 8cf2128..d6765b7 100644
--- a/init/uevent_listener.cpp
+++ b/init/uevent_listener.cpp
@@ -87,8 +87,8 @@
 }
 
 UeventListener::UeventListener() {
-    // is 2MB enough? udev uses 128MB!
-    device_fd_.reset(uevent_open_socket(2 * 1024 * 1024, true));
+    // is 16MB enough? udev uses 128MB!
+    device_fd_.reset(uevent_open_socket(16 * 1024 * 1024, true));
     if (device_fd_ == -1) {
         LOG(FATAL) << "Could not open uevent socket";
     }
diff --git a/libcutils/uevent.cpp b/libcutils/uevent.cpp
index 2dfceed..721de7c 100644
--- a/libcutils/uevent.cpp
+++ b/libcutils/uevent.cpp
@@ -95,6 +95,8 @@
 int uevent_open_socket(int buf_sz, bool passcred) {
     struct sockaddr_nl addr;
     int on = passcred;
+    int buf_sz_readback = 0;
+    socklen_t optlen = sizeof(buf_sz_readback);
     int s;
 
     memset(&addr, 0, sizeof(addr));
@@ -105,11 +107,21 @@
     s = socket(PF_NETLINK, SOCK_DGRAM | SOCK_CLOEXEC, NETLINK_KOBJECT_UEVENT);
     if (s < 0) return -1;
 
-    /* buf_sz should be less than net.core.rmem_max for this to succeed */
-    if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, &buf_sz, sizeof(buf_sz)) < 0) {
+    if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, &buf_sz, sizeof(buf_sz)) < 0 ||
+          getsockopt(s, SOL_SOCKET, SO_RCVBUF, &buf_sz_readback, &optlen) < 0) {
         close(s);
         return -1;
     }
+    /* Only if SO_RCVBUF was not effective, try SO_RCVBUFFORCE. Generally, we
+     * want to avoid SO_RCVBUFFORCE, because it generates SELinux denials in
+     * case we don't have CAP_NET_ADMIN. This is the case, for example, for
+     * healthd. */
+    if (buf_sz_readback < 2 * buf_sz) {
+        if (setsockopt(s, SOL_SOCKET, SO_RCVBUFFORCE, &buf_sz, sizeof(buf_sz)) < 0) {
+            close(s);
+            return -1;
+        }
+    }
 
     setsockopt(s, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on));