init: add umount_all builtin.

umount_all is the cleanup step for mount_all.

In particular, the mount_all builtin creates a verity device,
'postinstall-verity', for the following line:

system /postinstall ... ... slotselect_other,logical,avb_keys=...

cppreopt umounts /postinstall but doesn't destroy the postinstall-verity
device, causing OTA to fail (because it cannot destroy the
system_[other] device). umount_all also destroy the verity device.

Note that mount_all does not map system_[other]; it is mapped by
first stage init. Hence, umount_all doesn't destroy it either. The OTA
client is reponsible for unmapping the device itself.

Bug: 129988285
Test: flash, boot, then check `dmctl list devices`, then OTA

Change-Id: Id3ab65b3860b6ea6cfec310ab13652009c81f415
diff --git a/init/builtins.cpp b/init/builtins.cpp
index 8437e37..fc75072 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -451,13 +451,13 @@
     if (false) DumpState();
 }
 
-/* mount_fstab
+/* handle_fstab
  *
- *  Call fs_mgr_mount_all() to mount the given fstab
+ *  Read the given fstab file and execute func on it.
  */
-static Result<int> mount_fstab(const char* fstabfile, int mount_mode) {
+static Result<int> handle_fstab(const std::string& fstabfile, std::function<int(Fstab*)> func) {
     /*
-     * Call fs_mgr_mount_all() to mount all filesystems.  We fork(2) and
+     * Call fs_mgr_[u]mount_all() to [u]mount all filesystems.  We fork(2) and
      * do the call in the child to provide protection to the main init
      * process if anything goes wrong (crash or memory leak), and wait for
      * the child to finish in the parent.
@@ -478,25 +478,51 @@
             return Error() << "child aborted";
         }
     } else if (pid == 0) {
-        /* child, call fs_mgr_mount_all() */
+        /* child, call fs_mgr_[u]mount_all() */
 
-        // So we can always see what fs_mgr_mount_all() does.
+        // So we can always see what fs_mgr_[u]mount_all() does.
         // Only needed if someone explicitly changes the default log level in their init.rc.
         android::base::ScopedLogSeverity info(android::base::INFO);
 
         Fstab fstab;
         ReadFstabFromFile(fstabfile, &fstab);
 
-        int child_ret = fs_mgr_mount_all(&fstab, mount_mode);
-        if (child_ret == -1) {
-            PLOG(ERROR) << "fs_mgr_mount_all returned an error";
-        }
+        int child_ret = func(&fstab);
+
         _exit(child_ret);
     } else {
         return Error() << "fork() failed";
     }
 }
 
+/* mount_fstab
+ *
+ *  Call fs_mgr_mount_all() to mount the given fstab
+ */
+static Result<int> mount_fstab(const std::string& fstabfile, int mount_mode) {
+    return handle_fstab(fstabfile, [mount_mode](Fstab* fstab) {
+        int ret = fs_mgr_mount_all(fstab, mount_mode);
+        if (ret == -1) {
+            PLOG(ERROR) << "fs_mgr_mount_all returned an error";
+        }
+        return ret;
+    });
+}
+
+/* umount_fstab
+ *
+ *  Call fs_mgr_umount_all() to umount the given fstab
+ */
+static Result<int> umount_fstab(const std::string& fstabfile) {
+    return handle_fstab(fstabfile, [](Fstab* fstab) {
+        int ret = fs_mgr_umount_all(fstab);
+        if (ret != 0) {
+            PLOG(ERROR) << "fs_mgr_umount_all returned " << ret;
+        }
+        return ret;
+    });
+}
+
 /* Queue event based on fs_mgr return code.
  *
  * code: return code of fs_mgr_mount_all
@@ -583,7 +609,7 @@
     bool import_rc = true;
     bool queue_event = true;
     int mount_mode = MOUNT_MODE_DEFAULT;
-    const char* fstabfile = args[1].c_str();
+    const auto& fstabfile = args[1];
     std::size_t path_arg_end = args.size();
     const char* prop_post_fix = "default";
 
@@ -626,6 +652,15 @@
     return Success();
 }
 
+/* umount_all <fstab> */
+static Result<Success> do_umount_all(const BuiltinArguments& args) {
+    auto umount_fstab_return_code = umount_fstab(args[1]);
+    if (!umount_fstab_return_code) {
+        return Error() << "umount_fstab() failed " << umount_fstab_return_code.error();
+    }
+    return Success();
+}
+
 static Result<Success> do_swapon_all(const BuiltinArguments& args) {
     Fstab fstab;
     if (!ReadFstabFromFile(args[1], &fstab)) {
@@ -1165,6 +1200,7 @@
         {"mount",                   {3,     kMax, {false,  do_mount}}},
         {"parse_apex_configs",      {0,     0,    {false,  do_parse_apex_configs}}},
         {"umount",                  {1,     1,    {false,  do_umount}}},
+        {"umount_all",              {1,     1,    {false,  do_umount_all}}},
         {"readahead",               {1,     2,    {true,   do_readahead}}},
         {"restart",                 {1,     1,    {false,  do_restart}}},
         {"restorecon",              {1,     kMax, {true,   do_restorecon}}},