2012-01-07 03:09:42 +00:00
|
|
|
/*
|
|
|
|
* Copyright (C) 2012 The Android Open Source Project
|
|
|
|
*
|
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
* you may not use this file except in compliance with the License.
|
|
|
|
* You may obtain a copy of the License at
|
|
|
|
*
|
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
*
|
|
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
* See the License for the specific language governing permissions and
|
|
|
|
* limitations under the License.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <ctype.h>
|
|
|
|
#include <sys/mount.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/wait.h>
|
|
|
|
#include <libgen.h>
|
|
|
|
#include <time.h>
|
2013-07-09 02:11:55 +00:00
|
|
|
#include <sys/swap.h>
|
2014-12-17 20:26:54 +00:00
|
|
|
#include <dirent.h>
|
|
|
|
#include <ext4.h>
|
|
|
|
#include <ext4_sb.h>
|
2012-01-07 03:09:42 +00:00
|
|
|
|
2013-02-23 02:11:41 +00:00
|
|
|
#include <linux/loop.h>
|
2012-01-07 03:09:42 +00:00
|
|
|
#include <private/android_filesystem_config.h>
|
2014-06-20 05:12:20 +00:00
|
|
|
#include <cutils/android_reboot.h>
|
2012-01-07 03:09:42 +00:00
|
|
|
#include <cutils/partition_utils.h>
|
|
|
|
#include <cutils/properties.h>
|
fs_mgr: Capture the output of e2fsck and add to the kernel log
Currently, the output of e2fsck is not saved, and we have no insight
into how many errors e2fsck is finding and fixing. Using the new
abbreviated logging feature in liblogwrap, up to the first 100 lines,
and last 4K bytes of the output of e2fsck is captured by fs_mgr, and
added to the kernel log.
Usually, the filesystem will be clean, and this will only add a few
lines to the kernel log on boot, but when things go wrong, it should
save enough to indicate what the problem is, without potentially
filling the kernel log with only e2fsck output if the filesystem is
really corrupted.
Change-Id: I9c264798e6fe721c8f818b5ce15d0975027ddbdd
2013-03-20 02:38:44 +00:00
|
|
|
#include <logwrap/logwrap.h>
|
2012-01-07 03:09:42 +00:00
|
|
|
|
2013-02-23 02:11:41 +00:00
|
|
|
#include "mincrypt/rsa.h"
|
|
|
|
#include "mincrypt/sha.h"
|
|
|
|
#include "mincrypt/sha256.h"
|
|
|
|
|
2012-01-07 03:09:42 +00:00
|
|
|
#include "fs_mgr_priv.h"
|
2013-02-23 02:11:41 +00:00
|
|
|
#include "fs_mgr_priv_verity.h"
|
2012-01-07 03:09:42 +00:00
|
|
|
|
|
|
|
#define KEY_LOC_PROP "ro.crypto.keyfile.userdata"
|
|
|
|
#define KEY_IN_FOOTER "footer"
|
|
|
|
|
|
|
|
#define E2FSCK_BIN "/system/bin/e2fsck"
|
2014-06-18 00:01:14 +00:00
|
|
|
#define F2FS_FSCK_BIN "/system/bin/fsck.f2fs"
|
2013-07-09 02:11:55 +00:00
|
|
|
#define MKSWAP_BIN "/system/bin/mkswap"
|
|
|
|
|
2013-09-19 00:49:21 +00:00
|
|
|
#define FSCK_LOG_FILE "/dev/fscklogs/log"
|
|
|
|
|
2013-07-09 02:11:55 +00:00
|
|
|
#define ZRAM_CONF_DEV "/sys/block/zram0/disksize"
|
2012-01-07 03:09:42 +00:00
|
|
|
|
fs_mgr: Capture the output of e2fsck and add to the kernel log
Currently, the output of e2fsck is not saved, and we have no insight
into how many errors e2fsck is finding and fixing. Using the new
abbreviated logging feature in liblogwrap, up to the first 100 lines,
and last 4K bytes of the output of e2fsck is captured by fs_mgr, and
added to the kernel log.
Usually, the filesystem will be clean, and this will only add a few
lines to the kernel log on boot, but when things go wrong, it should
save enough to indicate what the problem is, without potentially
filling the kernel log with only e2fsck output if the filesystem is
really corrupted.
Change-Id: I9c264798e6fe721c8f818b5ce15d0975027ddbdd
2013-03-20 02:38:44 +00:00
|
|
|
#define ARRAY_SIZE(a) (sizeof(a) / sizeof(*(a)))
|
|
|
|
|
2012-01-07 03:09:42 +00:00
|
|
|
/*
|
|
|
|
* gettime() - returns the time in seconds of the system's monotonic clock or
|
|
|
|
* zero on error.
|
|
|
|
*/
|
|
|
|
static time_t gettime(void)
|
|
|
|
{
|
|
|
|
struct timespec ts;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
ret = clock_gettime(CLOCK_MONOTONIC, &ts);
|
|
|
|
if (ret < 0) {
|
|
|
|
ERROR("clock_gettime(CLOCK_MONOTONIC) failed: %s\n", strerror(errno));
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ts.tv_sec;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int wait_for_file(const char *filename, int timeout)
|
|
|
|
{
|
|
|
|
struct stat info;
|
|
|
|
time_t timeout_time = gettime() + timeout;
|
|
|
|
int ret = -1;
|
|
|
|
|
|
|
|
while (gettime() < timeout_time && ((ret = stat(filename, &info)) < 0))
|
|
|
|
usleep(10000);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2013-02-13 20:58:40 +00:00
|
|
|
static void check_fs(char *blk_device, char *fs_type, char *target)
|
2012-01-07 03:09:42 +00:00
|
|
|
{
|
|
|
|
int status;
|
2012-07-24 02:34:00 +00:00
|
|
|
int ret;
|
|
|
|
long tmpmnt_flags = MS_NOATIME | MS_NOEXEC | MS_NOSUID;
|
|
|
|
char *tmpmnt_opts = "nomblk_io_submit,errors=remount-ro";
|
fs_mgr: Capture the output of e2fsck and add to the kernel log
Currently, the output of e2fsck is not saved, and we have no insight
into how many errors e2fsck is finding and fixing. Using the new
abbreviated logging feature in liblogwrap, up to the first 100 lines,
and last 4K bytes of the output of e2fsck is captured by fs_mgr, and
added to the kernel log.
Usually, the filesystem will be clean, and this will only add a few
lines to the kernel log on boot, but when things go wrong, it should
save enough to indicate what the problem is, without potentially
filling the kernel log with only e2fsck output if the filesystem is
really corrupted.
Change-Id: I9c264798e6fe721c8f818b5ce15d0975027ddbdd
2013-03-20 02:38:44 +00:00
|
|
|
char *e2fsck_argv[] = {
|
|
|
|
E2FSCK_BIN,
|
|
|
|
"-y",
|
|
|
|
blk_device
|
|
|
|
};
|
2012-01-07 03:09:42 +00:00
|
|
|
|
|
|
|
/* Check for the types of filesystems we know how to check */
|
2013-02-13 20:58:40 +00:00
|
|
|
if (!strcmp(fs_type, "ext2") || !strcmp(fs_type, "ext3") || !strcmp(fs_type, "ext4")) {
|
2012-07-24 02:34:00 +00:00
|
|
|
/*
|
|
|
|
* First try to mount and unmount the filesystem. We do this because
|
|
|
|
* the kernel is more efficient than e2fsck in running the journal and
|
|
|
|
* processing orphaned inodes, and on at least one device with a
|
|
|
|
* performance issue in the emmc firmware, it can take e2fsck 2.5 minutes
|
|
|
|
* to do what the kernel does in about a second.
|
|
|
|
*
|
|
|
|
* After mounting and unmounting the filesystem, run e2fsck, and if an
|
|
|
|
* error is recorded in the filesystem superblock, e2fsck will do a full
|
|
|
|
* check. Otherwise, it does nothing. If the kernel cannot mount the
|
|
|
|
* filesytsem due to an error, e2fsck is still run to do a full check
|
|
|
|
* fix the filesystem.
|
|
|
|
*/
|
2013-02-13 20:58:40 +00:00
|
|
|
ret = mount(blk_device, target, fs_type, tmpmnt_flags, tmpmnt_opts);
|
2014-06-18 21:54:37 +00:00
|
|
|
INFO("%s(): mount(%s,%s,%s)=%d\n", __func__, blk_device, target, fs_type, ret);
|
2013-02-13 20:58:40 +00:00
|
|
|
if (!ret) {
|
2012-07-24 02:34:00 +00:00
|
|
|
umount(target);
|
|
|
|
}
|
|
|
|
|
2014-02-17 10:14:44 +00:00
|
|
|
/*
|
|
|
|
* Some system images do not have e2fsck for licensing reasons
|
|
|
|
* (e.g. recent SDK system images). Detect these and skip the check.
|
|
|
|
*/
|
|
|
|
if (access(E2FSCK_BIN, X_OK)) {
|
|
|
|
INFO("Not running %s on %s (executable not in system image)\n",
|
|
|
|
E2FSCK_BIN, blk_device);
|
|
|
|
} else {
|
|
|
|
INFO("Running %s on %s\n", E2FSCK_BIN, blk_device);
|
|
|
|
|
|
|
|
ret = android_fork_execvp_ext(ARRAY_SIZE(e2fsck_argv), e2fsck_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", E2FSCK_BIN);
|
|
|
|
}
|
2012-01-07 03:09:42 +00:00
|
|
|
}
|
2014-06-18 00:01:14 +00:00
|
|
|
} 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);
|
|
|
|
}
|
2012-01-07 03:09:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void remove_trailing_slashes(char *n)
|
|
|
|
{
|
|
|
|
int len;
|
|
|
|
|
|
|
|
len = strlen(n) - 1;
|
|
|
|
while ((*(n + len) == '/') && len) {
|
|
|
|
*(n + len) = '\0';
|
|
|
|
len--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-04-16 23:41:32 +00:00
|
|
|
/*
|
|
|
|
* Mark the given block device as read-only, using the BLKROSET ioctl.
|
|
|
|
* Return 0 on success, and -1 on error.
|
|
|
|
*/
|
|
|
|
static void fs_set_blk_ro(const char *blockdev)
|
|
|
|
{
|
|
|
|
int fd;
|
|
|
|
int ON = 1;
|
|
|
|
|
|
|
|
fd = open(blockdev, O_RDONLY);
|
|
|
|
if (fd < 0) {
|
|
|
|
// should never happen
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
ioctl(fd, BLKROSET, &ON);
|
|
|
|
close(fd);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* __mount(): wrapper around the mount() system call which also
|
|
|
|
* sets the underlying block device to read-only if the mount is read-only.
|
|
|
|
* See "man 2 mount" for return values.
|
|
|
|
*/
|
2014-06-18 21:54:37 +00:00
|
|
|
static int __mount(const char *source, const char *target, const struct fstab_rec *rec)
|
2013-04-16 23:41:32 +00:00
|
|
|
{
|
2014-06-18 21:54:37 +00:00
|
|
|
unsigned long mountflags = rec->flags;
|
|
|
|
int ret;
|
|
|
|
int save_errno;
|
2014-06-26 21:55:04 +00:00
|
|
|
|
|
|
|
/* 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);
|
2014-05-28 21:10:01 +00:00
|
|
|
mkdir(target, 0755);
|
2014-06-18 21:54:37 +00:00
|
|
|
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);
|
2013-04-16 23:41:32 +00:00
|
|
|
if ((ret == 0) && (mountflags & MS_RDONLY) != 0) {
|
|
|
|
fs_set_blk_ro(source);
|
|
|
|
}
|
2014-06-18 21:54:37 +00:00
|
|
|
errno = save_errno;
|
2013-04-16 23:41:32 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2012-01-07 03:09:42 +00:00
|
|
|
static int fs_match(char *in1, char *in2)
|
|
|
|
{
|
|
|
|
char *n1;
|
|
|
|
char *n2;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
n1 = strdup(in1);
|
|
|
|
n2 = strdup(in2);
|
|
|
|
|
|
|
|
remove_trailing_slashes(n1);
|
|
|
|
remove_trailing_slashes(n2);
|
|
|
|
|
|
|
|
ret = !strcmp(n1, n2);
|
|
|
|
|
|
|
|
free(n1);
|
|
|
|
free(n2);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2014-04-02 20:42:06 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2014-10-09 14:22:49 +00:00
|
|
|
static int device_is_secure() {
|
|
|
|
int ret = -1;
|
|
|
|
char value[PROP_VALUE_MAX];
|
|
|
|
ret = __system_property_get("ro.secure", value);
|
|
|
|
/* If error, we want to fail secure */
|
|
|
|
if (ret < 0)
|
|
|
|
return 1;
|
|
|
|
return strcmp(value, "0") ? 1 : 0;
|
|
|
|
}
|
|
|
|
|
2015-01-07 19:44:51 +00:00
|
|
|
static int device_is_force_encrypted() {
|
|
|
|
int ret = -1;
|
|
|
|
char value[PROP_VALUE_MAX];
|
|
|
|
ret = __system_property_get("ro.vold.forceencryption", value);
|
|
|
|
if (ret < 0)
|
|
|
|
return 0;
|
|
|
|
return strcmp(value, "1") ? 0 : 1;
|
|
|
|
}
|
|
|
|
|
2014-07-02 20:16:04 +00:00
|
|
|
/*
|
|
|
|
* 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)
|
2014-06-20 05:12:20 +00:00
|
|
|
{
|
2014-07-02 20:16:04 +00:00
|
|
|
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;
|
|
|
|
}
|
2014-06-20 05:12:20 +00:00
|
|
|
}
|
2014-07-02 20:16:04 +00:00
|
|
|
|
|
|
|
/* 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;
|
2014-06-20 05:12:20 +00:00
|
|
|
}
|
|
|
|
|
2014-12-17 20:26:54 +00:00
|
|
|
static int translate_ext_labels(struct fstab_rec *rec)
|
|
|
|
{
|
|
|
|
DIR *blockdir = NULL;
|
|
|
|
struct dirent *ent;
|
|
|
|
char *label;
|
|
|
|
size_t label_len;
|
|
|
|
int ret = -1;
|
|
|
|
|
|
|
|
if (strncmp(rec->blk_device, "LABEL=", 6))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
label = rec->blk_device + 6;
|
|
|
|
label_len = strlen(label);
|
|
|
|
|
|
|
|
if (label_len > 16) {
|
|
|
|
ERROR("FS label is longer than allowed by filesystem\n");
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
blockdir = opendir("/dev/block");
|
|
|
|
if (!blockdir) {
|
|
|
|
ERROR("couldn't open /dev/block\n");
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
while ((ent = readdir(blockdir))) {
|
|
|
|
int fd;
|
|
|
|
char super_buf[1024];
|
|
|
|
struct ext4_super_block *sb;
|
|
|
|
|
|
|
|
if (ent->d_type != DT_BLK)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
fd = openat(dirfd(blockdir), ent->d_name, O_RDONLY);
|
|
|
|
if (fd < 0) {
|
|
|
|
ERROR("Cannot open block device /dev/block/%s\n", ent->d_name);
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (TEMP_FAILURE_RETRY(lseek(fd, 1024, SEEK_SET)) < 0 ||
|
|
|
|
TEMP_FAILURE_RETRY(read(fd, super_buf, 1024)) != 1024) {
|
|
|
|
/* Probably a loopback device or something else without a readable
|
|
|
|
* superblock.
|
|
|
|
*/
|
|
|
|
close(fd);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
sb = (struct ext4_super_block *)super_buf;
|
|
|
|
if (sb->s_magic != EXT4_SUPER_MAGIC) {
|
|
|
|
INFO("/dev/block/%s not ext{234}\n", ent->d_name);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!strncmp(label, sb->s_volume_name, label_len)) {
|
|
|
|
char *new_blk_device;
|
|
|
|
|
|
|
|
if (asprintf(&new_blk_device, "/dev/block/%s", ent->d_name) < 0) {
|
|
|
|
ERROR("Could not allocate block device string\n");
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
INFO("resolved label %s to %s\n", rec->blk_device, new_blk_device);
|
|
|
|
|
|
|
|
free(rec->blk_device);
|
|
|
|
rec->blk_device = new_blk_device;
|
|
|
|
ret = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
out:
|
|
|
|
closedir(blockdir);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2014-06-18 21:54:37 +00:00
|
|
|
/* 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.
|
2014-07-02 20:16:04 +00:00
|
|
|
* Returns -1 on error, and FS_MGR_MNTALL_* otherwise.
|
2014-06-18 21:54:37 +00:00
|
|
|
*/
|
2013-02-13 20:58:40 +00:00
|
|
|
int fs_mgr_mount_all(struct fstab *fstab)
|
2012-01-07 03:09:42 +00:00
|
|
|
{
|
2014-07-02 20:16:04 +00:00
|
|
|
int i = 0;
|
|
|
|
int encryptable = FS_MGR_MNTALL_DEV_NOT_ENCRYPTED;
|
2014-03-10 22:40:29 +00:00
|
|
|
int error_count = 0;
|
2014-06-18 21:54:37 +00:00
|
|
|
int mret = -1;
|
|
|
|
int mount_errno = 0;
|
2014-07-02 20:16:04 +00:00
|
|
|
int attempted_idx = -1;
|
2012-01-07 03:09:42 +00:00
|
|
|
|
2013-02-13 20:58:40 +00:00
|
|
|
if (!fstab) {
|
2014-03-10 22:40:29 +00:00
|
|
|
return -1;
|
2012-01-07 03:09:42 +00:00
|
|
|
}
|
|
|
|
|
2013-02-13 20:58:40 +00:00
|
|
|
for (i = 0; i < fstab->num_entries; i++) {
|
|
|
|
/* Don't mount entries that are managed by vold */
|
2013-02-23 01:36:21 +00:00
|
|
|
if (fstab->recs[i].fs_mgr_flags & (MF_VOLDMANAGED | MF_RECOVERYONLY)) {
|
2013-02-13 20:58:40 +00:00
|
|
|
continue;
|
2012-01-07 03:09:42 +00:00
|
|
|
}
|
|
|
|
|
2013-07-09 02:11:55 +00:00
|
|
|
/* Skip swap and raw partition entries such as boot, recovery, etc */
|
|
|
|
if (!strcmp(fstab->recs[i].fs_type, "swap") ||
|
|
|
|
!strcmp(fstab->recs[i].fs_type, "emmc") ||
|
2013-02-13 20:58:40 +00:00
|
|
|
!strcmp(fstab->recs[i].fs_type, "mtd")) {
|
|
|
|
continue;
|
2012-01-07 03:09:42 +00:00
|
|
|
}
|
|
|
|
|
2014-12-17 20:26:54 +00:00
|
|
|
/* Translate LABEL= file system labels into block devices */
|
|
|
|
if (!strcmp(fstab->recs[i].fs_type, "ext2") ||
|
|
|
|
!strcmp(fstab->recs[i].fs_type, "ext3") ||
|
|
|
|
!strcmp(fstab->recs[i].fs_type, "ext4")) {
|
|
|
|
int tret = translate_ext_labels(&fstab->recs[i]);
|
|
|
|
if (tret < 0) {
|
|
|
|
ERROR("Could not translate label to block device\n");
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-02-13 20:58:40 +00:00
|
|
|
if (fstab->recs[i].fs_mgr_flags & MF_WAIT) {
|
|
|
|
wait_for_file(fstab->recs[i].blk_device, WAIT_TIMEOUT);
|
|
|
|
}
|
|
|
|
|
2014-10-09 14:22:49 +00:00
|
|
|
if ((fstab->recs[i].fs_mgr_flags & MF_VERIFY) && device_is_secure()) {
|
|
|
|
int rc = fs_mgr_setup_verity(&fstab->recs[i]);
|
|
|
|
if (device_is_debuggable() && rc == FS_MGR_SETUP_VERITY_DISABLED) {
|
|
|
|
INFO("Verity disabled");
|
|
|
|
} else if (rc != FS_MGR_SETUP_VERITY_SUCCESS) {
|
2014-06-20 05:12:20 +00:00
|
|
|
ERROR("Could not set up verified partition, skipping!\n");
|
2013-02-23 02:11:41 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
2014-07-02 20:16:04 +00:00
|
|
|
int last_idx_inspected;
|
|
|
|
mret = mount_with_alternatives(fstab, i, &last_idx_inspected, &attempted_idx);
|
|
|
|
i = last_idx_inspected;
|
|
|
|
mount_errno = errno;
|
2014-06-18 07:28:14 +00:00
|
|
|
|
2014-06-18 21:54:37 +00:00
|
|
|
/* Deal with encryptability. */
|
2012-01-07 03:09:42 +00:00
|
|
|
if (!mret) {
|
2014-02-03 21:27:49 +00:00
|
|
|
/* If this is encryptable, need to trigger encryption */
|
2015-01-21 17:57:01 +00:00
|
|
|
if (fs_mgr_is_encryptable(&fstab->recs[attempted_idx])) {
|
2014-07-02 20:16:04 +00:00
|
|
|
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;
|
2014-02-03 21:27:49 +00:00
|
|
|
} else {
|
2014-06-20 05:12:20 +00:00
|
|
|
ERROR("Only one encryptable/encrypted partition supported\n");
|
2014-07-02 20:16:04 +00:00
|
|
|
encryptable = FS_MGR_MNTALL_DEV_MIGHT_BE_ENCRYPTED;
|
2014-02-03 21:27:49 +00:00
|
|
|
}
|
|
|
|
} else {
|
2014-06-20 05:12:20 +00:00
|
|
|
INFO("Could not umount %s - allow continue unencrypted\n",
|
2014-07-02 20:16:04 +00:00
|
|
|
fstab->recs[attempted_idx].mount_point);
|
2014-02-03 21:27:49 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
2012-01-07 03:09:42 +00:00
|
|
|
/* Success! Go get the next one */
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2014-03-10 22:40:29 +00:00
|
|
|
/* mount(2) returned an error, check if it's encryptable and deal with it */
|
2014-06-18 21:54:37 +00:00
|
|
|
if (mret && mount_errno != EBUSY && mount_errno != EACCES &&
|
2014-07-02 21:26:54 +00:00
|
|
|
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;
|
2014-03-10 22:40:29 +00:00
|
|
|
continue;
|
2014-06-20 05:12:20 +00:00
|
|
|
} else {
|
|
|
|
/* Need to mount a tmpfs at this mountpoint for now, and set
|
|
|
|
* properties that vold will query later for decrypting
|
|
|
|
*/
|
2014-07-02 20:16:04 +00:00
|
|
|
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) {
|
2014-06-20 05:12:20 +00:00
|
|
|
++error_count;
|
|
|
|
continue;
|
|
|
|
}
|
2012-01-07 03:09:42 +00:00
|
|
|
}
|
2014-07-02 20:16:04 +00:00
|
|
|
encryptable = FS_MGR_MNTALL_DEV_MIGHT_BE_ENCRYPTED;
|
2012-01-07 03:09:42 +00:00
|
|
|
} else {
|
2014-01-14 19:33:44 +00:00
|
|
|
ERROR("Failed to mount an un-encryptable or wiped partition on"
|
2014-03-10 22:40:29 +00:00
|
|
|
"%s at %s options: %s error: %s\n",
|
2014-07-02 20:16:04 +00:00
|
|
|
fstab->recs[attempted_idx].blk_device, fstab->recs[attempted_idx].mount_point,
|
|
|
|
fstab->recs[attempted_idx].fs_options, strerror(mount_errno));
|
2014-03-10 22:40:29 +00:00
|
|
|
++error_count;
|
|
|
|
continue;
|
2012-01-07 03:09:42 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-03-10 22:40:29 +00:00
|
|
|
if (error_count) {
|
|
|
|
return -1;
|
|
|
|
} else {
|
2014-02-03 21:27:49 +00:00
|
|
|
return encryptable;
|
2014-03-10 22:40:29 +00:00
|
|
|
}
|
2012-01-07 03:09:42 +00:00
|
|
|
}
|
|
|
|
|
2013-02-13 20:58:40 +00:00
|
|
|
/* If tmp_mount_point is non-null, mount the filesystem there. This is for the
|
2012-01-07 03:09:42 +00:00
|
|
|
* tmp mount we do to check the user password
|
2014-06-18 21:54:37 +00:00
|
|
|
* 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.
|
2012-01-07 03:09:42 +00:00
|
|
|
*/
|
2013-02-13 20:58:40 +00:00
|
|
|
int fs_mgr_do_mount(struct fstab *fstab, char *n_name, char *n_blk_device,
|
|
|
|
char *tmp_mount_point)
|
2012-01-07 03:09:42 +00:00
|
|
|
{
|
|
|
|
int i = 0;
|
2014-09-09 17:44:51 +00:00
|
|
|
int ret = FS_MGR_DOMNT_FAILED;
|
2014-06-18 21:54:37 +00:00
|
|
|
int mount_errors = 0;
|
|
|
|
int first_mount_errno = 0;
|
2012-01-07 03:09:42 +00:00
|
|
|
char *m;
|
|
|
|
|
2013-02-13 20:58:40 +00:00
|
|
|
if (!fstab) {
|
2012-01-07 03:09:42 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2013-02-13 20:58:40 +00:00
|
|
|
for (i = 0; i < fstab->num_entries; i++) {
|
|
|
|
if (!fs_match(fstab->recs[i].mount_point, n_name)) {
|
2012-01-07 03:09:42 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* We found our match */
|
2013-07-09 02:11:55 +00:00
|
|
|
/* If this swap or a raw partition, report an error */
|
|
|
|
if (!strcmp(fstab->recs[i].fs_type, "swap") ||
|
|
|
|
!strcmp(fstab->recs[i].fs_type, "emmc") ||
|
2013-02-13 20:58:40 +00:00
|
|
|
!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;
|
|
|
|
}
|
|
|
|
|
2012-01-07 03:09:42 +00:00
|
|
|
/* First check the filesystem if requested */
|
2013-02-13 20:58:40 +00:00
|
|
|
if (fstab->recs[i].fs_mgr_flags & MF_WAIT) {
|
|
|
|
wait_for_file(n_blk_device, WAIT_TIMEOUT);
|
2012-01-07 03:09:42 +00:00
|
|
|
}
|
|
|
|
|
2013-02-13 20:58:40 +00:00
|
|
|
if (fstab->recs[i].fs_mgr_flags & MF_CHECK) {
|
|
|
|
check_fs(n_blk_device, fstab->recs[i].fs_type,
|
|
|
|
fstab->recs[i].mount_point);
|
2012-01-07 03:09:42 +00:00
|
|
|
}
|
|
|
|
|
2014-10-09 14:22:49 +00:00
|
|
|
if ((fstab->recs[i].fs_mgr_flags & MF_VERIFY) && device_is_secure()) {
|
|
|
|
int rc = fs_mgr_setup_verity(&fstab->recs[i]);
|
|
|
|
if (device_is_debuggable() && rc == FS_MGR_SETUP_VERITY_DISABLED) {
|
|
|
|
INFO("Verity disabled");
|
|
|
|
} else if (rc != FS_MGR_SETUP_VERITY_SUCCESS) {
|
2014-06-20 05:12:20 +00:00
|
|
|
ERROR("Could not set up verified partition, skipping!\n");
|
2013-02-23 02:11:41 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-01-07 03:09:42 +00:00
|
|
|
/* Now mount it where requested */
|
2013-02-13 20:58:40 +00:00
|
|
|
if (tmp_mount_point) {
|
|
|
|
m = tmp_mount_point;
|
2012-01-07 03:09:42 +00:00
|
|
|
} else {
|
2013-02-13 20:58:40 +00:00
|
|
|
m = fstab->recs[i].mount_point;
|
2012-01-07 03:09:42 +00:00
|
|
|
}
|
2014-06-18 21:54:37 +00:00
|
|
|
if (__mount(n_blk_device, m, &fstab->recs[i])) {
|
|
|
|
if (!first_mount_errno) first_mount_errno = errno;
|
|
|
|
mount_errors++;
|
|
|
|
continue;
|
2012-01-07 03:09:42 +00:00
|
|
|
} else {
|
|
|
|
ret = 0;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
}
|
2014-06-18 21:54:37 +00:00
|
|
|
if (mount_errors) {
|
|
|
|
ERROR("Cannot mount filesystem on %s at %s. error: %s\n",
|
|
|
|
n_blk_device, m, strerror(first_mount_errno));
|
2014-09-09 17:44:51 +00:00
|
|
|
if (first_mount_errno == EBUSY) {
|
|
|
|
ret = FS_MGR_DOMNT_BUSY;
|
|
|
|
} else {
|
|
|
|
ret = FS_MGR_DOMNT_FAILED;
|
|
|
|
}
|
2014-06-18 21:54:37 +00:00
|
|
|
} 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);
|
|
|
|
}
|
2012-01-07 03:09:42 +00:00
|
|
|
|
|
|
|
out:
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* mount a tmpfs filesystem at the given point.
|
|
|
|
* return 0 on success, non-zero on failure.
|
|
|
|
*/
|
|
|
|
int fs_mgr_do_tmpfs_mount(char *n_name)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
ret = mount("tmpfs", n_name, "tmpfs",
|
|
|
|
MS_NOATIME | MS_NOSUID | MS_NODEV, CRYPTO_TMPFS_OPTIONS);
|
|
|
|
if (ret < 0) {
|
|
|
|
ERROR("Cannot mount tmpfs filesystem at %s\n", n_name);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Success */
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-02-13 20:58:40 +00:00
|
|
|
int fs_mgr_unmount_all(struct fstab *fstab)
|
2012-01-07 03:09:42 +00:00
|
|
|
{
|
|
|
|
int i = 0;
|
|
|
|
int ret = 0;
|
|
|
|
|
2013-02-13 20:58:40 +00:00
|
|
|
if (!fstab) {
|
2012-01-07 03:09:42 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2013-02-13 20:58:40 +00:00
|
|
|
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);
|
2012-01-07 03:09:42 +00:00
|
|
|
ret = -1;
|
|
|
|
}
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
2013-07-09 02:11:55 +00:00
|
|
|
|
|
|
|
/* This must be called after mount_all, because the mkswap command needs to be
|
|
|
|
* available.
|
|
|
|
*/
|
|
|
|
int fs_mgr_swapon_all(struct fstab *fstab)
|
|
|
|
{
|
|
|
|
int i = 0;
|
|
|
|
int flags = 0;
|
|
|
|
int err = 0;
|
|
|
|
int ret = 0;
|
|
|
|
int status;
|
|
|
|
char *mkswap_argv[2] = {
|
|
|
|
MKSWAP_BIN,
|
|
|
|
NULL
|
|
|
|
};
|
|
|
|
|
|
|
|
if (!fstab) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < fstab->num_entries; i++) {
|
|
|
|
/* Skip non-swap entries */
|
|
|
|
if (strcmp(fstab->recs[i].fs_type, "swap")) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (fstab->recs[i].zram_size > 0) {
|
|
|
|
/* A zram_size was specified, so we need to configure the
|
|
|
|
* device. There is no point in having multiple zram devices
|
|
|
|
* on a system (all the memory comes from the same pool) so
|
|
|
|
* we can assume the device number is 0.
|
|
|
|
*/
|
|
|
|
FILE *zram_fp;
|
|
|
|
|
|
|
|
zram_fp = fopen(ZRAM_CONF_DEV, "r+");
|
|
|
|
if (zram_fp == NULL) {
|
2014-06-20 05:12:20 +00:00
|
|
|
ERROR("Unable to open zram conf device %s\n", ZRAM_CONF_DEV);
|
2013-07-09 02:11:55 +00:00
|
|
|
ret = -1;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
fprintf(zram_fp, "%d\n", fstab->recs[i].zram_size);
|
|
|
|
fclose(zram_fp);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (fstab->recs[i].fs_mgr_flags & MF_WAIT) {
|
|
|
|
wait_for_file(fstab->recs[i].blk_device, WAIT_TIMEOUT);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Initialize the swap area */
|
|
|
|
mkswap_argv[1] = fstab->recs[i].blk_device;
|
|
|
|
err = android_fork_execvp_ext(ARRAY_SIZE(mkswap_argv), mkswap_argv,
|
2013-09-19 00:49:21 +00:00
|
|
|
&status, true, LOG_KLOG, false, NULL);
|
2013-07-09 02:11:55 +00:00
|
|
|
if (err) {
|
|
|
|
ERROR("mkswap failed for %s\n", fstab->recs[i].blk_device);
|
|
|
|
ret = -1;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If -1, then no priority was specified in fstab, so don't set
|
|
|
|
* SWAP_FLAG_PREFER or encode the priority */
|
|
|
|
if (fstab->recs[i].swap_prio >= 0) {
|
|
|
|
flags = (fstab->recs[i].swap_prio << SWAP_FLAG_PRIO_SHIFT) &
|
|
|
|
SWAP_FLAG_PRIO_MASK;
|
|
|
|
flags |= SWAP_FLAG_PREFER;
|
|
|
|
} else {
|
|
|
|
flags = 0;
|
|
|
|
}
|
|
|
|
err = swapon(fstab->recs[i].blk_device, flags);
|
|
|
|
if (err) {
|
|
|
|
ERROR("swapon failed for %s\n", fstab->recs[i].blk_device);
|
|
|
|
ret = -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2012-01-07 03:09:42 +00:00
|
|
|
/*
|
|
|
|
* key_loc must be at least PROPERTY_VALUE_MAX bytes long
|
|
|
|
*
|
2013-02-13 20:58:40 +00:00
|
|
|
* real_blk_device must be at least PROPERTY_VALUE_MAX bytes long
|
2012-01-07 03:09:42 +00:00
|
|
|
*/
|
2013-02-13 20:58:40 +00:00
|
|
|
int fs_mgr_get_crypt_info(struct fstab *fstab, char *key_loc, char *real_blk_device, int size)
|
2012-01-07 03:09:42 +00:00
|
|
|
{
|
|
|
|
int i = 0;
|
|
|
|
|
2013-02-13 20:58:40 +00:00
|
|
|
if (!fstab) {
|
2012-01-07 03:09:42 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
/* Initialize return values to null strings */
|
|
|
|
if (key_loc) {
|
|
|
|
*key_loc = '\0';
|
|
|
|
}
|
2013-02-13 20:58:40 +00:00
|
|
|
if (real_blk_device) {
|
|
|
|
*real_blk_device = '\0';
|
2012-01-07 03:09:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Look for the encryptable partition to find the data */
|
2013-02-13 20:58:40 +00:00
|
|
|
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;
|
|
|
|
}
|
2014-04-04 16:34:19 +00:00
|
|
|
if (!(fstab->recs[i].fs_mgr_flags & (MF_CRYPT | MF_FORCECRYPT))) {
|
2012-01-07 03:09:42 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* We found a match */
|
|
|
|
if (key_loc) {
|
2013-02-13 20:58:40 +00:00
|
|
|
strlcpy(key_loc, fstab->recs[i].key_loc, size);
|
2012-01-07 03:09:42 +00:00
|
|
|
}
|
2013-02-13 20:58:40 +00:00
|
|
|
if (real_blk_device) {
|
|
|
|
strlcpy(real_blk_device, fstab->recs[i].blk_device, size);
|
2012-01-07 03:09:42 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|