summaryrefslogtreecommitdiffstats
path: root/fs_mgr/fs_mgr.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs_mgr/fs_mgr.c')
-rw-r--r--fs_mgr/fs_mgr.c262
1 files changed, 203 insertions, 59 deletions
diff --git a/fs_mgr/fs_mgr.c b/fs_mgr/fs_mgr.c
index dcda005..91e6c33 100644
--- a/fs_mgr/fs_mgr.c
+++ b/fs_mgr/fs_mgr.c
@@ -31,6 +31,7 @@
#include <linux/loop.h>
#include <private/android_filesystem_config.h>
+#include <cutils/android_reboot.h>
#include <cutils/partition_utils.h>
#include <cutils/properties.h>
#include <logwrap/logwrap.h>
@@ -46,6 +47,7 @@
#define KEY_IN_FOOTER "footer"
#define E2FSCK_BIN "/system/bin/e2fsck"
+#define F2FS_FSCK_BIN "/system/bin/fsck.f2fs"
#define MKSWAP_BIN "/system/bin/mkswap"
#define FSCK_LOG_FILE "/dev/fscklogs/log"
@@ -112,6 +114,7 @@ static void check_fs(char *blk_device, char *fs_type, char *target)
* fix the filesystem.
*/
ret = mount(blk_device, target, fs_type, tmpmnt_flags, tmpmnt_opts);
+ INFO("%s(): mount(%s,%s,%s)=%d\n", __func__, blk_device, target, fs_type, ret);
if (!ret) {
umount(target);
}
@@ -135,6 +138,20 @@ static void check_fs(char *blk_device, char *fs_type, char *target)
ERROR("Failed trying to run %s\n", E2FSCK_BIN);
}
}
+ } else if (!strcmp(fs_type, "f2fs")) {
+ char *f2fs_fsck_argv[] = {
+ F2FS_FSCK_BIN,
+ blk_device
+ };
+ INFO("Running %s on %s\n", F2FS_FSCK_BIN, blk_device);
+
+ ret = android_fork_execvp_ext(ARRAY_SIZE(f2fs_fsck_argv), f2fs_fsck_argv,
+ &status, true, LOG_KLOG | LOG_FILE,
+ true, FSCK_LOG_FILE);
+ if (ret < 0) {
+ /* No need to check for error in fork, we can't really handle it now */
+ ERROR("Failed trying to run %s\n", F2FS_FSCK_BIN);
+ }
}
return;
@@ -175,16 +192,27 @@ static void fs_set_blk_ro(const char *blockdev)
* sets the underlying block device to read-only if the mount is read-only.
* See "man 2 mount" for return values.
*/
-static int __mount(const char *source, const char *target,
- const char *filesystemtype, unsigned long mountflags,
- const void *data)
+static int __mount(const char *source, const char *target, const struct fstab_rec *rec)
{
- int ret = mount(source, target, filesystemtype, mountflags, data);
+ unsigned long mountflags = rec->flags;
+ int ret;
+ int save_errno;
+ /* We need this because sometimes we have legacy symlinks
+ * that are lingering around and need cleaning up.
+ */
+ struct stat info;
+ if (!lstat(target, &info))
+ if ((info.st_mode & S_IFMT) == S_IFLNK)
+ unlink(target);
+ mkdir(target, 0755);
+ ret = mount(source, target, rec->fs_type, mountflags, rec->fs_options);
+ save_errno = errno;
+ INFO("%s(source=%s,target=%s,type=%s)=%d\n", __func__, source, target, rec->fs_type, ret);
if ((ret == 0) && (mountflags & MS_RDONLY) != 0) {
fs_set_blk_ro(source);
}
-
+ errno = save_errno;
return ret;
}
@@ -208,16 +236,101 @@ static int fs_match(char *in1, char *in2)
return ret;
}
+static int device_is_debuggable() {
+ int ret = -1;
+ char value[PROP_VALUE_MAX];
+ ret = __system_property_get("ro.debuggable", value);
+ if (ret < 0)
+ return ret;
+ return strcmp(value, "1") ? 0 : 1;
+}
+
+/*
+ * 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)
+{
+ 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 {
+ /* 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;
- int encrypted = 0;
- int ret = -1;
- int mret;
- int mount_errno;
+ int encryptable = FS_MGR_MNTALL_DEV_NOT_ENCRYPTED;
+ int error_count = 0;
+ int mret = -1;
+ int mount_errno = 0;
+ int attempted_idx = -1;
if (!fstab) {
- return ret;
+ return -1;
}
for (i = 0; i < fstab->num_entries; i++) {
@@ -237,70 +350,92 @@ int fs_mgr_mount_all(struct fstab *fstab)
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);
- }
-
- if (fstab->recs[i].fs_mgr_flags & MF_VERIFY) {
+ if ((fstab->recs[i].fs_mgr_flags & MF_VERIFY) &&
+ !device_is_debuggable()) {
if (fs_mgr_setup_verity(&fstab->recs[i]) < 0) {
- ERROR("Could not set up verified partition, skipping!");
+ ERROR("Could not set up verified partition, skipping!\n");
continue;
}
}
+ int last_idx_inspected;
+ mret = mount_with_alternatives(fstab, i, &last_idx_inspected, &attempted_idx);
+ i = last_idx_inspected;
+ mount_errno = errno;
- 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);
-
+ /* Deal with encryptability. */
if (!mret) {
+ /* If this is encryptable, need to trigger encryption */
+ 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 = FS_MGR_MNTALL_DEV_MIGHT_BE_ENCRYPTED;
+ }
+ } else {
+ INFO("Could not umount %s - allow continue unencrypted\n",
+ fstab->recs[attempted_idx].mount_point);
+ continue;
+ }
+ }
/* Success! Go get the next one */
continue;
}
- /* back up errno as partition_wipe clobbers the value */
- mount_errno = errno;
-
- /* mount(2) returned an error, check if it's encrypted and deal with it */
- 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->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 error: %s\n",
- fstab->recs[i].mount_point, strerror(errno));
- goto out;
+ /* 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[attempted_idx])) {
+ if(partition_wiped(fstab->recs[attempted_idx].blk_device)) {
+ ERROR("%s(): %s is wiped and %s %s is encryptable. Suggest recovery...\n", __func__,
+ fstab->recs[attempted_idx].blk_device, fstab->recs[attempted_idx].mount_point,
+ fstab->recs[attempted_idx].fs_type);
+ encryptable = FS_MGR_MNTALL_DEV_NEEDS_RECOVERY;
+ continue;
+ } else {
+ /* Need to mount a tmpfs at this mountpoint for now, and set
+ * properties that vold will query later for decrypting
+ */
+ 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;
+ }
}
- encrypted = 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));
- goto out;
+ "%s at %s options: %s error: %s\n",
+ fstab->recs[attempted_idx].blk_device, fstab->recs[attempted_idx].mount_point,
+ fstab->recs[attempted_idx].fs_options, strerror(mount_errno));
+ ++error_count;
+ continue;
}
}
- if (encrypted) {
- ret = 1;
+ if (error_count) {
+ return -1;
} else {
- ret = 0;
+ return encryptable;
}
-
-out:
- return ret;
}
/* If tmp_mount_point is non-null, mount the filesystem there. This is for the
* tmp mount we do to check the user password
+ * If multiple fstab entries are to be mounted on "n_name", it will try to mount each one
+ * in turn, and stop on 1st success, or no more match.
*/
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;
+ int ret = FS_MGR_DOMNT_FAILED;
+ int mount_errors = 0;
+ int first_mount_errno = 0;
char *m;
if (!fstab) {
@@ -332,9 +467,10 @@ int fs_mgr_do_mount(struct fstab *fstab, char *n_name, char *n_blk_device,
fstab->recs[i].mount_point);
}
- if (fstab->recs[i].fs_mgr_flags & MF_VERIFY) {
+ if ((fstab->recs[i].fs_mgr_flags & MF_VERIFY) &&
+ !device_is_debuggable()) {
if (fs_mgr_setup_verity(&fstab->recs[i]) < 0) {
- ERROR("Could not set up verified partition, skipping!");
+ ERROR("Could not set up verified partition, skipping!\n");
continue;
}
}
@@ -345,19 +481,27 @@ int fs_mgr_do_mount(struct fstab *fstab, char *n_name, char *n_blk_device,
} else {
m = fstab->recs[i].mount_point;
}
- 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 options: %s error: %s\n",
- n_blk_device, m, fstab->recs[i].fs_options, strerror(errno));
- goto out;
+ if (__mount(n_blk_device, m, &fstab->recs[i])) {
+ if (!first_mount_errno) first_mount_errno = errno;
+ mount_errors++;
+ continue;
} else {
ret = 0;
goto out;
}
}
-
- /* We didn't find a match, say so and return an error */
- ERROR("Cannot find mount point %s in fstab\n", fstab->recs[i].mount_point);
+ if (mount_errors) {
+ ERROR("Cannot mount filesystem on %s at %s. error: %s\n",
+ n_blk_device, m, strerror(first_mount_errno));
+ if (first_mount_errno == EBUSY) {
+ ret = FS_MGR_DOMNT_BUSY;
+ } else {
+ ret = FS_MGR_DOMNT_FAILED;
+ }
+ } else {
+ /* We didn't find a match, say so and return an error */
+ ERROR("Cannot find mount point %s in fstab\n", fstab->recs[i].mount_point);
+ }
out:
return ret;
@@ -437,7 +581,7 @@ int fs_mgr_swapon_all(struct fstab *fstab)
zram_fp = fopen(ZRAM_CONF_DEV, "r+");
if (zram_fp == NULL) {
- ERROR("Unable to open zram conf device " ZRAM_CONF_DEV);
+ ERROR("Unable to open zram conf device %s\n", ZRAM_CONF_DEV);
ret = -1;
continue;
}
@@ -504,7 +648,7 @@ int fs_mgr_get_crypt_info(struct fstab *fstab, char *key_loc, char *real_blk_dev
if (fstab->recs[i].fs_mgr_flags & MF_VOLDMANAGED) {
continue;
}
- if (!(fstab->recs[i].fs_mgr_flags & MF_CRYPT)) {
+ if (!(fstab->recs[i].fs_mgr_flags & (MF_CRYPT | MF_FORCECRYPT))) {
continue;
}