Merge changes from topic 'fstab_relocation'
am: ac13718d0a

Change-Id: Id94e7c5cc454f5b7d9c7b410d3358eaaa8768a97
diff --git a/fs_mgr/fs_mgr_fstab.cpp b/fs_mgr/fs_mgr_fstab.cpp
index 5b0243d..2e54d69 100644
--- a/fs_mgr/fs_mgr_fstab.cpp
+++ b/fs_mgr/fs_mgr_fstab.cpp
@@ -404,7 +404,7 @@
     return false;
 }
 
-struct fstab *fs_mgr_read_fstab_file(FILE *fstab_file)
+static struct fstab *fs_mgr_read_fstab_file(FILE *fstab_file)
 {
     int cnt, entries;
     ssize_t len;
@@ -540,6 +540,41 @@
     return NULL;
 }
 
+/* merges fstab entries from both a and b, then returns the merged result.
+ * note that the caller should only manage the return pointer without
+ * doing further memory management for the two inputs, i.e. only need to
+ * frees up memory of the return value without touching a and b. */
+static struct fstab *in_place_merge(struct fstab *a, struct fstab *b)
+{
+    if (!a) return b;
+    if (!b) return a;
+
+    int total_entries = a->num_entries + b->num_entries;
+    a->recs = static_cast<struct fstab_rec *>(realloc(
+        a->recs, total_entries * (sizeof(struct fstab_rec))));
+    if (!a->recs) {
+        LERROR << __FUNCTION__ << "(): failed to allocate fstab recs";
+        // If realloc() fails the original block is left untouched;
+        // it is not freed or moved. So we have to free both a and b here.
+        fs_mgr_free_fstab(a);
+        fs_mgr_free_fstab(b);
+        return nullptr;
+    }
+
+    for (int i = a->num_entries, j = 0; i < total_entries; i++, j++) {
+        // copy the pointer directly *without* malloc and memcpy
+        a->recs[i] = b->recs[j];
+    }
+
+    // Frees up b, but don't free b->recs[X] to make sure they are
+    // accessible through a->recs[X].
+    free(b->fstab_filename);
+    free(b);
+
+    a->num_entries = total_entries;
+    return a;
+}
+
 struct fstab *fs_mgr_read_fstab(const char *fstab_path)
 {
     FILE *fstab_file;
@@ -547,13 +582,17 @@
 
     fstab_file = fopen(fstab_path, "r");
     if (!fstab_file) {
-        LERROR << "Cannot open file " << fstab_path;
-        return NULL;
+        PERROR << __FUNCTION__<< "(): cannot open file: '" << fstab_path << "'";
+        return nullptr;
     }
+
     fstab = fs_mgr_read_fstab_file(fstab_file);
     if (fstab) {
         fstab->fstab_filename = strdup(fstab_path);
+    } else {
+        LERROR << __FUNCTION__ << "(): failed to load fstab from : '" << fstab_path << "'";
     }
+
     fclose(fstab_file);
     return fstab;
 }
