Merge tag 'LA.UM.5.8.r1-01600-8x98.0' into n-mr1
"LA.UM.5.8.r1-01600-8x98.0"
diff --git a/Android.mk b/Android.mk
index cabf9b3..32dc9c0 100644
--- a/Android.mk
+++ b/Android.mk
@@ -3,22 +3,23 @@
common_src_files := \
VolumeManager.cpp \
CommandListener.cpp \
- CryptCommandListener.cpp \
VoldCommand.cpp \
NetlinkManager.cpp \
NetlinkHandler.cpp \
Process.cpp \
+ fs/Exfat.cpp \
fs/Ext4.cpp \
fs/F2fs.cpp \
+ fs/Ntfs.cpp \
fs/Vfat.cpp \
Loop.cpp \
Devmapper.cpp \
ResponseCode.cpp \
CheckBattery.cpp \
- Ext4Crypt.cpp \
VoldUtil.c \
cryptfs.c \
Disk.cpp \
+ DiskPartition.cpp \
VolumeBase.cpp \
PublicVolume.cpp \
PrivateVolume.cpp \
@@ -27,10 +28,15 @@
MoveTask.cpp \
Benchmark.cpp \
TrimTask.cpp \
+ secontext.cpp \
+ main.cpp
+
+crypto_src_files := \
+ CryptCommandListener.cpp \
+ Ext4Crypt.cpp \
Keymaster.cpp \
KeyStorage.cpp \
- ScryptParameters.cpp \
- secontext.cpp \
+ ScryptParameters.cpp
common_c_includes := \
system/extras/ext4_utils \
@@ -39,45 +45,63 @@
frameworks/native/include \
system/security/keystore \
hardware/libhardware/include/hardware \
- system/security/softkeymaster/include/keymaster
+ system/security/softkeymaster/include/keymaster \
+ external/e2fsprogs/lib
-common_shared_libraries := \
+common_libraries := \
libsysutils \
libbinder \
libcutils \
liblog \
libdiskconfig \
- libhardware_legacy \
liblogwrap \
- libext4_utils \
libf2fs_sparseblock \
- libcrypto \
libselinux \
- libutils \
+ libutils
+
+common_shared_libraries := \
+ $(common_libraries) \
+ libhardware_legacy \
+ libext4_utils \
+ libcrypto \
libhardware \
libsoftkeymaster \
libbase \
libkeymaster_messages \
+ libext2_blkid
common_static_libraries := \
libbootloader_message \
libfs_mgr \
libfec \
libfec_rs \
+ libext4_utils_static \
+ libsparse_static \
libsquashfs_utils \
libscrypt_static \
libmincrypt \
libbatteryservice \
+ libext2_blkid \
+ libext2_uuid_static \
+ libz
vold_conlyflags := -std=c11
vold_cflags := -Werror -Wall -Wno-missing-field-initializers -Wno-unused-variable -Wno-unused-parameter
+ifeq ($(TARGET_KERNEL_HAVE_EXFAT),true)
+vold_cflags += -DCONFIG_KERNEL_HAVE_EXFAT
+endif
+
+ifeq ($(TARGET_KERNEL_HAVE_NTFS),true)
+vold_cflags += -DCONFIG_KERNEL_HAVE_NTFS
+endif
+
include $(CLEAR_VARS)
LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
LOCAL_MODULE := libvold
LOCAL_CLANG := true
-LOCAL_SRC_FILES := $(common_src_files)
+LOCAL_SRC_FILES := $(common_src_files) $(crypto_src_files)
LOCAL_C_INCLUDES := $(common_c_includes)
LOCAL_SHARED_LIBRARIES := $(common_shared_libraries)
LOCAL_STATIC_LIBRARIES := $(common_static_libraries)
@@ -85,6 +109,12 @@
LOCAL_CFLAGS := $(vold_cflags)
LOCAL_CONLYFLAGS := $(vold_conlyflags)
+ifeq ($(TARGET_HW_DISK_ENCRYPTION),true)
+TARGET_CRYPTFS_HW_PATH ?= vendor/qcom/opensource/cryptfs_hw
+LOCAL_C_INCLUDES += $(TARGET_CRYPTFS_HW_PATH)
+LOCAL_CFLAGS += -DCONFIG_HW_DISK_ENCRYPTION
+endif
+
include $(BUILD_STATIC_LIBRARY)
include $(CLEAR_VARS)
@@ -93,8 +123,7 @@
LOCAL_MODULE := vold
LOCAL_CLANG := true
LOCAL_SRC_FILES := \
- main.cpp \
- $(common_src_files)
+ vold.c
LOCAL_INIT_RC := vold.rc
@@ -102,14 +131,12 @@
LOCAL_CFLAGS := $(vold_cflags)
LOCAL_CONLYFLAGS := $(vold_conlyflags)
-ifeq ($(TARGET_HW_DISK_ENCRYPTION),true)
-LOCAL_C_INCLUDES += $(TARGET_CRYPTFS_HW_PATH)
-common_shared_libraries += libcryptfs_hw
-LOCAL_CFLAGS += -DCONFIG_HW_DISK_ENCRYPTION
-endif
-
LOCAL_SHARED_LIBRARIES := $(common_shared_libraries)
-LOCAL_STATIC_LIBRARIES := $(common_static_libraries)
+LOCAL_STATIC_LIBRARIES := libvold $(common_static_libraries)
+
+ifeq ($(TARGET_HW_DISK_ENCRYPTION),true)
+LOCAL_SHARED_LIBRARIES += libcryptfs_hw
+endif
include $(BUILD_EXECUTABLE)
@@ -137,3 +164,16 @@
LOCAL_CONLYFLAGS := $(vold_conlyflags)
include $(BUILD_EXECUTABLE)
+
+include $(CLEAR_VARS)
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
+LOCAL_MODULE := libminivold_static
+LOCAL_CLANG := true
+LOCAL_SRC_FILES := $(common_src_files)
+LOCAL_C_INCLUDES := $(common_c_includes) system/core/fs_mgr/include system/core/logwrapper/include
+LOCAL_SHARED_LIBRARIES := $(common_shared_libraries)
+LOCAL_STATIC_LIBRARIES := $(common_static_libraries)
+LOCAL_MODULE_TAGS := eng tests
+LOCAL_CFLAGS := $(vold_cflags) -DMINIVOLD
+LOCAL_CONLYFLAGS := $(vold_conlyflags)
+include $(BUILD_STATIC_LIBRARY)
diff --git a/CommandListener.cpp b/CommandListener.cpp
index b548a91..56c0946 100644
--- a/CommandListener.cpp
+++ b/CommandListener.cpp
@@ -226,14 +226,15 @@
return sendGenericOkFail(cli, res);
} else if (cmd == "unmount" && argc > 2) {
- // unmount [volId]
+ // unmount [volId] [detach]
std::string id(argv[2]);
auto vol = vm->findVolume(id);
if (vol == nullptr) {
return cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown volume", false);
}
+ bool detach = (argc > 3 && !strcmp(argv[3], "detach"));
- return sendGenericOkFail(cli, vol->unmount());
+ return sendGenericOkFail(cli, vol->unmount(detach));
} else if (cmd == "format" && argc > 3) {
// format [volId] [fsType|auto]
diff --git a/Disk.cpp b/Disk.cpp
index 1e1a63e..5ad375b 100644
--- a/Disk.cpp
+++ b/Disk.cpp
@@ -44,7 +44,11 @@
namespace android {
namespace vold {
+#ifdef MINIVOLD
+static const char* kSgdiskPath = "/sbin/sgdisk";
+#else
static const char* kSgdiskPath = "/system/bin/sgdisk";
+#endif
static const char* kSgdiskToken = " \t\n";
static const char* kSysfsMmcMaxMinors = "/sys/module/mmcblk/parameters/perdev_minors";
@@ -109,8 +113,8 @@
Disk::Disk(const std::string& eventPath, dev_t device,
const std::string& nickname, int flags) :
mDevice(device), mSize(-1), mNickname(nickname), mFlags(flags), mCreated(
- false), mJustPartitioned(false) {
- mId = StringPrintf("disk:%u,%u", major(device), minor(device));
+ false), mJustPartitioned(false), mSkipChange(false) {
+ mId = StringPrintf("disk:%u_%u", major(device), minor(device));
mEventPath = eventPath;
mSysPath = StringPrintf("/sys/%s", eventPath.c_str());
mDevPath = StringPrintf("/dev/block/vold/%s", mId.c_str());
@@ -161,8 +165,10 @@
return OK;
}
-void Disk::createPublicVolume(dev_t device) {
- auto vol = std::shared_ptr<VolumeBase>(new PublicVolume(device));
+void Disk::createPublicVolume(dev_t device,
+ const std::string& fstype /* = "" */,
+ const std::string& mntopts /* = "" */) {
+ auto vol = std::shared_ptr<VolumeBase>(new PublicVolume(device, mNickname, fstype, mntopts));
if (mJustPartitioned) {
LOG(DEBUG) << "Device just partitioned; silently formatting";
vol->setSilent(true);
@@ -216,6 +222,11 @@
}
status_t Disk::readMetadata() {
+
+ if (mSkipChange) {
+ return OK;
+ }
+
mSize = -1;
mLabel.clear();
@@ -285,6 +296,12 @@
return -ENOTSUP;
}
+ if (mSkipChange) {
+ mSkipChange = false;
+ LOG(INFO) << "Skip first change";
+ return OK;
+ }
+
destroyAllVolumes();
// Parse partition table
@@ -332,9 +349,11 @@
switch (strtol(type, nullptr, 16)) {
case 0x06: // FAT16
+ case 0x07: // NTFS/exFAT
case 0x0b: // W95 FAT32 (LBA)
case 0x0c: // W95 FAT32 (LBA)
case 0x0e: // W95 FAT16 (LBA)
+ case 0x83: // Linux EXT4/F2FS/...
createPublicVolume(partDevice);
break;
}
@@ -383,9 +402,46 @@
destroyAllVolumes();
mJustPartitioned = true;
- // First nuke any existing partition table
+ // Determine if we're coming from MBR
std::vector<std::string> cmd;
cmd.push_back(kSgdiskPath);
+ cmd.push_back("--android-dump");
+ cmd.push_back(mDevPath);
+
+ std::vector<std::string> output;
+ res = ForkExecvp(cmd, output);
+ if (res != OK) {
+ LOG(WARNING) << "sgdisk failed to scan " << mDevPath;
+ mJustPartitioned = false;
+ return res;
+ }
+
+ Table table = Table::kUnknown;
+ for (auto line : output) {
+ char* cline = (char*) line.c_str();
+ char* token = strtok(cline, kSgdiskToken);
+ if (token == nullptr) continue;
+
+ if (!strcmp(token, "DISK")) {
+ const char* type = strtok(nullptr, kSgdiskToken);
+ if (!strcmp(type, "mbr")) {
+ table = Table::kMbr;
+ break;
+ } else if (!strcmp(type, "gpt")) {
+ table = Table::kGpt;
+ break;
+ }
+ }
+ }
+
+ if (table == Table::kMbr) {
+ LOG(INFO) << "skip first disk change event due to MBR -> GPT switch";
+ mSkipChange = true;
+ }
+
+ // First nuke any existing partition table
+ cmd.clear();
+ cmd.push_back(kSgdiskPath);
cmd.push_back("--zap-all");
cmd.push_back(mDevPath);
diff --git a/Disk.h b/Disk.h
index 77ec7df..20f5522 100644
--- a/Disk.h
+++ b/Disk.h
@@ -52,6 +52,8 @@
kUsb = 1 << 3,
/* Flag that disk is EMMC internal */
kEmmc = 1 << 4,
+ /* Flag that disk is non-removable */
+ kNonRemovable = 1 << 5,
};
const std::string& getId() { return mId; }
@@ -67,22 +69,22 @@
void listVolumes(VolumeBase::Type type, std::list<std::string>& list);
- status_t create();
- status_t destroy();
+ virtual status_t create();
+ virtual status_t destroy();
- status_t readMetadata();
- status_t readPartitions();
+ virtual status_t readMetadata();
+ virtual status_t readPartitions();
status_t unmountAll();
- status_t partitionPublic();
- status_t partitionPrivate();
- status_t partitionMixed(int8_t ratio);
+ virtual status_t partitionPublic();
+ virtual status_t partitionPrivate();
+ virtual status_t partitionMixed(int8_t ratio);
void notifyEvent(int msg);
void notifyEvent(int msg, const std::string& value);
-private:
+protected:
/* ID that uniquely references this disk */
std::string mId;
/* Original event path */
@@ -107,8 +109,12 @@
bool mCreated;
/* Flag that we just partitioned and should format all volumes */
bool mJustPartitioned;
+ /* Flag that we need to skip first disk change events after partitioning*/
+ bool mSkipChange;
- void createPublicVolume(dev_t device);
+ void createPublicVolume(dev_t device,
+ const std::string& fstype = "",
+ const std::string& mntopts = "");
void createPrivateVolume(dev_t device, const std::string& partGuid);
void destroyAllVolumes();
diff --git a/DiskPartition.cpp b/DiskPartition.cpp
new file mode 100644
index 0000000..13b084b
--- /dev/null
+++ b/DiskPartition.cpp
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2015 Cyanogen, 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 "DiskPartition.h"
+#include "PublicVolume.h"
+#include "PrivateVolume.h"
+#include "Utils.h"
+#include "VolumeBase.h"
+#include "VolumeManager.h"
+#include "ResponseCode.h"
+
+#include <android-base/file.h>
+#include <android-base/stringprintf.h>
+#include <android-base/logging.h>
+#include <diskconfig/diskconfig.h>
+
+#include <vector>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mount.h>
+
+using android::base::ReadFileToString;
+using android::base::WriteStringToFile;
+using android::base::StringPrintf;
+
+namespace android {
+namespace vold {
+
+DiskPartition::DiskPartition(const std::string& eventPath, dev_t device,
+ const std::string& nickname, int flags, int partnum,
+ const std::string& fstype /* = "" */, const std::string& mntopts /* = "" */) :
+ Disk(eventPath, device, nickname, flags),
+ mPartNum(partnum),
+ mFsType(fstype),
+ mMntOpts(mntopts) {
+ // Empty
+}
+
+DiskPartition::~DiskPartition() {
+ // Empty
+}
+
+status_t DiskPartition::create() {
+ CHECK(!mCreated);
+ mCreated = true;
+ notifyEvent(ResponseCode::DiskCreated, StringPrintf("%d", mFlags));
+ dev_t partDevice = makedev(major(mDevice), minor(mDevice) + mPartNum);
+ createPublicVolume(partDevice, mFsType, mMntOpts);
+ return OK;
+}
+
+status_t DiskPartition::destroy() {
+ CHECK(mCreated);
+ destroyAllVolumes();
+ mCreated = false;
+ notifyEvent(ResponseCode::DiskDestroyed);
+ return OK;
+}
+
+status_t DiskPartition::partitionPublic() {
+ return -1;
+}
+
+status_t DiskPartition::partitionPrivate() {
+ return -1;
+}
+
+status_t DiskPartition::partitionMixed(int8_t ratio) {
+ return -1;
+}
+
+} // namespace vold
+} // namespace android
diff --git a/DiskPartition.h b/DiskPartition.h
new file mode 100644
index 0000000..b1fa33b
--- /dev/null
+++ b/DiskPartition.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2015 Cyanogen, 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 ANDROID_VOLD_DISKPARTITION_H
+#define ANDROID_VOLD_DISKPARTITION_H
+
+#include "Disk.h"
+
+namespace android {
+namespace vold {
+
+/*
+ * Representation of a single partition on physical media. Useful for
+ * single media partitions such as "internal" sdcard partitions.
+ */
+
+class DiskPartition : public Disk {
+public:
+ DiskPartition(const std::string& eventPath, dev_t device,
+ const std::string& nickname,
+ int flags, int partnum,
+ const std::string& fstype = "", const std::string& mntopts = "");
+ virtual ~DiskPartition();
+
+ virtual status_t create();
+ virtual status_t destroy();
+
+ virtual status_t partitionPublic();
+ virtual status_t partitionPrivate();
+ virtual status_t partitionMixed(int8_t ratio);
+
+private:
+ /* Partition number */
+ int mPartNum;
+ /* Filesystem type */
+ std::string mFsType;
+ /* Mount options */
+ std::string mMntOpts;
+};
+
+} // namespace vold
+} // namespace android
+
+#endif
diff --git a/EmulatedVolume.cpp b/EmulatedVolume.cpp
index 581c322..1d1c12e 100644
--- a/EmulatedVolume.cpp
+++ b/EmulatedVolume.cpp
@@ -16,6 +16,7 @@
#include "EmulatedVolume.h"
#include "Utils.h"
+#include "ResponseCode.h"
#include <android-base/stringprintf.h>
#include <android-base/logging.h>
@@ -34,7 +35,11 @@
namespace android {
namespace vold {
+#ifdef MINIVOLD
+static const char* kFusePath = "/sbin/sdcard";
+#else
static const char* kFusePath = "/system/bin/sdcard";
+#endif
EmulatedVolume::EmulatedVolume(const std::string& rawPath) :
VolumeBase(Type::kEmulated), mFusePid(0) {
@@ -45,7 +50,7 @@
EmulatedVolume::EmulatedVolume(const std::string& rawPath, dev_t device,
const std::string& fsUuid) : VolumeBase(Type::kEmulated), mFusePid(0) {
- setId(StringPrintf("emulated:%u,%u", major(device), minor(device)));
+ setId(StringPrintf("emulated:%u_%u", major(device), minor(device)));
mRawPath = rawPath;
mLabel = fsUuid;
}
@@ -53,6 +58,13 @@
EmulatedVolume::~EmulatedVolume() {
}
+status_t EmulatedVolume::doCreate() {
+ if (mLabel.size() > 0) {
+ notifyEvent(ResponseCode::VolumeFsLabelChanged, mLabel);
+ }
+ return OK;
+}
+
status_t EmulatedVolume::doMount() {
// We could have migrated storage to an adopted private volume, so always
// call primary storage "emulated" to avoid media rescans.
@@ -106,7 +118,7 @@
return OK;
}
-status_t EmulatedVolume::doUnmount() {
+status_t EmulatedVolume::doUnmount(bool detach /* = false */) {
// Unmount the storage before we kill the FUSE process. If we kill
// the FUSE process first, most file system operations will return
// ENOTCONN until the unmount completes. This is an exotic and unusual
diff --git a/EmulatedVolume.h b/EmulatedVolume.h
index 09686c1..ea397fa 100644
--- a/EmulatedVolume.h
+++ b/EmulatedVolume.h
@@ -42,8 +42,9 @@
virtual ~EmulatedVolume();
protected:
+ status_t doCreate() override;
status_t doMount() override;
- status_t doUnmount() override;
+ status_t doUnmount(bool detach = false) override;
private:
std::string mRawPath;
diff --git a/PrivateVolume.cpp b/PrivateVolume.cpp
index e5809fb..c83a6ed 100644
--- a/PrivateVolume.cpp
+++ b/PrivateVolume.cpp
@@ -45,7 +45,7 @@
PrivateVolume::PrivateVolume(dev_t device, const std::string& keyRaw) :
VolumeBase(Type::kPrivate), mRawDevice(device), mKeyRaw(keyRaw) {
- setId(StringPrintf("private:%u,%u", major(device), minor(device)));
+ setId(StringPrintf("private:%u_%u", major(device), minor(device)));
mRawDevPath = StringPrintf("/dev/block/vold/%s", getId().c_str());
}
@@ -105,7 +105,7 @@
}
if (mFsType == "ext4") {
- int res = ext4::Check(mDmDevPath, mPath);
+ int res = ext4::Check(mDmDevPath, mPath, true);
if (res == 0 || res == 1) {
LOG(DEBUG) << getId() << " passed filesystem check";
} else {
@@ -113,13 +113,13 @@
return -EIO;
}
- if (ext4::Mount(mDmDevPath, mPath, false, false, true)) {
+ if (ext4::Mount(mDmDevPath, mPath, false, false, true, "", true)) {
PLOG(ERROR) << getId() << " failed to mount";
return -EIO;
}
} else if (mFsType == "f2fs") {
- int res = f2fs::Check(mDmDevPath);
+ int res = f2fs::Check(mDmDevPath, true);
if (res == 0) {
LOG(DEBUG) << getId() << " passed filesystem check";
} else {
@@ -127,7 +127,7 @@
return -EIO;
}
- if (f2fs::Mount(mDmDevPath, mPath)) {
+ if (f2fs::Mount(mDmDevPath, mPath, "", true)) {
PLOG(ERROR) << getId() << " failed to mount";
return -EIO;
}
@@ -162,7 +162,7 @@
return OK;
}
-status_t PrivateVolume::doUnmount() {
+status_t PrivateVolume::doUnmount(bool detach /* = false */) {
ForceUnmount(mPath);
if (TEMP_FAILURE_RETRY(rmdir(mPath.c_str()))) {
diff --git a/PrivateVolume.h b/PrivateVolume.h
index 95b718d..3a92aba 100644
--- a/PrivateVolume.h
+++ b/PrivateVolume.h
@@ -44,7 +44,7 @@
status_t doCreate() override;
status_t doDestroy() override;
status_t doMount() override;
- status_t doUnmount() override;
+ status_t doUnmount(bool detach = false) override;
status_t doFormat(const std::string& fsType) override;
status_t readMetadata();
diff --git a/PublicVolume.cpp b/PublicVolume.cpp
index 893f928..96698ab 100644
--- a/PublicVolume.cpp
+++ b/PublicVolume.cpp
@@ -14,6 +14,10 @@
* limitations under the License.
*/
+#include "fs/Exfat.h"
+#include "fs/Ext4.h"
+#include "fs/F2fs.h"
+#include "fs/Ntfs.h"
#include "fs/Vfat.h"
#include "PublicVolume.h"
#include "Utils.h"
@@ -37,13 +41,20 @@
namespace android {
namespace vold {
+#ifdef MINIVOLD
+static const char* kFusePath = "/sbin/sdcard";
+#else
static const char* kFusePath = "/system/bin/sdcard";
+#endif
static const char* kAsecPath = "/mnt/secure/asec";
-PublicVolume::PublicVolume(dev_t device) :
- VolumeBase(Type::kPublic), mDevice(device), mFusePid(0) {
- setId(StringPrintf("public:%u,%u", major(device), minor(device)));
+PublicVolume::PublicVolume(dev_t device, const std::string& nickname,
+ const std::string& fstype /* = "" */,
+ const std::string& mntopts /* = "" */) :
+ VolumeBase(Type::kPublic), mDevice(device), mFusePid(0),
+ mFsType(fstype), mFsLabel(nickname), mMntOpts(mntopts) {
+ setId(StringPrintf("public:%u_%u", major(device), minor(device)));
mDevPath = StringPrintf("/dev/block/vold/%s", getId().c_str());
}
@@ -83,6 +94,9 @@
}
status_t PublicVolume::doCreate() {
+ if (mFsLabel.size() > 0) {
+ notifyEvent(ResponseCode::VolumeFsLabelChanged, mFsLabel);
+ }
return CreateDeviceNode(mDevPath, mDevice);
}
@@ -94,27 +108,29 @@
// TODO: expand to support mounting other filesystems
readMetadata();
- if (mFsType != "vfat") {
+ if (!IsFilesystemSupported(mFsType)) {
LOG(ERROR) << getId() << " unsupported filesystem " << mFsType;
return -EIO;
}
- if (vfat::Check(mDevPath)) {
- LOG(ERROR) << getId() << " failed filesystem check";
- return -EIO;
- }
-
// Use UUID as stable name, if available
std::string stableName = getId();
if (!mFsUuid.empty()) {
stableName = mFsUuid;
}
+#ifdef MINIVOLD
+ // In recovery, directly mount to /storage/* since we have no fuse daemon
+ mRawPath = StringPrintf("/storage/%s", stableName.c_str());
+ mFuseDefault = StringPrintf("/storage/%s", stableName.c_str());
+ mFuseRead = StringPrintf("/storage/%s", stableName.c_str());
+ mFuseWrite = StringPrintf("/storage/%s", stableName.c_str());
+#else
mRawPath = StringPrintf("/mnt/media_rw/%s", stableName.c_str());
-
mFuseDefault = StringPrintf("/mnt/runtime/default/%s", stableName.c_str());
mFuseRead = StringPrintf("/mnt/runtime/read/%s", stableName.c_str());
mFuseWrite = StringPrintf("/mnt/runtime/write/%s", stableName.c_str());
+#endif
setInternalPath(mRawPath);
if (getMountFlags() & MountFlags::kVisible) {
@@ -128,12 +144,52 @@
return -errno;
}
- if (vfat::Mount(mDevPath, mRawPath, false, false, false,
- AID_MEDIA_RW, AID_MEDIA_RW, 0007, true)) {
+ int ret = 0;
+ if (mFsType == "exfat") {
+ ret = exfat::Check(mDevPath);
+ } else if (mFsType == "ext4") {
+ ret = ext4::Check(mDevPath, mRawPath, false);
+ } else if (mFsType == "f2fs") {
+ ret = f2fs::Check(mDevPath, false);
+ } else if (mFsType == "ntfs") {
+ ret = ntfs::Check(mDevPath);
+ } else if (mFsType == "vfat") {
+ ret = vfat::Check(mDevPath);
+ } else {
+ LOG(WARNING) << getId() << " unsupported filesystem check, skipping";
+ }
+ if (ret) {
+ LOG(ERROR) << getId() << " failed filesystem check";
+ return -EIO;
+ }
+
+ if (mFsType == "exfat") {
+ ret = exfat::Mount(mDevPath, mRawPath, false, false, false,
+ AID_MEDIA_RW, AID_MEDIA_RW, 0007);
+ } else if (mFsType == "ext4") {
+ ret = ext4::Mount(mDevPath, mRawPath, false, false, true, mMntOpts,
+ false, true);
+ } else if (mFsType == "f2fs") {
+ ret = f2fs::Mount(mDevPath, mRawPath, mMntOpts, false, true);
+ } else if (mFsType == "ntfs") {
+ ret = ntfs::Mount(mDevPath, mRawPath, false, false, false,
+ AID_MEDIA_RW, AID_MEDIA_RW, 0007, true);
+ } else if (mFsType == "vfat") {
+ ret = vfat::Mount(mDevPath, mRawPath, false, false, false,
+ AID_MEDIA_RW, AID_MEDIA_RW, 0007, true);
+ } else {
+ ret = ::mount(mDevPath.c_str(), mRawPath.c_str(), mFsType.c_str(), 0, NULL);
+ }
+ if (ret) {
PLOG(ERROR) << getId() << " failed to mount " << mDevPath;
return -EIO;
}
+#ifdef MINIVOLD
+ // In recovery, don't setup ASEC or FUSE
+ return OK;
+#endif
+
if (getMountFlags() & MountFlags::kPrimary) {
initAsecStage();
}
@@ -193,19 +249,22 @@
return OK;
}
-status_t PublicVolume::doUnmount() {
+status_t PublicVolume::doUnmount(bool detach /* = false */) {
// Unmount the storage before we kill the FUSE process. If we kill
// the FUSE process first, most file system operations will return
// ENOTCONN until the unmount completes. This is an exotic and unusual
// error code and might cause broken behaviour in applications.
KillProcessesUsingPath(getPath());
+#ifndef MINIVOLD
ForceUnmount(kAsecPath);
ForceUnmount(mFuseDefault);
ForceUnmount(mFuseRead);
ForceUnmount(mFuseWrite);
- ForceUnmount(mRawPath);
+#endif
+
+ ForceUnmount(mRawPath, detach);
if (mFusePid > 0) {
kill(mFusePid, SIGTERM);
@@ -227,19 +286,41 @@
}
status_t PublicVolume::doFormat(const std::string& fsType) {
- if (fsType == "vfat" || fsType == "auto") {
- if (WipeBlockDevice(mDevPath) != OK) {
- LOG(WARNING) << getId() << " failed to wipe";
- }
- if (vfat::Format(mDevPath, 0)) {
- LOG(ERROR) << getId() << " failed to format";
- return -errno;
- }
- } else {
+ // "auto" is used for newly partitioned disks (see Disk::partition*)
+ // and thus is restricted to external/removable storage.
+ if (!(IsFilesystemSupported(fsType) || fsType == "auto")) {
LOG(ERROR) << "Unsupported filesystem " << fsType;
return -EINVAL;
}
+ if (WipeBlockDevice(mDevPath) != OK) {
+ LOG(WARNING) << getId() << " failed to wipe";
+ }
+
+ int ret = 0;
+ if (fsType == "auto") {
+ ret = vfat::Format(mDevPath, 0);
+ } else if (fsType == "exfat") {
+ ret = exfat::Format(mDevPath);
+ } else if (fsType == "ext4") {
+ ret = ext4::Format(mDevPath, 0, mRawPath);
+ } else if (fsType == "f2fs") {
+ ret = f2fs::Format(mDevPath);
+ } else if (fsType == "ntfs") {
+ ret = ntfs::Format(mDevPath, 0);
+ } else if (fsType == "vfat") {
+ ret = vfat::Format(mDevPath, 0);
+ } else {
+ LOG(ERROR) << getId() << " unrecognized filesystem " << fsType;
+ ret = -1;
+ errno = EIO;
+ }
+
+ if (ret) {
+ LOG(ERROR) << getId() << " failed to format";
+ return -errno;
+ }
+
return OK;
}
diff --git a/PublicVolume.h b/PublicVolume.h
index 3aa7a73..e9e2926 100644
--- a/PublicVolume.h
+++ b/PublicVolume.h
@@ -39,14 +39,15 @@
*/
class PublicVolume : public VolumeBase {
public:
- explicit PublicVolume(dev_t device);
+ PublicVolume(dev_t device, const std::string& nickname,
+ const std::string& mntopts = "", const std::string& fstype = "");
virtual ~PublicVolume();
protected:
status_t doCreate() override;
status_t doDestroy() override;
status_t doMount() override;
- status_t doUnmount() override;
+ status_t doUnmount(bool detach = false) override;
status_t doFormat(const std::string& fsType) override;
status_t readMetadata();
@@ -73,6 +74,8 @@
std::string mFsUuid;
/* User-visible filesystem label */
std::string mFsLabel;
+ /* Mount options */
+ std::string mMntOpts;
DISALLOW_COPY_AND_ASSIGN(PublicVolume);
};
diff --git a/Utils.cpp b/Utils.cpp
index 014055b..cc66101 100644
--- a/Utils.cpp
+++ b/Utils.cpp
@@ -21,6 +21,9 @@
#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/stringprintf.h>
+#include "fs/Exfat.h"
+#include "fs/Ntfs.h"
+
#include <cutils/fs.h>
#include <cutils/properties.h>
#include <private/android_filesystem_config.h>
@@ -52,7 +55,11 @@
security_context_t sFsckContext = nullptr;
security_context_t sFsckUntrustedContext = nullptr;
+#ifdef MINIVOLD
+#include <blkid/blkid.h>
+#else
static const char* kBlkidPath = "/system/bin/blkid";
+#endif
static const char* kKeyPath = "/data/misc/vold";
static const char* kProcFilesystems = "/proc/filesystems";
@@ -118,8 +125,15 @@
}
}
-status_t ForceUnmount(const std::string& path) {
+status_t ForceUnmount(const std::string& path, bool detach /* = false */) {
const char* cpath = path.c_str();
+ if (detach) {
+ if (!umount2(path.c_str(), UMOUNT_NOFOLLOW | MNT_DETACH) || errno == EINVAL || errno == ENOENT) {
+ return OK;
+ }
+ PLOG(WARNING) << "Failed to unmount " << path;
+ return -errno;
+ }
if (!umount2(cpath, UMOUNT_NOFOLLOW) || errno == EINVAL || errno == ENOENT) {
return OK;
}
@@ -184,10 +198,21 @@
static status_t readMetadata(const std::string& path, std::string& fsType,
std::string& fsUuid, std::string& fsLabel, bool untrusted) {
- fsType.clear();
- fsUuid.clear();
- fsLabel.clear();
-
+#ifdef MINIVOLD
+ char *val = NULL;
+ val = blkid_get_tag_value(NULL, "TYPE", path.c_str());
+ if (val) {
+ fsType = val;
+ }
+ val = blkid_get_tag_value(NULL, "UUID", path.c_str());
+ if (val) {
+ fsUuid = val;
+ }
+ val = blkid_get_tag_value(NULL, "LABEL", path.c_str());
+ if (val) {
+ fsUuid = val;
+ }
+#else
std::vector<std::string> cmd;
cmd.push_back(kBlkidPath);
cmd.push_back("-c");
@@ -226,6 +251,7 @@
fsLabel = value;
}
}
+#endif
return OK;
}
@@ -511,6 +537,11 @@
PLOG(ERROR) << "Failed to read supported filesystems";
return false;
}
+
+ /* fuse filesystems */
+ supported.append("fuse\tntfs\n"
+ "fuse\texfat\n");
+
return supported.find(fsType + "\n") != std::string::npos;
}
diff --git a/Utils.h b/Utils.h
index 4bfd8e9..3dfb8d9 100644
--- a/Utils.h
+++ b/Utils.h
@@ -50,7 +50,7 @@
status_t PrepareDir(const std::string& path, mode_t mode, uid_t uid, gid_t gid);
/* Really unmounts the path, killing active processes along the way */
-status_t ForceUnmount(const std::string& path);
+status_t ForceUnmount(const std::string& path, bool detach = false);
/* Kills any processes using given path */
status_t KillProcessesUsingPath(const std::string& path);
diff --git a/VolumeBase.cpp b/VolumeBase.cpp
index ea4d372..fdb5399 100644
--- a/VolumeBase.cpp
+++ b/VolumeBase.cpp
@@ -161,12 +161,14 @@
}
status_t VolumeBase::create() {
- CHECK(!mCreated);
+ if (mCreated) {
+ return BAD_VALUE;
+ }
mCreated = true;
- status_t res = doCreate();
notifyEvent(ResponseCode::VolumeCreated,
StringPrintf("%d \"%s\" \"%s\"", mType, mDiskId.c_str(), mPartGuid.c_str()));
+ status_t res = doCreate();
setState(State::kUnmounted);
return res;
}
@@ -176,7 +178,9 @@
}
status_t VolumeBase::destroy() {
- CHECK(mCreated);
+ if (!mCreated) {
+ return NO_INIT;
+ }
if (mState == State::kMounted) {
unmount();
@@ -212,7 +216,7 @@
return res;
}
-status_t VolumeBase::unmount() {
+status_t VolumeBase::unmount(bool detach /* = false */) {
if (mState != State::kMounted) {
LOG(WARNING) << getId() << " unmount requires state mounted";
return -EBUSY;
@@ -227,7 +231,7 @@
}
mVolumes.clear();
- status_t res = doUnmount();
+ status_t res = doUnmount(detach);
setState(State::kUnmounted);
return res;
}
diff --git a/VolumeBase.h b/VolumeBase.h
index d417019..4f2c397 100644
--- a/VolumeBase.h
+++ b/VolumeBase.h
@@ -98,7 +98,7 @@
status_t create();
status_t destroy();
status_t mount();
- status_t unmount();
+ status_t unmount(bool detach = false);
status_t format(const std::string& fsType);
protected:
@@ -107,7 +107,7 @@
virtual status_t doCreate();
virtual status_t doDestroy();
virtual status_t doMount() = 0;
- virtual status_t doUnmount() = 0;
+ virtual status_t doUnmount(bool detach = false) = 0;
virtual status_t doFormat(const std::string& fsType);
status_t setId(const std::string& id);
diff --git a/VolumeManager.cpp b/VolumeManager.cpp
index 5cc60a1..6c4771c 100644
--- a/VolumeManager.cpp
+++ b/VolumeManager.cpp
@@ -311,8 +311,13 @@
flags |= android::vold::Disk::Flags::kUsb;
}
- auto disk = new android::vold::Disk(eventPath, device,
- source->getNickname(), flags);
+ android::vold::Disk* disk = (source->getPartNum() == -1) ?
+ new android::vold::Disk(eventPath, device,
+ source->getNickname(), flags) :
+ new android::vold::DiskPartition(eventPath, device,
+ source->getNickname(), flags,
+ source->getPartNum(),
+ source->getFsType(), source->getMntOpts());
disk->create();
mDisks.push_back(std::shared_ptr<android::vold::Disk>(disk));
break;
diff --git a/VolumeManager.h b/VolumeManager.h
index 39fc8f9..dfd8c8f 100644
--- a/VolumeManager.h
+++ b/VolumeManager.h
@@ -36,6 +36,7 @@
#include <sysutils/NetlinkEvent.h>
#include "Disk.h"
+#include "DiskPartition.h"
#include "VolumeBase.h"
/* The length of an MD5 hash when encoded into ASCII hex characters */
@@ -96,8 +97,12 @@
class DiskSource {
public:
- DiskSource(const std::string& sysPattern, const std::string& nickname, int flags) :
- mSysPattern(sysPattern), mNickname(nickname), mFlags(flags) {
+ DiskSource(const std::string& sysPattern, const std::string& nickname,
+ int partnum, int flags,
+ const std::string& fstype, const std::string mntopts) :
+ mSysPattern(sysPattern), mNickname(nickname),
+ mPartNum(partnum), mFlags(flags),
+ mFsType(fstype), mMntOpts(mntopts) {
}
bool matches(const std::string& sysPath) {
@@ -105,12 +110,18 @@
}
const std::string& getNickname() { return mNickname; }
+ int getPartNum() { return mPartNum; }
int getFlags() { return mFlags; }
+ const std::string& getFsType() { return mFsType; }
+ const std::string& getMntOpts() { return mMntOpts; }
private:
std::string mSysPattern;
std::string mNickname;
+ int mPartNum;
int mFlags;
+ std::string mFsType;
+ std::string mMntOpts;
};
void addDiskSource(const std::shared_ptr<DiskSource>& diskSource);
diff --git a/cryptfs.c b/cryptfs.c
index ef8fe76..1618619 100644
--- a/cryptfs.c
+++ b/cryptfs.c
@@ -249,6 +249,18 @@
}
#endif
+#ifdef MINIVOLD
+inline int release_wake_lock(const char* id) { return 0; }
+inline int acquire_wake_lock(int lock, const char* id) { return 0; }
+
+static const char* kMkExt4fsPath = "/sbin/mke2fs";
+static const char* kMkF2fsPath = "/sbin/mkfs.f2fs";
+#else
+static const char* kMkExt4fsPath = "/system/bin/make_ext4fs";
+static const char* kMkF2fsPath = "/system/bin/mkfs.f2fs";
+#endif
+
+#ifndef MINIVOLD // no HALs in recovery...
static int keymaster_init(keymaster0_device_t **keymaster0_dev,
keymaster1_device_t **keymaster1_dev)
{
@@ -287,10 +299,14 @@
*keymaster1_dev = NULL;
return rc;
}
+#endif
/* Should we use keymaster? */
static int keymaster_check_compatibility()
{
+#ifdef MINIVOLD
+ return -1;
+#else
keymaster0_device_t *keymaster0_dev = 0;
keymaster1_device_t *keymaster1_dev = 0;
int rc = 0;
@@ -332,11 +348,15 @@
keymaster0_close(keymaster0_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;
keymaster0_device_t *keymaster0_dev = 0;
keymaster1_device_t *keymaster1_dev = 0;
@@ -424,6 +444,7 @@
keymaster1_close(keymaster1_dev);
free(key);
return rc;
+#endif
}
/* This signs the given object using the keymaster key. */
@@ -433,6 +454,9 @@
unsigned char **signature,
size_t *signature_size)
{
+#ifdef MINIVOLD // no HALs in recovery...
+ return -1;
+#else
int rc = 0;
keymaster0_device_t *keymaster0_dev = 0;
keymaster1_device_t *keymaster1_dev = 0;
@@ -558,6 +582,7 @@
keymaster0_close(keymaster0_dev);
return rc;
+#endif
}
/* Store password when userdata is successfully decrypted and mounted.
@@ -2529,7 +2554,7 @@
int rc = -1;
if (type == EXT4_FS) {
- args[0] = "/system/bin/make_ext4fs";
+ args[0] = kMkExt4fsPath;
args[1] = "-a";
args[2] = "/data";
args[3] = "-l";
@@ -2540,7 +2565,7 @@
SLOGI("Making empty filesystem with command %s %s %s %s %s %s\n",
args[0], args[1], args[2], args[3], args[4], args[5]);
} else if (type == F2FS_FS) {
- args[0] = "/system/bin/mkfs.f2fs";
+ args[0] = kMkF2fsPath;
args[1] = "-t";
args[2] = "-d1";
args[3] = crypto_blkdev;
@@ -4214,6 +4239,12 @@
int cryptfs_isConvertibleToFBE()
{
struct fstab_rec* rec = fs_mgr_get_entry_for_mount_point(fstab, DATA_MNT_POINT);
+ // MultiROM secondary ROMs hate fstab assumptions
+ if (!rec) {
+ SLOGE("Can't get fstab record for %s\n", DATA_MNT_POINT);
+ return 0;
+ }
+
return fs_mgr_is_convertible_to_fbe(rec) ? 1 : 0;
}
diff --git a/fs/Exfat.cpp b/fs/Exfat.cpp
new file mode 100644
index 0000000..0e20964
--- /dev/null
+++ b/fs/Exfat.cpp
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2015 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 "Exfat.h"
+#include "Utils.h"
+
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
+
+#include <vector>
+#include <string>
+
+#include <sys/mount.h>
+
+using android::base::StringPrintf;
+
+namespace android {
+namespace vold {
+namespace exfat {
+
+#ifdef MINIVOLD
+static const char* kMkfsPath = "/sbin/mkfs.exfat";
+static const char* kFsckPath = "/sbin/fsck.exfat";
+#ifdef CONFIG_KERNEL_HAVE_EXFAT
+static const char* kMountPath = "/sbin/mount";
+#else
+static const char* kMountPath = "/sbin/mount.exfat";
+#endif
+#else
+static const char* kMkfsPath = "/system/bin/mkfs.exfat";
+static const char* kFsckPath = "/system/bin/fsck.exfat";
+#ifdef CONFIG_KERNEL_HAVE_EXFAT
+static const char* kMountPath = "/system/bin/mount";
+#else
+static const char* kMountPath = "/system/bin/mount.exfat";
+#endif
+#endif
+
+bool IsSupported() {
+ return access(kMkfsPath, X_OK) == 0
+ && access(kFsckPath, X_OK) == 0
+ && access(kMountPath, X_OK) == 0
+ && IsFilesystemSupported("exfat");
+}
+
+status_t Check(const std::string& source) {
+ std::vector<std::string> cmd;
+ cmd.push_back(kFsckPath);
+ cmd.push_back(source);
+
+ // Exfat devices are currently always untrusted
+ return ForkExecvp(cmd, sFsckUntrustedContext);
+}
+
+status_t Mount(const std::string& source, const std::string& target, bool ro,
+ bool remount, bool executable, int ownerUid, int ownerGid, int permMask) {
+ char mountData[255];
+
+ const char* c_source = source.c_str();
+ const char* c_target = target.c_str();
+
+ sprintf(mountData,
+#ifdef CONFIG_KERNEL_HAVE_EXFAT
+ "noatime,nodev,nosuid,uid=%d,gid=%d,fmask=%o,dmask=%o,%s,%s",
+#else
+ "noatime,nodev,nosuid,dirsync,uid=%d,gid=%d,fmask=%o,dmask=%o,%s,%s",
+#endif
+ ownerUid, ownerGid, permMask, permMask,
+ (executable ? "exec" : "noexec"),
+ (ro ? "ro" : "rw"));
+
+ std::vector<std::string> cmd;
+ cmd.push_back(kMountPath);
+#ifdef CONFIG_KERNEL_HAVE_EXFAT
+ cmd.push_back("-t");
+ cmd.push_back("exfat");
+#endif
+ cmd.push_back("-o");
+ cmd.push_back(mountData);
+ cmd.push_back(c_source);
+ cmd.push_back(c_target);
+
+ return ForkExecvp(cmd);
+}
+
+status_t Format(const std::string& source) {
+ std::vector<std::string> cmd;
+ cmd.push_back(kMkfsPath);
+ cmd.push_back(source);
+
+ return ForkExecvp(cmd);
+}
+
+} // namespace exfat
+} // namespace vold
+} // namespace android
diff --git a/fs/Exfat.h b/fs/Exfat.h
new file mode 100644
index 0000000..cd4fb5d
--- /dev/null
+++ b/fs/Exfat.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2015 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 ANDROID_VOLD_EXFAT_H
+#define ANDROID_VOLD_EXFAT_H
+
+#include <utils/Errors.h>
+
+#include <string>
+
+namespace android {
+namespace vold {
+namespace exfat {
+
+bool IsSupported();
+
+status_t Check(const std::string& source);
+status_t Mount(const std::string& source, const std::string& target, bool ro,
+ bool remount, bool executable, int ownerUid, int ownerGid, int permMask);
+status_t Format(const std::string& source);
+
+} // namespace exfat
+} // namespace vold
+} // namespace android
+
+#endif
diff --git a/fs/Ext4.cpp b/fs/Ext4.cpp
index 0bd5b0c..6de0e41 100644
--- a/fs/Ext4.cpp
+++ b/fs/Ext4.cpp
@@ -42,6 +42,7 @@
#include <cutils/log.h>
#include <cutils/properties.h>
#include <logwrap/logwrap.h>
+#include <private/android_filesystem_config.h>
#include <selinux/selinux.h>
#include "Ext4.h"
@@ -54,9 +55,15 @@
namespace vold {
namespace ext4 {
+#ifdef MINIVOLD
+static const char* kResizefsPath = "/sbin/resize2fs";
+static const char* kMkfsPath = "/sbin/mke2fs";
+static const char* kFsckPath = "/sbin/e2fsck";
+#else
static const char* kResizefsPath = "/system/bin/resize2fs";
static const char* kMkfsPath = "/system/bin/make_ext4fs";
static const char* kFsckPath = "/system/bin/e2fsck";
+#endif
bool IsSupported() {
return access(kMkfsPath, X_OK) == 0
@@ -64,7 +71,7 @@
&& IsFilesystemSupported("ext4");
}
-status_t Check(const std::string& source, const std::string& target) {
+status_t Check(const std::string& source, const std::string& target, bool trusted) {
// The following is shamelessly borrowed from fs_mgr.c, so it should be
// kept in sync with any changes over there.
@@ -119,33 +126,53 @@
cmd.push_back("-y");
cmd.push_back(c_source);
- // ext4 devices are currently always trusted
- return ForkExecvp(cmd, sFsckContext);
+ return ForkExecvp(cmd, trusted ? sFsckContext : sFsckUntrustedContext);
}
return 0;
}
status_t Mount(const std::string& source, const std::string& target, bool ro,
- bool remount, bool executable) {
+ bool remount, bool executable, const std::string& opts /* = "" */,
+ bool trusted, bool portable) {
int rc;
unsigned long flags;
+ std::string data(opts);
+
+ if (portable) {
+ if (!data.empty()) {
+ data += ",";
+ }
+ data += "context=u:object_r:sdcard_posix:s0";
+ }
+
const char* c_source = source.c_str();
const char* c_target = target.c_str();
+ const char* c_data = data.c_str();
- flags = MS_NOATIME | MS_NODEV | MS_NOSUID | MS_DIRSYNC;
+ flags = MS_NOATIME | MS_NODEV | MS_NOSUID;
+
+ // Only use MS_DIRSYNC if we're not mounting adopted storage
+ if (!trusted) {
+ flags |= MS_DIRSYNC;
+ }
flags |= (executable ? 0 : MS_NOEXEC);
flags |= (ro ? MS_RDONLY : 0);
flags |= (remount ? MS_REMOUNT : 0);
- rc = mount(c_source, c_target, "ext4", flags, NULL);
+ rc = mount(c_source, c_target, "ext4", flags, c_data);
+
+ if (portable && rc == 0) {
+ chown(c_target, AID_MEDIA_RW, AID_MEDIA_RW);
+ chmod(c_target, 0775);
+ }
if (rc && errno == EROFS) {
SLOGE("%s appears to be a read only filesystem - retrying mount RO", c_source);
flags |= MS_RDONLY;
- rc = mount(c_source, c_target, "ext4", flags, NULL);
+ rc = mount(c_source, c_target, "ext4", flags, c_data);
}
return rc;
diff --git a/fs/Ext4.h b/fs/Ext4.h
index f78dc95..7445fe3 100644
--- a/fs/Ext4.h
+++ b/fs/Ext4.h
@@ -27,9 +27,11 @@
bool IsSupported();
-status_t Check(const std::string& source, const std::string& target);
+status_t Check(const std::string& source, const std::string& target,
+ bool trusted);
status_t Mount(const std::string& source, const std::string& target, bool ro,
- bool remount, bool executable);
+ bool remount, bool executable, const std::string& opts = "",
+ bool trusted = false, bool portable = false);
status_t Format(const std::string& source, unsigned long numSectors,
const std::string& target);
status_t Resize(const std::string& source, unsigned long numSectors);
diff --git a/fs/F2fs.cpp b/fs/F2fs.cpp
index 0d12b07..6afa8ce 100644
--- a/fs/F2fs.cpp
+++ b/fs/F2fs.cpp
@@ -19,11 +19,13 @@
#include <android-base/logging.h>
#include <android-base/stringprintf.h>
+#include <private/android_filesystem_config.h>
#include <vector>
#include <string>
#include <sys/mount.h>
+#include <sys/stat.h>
using android::base::StringPrintf;
@@ -31,8 +33,13 @@
namespace vold {
namespace f2fs {
-static const char* kMkfsPath = "/system/bin/make_f2fs";
+#ifdef MINIVOLD
+static const char* kMkfsPath = "/sbin/mkfs.f2fs";
+static const char* kFsckPath = "/sbin/fsck.f2fs";
+#else
+static const char* kMkfsPath = "/system/bin/mkfs.f2fs";
static const char* kFsckPath = "/system/bin/fsck.f2fs";
+#endif
bool IsSupported() {
return access(kMkfsPath, X_OK) == 0
@@ -40,26 +47,48 @@
&& IsFilesystemSupported("f2fs");
}
-status_t Check(const std::string& source) {
+status_t Check(const std::string& source, bool trusted) {
std::vector<std::string> cmd;
cmd.push_back(kFsckPath);
cmd.push_back("-a");
cmd.push_back(source);
- // f2fs devices are currently always trusted
- return ForkExecvp(cmd, sFsckContext);
+ return ForkExecvp(cmd, trusted ? sFsckContext : sFsckUntrustedContext);
}
-status_t Mount(const std::string& source, const std::string& target) {
+status_t Mount(const std::string& source, const std::string& target,
+ const std::string& opts /* = "" */, bool trusted, bool portable) {
+ std::string data(opts);
+
+ if (portable) {
+ if (!data.empty()) {
+ data += ",";
+ }
+ data += "context=u:object_r:sdcard_posix:s0";
+ }
+
const char* c_source = source.c_str();
const char* c_target = target.c_str();
- unsigned long flags = MS_NOATIME | MS_NODEV | MS_NOSUID | MS_DIRSYNC;
+ const char* c_data = data.c_str();
- int res = mount(c_source, c_target, "f2fs", flags, NULL);
+ unsigned long flags = MS_NOATIME | MS_NODEV | MS_NOSUID;
+
+ // Only use MS_DIRSYNC if we're not mounting adopted storage
+ if (!trusted) {
+ flags |= MS_DIRSYNC;
+ }
+
+ int res = mount(c_source, c_target, "f2fs", flags, c_data);
+
+ if (portable && res == 0) {
+ chown(c_target, AID_MEDIA_RW, AID_MEDIA_RW);
+ chmod(c_target, 0775);
+ }
+
if (res != 0) {
PLOG(ERROR) << "Failed to mount " << source;
if (errno == EROFS) {
- res = mount(c_source, c_target, "f2fs", flags | MS_RDONLY, NULL);
+ res = mount(c_source, c_target, "f2fs", flags | MS_RDONLY, c_data);
if (res != 0) {
PLOG(ERROR) << "Failed to mount read-only " << source;
}
diff --git a/fs/F2fs.h b/fs/F2fs.h
index f710212..ecfc0c7 100644
--- a/fs/F2fs.h
+++ b/fs/F2fs.h
@@ -27,8 +27,10 @@
bool IsSupported();
-status_t Check(const std::string& source);
-status_t Mount(const std::string& source, const std::string& target);
+status_t Check(const std::string& source, bool trusted);
+status_t Mount(const std::string& source, const std::string& target,
+ const std::string& opts = "", bool trusted = false,
+ bool portable = false);
status_t Format(const std::string& source);
} // namespace f2fs
diff --git a/fs/Ntfs.cpp b/fs/Ntfs.cpp
new file mode 100644
index 0000000..c6d0813
--- /dev/null
+++ b/fs/Ntfs.cpp
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2015 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 "Ntfs.h"
+#include "Utils.h"
+
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
+
+#include <vector>
+#include <string>
+
+#include <sys/mount.h>
+
+using android::base::StringPrintf;
+
+namespace android {
+namespace vold {
+namespace ntfs {
+
+#ifdef MINIVOLD
+static const char* kMkfsPath = "/sbin/mkfs.ntfs";
+static const char* kFsckPath = "/sbin/fsck.ntfs";
+#ifdef CONFIG_KERNEL_HAVE_NTFS
+static const char* kMountPath = "/sbin/mount";
+#else
+static const char* kMountPath = "/sbin/mount.ntfs";
+#endif
+#else
+static const char* kMkfsPath = "/system/bin/mkfs.ntfs";
+static const char* kFsckPath = "/system/bin/fsck.ntfs";
+#ifdef CONFIG_KERNEL_HAVE_NTFS
+static const char* kMountPath = "/system/bin/mount";
+#else
+static const char* kMountPath = "/system/bin/mount.ntfs";
+#endif
+#endif
+
+bool IsSupported() {
+ return access(kMkfsPath, X_OK) == 0
+ && access(kFsckPath, X_OK) == 0
+ && access(kMountPath, X_OK) == 0
+ && IsFilesystemSupported("ntfs");
+}
+
+status_t Check(const std::string& source) {
+ std::vector<std::string> cmd;
+ cmd.push_back(kFsckPath);
+ cmd.push_back("-n");
+ cmd.push_back(source);
+
+ // Ntfs devices are currently always untrusted
+ return ForkExecvp(cmd, sFsckUntrustedContext);
+}
+
+status_t Mount(const std::string& source, const std::string& target, bool ro,
+ bool remount, bool executable, int ownerUid, int ownerGid, int permMask,
+ bool createLost) {
+ char mountData[255];
+
+ const char* c_source = source.c_str();
+ const char* c_target = target.c_str();
+
+ sprintf(mountData,
+#ifdef CONFIG_KERNEL_HAVE_NTFS
+ "utf8,uid=%d,gid=%d,fmask=%o,dmask=%o,nodev,nosuid",
+#else
+ "utf8,uid=%d,gid=%d,fmask=%o,dmask=%o,"
+ "shortname=mixed,nodev,nosuid,dirsync",
+#endif
+ ownerUid, ownerGid, permMask, permMask);
+
+ if (!executable)
+ strcat(mountData, ",noexec");
+ if (ro)
+ strcat(mountData, ",ro");
+ if (remount)
+ strcat(mountData, ",remount");
+
+ std::vector<std::string> cmd;
+ cmd.push_back(kMountPath);
+#ifdef CONFIG_KERNEL_HAVE_NTFS
+ cmd.push_back("-t");
+ cmd.push_back("ntfs");
+#endif
+ cmd.push_back("-o");
+ cmd.push_back(mountData);
+ cmd.push_back(c_source);
+ cmd.push_back(c_target);
+
+ return ForkExecvp(cmd);
+}
+
+status_t Format(const std::string& source, bool wipe) {
+ std::vector<std::string> cmd;
+ cmd.push_back(kMkfsPath);
+ if (wipe)
+ cmd.push_back("-f");
+ cmd.push_back(source);
+
+ return ForkExecvp(cmd);
+}
+
+} // namespace ntfs
+} // namespace vold
+} // namespace android
diff --git a/fs/Ntfs.h b/fs/Ntfs.h
new file mode 100644
index 0000000..805fb99
--- /dev/null
+++ b/fs/Ntfs.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2015 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 ANDROID_VOLD_NTFS_H
+#define ANDROID_VOLD_NTFS_H
+
+#include <utils/Errors.h>
+
+#include <string>
+
+namespace android {
+namespace vold {
+namespace ntfs {
+
+bool IsSupported();
+
+status_t Check(const std::string& source);
+status_t Mount(const std::string& source, const std::string& target, bool ro,
+ bool remount, bool executable, int ownerUid, int ownerGid, int permMask,
+ bool createLost);
+status_t Format(const std::string& source, bool wipe);
+
+} // namespace ntfs
+} // namespace vold
+} // namespace android
+
+#endif
diff --git a/main.cpp b/main.cpp
index 68477ac..e1e59b0 100644
--- a/main.cpp
+++ b/main.cpp
@@ -17,7 +17,9 @@
#include "Disk.h"
#include "VolumeManager.h"
#include "CommandListener.h"
+#ifndef MINIVOLD
#include "CryptCommandListener.h"
+#endif
#include "NetlinkManager.h"
#include "cryptfs.h"
#include "sehandle.h"
@@ -45,24 +47,32 @@
struct fstab *fstab;
+#ifdef MINIVOLD
+extern struct selabel_handle *sehandle;
+#else
struct selabel_handle *sehandle;
+#endif
using android::base::StringPrintf;
-int main(int argc, char** argv) {
+extern "C" int vold_main(int argc, char** argv) {
setenv("ANDROID_LOG_TAGS", "*:v", 1);
android::base::InitLogging(argv, android::base::LogdLogger(android::base::SYSTEM));
LOG(INFO) << "Vold 3.0 (the awakening) firing up";
LOG(VERBOSE) << "Detected support for:"
+ << (android::vold::IsFilesystemSupported("exfat") ? " exfat" : "")
<< (android::vold::IsFilesystemSupported("ext4") ? " ext4" : "")
<< (android::vold::IsFilesystemSupported("f2fs") ? " f2fs" : "")
+ << (android::vold::IsFilesystemSupported("ntfs") ? " ntfs" : "")
<< (android::vold::IsFilesystemSupported("vfat") ? " vfat" : "");
VolumeManager *vm;
CommandListener *cl;
+#ifndef MINIVOLD
CryptCommandListener *ccl;
+#endif
NetlinkManager *nm;
parse_args(argc, argv);
@@ -97,7 +107,9 @@
}
cl = new CommandListener();
+#ifndef MINIVOLD
ccl = new CryptCommandListener();
+#endif
vm->setBroadcaster((SocketListener *) cl);
nm->setBroadcaster((SocketListener *) cl);
@@ -128,10 +140,12 @@
exit(1);
}
+#ifndef MINIVOLD
if (ccl->startListener()) {
PLOG(ERROR) << "Unable to start CryptCommandListener";
exit(1);
}
+#endif
// This call should go after listeners are started to avoid
// a deadlock between vold and init (see b/34278978 for details)
@@ -225,13 +239,17 @@
*has_adoptable = false;
for (int i = 0; i < fstab->num_entries; i++) {
if (fs_mgr_is_voldmanaged(&fstab->recs[i])) {
- if (fs_mgr_is_nonremovable(&fstab->recs[i])) {
- LOG(WARNING) << "nonremovable no longer supported; ignoring volume";
- continue;
- }
-
std::string sysPattern(fstab->recs[i].blk_device);
+ std::string fstype;
+ if (fstab->recs[i].fs_type) {
+ fstype = fstab->recs[i].fs_type;
+ }
+ std::string mntopts;
+ if (fstab->recs[i].fs_options) {
+ mntopts = fstab->recs[i].fs_options;
+ }
std::string nickname(fstab->recs[i].label);
+ int partnum = fstab->recs[i].partnum;
int flags = 0;
if (fs_mgr_is_encryptable(&fstab->recs[i])) {
@@ -242,9 +260,13 @@
|| property_get_bool("vold.debug.default_primary", false)) {
flags |= android::vold::Disk::Flags::kDefaultPrimary;
}
+ if (fs_mgr_is_nonremovable(&fstab->recs[i])) {
+ flags |= android::vold::Disk::Flags::kNonRemovable;
+ }
vm->addDiskSource(std::shared_ptr<VolumeManager::DiskSource>(
- new VolumeManager::DiskSource(sysPattern, nickname, flags)));
+ new VolumeManager::DiskSource(sysPattern, nickname, partnum, flags,
+ fstype, mntopts)));
}
}
return 0;
diff --git a/vdc.cpp b/vdc.cpp
index 4eb26cd..0f43dab 100644
--- a/vdc.cpp
+++ b/vdc.cpp
@@ -41,7 +41,7 @@
static constexpr int kCommandTimeoutMs = 20 * 1000;
-int main(int argc, char **argv) {
+extern "C" int vdc_main(int argc, char **argv) {
int sock;
int wait_for_socket;
char *progname;
@@ -172,3 +172,10 @@
fprintf(stderr,
"Usage: %s [--wait] <monitor>|<cmd> [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 0000000..9dc9f10
--- /dev/null
+++ b/vold.c
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2015 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(argc, argv);
+}
diff --git a/vold.h b/vold.h
new file mode 100644
index 0000000..a873992
--- /dev/null
+++ b/vold.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2015 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
+