diff options
Diffstat (limited to 'fs_mgr/fs_mgr.c')
-rw-r--r-- | fs_mgr/fs_mgr.c | 256 |
1 files changed, 198 insertions, 58 deletions
diff --git a/fs_mgr/fs_mgr.c b/fs_mgr/fs_mgr.c index dcda005..3f94af5 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 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,23 @@ 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)); + ret = -1; + } 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 +577,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 +644,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; } |