@@ -565,75 +604,58 @@
 {
     std::string fstab_buf = read_fstab_from_dt();
     if (fstab_buf.empty()) {
-        return NULL;
+        LERROR << __FUNCTION__ << "(): failed to read fstab from dt";
+        return nullptr;
     }
 
     std::unique_ptr<FILE, decltype(&fclose)> fstab_file(
         fmemopen(static_cast<void*>(const_cast<char*>(fstab_buf.c_str())),
                  fstab_buf.length(), "r"), fclose);
     if (!fstab_file) {
-        return NULL;
+        PERROR << __FUNCTION__ << "(): failed to create a file stream for fstab dt";
+        return nullptr;
     }
 
     struct fstab *fstab = fs_mgr_read_fstab_file(fstab_file.get());
     if (!fstab) {
-        LERROR << "failed to load fstab from kernel:" << std::endl << fstab_buf;
+        LERROR << __FUNCTION__ << "(): failed to load fstab from kernel:"
+               << std::endl << fstab_buf;
     }
 
     return fstab;
 }
 
 /* combines fstab entries passed in from device tree with
- * the ones found in /fstab.<hardware>
+ * the ones found from fstab_path
+ */
+struct fstab *fs_mgr_read_fstab_with_dt(const char *fstab_path)
+{
+    struct fstab *fstab_dt = fs_mgr_read_fstab_dt();
+    struct fstab *fstab = fs_mgr_read_fstab(fstab_path);
+
+    return in_place_merge(fstab_dt, fstab);
+}
+
+/*
+ * tries to load default fstab.<hardware> file from /odm/etc, /vendor/etc
+ * or /. loads the first one found and also combines fstab entries passed
+ * in from device tree.
  */
 struct fstab *fs_mgr_read_fstab_default()
 {
-    struct fstab *fstab = fs_mgr_read_fstab_dt();
     std::string hw;
-    if (!fs_mgr_get_boot_config("hardware", &hw)) {
-        // if we fail to find this, return whatever was found in device tree
-        LWARNING << "failed to find device hardware name";
-        return fstab;
-    }
+    std::string default_fstab;
 
-    std::string default_fstab = FSTAB_PREFIX + hw;
-    struct fstab *f = fs_mgr_read_fstab(default_fstab.c_str());
-    if (!f) {
-        // return what we have
-        LWARNING << "failed to read fstab entries from '" << default_fstab << "'";
-        return fstab;
-    }
-
-    // return the fstab read from file if device tree doesn't
-    // have one, other wise merge the two
-    if (!fstab) {
-        fstab = f;
+    if (fs_mgr_get_boot_config("hardware", &hw)) {
+        for (const char *prefix : {"/odm/etc/fstab.","/vendor/etc/fstab.", "/fstab."}) {
+            default_fstab = prefix + hw;
+            if (access(default_fstab.c_str(), F_OK) == 0) break;
+        }
     } else {
-        int total_entries = fstab->num_entries + f->num_entries;
-        fstab->recs = static_cast<struct fstab_rec *>(realloc(
-                        fstab->recs, total_entries * (sizeof(struct fstab_rec))));
-        if (!fstab->recs) {
-            LERROR << "failed to allocate fstab recs";
-            fstab->num_entries = 0;
-            fs_mgr_free_fstab(fstab);
-            return NULL;
-        }
-
-        for (int i = fstab->num_entries, j = 0; i < total_entries; i++, j++) {
-            // copy everything and *not* strdup
-            fstab->recs[i] = f->recs[j];
-        }
-
-        // free up fstab entries read from file, but don't cleanup
-        // the strings within f->recs[X] to make sure they are accessible
-        // through fstab->recs[X].
-        free(f->fstab_filename);
-        free(f);
-
-        fstab->num_entries = total_entries;
+        LWARNING << __FUNCTION__ << "(): failed to find device hardware name";
     }
 
-    return fstab;
+    return fs_mgr_read_fstab_with_dt(default_fstab.c_str());
 }
 
 void fs_mgr_free_fstab(struct fstab *fstab)
diff --git a/fs_mgr/fs_mgr_priv.h b/fs_mgr/fs_mgr_priv.h
index 4e2ac8b..377d2ec 100644
--- a/fs_mgr/fs_mgr_priv.h
+++ b/fs_mgr/fs_mgr_priv.h
@@ -41,8 +41,6 @@
 #define PWARNING PLOG(WARNING) << FS_MGR_TAG
 #define PERROR   PLOG(ERROR) << FS_MGR_TAG
 
-const std::string FSTAB_PREFIX("/fstab.");
-
 __BEGIN_DECLS
 
 #define CRYPTO_TMPFS_OPTIONS "size=256m,mode=0771,uid=1000,gid=1000"
diff --git a/fs_mgr/include/fs_mgr.h b/fs_mgr/include/fs_mgr.h
index a5e5beb..e4aeb48 100644
--- a/fs_mgr/include/fs_mgr.h
+++ b/fs_mgr/include/fs_mgr.h
@@ -87,8 +87,8 @@
 
 struct fstab *fs_mgr_read_fstab_default();
 struct fstab *fs_mgr_read_fstab_dt();
-struct fstab *fs_mgr_read_fstab_file(FILE *fstab_file);
 struct fstab *fs_mgr_read_fstab(const char *fstab_path);
+struct fstab *fs_mgr_read_fstab_with_dt(const char *fstab_path);
 void fs_mgr_free_fstab(struct fstab *fstab);
 
 #define FS_MGR_MNTALL_DEV_FILE_ENCRYPTED 5
diff --git a/init/property_service.cpp b/init/property_service.cpp
index d88b72e..983e684 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -62,7 +62,6 @@
 using android::base::StringPrintf;
 
 #define PERSISTENT_PROPERTY_DIR  "/data/property"
-#define FSTAB_PREFIX "/fstab."
 #define RECOVERY_MOUNT_POINT "/recovery"
 
 static int persistent_properties_loaded = 0;
@@ -613,21 +612,14 @@
 }
 
 void load_recovery_id_prop() {
-    std::string ro_hardware = property_get("ro.hardware");
-    if (ro_hardware.empty()) {
-        LOG(ERROR) << "ro.hardware not set - unable to load recovery id";
-        return;
-    }
-    std::string fstab_filename = FSTAB_PREFIX + ro_hardware;
-
-    std::unique_ptr<fstab, void(*)(fstab*)> tab(fs_mgr_read_fstab(fstab_filename.c_str()),
-                                                fs_mgr_free_fstab);
-    if (!tab) {
-        PLOG(ERROR) << "unable to read fstab " << fstab_filename;
+    std::unique_ptr<fstab, decltype(&fs_mgr_free_fstab)> fstab(fs_mgr_read_fstab_default(),
+                                                               fs_mgr_free_fstab);
+    if (!fstab) {
+        PLOG(ERROR) << "unable to read default fstab";
         return;
     }
 
-    fstab_rec* rec = fs_mgr_get_entry_for_mount_point(tab.get(), RECOVERY_MOUNT_POINT);
+    fstab_rec* rec = fs_mgr_get_entry_for_mount_point(fstab.get(), RECOVERY_MOUNT_POINT);
     if (rec == NULL) {
         LOG(ERROR) << "/recovery not specified in fstab";
         return;