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: JP Abgrall <jpa@google.com>
This commit is contained in:
JP Abgrall 2014-07-02 13:16:04 -07:00
parent 686bce6390
commit f22b745294
3 changed files with 100 additions and 66 deletions

View file

@ -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);
} else {
ERROR("could not open /cache/recovery/command\n");
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;
}
property_set(ANDROID_RB_PROPERTY, "reboot,recovery");
/* 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 {
/* back up errno for crypto decisions */
mount_errno = errno;
}
}
/* 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 */
mount_errno = errno;
}
}
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;
}

View file

@ -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);

View file

@ -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;
}