Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f22b7452 authored by JP Abgrall's avatar JP Abgrall
Browse files

fs_mrg: clean up multi-type mount_all



Move the code that attempts to mount alternative fstab entries
into its own function.
Clarify return codes.
Suggest wipe via recovery in error messages.

Bug: 15747366
Change-Id: I3634477cd4d1d73f974f3e906c53285f0d9e0eac
Signed-off-by: default avatarJP Abgrall <jpa@google.com>
parent 686bce63
Loading
Loading
Loading
Loading
+91 −60
Original line number Diff line number Diff line
@@ -245,31 +245,89 @@ static int device_is_debuggable() {
    return strcmp(value, "1") ? 0 : 1;
}

void wipe_data_via_recovery()
/*
 * Tries to mount any of the consecutive fstab entries that match
 * the mountpoint of the one given by fstab->recs[start_idx].
 *
 * end_idx: On return, will be the last rec that was looked at.
 * attempted_idx: On return, will indicate which fstab rec
 *     succeeded. In case of failure, it will be the start_idx.
 * Returns
 *   -1 on failure with errno set to match the 1st mount failure.
 *   0 on success.
 */
static int mount_with_alternatives(struct fstab *fstab, int start_idx, int *end_idx, int *attempted_idx)
{
    mkdir("/cache/recovery", 0700);
    int fd = open("/cache/recovery/command", O_RDWR|O_CREAT|O_TRUNC, 0600);
    if (fd >= 0) {
        write(fd, "--wipe_data", strlen("--wipe_data") + 1);
        close(fd);
    int i;
    int mount_errno = 0;
    int mounted = 0;

    if (!end_idx || !attempted_idx || start_idx >= fstab->num_entries) {
      errno = EINVAL;
      if (end_idx) *end_idx = start_idx;
      if (attempted_idx) *end_idx = start_idx;
      return -1;
    }

    /* Hunt down an fstab entry for the same mount point that might succeed */
    for (i = start_idx;
         /* We required that fstab entries for the same mountpoint be consecutive */
         i < fstab->num_entries && !strcmp(fstab->recs[start_idx].mount_point, fstab->recs[i].mount_point);
         i++) {
            /*
             * Don't try to mount/encrypt the same mount point again.
             * Deal with alternate entries for the same point which are required to be all following
             * each other.
             */
            if (mounted) {
                ERROR("%s(): skipping fstab dup mountpoint=%s rec[%d].fs_type=%s already mounted as %s.\n", __func__,
                     fstab->recs[i].mount_point, i, fstab->recs[i].fs_type, fstab->recs[*attempted_idx].fs_type);
                continue;
            }

            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);
            }
            if (!__mount(fstab->recs[i].blk_device, fstab->recs[i].mount_point, &fstab->recs[i])) {
                *attempted_idx = i;
                mounted = 1;
                if (i != start_idx) {
                    ERROR("%s(): Mounted %s on %s with fs_type=%s instead of %s\n", __func__,
                         fstab->recs[i].blk_device, fstab->recs[i].mount_point, fstab->recs[i].fs_type,
                         fstab->recs[start_idx].fs_type);
                }
            } else {
        ERROR("could not open /cache/recovery/command\n");
                /* back up errno for crypto decisions */
                mount_errno = errno;
            }
    }
    property_set(ANDROID_RB_PROPERTY, "reboot,recovery");

    /* Adjust i for the case where it was still withing the recs[] */
    if (i < fstab->num_entries) --i;

    *end_idx = i;
    if (!mounted) {
        *attempted_idx = start_idx;
        errno = mount_errno;
        return -1;
    }
    return 0;
}

/* When multiple fstab records share the same mount_point, it will
 * try to mount each one in turn, and ignore any duplicates after a
 * first successful mount.
 * Returns -1 on error, and  FS_MGR_MNTALL_* otherwise.
 */
