From c9c8ed466254a74b511b2570ebd86332466bd19a Mon Sep 17 00:00:00 2001 From: Readone !! ErcOne Date: Fri, 2 Jan 2015 15:29:44 +0700 Subject: [PATCH 1/2] fix sdcard --- DirectVolume.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/DirectVolume.cpp b/DirectVolume.cpp index 68e21c5fb..15dc2166f 100644 --- a/DirectVolume.cpp +++ b/DirectVolume.cpp @@ -210,10 +210,6 @@ void DirectVolume::handleDiskAdded(const char * /*devpath*/, mDiskNumParts = 1; } - mPendingPartCount = mDiskNumParts; - for (int i = 0; i < MAX_PARTITIONS; i++) - mPartMinors[i] = -1; - if (mDiskNumParts == 0) { #ifdef PARTITION_DEBUG SLOGD("Dv::diskIns - No partitions - good to go son!"); @@ -268,7 +264,7 @@ void DirectVolume::handlePartitionAdded(const char *devpath, NetlinkEvent *evt) SLOGD("Dv:partAdd: part_num = %d, minor = %d\n", part_num, minor); #endif if (part_num >= MAX_PARTITIONS) { - SLOGE("Dv:partAdd: ignoring part_num = %d (max: %d)\n", part_num, MAX_PARTITIONS-1); + SLOGE("Dv:partAdd: ignoring part_num = %d (max: %d)\n", part_num, MAX_PARTITIONS); } else { if ((mPartMinors[part_num - 1] == -1) && mPendingPartCount) mPendingPartCount--; From 45e128220d2a13e7cd08cc03d97fff8af70c1262 Mon Sep 17 00:00:00 2001 From: readone Date: Fri, 2 Jan 2015 16:05:45 +0700 Subject: [PATCH 2/2] fix --- Android.mk | 130 +++++++++++---- CleanSpec.mk | 1 + CommandListener.cpp | 23 ++- DirectVolume.cpp | 67 ++++++-- DirectVolume.h | 4 + Ext4.cpp | 57 +++++-- Ext4.h | 2 +- F2FS.cpp | 156 ++++++++++++++++++ F2FS.h | 30 ++++ Ntfs.cpp | 197 ++++++++++++++++++++++ Ntfs.h | 33 ++++ VoldUtil.c | 4 +- Volume.cpp | 86 ++++++++-- Volume.h | 9 +- VolumeManager.cpp | 94 +++++++---- VolumeManager.h | 2 +- cryptfs.c | 392 +++++++++++++++++++++++++++++++++++++++----- cryptfs.h | 5 + main.cpp | 11 +- vdc.c | 7 +- vold.c | 21 +++ vold.h | 30 ++++ 22 files changed, 1203 insertions(+), 158 deletions(-) create mode 100644 F2FS.cpp create mode 100644 F2FS.h create mode 100644 Ntfs.cpp create mode 100644 Ntfs.h create mode 100644 vold.c create mode 100644 vold.h diff --git a/Android.mk b/Android.mk index 82f8cee78..73a14f84b 100644 --- a/Android.mk +++ b/Android.mk @@ -1,20 +1,6 @@ LOCAL_PATH:= $(call my-dir) -common_cflags := \ - -Werror=format \ - -Wno-unused-parameter - -ifneq ($(BOARD_VOLD_MAX_PARTITIONS),) - common_cflags += -DVOLD_MAX_PARTITIONS=$(BOARD_VOLD_MAX_PARTITIONS) -endif - -ifeq ($(BOARD_VOLD_EMMC_SHARES_DEV_MAJOR), true) - common_cflags += -DVOLD_EMMC_SHARES_DEV_MAJOR -endif - -ifeq ($(BOARD_VOLD_DISC_HAS_MULTIPLE_MAJORS), true) - common_cflags += -DVOLD_DISC_HAS_MULTIPLE_MAJORS -endif +common_cflags := -Werror -Wno-unused-parameter common_src_files := \ VolumeManager.cpp \ @@ -27,14 +13,17 @@ common_src_files := \ Process.cpp \ Ext4.cpp \ Fat.cpp \ + Ntfs.cpp \ Exfat.cpp \ + F2FS.cpp \ Loop.cpp \ Devmapper.cpp \ ResponseCode.cpp \ CheckBattery.cpp \ VoldUtil.c \ fstrim.c \ - cryptfs.c + cryptfs.c \ + main.cpp common_c_includes := \ system/extras/ext4_utils \ @@ -49,57 +38,138 @@ common_c_includes := \ system/security/softkeymaster/include/keymaster \ external/e2fsprogs/lib -common_shared_libraries := \ +common_libraries := \ libsysutils \ - libstlport \ libbinder \ libcutils \ liblog \ libdiskconfig \ - libhardware_legacy \ liblogwrap \ - libext4_utils \ libf2fs_sparseblock \ - libcrypto \ libselinux \ libutils \ + +common_shared_libraries := \ + $(common_libraries) \ + libhardware_legacy \ + libcrypto \ libhardware \ + libstlport \ libsoftkeymaster \ libext2_blkid common_static_libraries := \ libfs_mgr \ + libext4_utils_static \ libscrypt_static \ - libmincrypt \ - libbatteryservice + libminshacrypt \ + libbatteryservice \ + libext2_blkid \ + libext2_uuid_static + +ifneq ($(BOARD_VOLD_MAX_PARTITIONS),) +common_cflags += -DVOLD_MAX_PARTITIONS=$(BOARD_VOLD_MAX_PARTITIONS) +endif + +ifeq ($(BOARD_VOLD_EMMC_SHARES_DEV_MAJOR), true) +common_cflags += -DVOLD_EMMC_SHARES_DEV_MAJOR +endif + +ifeq ($(BOARD_VOLD_DISC_HAS_MULTIPLE_MAJORS), true) +common_cflags += -DVOLD_DISC_HAS_MULTIPLE_MAJORS +endif include $(CLEAR_VARS) + LOCAL_MODULE := libvold + LOCAL_SRC_FILES := $(common_src_files) + LOCAL_C_INCLUDES := $(common_c_includes) + +LOCAL_CFLAGS := $(common_cflags) + LOCAL_SHARED_LIBRARIES := $(common_shared_libraries) + LOCAL_STATIC_LIBRARIES := $(common_static_libraries) -LOCAL_CFLAGS := $(common_cflags) + +ifeq ($(TARGET_HW_DISK_ENCRYPTION),true) +LOCAL_C_INCLUDES += device/qcom/common/cryptfs_hw +LOCAL_SHARED_LIBRARIES += libcryptfs_hw +LOCAL_CFLAGS += -DCONFIG_HW_DISK_ENCRYPTION +endif + LOCAL_MODULE_TAGS := eng tests + include $(BUILD_STATIC_LIBRARY) include $(CLEAR_VARS) + LOCAL_MODULE:= vold -LOCAL_SRC_FILES := \ - main.cpp \ - $(common_src_files) +LOCAL_SRC_FILES := vold.c LOCAL_C_INCLUDES := $(common_c_includes) -LOCAL_CFLAGS := $(common_cflags) + LOCAL_SHARED_LIBRARIES := $(common_shared_libraries) -LOCAL_STATIC_LIBRARIES := $(common_static_libraries) + +LOCAL_STATIC_LIBRARIES := libvold $(common_static_libraries) + +LOCAL_CFLAGS += -Werror=format + +ifeq ($(TARGET_HW_DISK_ENCRYPTION),true) +LOCAL_C_INCLUDES += device/qcom/common/cryptfs_hw +LOCAL_SHARED_LIBRARIES += libcryptfs_hw +LOCAL_CFLAGS += -DCONFIG_HW_DISK_ENCRYPTION +endif + +ifneq ($(BOARD_VOLD_MAX_PARTITIONS),) +LOCAL_CFLAGS += -DVOLD_MAX_PARTITIONS=$(BOARD_VOLD_MAX_PARTITIONS) +endif + +ifeq ($(BOARD_VOLD_DISC_HAS_MULTIPLE_MAJORS), true) +LOCAL_CFLAGS += -DVOLD_DISC_HAS_MULTIPLE_MAJORS +endif + +ifeq ($(BOARD_VOLD_EMMC_SHARES_DEV_MAJOR), true) +LOCAL_CFLAGS += -DVOLD_EMMC_SHARES_DEV_MAJOR +endif + include $(BUILD_EXECUTABLE) include $(CLEAR_VARS) + LOCAL_SRC_FILES:= vdc.c + LOCAL_MODULE:= vdc + LOCAL_C_INCLUDES := -LOCAL_CFLAGS := + +LOCAL_CFLAGS := $(common_cflags) + LOCAL_SHARED_LIBRARIES := libcutils + +include $(BUILD_EXECUTABLE) + +include $(CLEAR_VARS) +LOCAL_MODULE:= libminivold +LOCAL_SRC_FILES := $(common_src_files) +LOCAL_C_INCLUDES := $(common_c_includes) system/core/fs_mgr/include system/core/logwrapper/include +LOCAL_CFLAGS := $(common_cflags) -DMINIVOLD -DHELPER_PATH=\"/sbin/\" +LOCAL_MODULE_TAGS := optional +include $(BUILD_STATIC_LIBRARY) + +include $(CLEAR_VARS) +LOCAL_MODULE:= minivold +LOCAL_SRC_FILES := vold.c +LOCAL_C_INCLUDES := $(common_c_includes) +LOCAL_CFLAGS := $(common_cflags) -DMINIVOLD +LOCAL_STATIC_LIBRARIES := libminivold +LOCAL_STATIC_LIBRARIES += libc libstdc++ libstlport_static +LOCAL_STATIC_LIBRARIES += $(common_static_libraries) $(common_libraries) +LOCAL_STATIC_LIBRARIES += libcrypto_static libvold +LOCAL_FORCE_STATIC_EXECUTABLE := true +LOCAL_MODULE_CLASS := RECOVERY_EXECUTABLES +LOCAL_MODULE_PATH := $(TARGET_RECOVERY_ROOT_OUT)/sbin +LOCAL_MODULE_TAGS := optional include $(BUILD_EXECUTABLE) diff --git a/CleanSpec.mk b/CleanSpec.mk index b84e1b65e..7d1bf5fab 100644 --- a/CleanSpec.mk +++ b/CleanSpec.mk @@ -47,3 +47,4 @@ # ************************************************ # NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST # ************************************************ +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/EXECUTABLES/vold_intermediates) diff --git a/CommandListener.cpp b/CommandListener.cpp index 800309515..2b47f31a6 100644 --- a/CommandListener.cpp +++ b/CommandListener.cpp @@ -148,20 +148,25 @@ int CommandListener::VolumeCmd::runCommand(SocketClient *cli, } else if (!strcmp(argv[1], "unmount")) { if (argc < 3 || argc > 4 || ((argc == 4 && strcmp(argv[3], "force")) && - (argc == 4 && strcmp(argv[3], "force_and_revert")))) { - cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: volume unmount [force|force_and_revert]", false); + (argc == 4 && strcmp(argv[3], "force_and_revert")) && + (argc == 4 && strcmp(argv[3], "detach")))) { + cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: volume unmount [force|force_and_revert|detach]", false); return 0; } bool force = false; bool revert = false; + bool detach = false; if (argc >= 4 && !strcmp(argv[3], "force")) { force = true; } else if (argc >= 4 && !strcmp(argv[3], "force_and_revert")) { force = true; revert = true; } - rc = vm->unmountVolume(argv[2], force, revert); + else if (argc >= 4 && !strcmp(argv[3], "detach")) { + detach = true; + } + rc = vm->unmountVolume(argv[2], force, revert, detach); } else if (!strcmp(argv[1], "format")) { if (argc < 3 || argc > 4 || (argc == 4 && strcmp(argv[3], "wipe"))) { @@ -568,7 +573,17 @@ int CommandListener::CryptfsCmd::runCommand(SocketClient *cli, int rc = 0; - if (!strcmp(argv[1], "checkpw")) { + if (!strcmp(argv[1], "pfe")) { + if (argc != 3) { + cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: cryptfs pfe ", false); + return 0; + } + dumpArgs(argc, argv, 2); + if (!strcmp(argv[2], "enable")) + rc = cryptfs_pfe_activate(); + else if (!strcmp(argv[2], "disable")) + rc = cryptfs_pfe_deactivate(); + } else if (!strcmp(argv[1], "checkpw")) { if (argc != 3) { cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: cryptfs checkpw ", false); return 0; diff --git a/DirectVolume.cpp b/DirectVolume.cpp index 15dc2166f..2da3dbd49 100644 --- a/DirectVolume.cpp +++ b/DirectVolume.cpp @@ -80,6 +80,7 @@ DirectVolume::DirectVolume(VolumeManager *vm, const fstab_rec* rec, int flags) : mDiskMinor = -1; mDiskNumParts = 0; mIsDecrypted = 0; + mIsValid = true; if (strcmp(rec->mount_point, "auto") != 0) { ALOGE("Vold managed volumes must have auto mount point; ignoring %s", @@ -88,10 +89,16 @@ DirectVolume::DirectVolume(VolumeManager *vm, const fstab_rec* rec, int flags) : char mount[PATH_MAX]; +#ifdef MINIVOLD + // In recovery, directly mount to /storage/* since we have no fuse daemon + snprintf(mount, PATH_MAX, "%s/%s", Volume::FUSE_DIR, rec->label); + mMountpoint = mFuseMountpoint = strdup(mount); +#else snprintf(mount, PATH_MAX, "%s/%s", Volume::MEDIA_DIR, rec->label); mMountpoint = strdup(mount); snprintf(mount, PATH_MAX, "%s/%s", Volume::FUSE_DIR, rec->label); mFuseMountpoint = strdup(mount); +#endif setState(Volume::State_NoMedia); } @@ -115,14 +122,6 @@ dev_t DirectVolume::getDiskDevice() { dev_t DirectVolume::getShareDevice() { if (mPartIdx != -1) { -#ifdef VOLD_DISC_HAS_MULTIPLE_MAJORS - int major = getMajorNumberForBadPartition(mPartIdx); - if(major != -1) { - SLOGE("getShareDevice() returning correct major: %d, minor: %d", major, mPartMinors[mPartIdx - 1]); - return MKDEV(major, mPartMinors[mPartIdx - 1]); - } - else -#endif return MKDEV(mDiskMajor, mPartIdx); } else { return MKDEV(mDiskMajor, mDiskMinor); @@ -137,12 +136,38 @@ void DirectVolume::handleVolumeUnshared() { setState(Volume::State_Idle); } +int DirectVolume::getUICCVolumeNum(const char *dp) { + int mVolNum = -1; + if (strstr(dp, ":0:0:0")) + mVolNum = 0; + else if (strstr(dp, ":0:0:1")) + mVolNum = 1; + + return mVolNum; +} + int DirectVolume::handleBlockEvent(NetlinkEvent *evt) { const char *dp = evt->findParam("DEVPATH"); PathCollection::iterator it; for (it = mPaths->begin(); it != mPaths->end(); ++it) { if ((*it)->match(dp)) { + + /* Check for UICC prefix in label */ + if (strstr(getLabel(), "uicc")) { + char mLabel[15]; + int mNum = getUICCVolumeNum(dp); + if (mNum < 0) { + SLOGE("Invalid uicc volume number"); + continue; + } + + snprintf(mLabel, sizeof(mLabel), "uicc%d", mNum); + if (strncmp(getLabel(), mLabel, strlen(mLabel)) != 0) + continue; + } + setValidSysfs(true); + /* We can handle this disk */ int action = evt->getAction(); const char *devtype = evt->findParam("DEVTYPE"); @@ -210,6 +235,9 @@ void DirectVolume::handleDiskAdded(const char * /*devpath*/, mDiskNumParts = 1; } + mPendingPartCount = mDiskNumParts; + + if (mDiskNumParts == 0) { #ifdef PARTITION_DEBUG SLOGD("Dv::diskIns - No partitions - good to go son!"); @@ -263,7 +291,7 @@ void DirectVolume::handlePartitionAdded(const char *devpath, NetlinkEvent *evt) #ifdef PARTITION_DEBUG SLOGD("Dv:partAdd: part_num = %d, minor = %d\n", part_num, minor); #endif - if (part_num >= MAX_PARTITIONS) { + if (part_num > MAX_PARTITIONS) { SLOGE("Dv:partAdd: ignoring part_num = %d (max: %d)\n", part_num, MAX_PARTITIONS); } else { if ((mPartMinors[part_num - 1] == -1) && mPendingPartCount) @@ -343,6 +371,23 @@ void DirectVolume::handleDiskRemoved(const char * /*devpath*/, getLabel(), getFuseMountpoint(), major, minor); mVm->getBroadcaster()->sendBroadcast(ResponseCode::VolumeDiskRemoved, msg, false); + + if ((dev_t) MKDEV(major, minor) == mCurrentlyMountedKdev) { + + bool providesAsec = (getFlags() & VOL_PROVIDES_ASEC) != 0; + if (providesAsec && mVm->cleanupAsec(this, true)) { + SLOGE("Failed to cleanup ASEC - unmount will probably fail!"); + } + + if (Volume::unmountVol(true, false, false)) { + SLOGE("Failed to unmount volume on bad removal (%s)", + strerror(errno)); + // XXX: At this point we're screwed for now + } else { + SLOGD("Crisis averted"); + } + } + setState(Volume::State_NoMedia); } @@ -381,7 +426,7 @@ void DirectVolume::handlePartitionRemoved(const char * /*devpath*/, mVm->getBroadcaster()->sendBroadcast(ResponseCode::VolumeBadRemoval, msg, false); - if (Volume::unmountVol(true, false)) { + if (Volume::unmountVol(true, false, false)) { SLOGE("Failed to unmount volume on bad removal (%s)", strerror(errno)); // XXX: At this point we're screwed for now @@ -413,7 +458,7 @@ int DirectVolume::getDeviceNodes(dev_t *devs, int max) { // If the disk has no partitions, try the disk itself if (!mDiskNumParts) { devs[0] = MKDEV(mDiskMajor, mDiskMinor); - SLOGD("Disc has only one partition."); + SLOGD("Disc has only one partition."); return 1; } diff --git a/DirectVolume.h b/DirectVolume.h index 71725994b..7ab06c050 100644 --- a/DirectVolume.h +++ b/DirectVolume.h @@ -56,6 +56,7 @@ class DirectVolume : public Volume { int mDiskNumParts; int mPendingPartCount; int mIsDecrypted; + bool mIsValid; #ifdef VOLD_DISC_HAS_MULTIPLE_MAJORS private: @@ -75,6 +76,8 @@ class DirectVolume : public Volume { const char *getMountpoint() { return mMountpoint; } const char *getFuseMountpoint() { return mFuseMountpoint; } + bool isValidSysfs() { return mIsValid; } + void setValidSysfs(bool val) { mIsValid = val; } int handleBlockEvent(NetlinkEvent *evt); dev_t getDiskDevice(); @@ -98,6 +101,7 @@ class DirectVolume : public Volume { void handlePartitionChanged(const char *devpath, NetlinkEvent *evt); int doMountVfat(const char *deviceNode, const char *mountPoint); + int getUICCVolumeNum(const char *dp); #ifdef VOLD_DISC_HAS_MULTIPLE_MAJORS int getMajorNumberForBadPartition(int part_num); #endif diff --git a/Ext4.cpp b/Ext4.cpp index 878f9cd5b..0c6c32e60 100644 --- a/Ext4.cpp +++ b/Ext4.cpp @@ -46,11 +46,17 @@ static char E2FSCK_PATH[] = "/system/bin/e2fsck"; static char RESIZE2FS_PATH[] = "/system/bin/resize2fs"; static char MKEXT4FS_PATH[] = "/system/bin/make_ext4fs"; +static char MKE2FS_PATH[] = "/system/bin/mke2fs"; int Ext4::doMount(const char *fsPath, const char *mountPoint, bool ro, bool remount, - bool executable) { + bool executable, bool sdcard, const char *mountOpts) { int rc; unsigned long flags; + char data[1024]; + + data[0] = '\0'; + if (mountOpts) + strlcat(data, mountOpts, sizeof(data)); flags = MS_NOATIME | MS_NODEV | MS_NOSUID | MS_DIRSYNC; @@ -58,12 +64,19 @@ int Ext4::doMount(const char *fsPath, const char *mountPoint, bool ro, bool remo flags |= (ro ? MS_RDONLY : 0); flags |= (remount ? MS_REMOUNT : 0); - rc = mount(fsPath, mountPoint, "ext4", flags, NULL); + if (sdcard) { + // Mount external volumes with forced context + if (data[0]) + strlcat(data, ",", sizeof(data)); + strlcat(data, "context=u:object_r:sdcard_posix:s0", sizeof(data)); + } + + rc = mount(fsPath, mountPoint, "ext4", flags, data); if (rc && errno == EROFS) { SLOGE("%s appears to be a read only filesystem - retrying mount RO", fsPath); flags |= MS_RDONLY; - rc = mount(fsPath, mountPoint, "ext4", flags, NULL); + rc = mount(fsPath, mountPoint, "ext4", flags, data); } return rc; @@ -165,24 +178,32 @@ int Ext4::format(const char *fsPath, unsigned int numSectors, const char *mountp int rc; int status; - args[0] = MKEXT4FS_PATH; - args[1] = "-J"; - args[2] = "-a"; - args[3] = mountpoint; - if (numSectors) { - char tmp[32]; - snprintf(tmp, sizeof(tmp), "%u", numSectors * 512); - const char *size = tmp; - args[4] = "-l"; - args[5] = size; - args[6] = fsPath; - rc = android_fork_execvp(ARRAY_SIZE(args), (char **)args, &status, false, true); - } else { + if (mountpoint == NULL) { + args[0] = MKE2FS_PATH; + args[1] = "-j"; + args[2] = "-T"; + args[3] = "ext4"; args[4] = fsPath; rc = android_fork_execvp(5, (char **)args, &status, false, true); + } else { + args[0] = MKEXT4FS_PATH; + args[1] = "-J"; + args[2] = "-a"; + args[3] = mountpoint; + if (numSectors) { + char tmp[32]; + snprintf(tmp, sizeof(tmp), "%u", numSectors * 512); + const char *size = tmp; + args[4] = "-l"; + args[5] = size; + args[6] = fsPath; + rc = android_fork_execvp(ARRAY_SIZE(args), (char **)args, &status, false, true); + } else { + args[4] = fsPath; + rc = android_fork_execvp(5, (char **)args, &status, false, true); + } } - rc = android_fork_execvp(ARRAY_SIZE(args), (char **)args, &status, false, - true); + if (rc != 0) { SLOGE("Filesystem (ext4) format failed due to logwrap error"); errno = EIO; diff --git a/Ext4.h b/Ext4.h index 5b01a5308..f07960e70 100644 --- a/Ext4.h +++ b/Ext4.h @@ -22,7 +22,7 @@ class Ext4 { public: static int doMount(const char *fsPath, const char *mountPoint, bool ro, bool remount, - bool executable); + bool executable, bool sdcard, const char *mountOpts = NULL); static int check(const char *fsPath); static int format(const char *fsPath, unsigned int numSectors, const char *mountpoint); static int resize(const char *fsPath, unsigned int numSectors); diff --git a/F2FS.cpp b/F2FS.cpp new file mode 100644 index 000000000..077261dcf --- /dev/null +++ b/F2FS.cpp @@ -0,0 +1,156 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * Copyright (C) 2014 The CyanogenMod 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include "VoldUtil.h" + +#define LOG_TAG "Vold" +#include +#include + +#include + +#include "F2FS.h" + +static char F2FS_FSCK[] = "/system/bin/fsck.f2fs"; +static char F2FS_MKFS[] = "/system/bin/mkfs.f2fs"; + +int F2FS::doMount(const char *fsPath, const char *mountPoint, bool ro, bool + remount, bool executable, bool sdcard) { + int rc; + unsigned long flags; + char data[255] = "inline_xattr,background_gc=off,active_logs=2"; + + flags = MS_NOATIME | MS_NODEV | MS_NOSUID | MS_DIRSYNC; + + flags |= (executable ? 0 : MS_NOEXEC); + flags |= (ro ? MS_RDONLY : 0); + flags |= (remount ? MS_REMOUNT : 0); + + if (sdcard) { + // Mount external volumes with forced context + strcat(data, ",context=u:object_r:sdcard_posix:s0"); + } + + rc = mount(fsPath, mountPoint, "f2fs", flags, data); + + if (sdcard && rc == 0) { + // Write access workaround + chown(mountPoint, AID_MEDIA_RW, AID_MEDIA_RW); + chmod(mountPoint, 0755); + } + + if (rc && errno == EROFS) { + SLOGE("%s appears to be a read only filesystem - retrying mount RO", fsPath); + flags |= MS_RDONLY; + rc = mount(fsPath, mountPoint, "f2fs", flags, data); + } + + return rc; +} + +int F2FS::check(const char *fsPath) { + + int rc = -1; + int status; + + if (access(F2FS_FSCK, X_OK)) { + SLOGW("Skipping fs checks, fsck.f2fs not found.\n"); + return 0; + } + + do { + const char *args[3]; + args[0] = F2FS_FSCK; + args[1] = fsPath; + args[2] = NULL; + + rc = android_fork_execvp(ARRAY_SIZE(args), (char **)args, &status, false, + true); + + switch(rc) { + case 0: + SLOGI("F2FS filesystem check completed OK.\n"); + return 0; + case 1: + SLOGI("F2FS filesystem check completed, errors corrected OK.\n"); + return 0; + case 2: + SLOGE("F2FS filesystem check completed, errors corrected, need reboot.\n"); + return 0; + case 4: + SLOGE("F2FS filesystem errors left uncorrected.\n"); + return 0; + case 8: + SLOGE("F2FS.fsck operational error.\n"); + errno = EIO; + return -1; + default: + SLOGE("F2FS filesystem check failed (unknown exit code %d).\n", rc); + errno = EIO; + return -1; + } + } while (0); + + return 0; +} + +int F2FS::format(const char *fsPath) { + + const char *args[3]; + int rc = -1; + int status; + + if (access(F2FS_MKFS, X_OK)) { + SLOGE("Unable to format, mkfs.f2fs not found."); + return -1; + } + + args[0] = F2FS_MKFS; + args[1] = fsPath; + args[2] = NULL; + + rc = android_fork_execvp(ARRAY_SIZE(args), (char **)args, &status, false, + true); + + if (rc == 0) { + SLOGI("Filesystem (F2FS) formatted OK"); + return 0; + } else { + SLOGE("Format (F2FS) failed (unknown exit code %d)", rc); + errno = EIO; + return -1; + } + return 0; +} diff --git a/F2FS.h b/F2FS.h new file mode 100644 index 000000000..edad53a5a --- /dev/null +++ b/F2FS.h @@ -0,0 +1,30 @@ +/* + * 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. + */ + +#ifndef _F2FS_H +#define _F2FS_H + +#include + +class F2FS { +public: + static int doMount(const char *fsPath, const char *mountPoint, bool ro, bool remount, + bool executable, bool sdcard); + static int check(const char *fsPath); + static int format(const char *fsPath); +}; + +#endif diff --git a/Ntfs.cpp b/Ntfs.cpp new file mode 100644 index 000000000..4b3193277 --- /dev/null +++ b/Ntfs.cpp @@ -0,0 +1,197 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * Copyright (C) 2012 Freescale Semiconductor, Inc. + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include "VoldUtil.h" + +#define LOG_TAG "Vold" + +#include +#include + +#include "Ntfs.h" + +static char NTFS_FIX_PATH[] = "/system/bin/ntfsfix"; +static char NTFS_MOUNT_PATH[] = "/system/bin/ntfs-3g"; +static char MKNTFS_PATH[] = "/system/bin/mkntfs"; + +int Ntfs::check(const char *fsPath) { + + if (access(NTFS_FIX_PATH, X_OK)) { + SLOGW("Skipping fs checks\n"); + return 0; + } + + int rc = 0; + int status; + const char *args[4]; + /* we first use -n to do ntfs detection */ + args[0] = NTFS_FIX_PATH; + args[1] = "-n"; + args[2] = fsPath; + args[3] = NULL; + + rc = android_fork_execvp(ARRAY_SIZE(args), (char **)args, &status, false, + true); + if (rc) { + errno = ENODATA; + return -1; + } + + SLOGI("Ntfs filesystem existed"); + + /* do the real fix */ + /* redo the ntfsfix without -n to fix problems */ + args[1] = fsPath; + args[2] = NULL; + + rc = android_fork_execvp(ARRAY_SIZE(args), (char **)args, &status, false, + true); + if (rc) { + errno = EIO; + SLOGE("Filesystem check failed (unknown exit code %d)", rc); + return -1; + } + + SLOGI("Ntfs filesystem check completed OK"); + return 0; +} + +int Ntfs::doMount(const char *fsPath, const char *mountPoint, + bool ro, bool remount, bool executable, + int ownerUid, int ownerGid, int permMask, bool createLost) { + int rc; + char mountData[255]; + const char *args[6]; + int status; + + /* + * Note: This is a temporary hack. If the sampling profiler is enabled, + * we make the SD card world-writable so any process can write snapshots. + * + * TODO: Remove this code once we have a drop box in system_server. + */ + char value[PROPERTY_VALUE_MAX]; + property_get("persist.sampling_profiler", value, ""); + if (value[0] == '1') { + SLOGW("The SD card is world-writable because the" + " 'persist.sampling_profiler' system property is set to '1'."); + permMask = 0; + } + + sprintf(mountData, + "utf8,uid=%d,gid=%d,fmask=%o,dmask=%o," + "shortname=mixed,nodev,nosuid,dirsync", + ownerUid, ownerGid, permMask, permMask); + + if (!executable) + strcat(mountData, ",noexec"); + if (ro) + strcat(mountData, ",ro"); + if (remount) + strcat(mountData, ",remount"); + + SLOGD("Mounting ntfs with options:%s\n", mountData); + + args[0] = NTFS_MOUNT_PATH; + args[1] = "-o"; + args[2] = mountData; + args[3] = fsPath; + args[4] = mountPoint; + args[5] = NULL; + + rc = android_fork_execvp(ARRAY_SIZE(args), (char **)args, &status, false, + true); + + if (rc && errno == EROFS) { + SLOGE("%s appears to be a read only filesystem - retrying mount RO", fsPath); + strcat(mountData, ",ro"); + rc = android_fork_execvp(ARRAY_SIZE(args), (char **)args, &status, false, + true); + + } + + if (rc == 0 && createLost) { + char *lost_path; + asprintf(&lost_path, "%s/LOST.DIR", mountPoint); + if (access(lost_path, F_OK)) { + /* + * Create a LOST.DIR in the root so we have somewhere to put + * lost cluster chains (fsck_msdos doesn't currently do this) + */ + if (mkdir(lost_path, 0755)) { + SLOGE("Unable to create LOST.DIR (%s)", strerror(errno)); + } + } + free(lost_path); + } + + return rc; +} + +int Ntfs::format(const char *fsPath, bool wipe) { + + const char *args[4]; + int rc = -1; + int status; + + if (access(MKNTFS_PATH, X_OK)) { + SLOGE("Unable to format, mkntfs not found."); + return -1; + } + + args[0] = MKNTFS_PATH; + if (wipe) { + args[1] = fsPath; + args[2] = NULL; + } else { + args[1] = "-f"; + args[2] = fsPath; + args[3] = NULL; + } + + rc = android_fork_execvp(ARRAY_SIZE(args), (char **)args, &status, false, + true); + + if (rc == 0) { + SLOGI("Filesystem (NTFS) formatted OK"); + return 0; + } else { + SLOGE("Format (NTFS) failed (unknown exit code %d)", rc); + errno = EIO; + return -1; + } + return 0; +} diff --git a/Ntfs.h b/Ntfs.h new file mode 100644 index 000000000..92a8a64bc --- /dev/null +++ b/Ntfs.h @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * Copyright (C) 2012 Freescale Semiconductor, Inc. + * + * 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. + */ + +#ifndef _NTFS_H +#define _NTFS_H + +#include + +class Ntfs { +public: + static int check(const char *fsPath); + static int doMount(const char *fsPath, const char *mountPoint, + bool ro, bool remount, bool executable, + int ownerUid, int ownerGid, int permMask, + bool createLost); + static int format(const char *fsPath, bool wipe); +}; + +#endif diff --git a/VoldUtil.c b/VoldUtil.c index b5f994617..852062c96 100644 --- a/VoldUtil.c +++ b/VoldUtil.c @@ -19,11 +19,11 @@ unsigned int get_blkdev_size(int fd) { - unsigned int nr_sec; + unsigned long nr_sec; if ( (ioctl(fd, BLKGETSIZE, &nr_sec)) == -1) { nr_sec = 0; } - return nr_sec; + return (unsigned int)nr_sec; } diff --git a/Volume.cpp b/Volume.cpp index f00da9d23..a8747bd95 100644 --- a/Volume.cpp +++ b/Volume.cpp @@ -49,7 +49,9 @@ #include "ResponseCode.h" #include "Ext4.h" #include "Fat.h" +#include "Ntfs.h" #include "Exfat.h" +#include "F2FS.h" #include "Process.h" #include "cryptfs.h" @@ -122,6 +124,7 @@ Volume::Volume(VolumeManager *vm, const fstab_rec* rec, int flags) { mUserLabel = NULL; mState = Volume::State_Init; mFlags = flags; + mOpts = (rec->fs_options ? strdup(rec->fs_options) : NULL); mCurrentlyMountedKdev = -1; mPartIdx = rec->partnum; mRetryMount = false; @@ -131,6 +134,7 @@ Volume::~Volume() { free(mLabel); free(mUuid); free(mUserLabel); + free(mOpts); } void Volume::setDebug(bool enable) { @@ -295,28 +299,30 @@ int Volume::formatVol(bool wipe) { fstype = getFsType((const char*)devicePath); -#ifdef VOLD_EMMC_SHARES_DEV_MAJOR - // If emmc and sdcard share dev major number, vold may pick - // incorrectly based on partition nodes alone, formatting - // the wrong device. Use device nodes instead. - dev_t deviceNodes; - getDeviceNodes((dev_t *) &deviceNodes, 1); - sprintf(devicePath, "/dev/block/vold/%d:%d", major(deviceNodes), minor(deviceNodes)); -#endif + /* If the device has no filesystem, let's default to vfat. + * A NULL fstype will cause a MAPERR in the format + * switch below */ + if (fstype == NULL) { + fstype = strdup("vfat"); + } if (mDebug) { SLOGI("Formatting volume %s (%s) as %s", getLabel(), devicePath, fstype); } - if (strcmp(fstype, "ext4") == 0) { - ret = Ext4::format(devicePath, 0, NULL); + if (strcmp(fstype, "f2fs") == 0) { + ret = F2FS::format(devicePath); } else if (strcmp(fstype, "exfat") == 0) { ret = Exfat::format(devicePath); + } else if (strcmp(fstype, "ext4") == 0) { + ret = Ext4::format(devicePath, 0, NULL); + } else if (strcmp(fstype, "ntfs") == 0) { + ret = Ntfs::format(devicePath, wipe); } else { ret = Fat::format(devicePath, 0, wipe); } - if (Fat::format(devicePath, 0, wipe)) { + if (ret < 0) { SLOGE("Failed to format (%s)", strerror(errno)); } @@ -486,6 +492,7 @@ int Volume::mountVol() { SLOGE("%s failed to mount via VFAT (%s)\n", devicePath, strerror(errno)); continue; } + } else if (strcmp(fstype, "ext4") == 0) { if (Ext4::check(devicePath)) { @@ -497,11 +504,45 @@ int Volume::mountVol() { return -1; } - if (Ext4::doMount(devicePath, getMountpoint(), false, false, false)) { + if (Ext4::doMount(devicePath, getMountpoint(), false, false, false, true, mOpts)) { SLOGE("%s failed to mount via EXT4 (%s)\n", devicePath, strerror(errno)); continue; } + } else if (strcmp(fstype, "ntfs") == 0) { + + if (Ntfs::doMount(devicePath, getMountpoint(), false, false, false, + AID_MEDIA_RW, AID_MEDIA_RW, 0007, true)) { + SLOGE("%s failed to mount via NTFS (%s)\n", devicePath, strerror(errno)); + continue; + } + + } else if (strcmp(fstype, "f2fs") == 0) { + /* + * fsck.f2fs does not fix any inconsistencies "yet". + * + * Disable fsck routine as this is just wasting time + * consumed to mount f2fs volumes. + * + * The kernel can determine if a f2fs volume is too damaged + * that it shouldn't get mounted. + */ + #if 0 + if (F2FS::check(devicePath)) { + errno = EIO; + /* Badness - abort the mount */ + SLOGE("%s failed FS checks (%s)", devicePath, strerror(errno)); + setState(Volume::State_Idle); + free(fstype); + return -1; + } + #endif + + if (F2FS::doMount(devicePath, getMountpoint(), false, false, false, true)) { + SLOGE("%s failed to mount via F2FS (%s)\n", devicePath, strerror(errno)); + continue; + } + } else if (strcmp(fstype, "exfat") == 0) { if (Exfat::check(devicePath)) { @@ -539,12 +580,14 @@ int Volume::mountVol() { extractMetadata(devicePath); +#ifndef MINIVOLD if (providesAsec && mountAsecExternal() != 0) { SLOGE("Failed to mount secure area (%s)", strerror(errno)); umount(getMountpoint()); setState(Volume::State_Idle); return -1; } +#endif char service[64]; snprintf(service, 64, "fuse_%s", getLabel()); @@ -589,13 +632,22 @@ int Volume::mountAsecExternal() { return 0; } -int Volume::doUnmount(const char *path, bool force) { +int Volume::doUnmount(const char *path, bool force, bool detach) { int retries = 10; if (mDebug) { SLOGD("Unmounting {%s}, force = %d", path, force); } + if (detach) { + if (!umount2(path, MNT_DETACH) || errno == EINVAL || errno == ENOENT) { + SLOGI("%s sucessfully unmounted/detached", path); + return 0; + } + SLOGE("Failed to unmount/detach %s (%s)", path, strerror(errno)); + return -1; + } + while (retries--) { if (!umount(path) || errno == EINVAL || errno == ENOENT) { SLOGI("%s sucessfully unmounted", path); @@ -623,7 +675,7 @@ int Volume::doUnmount(const char *path, bool force) { return -1; } -int Volume::unmountVol(bool force, bool revert) { +int Volume::unmountVol(bool force, bool revert, bool detach) { int i, rc; int flags = getFlags(); @@ -646,19 +698,19 @@ int Volume::unmountVol(bool force, bool revert) { // TODO: determine failure mode if FUSE times out - if (providesAsec && doUnmount(Volume::SEC_ASECDIR_EXT, force) != 0) { + if (providesAsec && doUnmount(Volume::SEC_ASECDIR_EXT, force, detach) != 0) { SLOGE("Failed to unmount secure area on %s (%s)", getMountpoint(), strerror(errno)); goto out_mounted; } /* Now that the fuse daemon is dead, unmount it */ - if (doUnmount(getFuseMountpoint(), force) != 0) { + if (doUnmount(getFuseMountpoint(), force, detach) != 0) { SLOGE("Failed to unmount %s (%s)", getFuseMountpoint(), strerror(errno)); goto fail_remount_secure; } /* Unmount the real sd card */ - if (doUnmount(getMountpoint(), force) != 0) { + if (doUnmount(getMountpoint(), force, detach) != 0) { SLOGE("Failed to unmount %s (%s)", getMountpoint(), strerror(errno)); goto fail_remount_secure; } diff --git a/Volume.h b/Volume.h index 0be586508..af02c7412 100644 --- a/Volume.h +++ b/Volume.h @@ -27,6 +27,7 @@ class Volume { private: int mState; int mFlags; + char* mOpts; public: static const int State_Init = -1; @@ -68,7 +69,7 @@ class Volume { virtual ~Volume(); int mountVol(); - int unmountVol(bool force, bool revert); + int unmountVol(bool force, bool revert, bool detach=false); int formatVol(bool wipe); const char* getLabel() { return mLabel; } @@ -81,6 +82,10 @@ class Volume { virtual const char *getMountpoint() = 0; virtual const char *getFuseMountpoint() = 0; + /* validity of the mount points */ + virtual void setValidSysfs(bool val) = 0; + virtual bool isValidSysfs() = 0; + virtual int handleBlockEvent(NetlinkEvent *evt); virtual dev_t getDiskDevice(); virtual dev_t getShareDevice(); @@ -106,7 +111,7 @@ class Volume { int initializeMbr(const char *deviceNode); bool isMountpointMounted(const char *path); int mountAsecExternal(); - int doUnmount(const char *path, bool force); + int doUnmount(const char *path, bool force, bool detach); int extractMetadata(const char* devicePath); }; diff --git a/VolumeManager.cpp b/VolumeManager.cpp index 24ac8989d..946ecea08 100644 --- a/VolumeManager.cpp +++ b/VolumeManager.cpp @@ -54,6 +54,7 @@ #include "cryptfs.h" #define MASS_STORAGE_FILE_PATH "/sys/class/android_usb/android0/f_mass_storage/lun/file" +#define UICC0_MASS_STORAGE_PATH "/sys/class/android_usb/android0/f_mass_storage/uicc0/file" #define ROUND_UP_POWER_OF_2(number, po2) (((!!(number & ((1U << po2) - 1))) << po2)\ + (number & (~((1U << po2) - 1)))) @@ -233,6 +234,16 @@ int VolumeManager::stop() { } int VolumeManager::addVolume(Volume *v) { + // If entry is duplicated then mark isValid to false for both of them. + // Mark the valid entry on the first insertion of the card on handleBlockEvent() + VolumeCollection::iterator it; + for (it = mVolumes->begin(); it != mVolumes->end(); ++it) { + if(!strncmp((*it)->getLabel(), v->getLabel(), strlen((*it)->getLabel()))) { + (*it)->setValidSysfs(false); + v->setValidSysfs(false); + } + } + mVolumes->push_back(v); return 0; } @@ -265,12 +276,15 @@ int VolumeManager::listVolumes(SocketClient *cli, bool broadcast) { char msg[256]; for (i = mVolumes->begin(); i != mVolumes->end(); ++i) { - char *buffer; - asprintf(&buffer, "%s %s %d", - (*i)->getLabel(), (*i)->getFuseMountpoint(), - (*i)->getState()); - cli->sendMsg(ResponseCode::VolumeListResult, buffer, false); - free(buffer); + if ((*i)->isValidSysfs()) { + char *buffer; + asprintf(&buffer, "%s %s %d", + (*i)->getLabel(), (*i)->getFuseMountpoint(), + (*i)->getState()); + cli->sendMsg(ResponseCode::VolumeListResult, buffer, false); + free(buffer); + } + if (broadcast) { if((*i)->getUuid()) { snprintf(msg, sizeof(msg), "%s %s \"%s\"", (*i)->getLabel(), @@ -552,7 +566,7 @@ int VolumeManager::createAsec(const char *id, unsigned int numSectors, const cha int mountStatus; if (usingExt4) { - mountStatus = Ext4::doMount(dmDevice, mountPoint, false, false, false); + mountStatus = Ext4::doMount(dmDevice, mountPoint, false, false, false, false); } else { mountStatus = Fat::doMount(dmDevice, mountPoint, false, false, false, ownerUid, 0, 0000, false); @@ -771,7 +785,7 @@ int VolumeManager::finalizeAsec(const char *id) { int result = 0; if (sb.c_opts & ASEC_SB_C_OPTS_EXT4) { - result = Ext4::doMount(loopDevice, mountPoint, true, true, true); + result = Ext4::doMount(loopDevice, mountPoint, true, true, true, false); } else { result = Fat::doMount(loopDevice, mountPoint, true, true, true, 0, 0, 0227, false); } @@ -840,7 +854,8 @@ int VolumeManager::fixupAsecPermissions(const char *id, gid_t gid, const char* f int ret = Ext4::doMount(loopDevice, mountPoint, false /* read-only */, true /* remount */, - false /* executable */); + false /* executable */, + false /* sdcard */); if (ret) { SLOGE("Unable remount to fix permissions for %s (%s)", id, strerror(errno)); return -1; @@ -902,7 +917,8 @@ int VolumeManager::fixupAsecPermissions(const char *id, gid_t gid, const char* f result |= Ext4::doMount(loopDevice, mountPoint, true /* read-only */, true /* remount */, - true /* execute */); + true /* execute */, + false /* sdcard */); if (result) { SLOGE("ASEC fix permissions failed (%s)", strerror(errno)); @@ -1339,7 +1355,7 @@ int VolumeManager::mountAsec(const char *id, const char *key, int ownerUid, bool int result; if (sb.c_opts & ASEC_SB_C_OPTS_EXT4) { - result = Ext4::doMount(dmDevice, mountPoint, readOnly, false, readOnly); + result = Ext4::doMount(dmDevice, mountPoint, readOnly, false, readOnly, false); } else { result = Fat::doMount(dmDevice, mountPoint, readOnly, false, readOnly, ownerUid, 0, 0222, false); } @@ -1364,9 +1380,11 @@ Volume* VolumeManager::getVolumeForFile(const char *fileName) { VolumeCollection::iterator i; for (i = mVolumes->begin(); i != mVolumes->end(); ++i) { - const char* mountPoint = (*i)->getFuseMountpoint(); - if (!strncmp(fileName, mountPoint, strlen(mountPoint))) { - return *i; + if ((*i)->isValidSysfs()) { + const char* mountPoint = (*i)->getFuseMountpoint(); + if (!strncmp(fileName, mountPoint, strlen(mountPoint))) { + return *i; + } } } @@ -1594,6 +1612,18 @@ int VolumeManager::shareVolume(const char *label, const char *method) { return -1; } + if (!strncmp(v->getLabel(), "uicc0", strlen("uicc0"))) { + if ((fd = open(UICC0_MASS_STORAGE_PATH, O_WRONLY)) < 0) { + SLOGE("Unable to open ums lunfile (%s)", strerror(errno)); + return -1; + } + } else { + if ((fd = open(MASS_STORAGE_FILE_PATH, O_WRONLY)) < 0) { + SLOGE("Unable to open ums lunfile (%s)", strerror(errno)); + return -1; + } + } + if ((fd = open(MASS_STORAGE_FILE_PATH, O_WRONLY)) < 0) { SLOGE("Unable to open ums lunfile (%s)", strerror(errno)); return -1; @@ -1688,8 +1718,10 @@ int VolumeManager::getNumDirectVolumes(void) { int n=0; for (i = mVolumes->begin(); i != mVolumes->end(); ++i) { - if ((*i)->getShareDevice() != (dev_t)0) { - n++; + if ((*i)->isValidSysfs()) { + if ((*i)->getShareDevice() != (dev_t)0) { + n++; + } } } return n; @@ -1706,18 +1738,20 @@ int VolumeManager::getDirectVolumeList(struct volume_info *vol_list) { dev_t d; for (i = mVolumes->begin(); i != mVolumes->end(); ++i) { - if ((d=(*i)->getShareDevice()) != (dev_t)0) { - (*i)->getVolInfo(&vol_list[n]); - snprintf(vol_list[n].blk_dev, sizeof(vol_list[n].blk_dev), - "/dev/block/vold/%d:%d", major(d), minor(d)); - n++; + if ((*i)->isValidSysfs()) { + if ((d=(*i)->getShareDevice()) != (dev_t)0) { + (*i)->getVolInfo(&vol_list[n]); + snprintf(vol_list[n].blk_dev, sizeof(vol_list[n].blk_dev), + "/dev/block/vold/%d:%d", major(d), minor(d)); + n++; + } } } return 0; } -int VolumeManager::unmountVolume(const char *label, bool force, bool revert) { +int VolumeManager::unmountVolume(const char *label, bool force, bool revert, bool detach) { Volume *v = lookupVolume(label); if (!v) { @@ -1739,7 +1773,7 @@ int VolumeManager::unmountVolume(const char *label, bool force, bool revert) { cleanupAsec(v, force); - return v->unmountVol(force, revert); + return v->unmountVol(force, revert, detach); } extern "C" int vold_unmountAllAsecs(void) { @@ -1805,12 +1839,14 @@ Volume *VolumeManager::lookupVolume(const char *label) { VolumeCollection::iterator i; for (i = mVolumes->begin(); i != mVolumes->end(); ++i) { - if (label[0] == '/') { - if (!strcmp(label, (*i)->getFuseMountpoint())) - return (*i); - } else { - if (!strcmp(label, (*i)->getLabel())) - return (*i); + if ((*i)->isValidSysfs()) { + if (label[0] == '/') { + if (!strcmp(label, (*i)->getFuseMountpoint())) + return (*i); + } else { + if (!strcmp(label, (*i)->getLabel())) + return (*i); + } } } return NULL; diff --git a/VolumeManager.h b/VolumeManager.h index 17fa6f753..b3f9fd620 100644 --- a/VolumeManager.h +++ b/VolumeManager.h @@ -79,7 +79,7 @@ class VolumeManager { int listVolumes(SocketClient *cli, bool broadcast); int mountVolume(const char *label); - int unmountVolume(const char *label, bool force, bool revert); + int unmountVolume(const char *label, bool force, bool revert, bool detach=false); int shareVolume(const char *label, const char *method); int unshareVolume(const char *label, const char *method); int shareEnabled(const char *path, const char *method, bool *enabled); diff --git a/cryptfs.c b/cryptfs.c index a3c159965..52dfbf229 100644 --- a/cryptfs.c +++ b/cryptfs.c @@ -62,6 +62,10 @@ #define UNUSED __attribute__((unused)) +#ifdef CONFIG_HW_DISK_ENCRYPTION +#include "cryptfs_hw.h" +#endif + #define DM_CRYPT_BUF_SIZE 4096 #define HASH_COUNT 2000 @@ -92,6 +96,12 @@ static char *saved_mount_point; static int master_key_saved = 0; static struct crypt_persist_data *persist_data = NULL; +#ifdef MINIVOLD +inline int release_wake_lock(const char* id) { return 0; }; +inline int acquire_wake_lock(int lock, const char* id) { return 0; }; +#endif + +#ifndef MINIVOLD // no HALs in recovery... static int keymaster_init(keymaster_device_t **keymaster_dev) { int rc; @@ -116,10 +126,14 @@ static int keymaster_init(keymaster_device_t **keymaster_dev) *keymaster_dev = NULL; return rc; } +#endif /* Should we use keymaster? */ static int keymaster_check_compatibility() { +#ifdef MINIVOLD + return -1; +#else keymaster_device_t *keymaster_dev = 0; int rc = 0; @@ -144,11 +158,15 @@ static int keymaster_check_compatibility() out: keymaster_close(keymaster_dev); return rc; +#endif } /* Create a new keymaster key and store it in this footer */ static int keymaster_create_key(struct crypt_mnt_ftr *ftr) { +#ifdef MINIVOLD // no HALs in recovery... + return -1; +#else uint8_t* key = 0; keymaster_device_t *keymaster_dev = 0; @@ -185,6 +203,7 @@ static int keymaster_create_key(struct crypt_mnt_ftr *ftr) keymaster_close(keymaster_dev); free(key); return rc; +#endif } /* This signs the given object using the keymaster key. */ @@ -194,6 +213,9 @@ static int keymaster_sign_object(struct crypt_mnt_ftr *ftr, unsigned char **signature, size_t *signature_size) { +#ifdef MINIVOLD // no HALs in recovery... + return -1; +#else int rc = 0; keymaster_device_t *keymaster_dev = 0; if (keymaster_init(&keymaster_dev)) { @@ -271,6 +293,7 @@ static int keymaster_sign_object(struct crypt_mnt_ftr *ftr, keymaster_close(keymaster_dev); return rc; +#endif } /* Store password when userdata is successfully decrypted and mounted. @@ -990,12 +1013,23 @@ static int load_crypto_mapping_table(struct crypt_mnt_ftr *crypt_ftr, unsigned c tgt->status = 0; tgt->sector_start = 0; tgt->length = crypt_ftr->fs_size; +#ifdef CONFIG_HW_DISK_ENCRYPTION + if(is_hw_disk_encryption((char*)crypt_ftr->crypto_type_name)) + strlcpy(tgt->target_type, "req-crypt",DM_MAX_TYPE_NAME); + else + strlcpy(tgt->target_type, "crypt", DM_MAX_TYPE_NAME); +#else strcpy(tgt->target_type, "crypt"); +#endif crypt_params = buffer + sizeof(struct dm_ioctl) + sizeof(struct dm_target_spec); convert_key_to_hex_ascii(master_key, crypt_ftr->keysize, master_key_ascii); sprintf(crypt_params, "%s %s 0 %s 0 %s", crypt_ftr->crypto_type_name, master_key_ascii, real_blk_name, extra_params); + + SLOGI("%s: target_type = %s\n", __func__, tgt->target_type); + SLOGI("%s: real_blk_name = %s, extra_params = %s\n", __func__, real_blk_name, extra_params); + crypt_params += strlen(crypt_params) + 1; crypt_params = (char *) (((unsigned long)crypt_params + 7) & ~8); /* Align to an 8 byte boundary */ tgt->next = crypt_params - buffer; @@ -1036,7 +1070,11 @@ static int get_dm_crypt_version(int fd, const char *name, int *version) */ v = (struct dm_target_versions *) &buffer[sizeof(struct dm_ioctl)]; while (v->next) { +#ifdef CONFIG_HW_DISK_ENCRYPTION + if(!strcmp(v->name, "crypt") || !strcmp(v->name, "req-crypt")) { +#else if (! strcmp(v->name, "crypt")) { +#endif /* We found the crypt driver, return the version, and get out */ version[0] = v->version[0]; version[1] = v->version[1]; @@ -1058,12 +1096,16 @@ static int create_crypto_blk_dev(struct crypt_mnt_ftr *crypt_ftr, unsigned char struct dm_ioctl *io; struct dm_target_spec *tgt; unsigned int minor; - int fd; + int fd=0; int i; int retval = -1; int version[3]; char *extra_params; int load_count; +#ifdef CONFIG_HW_DISK_ENCRYPTION + char encrypted_state[PROPERTY_VALUE_MAX] = {0}; + char progress[PROPERTY_VALUE_MAX] = {0}; +#endif if ((fd = open("/dev/device-mapper", O_RDWR)) < 0 ) { SLOGE("Cannot open device-mapper\n"); @@ -1087,6 +1129,15 @@ static int create_crypto_blk_dev(struct crypt_mnt_ftr *crypt_ftr, unsigned char minor = (io->dev & 0xff) | ((io->dev >> 12) & 0xfff00); snprintf(crypto_blk_name, MAXPATHLEN, "/dev/block/dm-%u", minor); +#ifdef CONFIG_HW_DISK_ENCRYPTION + /* Set fde_enabled if either FDE completed or in-progress */ + property_get("ro.crypto.state", encrypted_state, ""); /* FDE completed */ + property_get("vold.encrypt_progress", progress, ""); /* FDE in progress */ + if (!strcmp(encrypted_state, "encrypted") || strcmp(progress, "")) + extra_params = "fde_enabled"; + else + extra_params = "fde_disabled"; +#else extra_params = ""; if (! get_dm_crypt_version(fd, name, version)) { /* Support for allow_discards was added in version 1.11.0 */ @@ -1096,6 +1147,7 @@ static int create_crypto_blk_dev(struct crypt_mnt_ftr *crypt_ftr, unsigned char SLOGI("Enabling support for allow_discards in dmcrypt.\n"); } } +#endif load_count = load_crypto_mapping_table(crypt_ftr, master_key, real_blk_name, name, fd, extra_params); @@ -1749,6 +1801,12 @@ static int test_mount_encrypted_fs(struct crypt_mnt_ftr* crypt_ftr, fs_mgr_get_crypt_info(fstab, 0, real_blkdev, sizeof(real_blkdev)); +#ifdef CONFIG_HW_DISK_ENCRYPTION + if(is_hw_disk_encryption((char*) crypt_ftr->crypto_type_name)) + if (!set_hw_device_encryption_key(passwd, (char*) crypt_ftr->crypto_type_name)) + rc = -1; +#endif + // Create crypto block device - all (non fatal) code paths // need it if (create_crypto_blk_dev(crypt_ftr, decrypted_master_key, @@ -3029,42 +3087,6 @@ int cryptfs_enable_internal(char *howarg, int crypt_type, char *passwd, } } - /* Do extra work for a better UX when doing the long inplace encryption */ - if (how == CRYPTO_ENABLE_INPLACE) { - /* Now that /data is unmounted, we need to mount a tmpfs - * /data, set a property saying we're doing inplace encryption, - * and restart the framework. - */ - if (fs_mgr_do_tmpfs_mount(DATA_MNT_POINT)) { - goto error_shutting_down; - } - /* Tells the framework that inplace encryption is starting */ - property_set("vold.encrypt_progress", "0"); - - /* restart the framework. */ - /* Create necessary paths on /data */ - if (prep_data_fs()) { - goto error_shutting_down; - } - - /* Ugh, shutting down the framework is not synchronous, so until it - * can be fixed, this horrible hack will wait a moment for it all to - * shut down before proceeding. Without it, some devices cannot - * restart the graphics services. - */ - sleep(2); - - /* startup service classes main and late_start */ - property_set("vold.decrypt", "trigger_restart_min_framework"); - SLOGD("Just triggered restart_min_framework\n"); - - /* OK, the framework is restarted and will soon be showing a - * progress bar. Time to setup an encrypted mapping, and - * either write a new filesystem, or encrypt in place updating - * the progress bar as we work. - */ - } - /* Start the actual work of making an encrypted filesystem */ /* Initialize a crypt_mnt_ftr for the partition */ if (previously_encrypted_upto == 0) { @@ -3084,7 +3106,13 @@ int cryptfs_enable_internal(char *howarg, int crypt_type, char *passwd, On successfully completing encryption, remove this flag */ crypt_ftr.flags |= CRYPT_INCONSISTENT_STATE; crypt_ftr.crypt_type = crypt_type; - strcpy((char *)crypt_ftr.crypto_type_name, "aes-cbc-essiv:sha256"); +#ifndef CONFIG_HW_DISK_ENCRYPTION + strlcpy((char *)crypt_ftr.crypto_type_name, "aes-cbc-essiv:sha256", MAX_CRYPTO_TYPE_NAME_LEN); +#else + strlcpy((char *)crypt_ftr.crypto_type_name, "aes-xts", MAX_CRYPTO_TYPE_NAME_LEN); + if(!set_hw_device_encryption_key(passwd, (char*)crypt_ftr.crypto_type_name)) + goto error_shutting_down; +#endif /* Make an encrypted master key */ if (create_encrypted_random_key(passwd, crypt_ftr.master_key, crypt_ftr.salt, &crypt_ftr)) { @@ -3110,6 +3138,42 @@ int cryptfs_enable_internal(char *howarg, int crypt_type, char *passwd, } } + /* Do extra work for a better UX when doing the long inplace encryption */ + if (how == CRYPTO_ENABLE_INPLACE) { + /* Now that /data is unmounted, we need to mount a tmpfs + * /data, set a property saying we're doing inplace encryption, + * and restart the framework. + */ + if (fs_mgr_do_tmpfs_mount(DATA_MNT_POINT)) { + goto error_shutting_down; + } + /* Tells the framework that inplace encryption is starting */ + property_set("vold.encrypt_progress", "0"); + + /* restart the framework. */ + /* Create necessary paths on /data */ + if (prep_data_fs()) { + goto error_shutting_down; + } + + /* Ugh, shutting down the framework is not synchronous, so until it + * can be fixed, this horrible hack will wait a moment for it all to + * shut down before proceeding. Without it, some devices cannot + * restart the graphics services. + */ + sleep(2); + + /* startup service classes main and late_start */ + property_set("vold.decrypt", "trigger_restart_min_framework"); + SLOGD("Just triggered restart_min_framework\n"); + + /* OK, the framework is restarted and will soon be showing a + * progress bar. Time to setup an encrypted mapping, and + * either write a new filesystem, or encrypt in place updating + * the progress bar as we work. + */ + } + decrypt_master_key(passwd, decrypted_master_key, &crypt_ftr, 0, 0); create_crypto_blk_dev(&crypt_ftr, decrypted_master_key, real_blkdev, crypto_blkdev, "userdata"); @@ -3158,6 +3222,8 @@ int cryptfs_enable_internal(char *howarg, int crypt_type, char *passwd, crypt_ftr.flags |= CRYPT_ENCRYPTION_IN_PROGRESS; } + if (how == CRYPTO_ENABLE_INPLACE) + crypt_ftr.flags |= CRYPT_FDE_COMPLETED; put_crypt_ftr_and_key(&crypt_ftr); if (crypt_ftr.encrypted_upto == crypt_ftr.fs_size) { @@ -3236,6 +3302,250 @@ int cryptfs_enable_internal(char *howarg, int crypt_type, char *passwd, return -1; } +/** + * Map /data to dm-req-crypt upon PFE Activation. + * + * The UI framework needs to be shut-down and restart. + * + * based on cryptfs_enable() + cryptfs_restart() + */ +int cryptfs_pfe_activate(void) +{ + char crypto_blkdev[MAXPATHLEN]; + char real_blkdev[MAXPATHLEN]; + unsigned long nr_sec; + unsigned char decrypted_master_key[KEY_LEN_BYTES] = {0}; /* N.A */ + int rc = -1; + int fd = -1; /* real_blkdev file descriptor */ + struct crypt_mnt_ftr crypt_ftr = {0}; + char encrypted_state[PROPERTY_VALUE_MAX] = {0}; + char pfe_state[PROPERTY_VALUE_MAX] = {0}; + char lockid[32] = { 0}; + char key_loc[PROPERTY_VALUE_MAX] = {0}; + int retry = 5; /* mount retry, /data might be hold by services going down */ + + SLOGI("Start PFE mapping upon activation.."); + + property_get("vold.pfe", pfe_state, ""); + if (!strcmp(pfe_state, "activated") ) { + SLOGI("PFE already activated!"); + return 0; + } + + /* If FDE actiavted, no mapping required, just set a flag in the footer */ + property_get("ro.crypto.state", encrypted_state, ""); + if (strcmp(encrypted_state, "encrypted") == 0) { + SLOGI("FDE activated , no need to map crypto-device"); + + /* get the footer */ + if (get_crypt_ftr_and_key(&crypt_ftr)) { + SLOGE("Error getting crypt footer"); + return -1; + } + + /* Set PFE flag */ + crypt_ftr.flags |= CRYPT_PFE_ACTIVATED; + + /* save the flag in the footer */ + if (put_crypt_ftr_and_key(&crypt_ftr)) { + SLOGE("Error saving crypt footer"); + return -1; + } + + property_set("vold.pfe", "activated"); + SLOGI("%s: PFE-Enable (after FDE) completed OK", __func__); + + return 0; + } + + property_set("vold.pfe", ""); /* reset prop */ + + fs_mgr_get_crypt_info(fstab, key_loc, 0, sizeof(key_loc)); + + fs_mgr_get_crypt_info(fstab, 0, real_blkdev, sizeof(real_blkdev)); + + /* Get the size of the real block device */ + fd = open(real_blkdev, O_RDONLY); + if ( (nr_sec = get_blkdev_size(fd)) == 0) { + SLOGE("Cannot get size of block device %s", real_blkdev); + goto get_size_error; + } + close(fd); + + /* Get a wakelock as this may take a while, and we don't want the + * device to sleep on us. We'll grab a partial wakelock, and if the UI + * wants to keep the screen on, it can grab a full wakelock. + */ + snprintf(lockid, sizeof(lockid), "enablecrypto%d", (int) getpid()); + acquire_wake_lock(PARTIAL_WAKE_LOCK, lockid); + + /* Allow caller to get response */ + sleep(1); + + /* The init files are setup to stop the class main and late start when + * vold sets trigger_shutdown_framework. + */ + property_set("vold.decrypt", "trigger_shutdown_framework"); + SLOGI("Just asked init to shut down class main"); + + if (vold_unmountAllAsecs()) { + /* Just report the error. If any are left mounted, + * umounting /data below will fail and handle the error. + */ + SLOGE("Error unmounting internal asecs"); + } + + /* Now unmount the /data partition. */ + if (wait_and_unmount(DATA_MNT_POINT, false)) { + SLOGE("%s: Unmount /data failed", __func__); + goto unmount_error; + } + + /* Start the actual work of making an encrypted filesystem */ + /* Initialize a crypt_mnt_ftr for the partition */ + cryptfs_init_crypt_mnt_ftr(&crypt_ftr); + + if (!strcmp(key_loc, KEY_IN_FOOTER)) { + SLOGI("Use fs_size from footer"); + crypt_ftr.fs_size = nr_sec - (CRYPT_FOOTER_OFFSET / 512); + } else { + SLOGI("Use fs_size from get-blk-size"); + crypt_ftr.fs_size = nr_sec; + } + + strlcpy((char *)crypt_ftr.crypto_type_name, "aes-xts", MAX_CRYPTO_TYPE_NAME_LEN); + + rc = create_crypto_blk_dev(&crypt_ftr, decrypted_master_key, + real_blkdev, crypto_blkdev, "userdata"); + if (rc) { + SLOGE("%s: Create crypto block-device failed !", __func__); + goto mapping_err; + } + + sleep(1); // Sleep before mount + + /* If that succeeded, then mount the decrypted filesystem */ + while (retry) { + rc = fs_mgr_do_mount(fstab, DATA_MNT_POINT, crypto_blkdev, 0); + if (rc) { + SLOGE("%s: Mount /data to crypto device FAILED !", __func__); + if (retry == 0) { + goto mapping_err; + } + } else { + SLOGI("%s: Mount /data to crypto device OK !", __func__); + break; + } + retry--; + sleep(3); // Sleep few seconds before retry + } + + property_set("vold.decrypt", "trigger_load_persist_props"); + /* Create necessary paths on /data */ + if (prep_data_fs()) { + SLOGE("%s: prep_data_fs() FAILED !", __func__); + goto mapping_err; + } + + /* startup service classes main and late_start */ + property_set("vold.decrypt", "trigger_restart_framework"); + SLOGI("Just triggered restart_framework"); + + /* Give it a few moments to get started */ + sleep(1); + + release_wake_lock(lockid); + + crypt_ftr.flags |= CRYPT_PFE_ACTIVATED; + + /* Write the footer with flag activated */ + put_crypt_ftr_and_key(&crypt_ftr); + + property_set("vold.pfe", "activated"); + + SLOGI("%s: PFE-Enable (no FDE) completed OK", __func__); + return 0; + +error_shutting_down: +mapping_err: + delete_crypto_blk_dev("userdata"); +error_unencrypted: +random_key_error: +unmount_error: + release_wake_lock(lockid); +get_size_error: + property_set("vold.pfe", "failed"); + SLOGI("%s: PFE Enable Failed", __func__); + + return -1; +} + +/* Clear PFE activated flag. */ +int cryptfs_pfe_deactivate(void) +{ + struct crypt_mnt_ftr crypt_ftr; + + SLOGI("Start cryptfs_pfe_deactivate"); + + /* get the footer */ + if (get_crypt_ftr_and_key(&crypt_ftr)) { + SLOGE("Error getting crypt footer"); + return -1; + } + + /* clear the flag */ + crypt_ftr.flags &= ~CRYPT_PFE_ACTIVATED; + + /* save the footer */ + if (put_crypt_ftr_and_key(&crypt_ftr)) { + SLOGE("Error saving crypt footer"); + return -1; + } + + property_set("vold.pfe", "deactivated"); + + return 0; +} + +/* + * Mount /data to dm-req-crypt on BOOT (if activated), same as after FDE. + * + * Note: After FDE is encrypted, the following commands are called on boot: + * 1. cryptocomplete -> cryptfs_crypto_complete() + * 2. checkpw -> cryptfs_check_passwd() + * 3. restart -> cryptfs_restart() + * + * see test_mount_encrypted_fs() + */ +int cryptfs_pfe_boot(void) +{ + struct crypt_mnt_ftr crypt_ftr = {0}; + + SLOGI("Check if PFE is activated on Boot"); + + if (get_crypt_ftr_and_key(&crypt_ftr)) { + SLOGE("Error getting crypt footer and key"); + goto exit_err; + } + + if (!(crypt_ftr.flags & CRYPT_PFE_ACTIVATED) ) { + SLOGE("PFE not activated"); + goto exit_err; + } + + if (crypt_ftr.flags & CRYPT_FDE_COMPLETED) { + SLOGI("FDE Completed , let FDE do the crypto mount"); + goto exit_err; + } + + /* Mount /data , same as on activate command */ + return cryptfs_pfe_activate(); + +exit_err: + property_set("vold.pfe", "deactivated"); /* Default */ + return -1; +} + int cryptfs_enable(char *howarg, int type, char *passwd, int allow_reboot) { char* adjusted_passwd = adjust_passwd(passwd); @@ -3294,7 +3604,11 @@ int cryptfs_changepw(int crypt_type, const char *newpw) /* save the key */ put_crypt_ftr_and_key(&crypt_ftr); - free(adjusted_passwd); +#ifdef CONFIG_HW_DISK_ENCRYPTION + update_hw_device_encryption_key(crypt_type == CRYPT_TYPE_DEFAULT ? + DEFAULT_PASSWORD : newpw, + (char*)crypt_ftr.crypto_type_name); +#endif return 0; } diff --git a/cryptfs.h b/cryptfs.h index 66e0b4cce..a72844fad 100644 --- a/cryptfs.h +++ b/cryptfs.h @@ -52,6 +52,8 @@ correctly marked partial encryption */ #define CRYPT_DATA_CORRUPT 0x8 /* Set when encryption is fine, but the underlying volume is corrupt */ +#define CRYPT_PFE_ACTIVATED 0x10 /* Per-File-Encryption is activated. */ +#define CRYPT_FDE_COMPLETED 0x20 /* Full-Disk-Encryption is completed. */ /* Allowed values for type in the structure below */ #define CRYPT_TYPE_PASSWORD 0 /* master_key is encrypted with a password @@ -210,6 +212,9 @@ extern "C" { int cryptfs_crypto_complete(void); int cryptfs_check_passwd(char *pw); + int cryptfs_pfe_activate(void); + int cryptfs_pfe_deactivate(void); + int cryptfs_pfe_boot(void); int cryptfs_verify_passwd(char *newpw); int cryptfs_restart(void); int cryptfs_enable(char *flag, int type, char *passwd, int allow_reboot); diff --git a/main.cpp b/main.cpp index d4b7d28d0..54e8c147a 100644 --- a/main.cpp +++ b/main.cpp @@ -43,7 +43,7 @@ static void coldboot(const char *path); #define FSTAB_PREFIX "/fstab." struct fstab *fstab; -int main() { +extern "C" int vold_main() { VolumeManager *vm; CommandListener *cl; @@ -81,6 +81,12 @@ int main() { SLOGE("Error reading configuration (%s)... continuing anyways", strerror(errno)); } + /* + * Mount /data to dm-req-crypt if PFE activated. + * Must call after process_config() because of fstab initialization. + */ + cryptfs_pfe_boot(); + if (nm->start()) { SLOGE("Unable to start NetlinkManager (%s)", strerror(errno)); exit(1); @@ -182,8 +188,7 @@ static int process_config(VolumeManager *vm) flags |= VOL_ENCRYPTABLE; } /* Only set this flag if there is not an emulated sd card */ - if (fs_mgr_is_noemulatedsd(&fstab->recs[i]) && - !strcmp(fstab->recs[i].fs_type, "vfat")) { + if (fs_mgr_is_noemulatedsd(&fstab->recs[i])) { flags |= VOL_PROVIDES_ASEC; } dv = new DirectVolume(vm, &(fstab->recs[i]), flags); diff --git a/vdc.c b/vdc.c index dcd2bc3c0..f44852f0b 100644 --- a/vdc.c +++ b/vdc.c @@ -36,7 +36,7 @@ static void usage(char *progname); static int do_monitor(int sock, int stop_after_cmd); static int do_cmd(int sock, int argc, char **argv); -int main(int argc, char **argv) { +int vdc_main(int argc, char **argv) { int sock; int wait_for_socket; char *progname; @@ -168,3 +168,8 @@ static void usage(char *progname) { "Usage: %s [--wait] | [arg1] [arg2...]\n", progname); } +#ifndef MINIVOLD +int main(int argc, char **argv) { + return vdc_main(argc, argv); +} +#endif diff --git a/vold.c b/vold.c new file mode 100644 index 000000000..689b2e694 --- /dev/null +++ b/vold.c @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2013 The CyanogenMod 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 "vold.h" + +int main(int argc, char **argv) { + return vold_main(); +} diff --git a/vold.h b/vold.h new file mode 100644 index 000000000..9e7ce6637 --- /dev/null +++ b/vold.h @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2013 The CyanogenMod 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. + */ + +#ifndef _VOLD_H +#define _VOLD_H + +#ifdef __cplusplus +extern "C" { +#endif + +int vold_main(); + +#ifdef __cplusplus +} +#endif +#endif +