fs_mgr: support a unified fstab format.

Update fs_mgr to support more flags needed to unify the 3
fstabs currently in android into one.

Change-Id: Ie46cea61a5b19882c55098bdd70f39e78fb603be
diff --git a/fs_mgr/fs_mgr.c b/fs_mgr/fs_mgr.c
index e51c9cf..fd6f13d 100644
--- a/fs_mgr/fs_mgr.c
+++ b/fs_mgr/fs_mgr.c
@@ -72,6 +72,9 @@
     { "wait",        MF_WAIT },
     { "check",       MF_CHECK },
     { "encryptable=",MF_CRYPT },
+    { "nonremovable",MF_NONREMOVABLE },
+    { "voldmanaged=",MF_VOLDMANAGED},
+    { "length=",     MF_LENGTH },
     { "defaults",    0 },
     { 0,             0 },
 };
@@ -106,7 +109,8 @@
     return ret;
 }
 
-static int parse_flags(char *flags, struct flag_list *fl, char **key_loc,
+static int parse_flags(char *flags, struct flag_list *fl,
+                       char **key_loc, long long *part_length, char **label, int *partnum,
                        char *fs_options, int fs_options_len)
 {
     int f = 0;
@@ -119,6 +123,18 @@
     if (key_loc) {
         *key_loc = NULL;
     }
+    /* initialize part_length to 0, if we find an MF_LENGTH flag,
+     * then we'll set part_length to the proper value */
+    if (part_length) {
+        *part_length = 0;
+    }
+    if (partnum) {
+        *partnum = -1;
+    }
+    if (label) {
+        *label = NULL;
+    }
+
     /* initialize fs_options to the null string */
     if (fs_options && (fs_options_len > 0)) {
         fs_options[0] = '\0';
@@ -137,6 +153,36 @@
                      * location of the keys.  Get it and return it.
                      */
                     *key_loc = strdup(strchr(p, '=') + 1);
+                } else if ((fl[i].flag == MF_LENGTH) && part_length) {
+                    /* The length flag is followed by an = and the
+                     * size of the partition.  Get it and return it.
+                     */
+                    *part_length = strtoll(strchr(p, '=') + 1, NULL, 0);
+                } else if ((fl[i].flag == MF_VOLDMANAGED) && label && partnum) {
+                    /* The voldmanaged flag is followed by an = and the
+                     * label, a colon and the partition number or the
+                     * word "auto", e.g.
+                     *   voldmanaged=sdcard:3
+                     * Get and return them.
+                     */
+                    char *label_start;
+                    char *label_end;
+                    char *part_start;
+
+                    label_start = strchr(p, '=') + 1;
+                    label_end = strchr(p, ':');
+                    if (label_end) {
+                        *label = strndup(label_start,
+                                         (int) (label_end - label_start));
+                        part_start = strchr(p, ':') + 1;
+                        if (!strcmp(part_start, "auto")) {
+                            *partnum = -1;
+                        } else {
+                            *partnum = strtol(part_start, NULL, 0);
+                        }
+                    } else {
+                        ERROR("Warning: voldmanaged= flag malformed\n");
+                    }
                 }
                 break;
             }
@@ -227,7 +273,7 @@
     }
 }
 
-static struct fstab_rec *read_fstab(char *fstab_path)
+struct fstab *fs_mgr_read_fstab(const char *fstab_path)
 {
     FILE *fstab_file;
     int cnt, entries;
@@ -235,8 +281,12 @@
     char line[256];
     const char *delim = " \t";
     char *save_ptr, *p;
-    struct fstab_rec *fstab;
+    struct fstab *fstab;
+    struct fstab_rec *recs;
     char *key_loc;
+    long long part_length;
+    char *label;
+    int partnum;
 #define FS_OPTIONS_LEN 1024
     char tmp_fs_options[FS_OPTIONS_LEN];
 
@@ -269,7 +319,11 @@
         return 0;
     }
 