int fs_mgr_mount_all(struct fstab *fstab)
{
    int i = 0, j = 0;
    int encryptable = 0;
    int i = 0;
    int encryptable = FS_MGR_MNTALL_DEV_NOT_ENCRYPTED;
    int error_count = 0;
    int mret = -1;
    int mount_errno = 0;
    const char *last_ok_mount_point = NULL;
    int attempted_idx = -1;

    if (!fstab) {
        return -1;
@@ -299,55 +357,27 @@ int fs_mgr_mount_all(struct fstab *fstab)
                continue;
            }
        }

        /*
         * Don't try to mount/encrypt the same mount point again.
         * Deal with alternate entries for the same point which are required to be all following
         * each other.
         */
        if (last_ok_mount_point && !strcmp(last_ok_mount_point, fstab->recs[i].mount_point)) {
            INFO("%s(): skipping fstab dup mountpoint=%s rec[%d].fs_type=%s already mounted.\n", __func__,
                 last_ok_mount_point, i, fstab->recs[i].fs_type);
            continue;
        }
        /* Hunt down an fstab entry for the same mount point that might succeed */
        for (j = i;
             /* We required that fstab entries for the same mountpoint be consecutive */
             j < fstab->num_entries && !strcmp(fstab->recs[i].mount_point, fstab->recs[j].mount_point);
             j++) {
                if (fstab->recs[i].fs_mgr_flags & MF_CHECK) {
                    check_fs(fstab->recs[j].blk_device, fstab->recs[j].fs_type,
                             fstab->recs[j].mount_point);
                }
                mret = __mount(fstab->recs[j].blk_device, fstab->recs[j].mount_point, &fstab->recs[j]);
                if (!mret) {
                    last_ok_mount_point = fstab->recs[j].mount_point;
                    if (i != j) {
                        INFO("%s(): some alternate mount worked for mount_point=%s fs_type=%s instead of fs_type=%s\n", __func__,
                             last_ok_mount_point, fstab->recs[j].fs_type, fstab->recs[i].fs_type);
                        i = j;   /* We advance the recs index to the working entry */
                    }
                    break;
                } else {
                    /* back up errno for crypto decisions */
        int last_idx_inspected;
        mret = mount_with_alternatives(fstab, i, &last_idx_inspected, &attempted_idx);
        i = last_idx_inspected;
        mount_errno = errno;
                }
        }

        /* Deal with encryptability. */
        if (!mret) {
            /* If this is encryptable, need to trigger encryption */
            if ((fstab->recs[i].fs_mgr_flags & MF_FORCECRYPT)) {
                if (umount(fstab->recs[i].mount_point) == 0) {
                    if (!encryptable) {
                        encryptable = 2;
            if ((fstab->recs[attempted_idx].fs_mgr_flags & MF_FORCECRYPT)) {
                if (umount(fstab->recs[attempted_idx].mount_point) == 0) {
                    if (encryptable == FS_MGR_MNTALL_DEV_NOT_ENCRYPTED) {
                        ERROR("Will try to encrypt %s %s\n", fstab->recs[attempted_idx].mount_point,
                              fstab->recs[attempted_idx].fs_type);
                        encryptable = FS_MGR_MNTALL_DEV_NEEDS_ENCRYPTION;
                    } else {
                        ERROR("Only one encryptable/encrypted partition supported\n");
                        encryptable = 1;
                        encryptable = FS_MGR_MNTALL_DEV_MIGHT_BE_ENCRYPTED;
                    }
                } else {
                    INFO("Could not umount %s - allow continue unencrypted\n",
                         fstab->recs[i].mount_point);
                         fstab->recs[attempted_idx].mount_point);
                    continue;
                }
            }
@@ -358,27 +388,28 @@ int fs_mgr_mount_all(struct fstab *fstab)
        /* mount(2) returned an error, check if it's encryptable and deal with it */
        if (mret && mount_errno != EBUSY && mount_errno != EACCES &&
            fs_mgr_is_encryptable(&fstab->recs[i])) {
            if(partition_wiped(fstab->recs[i].blk_device) && fstab->recs[i].fs_mgr_flags & MF_FORCECRYPT) {
                ERROR("Found an encryptable wiped partition with force encrypt. Formating via recovery.\n");
                wipe_data_via_recovery();  /* This is queue up a reboot */
            if (partition_wiped(fstab->recs[i].blk_device)) {
                ERROR("%s(): Encryptable wiped partition %s. Recommend wiping via recovery. Fail for now.\n", __func__, fstab->recs[i].mount_point);
                ++error_count;
                continue;
            } else {
                /* Need to mount a tmpfs at this mountpoint for now, and set
                 * properties that vold will query later for decrypting
                 */
                if (fs_mgr_do_tmpfs_mount(fstab->recs[i].mount_point) < 0) {
                ERROR("%s(): possibly an encryptable blkdev %s for mount %s type %s )\n", __func__,
                      fstab->recs[attempted_idx].blk_device, fstab->recs[attempted_idx].mount_point,
                      fstab->recs[attempted_idx].fs_type);
                if (fs_mgr_do_tmpfs_mount(fstab->recs[attempted_idx].mount_point) < 0) {
                    ++error_count;
                    continue;
                }
                last_ok_mount_point = fstab->recs[i].mount_point;
            }
            encryptable = 1;
            encryptable = FS_MGR_MNTALL_DEV_MIGHT_BE_ENCRYPTED;
        } else {
            ERROR("Failed to mount an un-encryptable or wiped partition on"
                   "%s at %s options: %s error: %s\n",
                   fstab->recs[i].blk_device, fstab->recs[i].mount_point,
                   fstab->recs[i].fs_options, strerror(mount_errno));
                   fstab->recs[attempted_idx].blk_device, fstab->recs[attempted_idx].mount_point,
                   fstab->recs[attempted_idx].fs_options, strerror(mount_errno));
            ++error_count;
            continue;
        }
+4 −0
Original line number Diff line number Diff line
@@ -53,6 +53,10 @@ struct fstab_rec {

struct fstab *fs_mgr_read_fstab(const char *fstab_path);
void fs_mgr_free_fstab(struct fstab *fstab);

#define FS_MGR_MNTALL_DEV_NEEDS_ENCRYPTION 2
#define FS_MGR_MNTALL_DEV_MIGHT_BE_ENCRYPTED 1
#define FS_MGR_MNTALL_DEV_NOT_ENCRYPTED 0
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);
+5 −6
Original line number Diff line number Diff line
@@ -511,27 +511,26 @@ int do_mount_all(int nargs, char **args)
        if (child_ret == -1) {
            ERROR("fs_mgr_mount_all returned an error\n");
        }
        exit(child_ret);
        _exit(child_ret);
    } else {
        /* fork failed, return an error */
        return -1;
    }

    /* ret is 2 if device needs encrypted, 1 if the device appears encrypted,
     * 0 if not, and -1 on error */
    if (ret == 2) {
    if (ret == FS_MGR_MNTALL_DEV_NEEDS_ENCRYPTION) {
        property_set("ro.crypto.state", "unencrypted");
        property_set("vold.decrypt", "trigger_encryption");
    } else if (ret == 1) {
    } else if (ret == FS_MGR_MNTALL_DEV_MIGHT_BE_ENCRYPTED) {
        property_set("ro.crypto.state", "encrypted");
        property_set("vold.decrypt", "trigger_default_encryption");
    } else if (ret == 0) {
    } else if (ret == FS_MGR_MNTALL_DEV_NOT_ENCRYPTED) {
        property_set("ro.crypto.state", "unencrypted");
        /* If fs_mgr determined this is an unencrypted device, then trigger
         * that action.
         */
        action_for_each_trigger("nonencrypted", action_add_queue_tail);
    }
    /* else ... < 0: error */

    return ret;
}