-    fstab = calloc(entries + 1, sizeof(struct fstab_rec));
+    /* Allocate and init the fstab structure */
+    fstab = calloc(1, sizeof(struct fstab));
+    fstab->num_entries = entries;
+    fstab->fstab_filename = strdup(fstab_path);
+    fstab->recs = calloc(fstab->num_entries, sizeof(struct fstab_rec));
 
     fseek(fstab_file, 0, SEEK_SET);
 
@@ -303,41 +357,48 @@
             ERROR("Error parsing mount source\n");
             return 0;
         }
-        fstab[cnt].blk_dev = strdup(p);
+        fstab->recs[cnt].blk_device = strdup(p);
 
         if (!(p = strtok_r(NULL, delim, &save_ptr))) {
-            ERROR("Error parsing mnt_point\n");
+            ERROR("Error parsing mount_point\n");
             return 0;
         }
-        fstab[cnt].mnt_point = strdup(p);
+        fstab->recs[cnt].mount_point = strdup(p);
 
         if (!(p = strtok_r(NULL, delim, &save_ptr))) {
             ERROR("Error parsing fs_type\n");
             return 0;
         }
-        fstab[cnt].type = strdup(p);
+        fstab->recs[cnt].fs_type = strdup(p);
 
         if (!(p = strtok_r(NULL, delim, &save_ptr))) {
             ERROR("Error parsing mount_flags\n");
             return 0;
         }
         tmp_fs_options[0] = '\0';
-        fstab[cnt].flags = parse_flags(p, mount_flags, 0, tmp_fs_options, FS_OPTIONS_LEN);
+        fstab->recs[cnt].flags = parse_flags(p, mount_flags,
+                                       NULL, NULL, NULL, NULL,
+                                       tmp_fs_options, FS_OPTIONS_LEN);
 
         /* fs_options are optional */
         if (tmp_fs_options[0]) {
-            fstab[cnt].fs_options = strdup(tmp_fs_options);
+            fstab->recs[cnt].fs_options = strdup(tmp_fs_options);
         } else {
-            fstab[cnt].fs_options = NULL;
+            fstab->recs[cnt].fs_options = NULL;
         }
 
         if (!(p = strtok_r(NULL, delim, &save_ptr))) {
             ERROR("Error parsing fs_mgr_options\n");
             return 0;
         }
-        fstab[cnt].fs_mgr_flags = parse_flags(p, fs_mgr_flags, &key_loc, 0, 0);
-        fstab[cnt].key_loc = key_loc;
-
+        fstab->recs[cnt].fs_mgr_flags = parse_flags(p, fs_mgr_flags,
+                                              &key_loc, &part_length,
+                                              &label, &partnum,
+                                              NULL, 0);
+        fstab->recs[cnt].key_loc = key_loc;
+        fstab->recs[cnt].length = part_length;
+        fstab->recs[cnt].label = label;
+        fstab->recs[cnt].partnum = partnum;
         cnt++;
     }
     fclose(fstab_file);
@@ -345,26 +406,32 @@
     return fstab;
 }
 
-static void free_fstab(struct fstab_rec *fstab)
+void fs_mgr_free_fstab(struct fstab *fstab)
 {
-    int i = 0;
+    int i;
 
-    while (fstab[i].blk_dev) {
+    for (i = 0; i < fstab->num_entries; i++) {
         /* Free the pointers return by strdup(3) */
-        free(fstab[i].blk_dev);
-        free(fstab[i].mnt_point);
-        free(fstab[i].type);
-        free(fstab[i].fs_options);
-        free(fstab[i].key_loc);
-
+        free(fstab->recs[i].blk_device);
+        free(fstab->recs[i].mount_point);
+        free(fstab->recs[i].fs_type);
+        free(fstab->recs[i].fs_options);
+        free(fstab->recs[i].key_loc);
+        free(fstab->recs[i].label);
         i++;
     }
 
-    /* Free the actual fstab array created by calloc(3) */
+    /* Free the fstab_recs array created by calloc(3) */
+    free(fstab->recs);
+
+    /* Free the fstab filename */
+    free(fstab->fstab_filename);
+
+    /* Free fstab */
     free(fstab);
 }
 
-static void check_fs(char *blk_dev, char *type, char *target)
+static void check_fs(char *blk_device, char *fs_type, char *target)
 {
     pid_t pid;
     int status;
@@ -373,7 +440,7 @@
     char *tmpmnt_opts = "nomblk_io_submit,errors=remount-ro";
 
     /* Check for the types of filesystems we know how to check */
-    if (!strcmp(type, "ext2") || !strcmp(type, "ext3") || !strcmp(type, "ext4")) {
+    if (!strcmp(fs_type, "ext2") || !strcmp(fs_type, "ext3") || !strcmp(fs_type, "ext4")) {
         /*
          * First try to mount and unmount the filesystem.  We do this because
          * the kernel is more efficient than e2fsck in running the journal and
@@ -387,19 +454,19 @@
          * filesytsem due to an error, e2fsck is still run to do a full check
          * fix the filesystem.
          */
-        ret = mount(blk_dev, target, type, tmpmnt_flags, tmpmnt_opts);
-        if (! ret) {
+        ret = mount(blk_device, target, fs_type, tmpmnt_flags, tmpmnt_opts);
+        if (!ret) {
             umount(target);
         }
 
-        INFO("Running %s on %s\n", E2FSCK_BIN, blk_dev);
+        INFO("Running %s on %s\n", E2FSCK_BIN, blk_device);
         pid = fork();
         if (pid > 0) {
             /* Parent, wait for the child to return */
             waitpid(pid, &status, 0);
         } else if (pid == 0) {
             /* child, run checker */
-            execlp(E2FSCK_BIN, E2FSCK_BIN, "-y", blk_dev, (char *)NULL);
+            execlp(E2FSCK_BIN, E2FSCK_BIN, "-y", blk_device, (char *)NULL);
 
             /* Only gets here on error */
             ERROR("Cannot run fs_mgr binary %s\n", E2FSCK_BIN);
@@ -443,49 +510,62 @@
     return ret;
 }
 
-int fs_mgr_mount_all(char *fstab_file)
+int fs_mgr_mount_all(struct fstab *fstab)
 {
     int i = 0;
     int encrypted = 0;
     int ret = -1;
     int mret;
-    struct fstab_rec *fstab = 0;
 
-    if (!(fstab = read_fstab(fstab_file))) {
+    if (!fstab) {
         return ret;
     }
 
-    for (i = 0; fstab[i].blk_dev; i++) {
-        if (fstab[i].fs_mgr_flags & MF_WAIT) {
-            wait_for_file(fstab[i].blk_dev, WAIT_TIMEOUT);
+    for (i = 0; i < fstab->num_entries; i++) {
+        /* Don't mount entries that are managed by vold */
+        if (fstab->recs[i].fs_mgr_flags & MF_VOLDMANAGED) {
+            continue;
         }
 
-        if (fstab[i].fs_mgr_flags & MF_CHECK) {
-            check_fs(fstab[i].blk_dev, fstab[i].type, fstab[i].mnt_point);
+        /* Skip raw partition entries such as boot, recovery, etc */
+        if (!strcmp(fstab->recs[i].fs_type, "emmc") ||
+            !strcmp(fstab->recs[i].fs_type, "mtd")) {
+            continue;
         }
 
-        mret = mount(fstab[i].blk_dev, fstab[i].mnt_point, fstab[i].type,
-                     fstab[i].flags, fstab[i].fs_options);
+        if (fstab->recs[i].fs_mgr_flags & MF_WAIT) {
+            wait_for_file(fstab->recs[i].blk_device, WAIT_TIMEOUT);
+        }
+
+        if (fstab->recs[i].fs_mgr_flags & MF_CHECK) {
+            check_fs(fstab->recs[i].blk_device, fstab->recs[i].fs_type,
+                     fstab->recs[i].mount_point);
+        }
+
+        mret = mount(fstab->recs[i].blk_device, fstab->recs[i].mount_point,
+                     fstab->recs[i].fs_type, fstab->recs[i].flags,
+                     fstab->recs[i].fs_options);
         if (!mret) {
             /* Success!  Go get the next one */
             continue;
         }
 
         /* mount(2) returned an error, check if it's encrypted and deal with it */
-        if ((fstab[i].fs_mgr_flags & MF_CRYPT) && !partition_wiped(fstab[i].blk_dev)) {
+        if ((fstab->recs[i].fs_mgr_flags & MF_CRYPT) &&
+            !partition_wiped(fstab->recs[i].blk_device)) {
             /* Need to mount a tmpfs at this mountpoint for now, and set
              * properties that vold will query later for decrypting
              */
-            if (mount("tmpfs", fstab[i].mnt_point, "tmpfs",
+            if (mount("tmpfs", fstab->recs[i].mount_point, "tmpfs",
                   MS_NOATIME | MS_NOSUID | MS_NODEV, CRYPTO_TMPFS_OPTIONS) < 0) {
                 ERROR("Cannot mount tmpfs filesystem for encrypted fs at %s\n",
-                        fstab[i].mnt_point);
+                        fstab->recs[i].mount_point);
                 goto out;
             }
             encrypted = 1;
         } else {
             ERROR("Cannot mount filesystem on %s at %s\n",
-                    fstab[i].blk_dev, fstab[i].mnt_point);
+                    fstab->recs[i].blk_device, fstab->recs[i].mount_point);
             goto out;
         }
     }
@@ -497,49 +577,57 @@
     }
 
 out:
-    free_fstab(fstab);
     return ret;
 }
 
-/* If tmp_mnt_point is non-null, mount the filesystem there.  This is for the
+/* If tmp_mount_point is non-null, mount the filesystem there.  This is for the
  * tmp mount we do to check the user password
  */
-int fs_mgr_do_mount(char *fstab_file, char *n_name, char *n_blk_dev, char *tmp_mnt_point)
+int fs_mgr_do_mount(struct fstab *fstab, char *n_name, char *n_blk_device,
+                    char *tmp_mount_point)
 {
     int i = 0;
     int ret = -1;
-    struct fstab_rec *fstab = 0;
     char *m;
 
-    if (!(fstab = read_fstab(fstab_file))) {
+    if (!fstab) {
         return ret;
     }
 
-    for (i = 0; fstab[i].blk_dev; i++) {
-        if (!fs_match(fstab[i].mnt_point, n_name)) {
+    for (i = 0; i < fstab->num_entries; i++) {
+        if (!fs_match(fstab->recs[i].mount_point, n_name)) {
             continue;
         }
 
         /* We found our match */
-        /* First check the filesystem if requested */
-        if (fstab[i].fs_mgr_flags & MF_WAIT) {
-            wait_for_file(n_blk_dev, WAIT_TIMEOUT);
+        /* If this is a raw partition, report an error */
+        if (!strcmp(fstab->recs[i].fs_type, "emmc") ||
+            !strcmp(fstab->recs[i].fs_type, "mtd")) {
+            ERROR("Cannot mount filesystem of type %s on %s\n",
+                  fstab->recs[i].fs_type, n_blk_device);
+            goto out;
         }
 
-        if (fstab[i].fs_mgr_flags & MF_CHECK) {
-            check_fs(n_blk_dev, fstab[i].type, fstab[i].mnt_point);
+        /* First check the filesystem if requested */
+        if (fstab->recs[i].fs_mgr_flags & MF_WAIT) {
+            wait_for_file(n_blk_device, WAIT_TIMEOUT);
+        }
+
+        if (fstab->recs[i].fs_mgr_flags & MF_CHECK) {
+            check_fs(n_blk_device, fstab->recs[i].fs_type,
+                     fstab->recs[i].mount_point);
         }
 
         /* Now mount it where requested */
-        if (tmp_mnt_point) {
-            m = tmp_mnt_point;
+        if (tmp_mount_point) {
+            m = tmp_mount_point;
         } else {
-            m = fstab[i].mnt_point;
+            m = fstab->recs[i].mount_point;
         }
-        if (mount(n_blk_dev, m, fstab[i].type,
-                  fstab[i].flags, fstab[i].fs_options)) {
+        if (mount(n_blk_device, m, fstab->recs[i].fs_type,
+                  fstab->recs[i].flags, fstab->recs[i].fs_options)) {
             ERROR("Cannot mount filesystem on %s at %s\n",
-                    n_blk_dev, m);
+                    n_blk_device, m);
             goto out;
         } else {
             ret = 0;
@@ -548,10 +636,9 @@
     }
 
     /* We didn't find a match, say so and return an error */
-    ERROR("Cannot find mount point %s in fstab\n", fstab[i].mnt_point);
+    ERROR("Cannot find mount point %s in fstab\n", fstab->recs[i].mount_point);
 
 out:
-    free_fstab(fstab);
     return ret;
 }
 
@@ -574,65 +661,128 @@
     return 0;
 }
 
-int fs_mgr_unmount_all(char *fstab_file)
+int fs_mgr_unmount_all(struct fstab *fstab)
 {
     int i = 0;
     int ret = 0;
-    struct fstab_rec *fstab = 0;
 
-    if (!(fstab = read_fstab(fstab_file))) {
+    if (!fstab) {
         return -1;
     }
 
-    while (fstab[i].blk_dev) {
-        if (umount(fstab[i].mnt_point)) {
-            ERROR("Cannot unmount filesystem at %s\n", fstab[i].mnt_point);
+    while (fstab->recs[i].blk_device) {
+        if (umount(fstab->recs[i].mount_point)) {
+            ERROR("Cannot unmount filesystem at %s\n", fstab->recs[i].mount_point);
             ret = -1;
         }
         i++;
     }
 
-    free_fstab(fstab);
     return ret;
 }
 /*
  * key_loc must be at least PROPERTY_VALUE_MAX bytes long
  *
- * real_blk_dev must be at least PROPERTY_VALUE_MAX bytes long
+ * real_blk_device must be at least PROPERTY_VALUE_MAX bytes long
  */
-int fs_mgr_get_crypt_info(char *fstab_file, char *key_loc, char *real_blk_dev, int size)
+int fs_mgr_get_crypt_info(struct fstab *fstab, char *key_loc, char *real_blk_device, int size)
 {
     int i = 0;
-    struct fstab_rec *fstab = 0;
 
-    if (!(fstab = read_fstab(fstab_file))) {
+    if (!fstab) {
         return -1;
     }
     /* Initialize return values to null strings */
     if (key_loc) {
         *key_loc = '\0';
     }
-    if (real_blk_dev) {
-        *real_blk_dev = '\0';
+    if (real_blk_device) {
+        *real_blk_device = '\0';
     }
 
     /* Look for the encryptable partition to find the data */
-    for (i = 0; fstab[i].blk_dev; i++) {
-        if (!(fstab[i].fs_mgr_flags & MF_CRYPT)) {
+    for (i = 0; i < fstab->num_entries; i++) {
+        /* Don't deal with vold managed enryptable partitions here */
+        if (fstab->recs[i].fs_mgr_flags & MF_VOLDMANAGED) {
+            continue;
+        }
+        if (!(fstab->recs[i].fs_mgr_flags & MF_CRYPT)) {
             continue;
         }
 
         /* We found a match */
         if (key_loc) {
-            strlcpy(key_loc, fstab[i].key_loc, size);
+            strlcpy(key_loc, fstab->recs[i].key_loc, size);
         }
-        if (real_blk_dev) {
-            strlcpy(real_blk_dev, fstab[i].blk_dev, size);
+        if (real_blk_device) {
+            strlcpy(real_blk_device, fstab->recs[i].blk_device, size);
         }
         break;
     }
 
-    free_fstab(fstab);
     return 0;
 }
 
+/* Add an entry to the fstab, and return 0 on success or -1 on error */
+int fs_mgr_add_entry(struct fstab *fstab,
+                     const char *mount_point, const char *fs_type,
+                     const char *blk_device, long long length)
+{
+    struct fstab_rec *new_fstab_recs;
+    int n = fstab->num_entries;
+
+    new_fstab_recs = (struct fstab_rec *)
+                     realloc(fstab->recs, sizeof(struct fstab_rec) * (n + 1));
+
+    if (!new_fstab_recs) {
+        return -1;
+    }
+
+    /* A new entry was added, so initialize it */
+     memset(&new_fstab_recs[n], 0, sizeof(struct fstab_rec));
+     new_fstab_recs[n].mount_point = strdup(mount_point);
+     new_fstab_recs[n].fs_type = strdup(fs_type);
+     new_fstab_recs[n].blk_device = strdup(blk_device);
+     new_fstab_recs[n].length = 0;
+
+     /* Update the fstab struct */
+     fstab->recs = new_fstab_recs;
+     fstab->num_entries++;
+
+     return 0;
+}
+
+struct fstab_rec *fs_mgr_get_entry_for_mount_point(struct fstab *fstab, const char *path)
+{
+    int i;
+
+    if (!fstab) {
+        return NULL;
+    }
+
+    for (i = 0; i < fstab->num_entries; i++) {
+        int len = strlen(fstab->recs[i].mount_point);
+        if (strncmp(path, fstab->recs[i].mount_point, len) == 0 &&
+            (path[len] == '\0' || path[len] == '/')) {
+            return &fstab->recs[i];
+        }
+    }
+
+    return NULL;
+}
+
+int fs_mgr_is_voldmanaged(struct fstab_rec *fstab)
+{
+    return fstab->fs_mgr_flags & MF_VOLDMANAGED;
+}
+
+int fs_mgr_is_nonremovable(struct fstab_rec *fstab)
+{
+    return fstab->fs_mgr_flags & MF_NONREMOVABLE;
+}
+
+int fs_mgr_is_encryptable(struct fstab_rec *fstab)
+{
+    return fstab->fs_mgr_flags & MF_CRYPT;
+}
+
diff --git a/fs_mgr/fs_mgr_main.c b/fs_mgr/fs_mgr_main.c
index 81febf1..4bde4a1 100644
--- a/fs_mgr/fs_mgr_main.c
+++ b/fs_mgr/fs_mgr_main.c
@@ -82,7 +82,8 @@
     int n_flag=0;
     char *n_name;
     char *n_blk_dev;
-    char *fstab;
+    char *fstab_file;
+    struct fstab *fstab;
 
     klog_init();
     klog_set_level(6);
@@ -90,7 +91,9 @@
     parse_options(argc, argv, &a_flag, &u_flag, &n_flag, &n_name, &n_blk_dev);
 
     /* The name of the fstab file is last, after the option */
-    fstab = argv[argc - 1];
+    fstab_file = argv[argc - 1];
+
+    fstab = fs_mgr_read_fstab(fstab_file);
 
     if (a_flag) {
         return fs_mgr_mount_all(fstab);
@@ -103,6 +106,8 @@
         exit(1);
     }
 
+    fs_mgr_free_fstab(fstab);
+
     /* Should not get here */
     exit(1);
 }
diff --git a/fs_mgr/fs_mgr_priv.h b/fs_mgr/fs_mgr_priv.h
index 175fdab..374931b 100644
--- a/fs_mgr/fs_mgr_priv.h
+++ b/fs_mgr/fs_mgr_priv.h
@@ -25,16 +25,6 @@
 
 #define CRYPTO_TMPFS_OPTIONS "size=128m,mode=0771,uid=1000,gid=1000"
 
-struct fstab_rec {
-    char *blk_dev;
-    char *mnt_point;
-    char *type;
-    unsigned long flags;
-    char *fs_options;
-    int fs_mgr_flags;
-    char *key_loc;
-};
-
 #define WAIT_TIMEOUT 5
 
 /* fstab has the following format:
@@ -59,8 +49,8 @@
  *                     run an fscheck program on the <source> before mounting the filesystem.
  *                     If check is specifed on a read-only filesystem, it is ignored.
  *                     Also, "encryptable" means that filesystem can be encrypted.
- *                     The "encryptable" flag _MUST_ be followed by a : and a string which
- *                     is the location of the encryption keys.  I can either be a path
+ *                     The "encryptable" flag _MUST_ be followed by a = and a string which
+ *                     is the location of the encryption keys.  It can either be a path
  *                     to a file or partition which contains the keys, or the word "footer"
  *                     which means the keys are in the last 16 Kbytes of the partition
  *                     containing the filesystem.
@@ -72,9 +62,12 @@
  *
  */
 
-#define MF_WAIT      0x1
-#define MF_CHECK     0x2
-#define MF_CRYPT     0x4
+#define MF_WAIT         0x1
+#define MF_CHECK        0x2
+#define MF_CRYPT        0x4
+#define MF_NONREMOVABLE 0x8
+#define MF_VOLDMANAGED  0x10
+#define MF_LENGTH       0x20
 
 #endif /* __CORE_FS_MGR_PRIV_H */
 
diff --git a/fs_mgr/include/fs_mgr.h b/fs_mgr/include/fs_mgr.h
index 76abb83..05bcc1b 100644
--- a/fs_mgr/include/fs_mgr.h
+++ b/fs_mgr/include/fs_mgr.h
@@ -17,11 +17,48 @@
 #ifndef __CORE_FS_MGR_H
 #define __CORE_FS_MGR_H
 
-int fs_mgr_mount_all(char *fstab_file);
-int fs_mgr_do_mount(char *fstab_file, char *n_name, char *n_blk_dev, char *tmp_mnt_point);
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct fstab {
+    int num_entries;
+    struct fstab_rec *recs;
+    char *fstab_filename;
+};
+
+struct fstab_rec {
+    char *blk_device;
+    char *mount_point;
+    char *fs_type;
+    unsigned long flags;
+    char *fs_options;
+    int fs_mgr_flags;
+    char *key_loc;
+    long long length;
+    char *label;
+    int partnum;
+};
+
+struct fstab *fs_mgr_read_fstab(const char *fstab_path);
+void fs_mgr_free_fstab(struct fstab *fstab);
+int fs_mgr_mount_all(struct fstab *fstab);
+int fs_mgr_do_mount(struct fstab *fstab, char *n_name, char *n_blk_device,
+                    char *tmp_mount_point);
 int fs_mgr_do_tmpfs_mount(char *n_name);
-int fs_mgr_unmount_all(char *fstab_file);
-int fs_mgr_get_crypt_info(char *fstab_file, char *key_loc, char *real_blk_dev, int size);
+int fs_mgr_unmount_all(struct fstab *fstab);
+int fs_mgr_get_crypt_info(struct fstab *fstab, char *key_loc,
+                          char *real_blk_device, int size);
+int fs_mgr_add_entry(struct fstab *fstab,
+                     const char *mount_point, const char *fs_type,
+                     const char *blk_device, long long length);
+struct fstab_rec *fs_mgr_get_entry_for_mount_point(struct fstab *fstab, const char *path);
+int fs_mgr_is_voldmanaged(struct fstab_rec *fstab);
+int fs_mgr_is_nonremovable(struct fstab_rec *fstab);
+int fs_mgr_is_encryptable(struct fstab_rec *fstab);
+#ifdef __cplusplus
+}
+#endif
 
 #endif /* __CORE_FS_MGR_H */
 
diff --git a/init/builtins.c b/init/builtins.c
index dc7900e..0f9f131 100644
--- a/init/builtins.c
+++ b/init/builtins.c
@@ -464,6 +464,7 @@
     int child_ret = -1;
     int status;
     const char *prop;
+    struct fstab *fstab;
 
     if (nargs != 2) {
         return -1;
@@ -487,7 +488,9 @@
     } else if (pid == 0) {
         /* child, call fs_mgr_mount_all() */
         klog_set_level(6);  /* So we can see what fs_mgr_mount_all() does */
-        child_ret = fs_mgr_mount_all(args[1]);
+        fstab = fs_mgr_read_fstab(args[1]);
+        child_ret = fs_mgr_mount_all(fstab);
+        fs_mgr_free_fstab(fstab);
         if (child_ret == -1) {
             ERROR("fs_mgr_mount_all returned an error\n");
         }