diff --git a/Android.mk b/Android.mk index f5cd54d..4bab604 100644 --- a/Android.mk +++ b/Android.mk @@ -8,8 +8,9 @@ common_src_files := \ NetlinkManager.cpp \ NetlinkHandler.cpp \ Process.cpp \ - Ext4.cpp \ - Fat.cpp \ + fs/Ext4.cpp \ + fs/F2fs.cpp \ + fs/Vfat.cpp \ Loop.cpp \ Devmapper.cpp \ ResponseCode.cpp \ diff --git a/CommandListener.cpp b/CommandListener.cpp index 2bfd58c..1f89b6a 100644 --- a/CommandListener.cpp +++ b/CommandListener.cpp @@ -223,15 +223,16 @@ int CommandListener::VolumeCmd::runCommand(SocketClient *cli, return sendGenericOkFail(cli, vol->unmount()); - } else if (cmd == "format" && argc > 2) { - // format [volId] + } else if (cmd == "format" && argc > 3) { + // format [volId] [fsType|auto] std::string id(argv[2]); + std::string fsType(argv[3]); auto vol = vm->findVolume(id); if (vol == nullptr) { return cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown volume", false); } - return sendGenericOkFail(cli, vol->format()); + return sendGenericOkFail(cli, vol->format(fsType)); } else if (cmd == "move_storage" && argc > 3) { // move_storage [fromVolId] [toVolId] diff --git a/Disk.cpp b/Disk.cpp index 5b5d769..a536dbf 100644 --- a/Disk.cpp +++ b/Disk.cpp @@ -136,7 +136,7 @@ void Disk::createPublicVolume(dev_t device) { LOG(DEBUG) << "Device just partitioned; silently formatting"; vol->setSilent(true); vol->create(); - vol->format(); + vol->format("auto"); vol->destroy(); vol->setSilent(false); } @@ -168,7 +168,7 @@ void Disk::createPrivateVolume(dev_t device, const std::string& partGuid) { LOG(DEBUG) << "Device just partitioned; silently formatting"; vol->setSilent(true); vol->create(); - vol->format(); + vol->format("auto"); vol->destroy(); vol->setSilent(false); } diff --git a/PrivateVolume.cpp b/PrivateVolume.cpp index ff2c7b3..a1bbb3b 100644 --- a/PrivateVolume.cpp +++ b/PrivateVolume.cpp @@ -14,7 +14,8 @@ * limitations under the License. */ -#include "Ext4.h" +#include "fs/Ext4.h" +#include "fs/F2fs.h" #include "PrivateVolume.h" #include "EmulatedVolume.h" #include "Utils.h" @@ -40,6 +41,8 @@ using android::base::StringPrintf; namespace android { namespace vold { +static const unsigned int kMajorBlockMmc = 179; + 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))); @@ -101,16 +104,36 @@ status_t PrivateVolume::doMount() { return -EIO; } - int res = Ext4::check(mDmDevPath.c_str(), mPath.c_str()); - if (res == 0 || res == 1) { - LOG(DEBUG) << getId() << " passed filesystem check"; - } else { - PLOG(ERROR) << getId() << " failed filesystem check"; - return -EIO; - } + if (mFsType == "ext4") { + int res = ext4::Check(mDmDevPath, mPath); + if (res == 0 || res == 1) { + LOG(DEBUG) << getId() << " passed filesystem check"; + } else { + PLOG(ERROR) << getId() << " failed filesystem check"; + return -EIO; + } + + if (ext4::Mount(mDmDevPath, mPath, false, false, true)) { + PLOG(ERROR) << getId() << " failed to mount"; + return -EIO; + } + + } else if (mFsType == "f2fs") { + int res = f2fs::Check(mDmDevPath); + if (res == 0) { + LOG(DEBUG) << getId() << " passed filesystem check"; + } else { + PLOG(ERROR) << getId() << " failed filesystem check"; + return -EIO; + } + + if (f2fs::Mount(mDmDevPath, mPath)) { + PLOG(ERROR) << getId() << " failed to mount"; + return -EIO; + } - if (Ext4::doMount(mDmDevPath.c_str(), mPath.c_str(), false, false, true)) { - PLOG(ERROR) << getId() << " failed to mount"; + } else { + LOG(ERROR) << getId() << " unsupported filesystem " << mFsType; return -EIO; } @@ -124,6 +147,8 @@ status_t PrivateVolume::doMount() { return -EIO; } + // TODO: restorecon all the things! + // Create a new emulated volume stacked above us, it will automatically // be destroyed during unmount std::string mediaPath(mPath + "/media"); @@ -145,11 +170,33 @@ status_t PrivateVolume::doUnmount() { return OK; } -status_t PrivateVolume::doFormat() { - // TODO: change mountpoint once we have selinux labels - if (Ext4::format(mDmDevPath.c_str(), 0, "/data")) { - PLOG(ERROR) << getId() << " failed to format"; - return -EIO; +status_t PrivateVolume::doFormat(const std::string& fsType) { + std::string resolvedFsType = fsType; + if (fsType == "auto") { + // For now, assume that all MMC devices are flash-based SD cards, and + // give everyone else ext4 because sysfs rotational isn't reliable. + if ((major(mRawDevice) == kMajorBlockMmc) && f2fs::IsSupported()) { + resolvedFsType = "f2fs"; + } else { + resolvedFsType = "ext4"; + } + LOG(DEBUG) << "Resolved auto to " << resolvedFsType; + } + + if (resolvedFsType == "ext4") { + // TODO: change reported mountpoint once we have better selinux support + if (ext4::Format(mDmDevPath, 0, "/data")) { + PLOG(ERROR) << getId() << " failed to format"; + return -EIO; + } + } else if (resolvedFsType == "f2fs") { + if (f2fs::Format(mDmDevPath)) { + PLOG(ERROR) << getId() << " failed to format"; + return -EIO; + } + } else { + LOG(ERROR) << getId() << " unsupported filesystem " << fsType; + return -EINVAL; } return OK; diff --git a/PrivateVolume.h b/PrivateVolume.h index bd464e6..95b718d 100644 --- a/PrivateVolume.h +++ b/PrivateVolume.h @@ -45,7 +45,7 @@ protected: status_t doDestroy() override; status_t doMount() override; status_t doUnmount() override; - status_t doFormat() override; + status_t doFormat(const std::string& fsType) override; status_t readMetadata(); diff --git a/PublicVolume.cpp b/PublicVolume.cpp index 2b2c32b..9d6887d 100644 --- a/PublicVolume.cpp +++ b/PublicVolume.cpp @@ -14,7 +14,7 @@ * limitations under the License. */ -#include "Fat.h" +#include "fs/Vfat.h" #include "PublicVolume.h" #include "Utils.h" #include "VolumeManager.h" @@ -94,7 +94,7 @@ status_t PublicVolume::doMount() { // TODO: expand to support mounting other filesystems readMetadata(); - if (Fat::check(mDevPath.c_str())) { + if (vfat::Check(mDevPath)) { LOG(ERROR) << getId() << " failed filesystem check"; return -EIO; } @@ -119,7 +119,7 @@ status_t PublicVolume::doMount() { return -errno; } - if (Fat::doMount(mDevPath.c_str(), mRawPath.c_str(), false, false, false, + if (vfat::Mount(mDevPath, mRawPath, false, false, false, AID_MEDIA_RW, AID_MEDIA_RW, 0007, true)) { PLOG(ERROR) << getId() << " failed to mount " << mDevPath; return -EIO; @@ -200,11 +200,20 @@ status_t PublicVolume::doUnmount() { return OK; } -status_t PublicVolume::doFormat() { - if (Fat::format(mDevPath.c_str(), 0, true)) { - LOG(ERROR) << getId() << " failed to format"; - return -errno; +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 { + LOG(ERROR) << "Unsupported filesystem " << fsType; + return -EINVAL; } + return OK; } diff --git a/PublicVolume.h b/PublicVolume.h index 45313ec..fd400f2 100644 --- a/PublicVolume.h +++ b/PublicVolume.h @@ -47,7 +47,7 @@ protected: status_t doDestroy() override; status_t doMount() override; status_t doUnmount() override; - status_t doFormat() override; + status_t doFormat(const std::string& fsType) override; status_t readMetadata(); status_t initAsecStage(); diff --git a/Utils.cpp b/Utils.cpp index 0b8ccfd..e06111a 100644 --- a/Utils.cpp +++ b/Utils.cpp @@ -18,6 +18,7 @@ #include "Utils.h" #include "Process.h" +#include #include #include #include @@ -39,6 +40,7 @@ #define UMOUNT_NOFOLLOW 0x00000008 /* Don't follow symlink on umount */ #endif +using android::base::ReadFileToString; using android::base::StringPrintf; namespace android { @@ -51,6 +53,8 @@ security_context_t sFsckUntrustedContext = nullptr; static const char* kBlkidPath = "/system/bin/blkid"; +static const char* kProcFilesystems = "/proc/filesystems"; + status_t CreateDeviceNode(const std::string& path, dev_t dev) { const char* cpath = path.c_str(); status_t res = 0; @@ -463,5 +467,47 @@ uint64_t GetTreeBytes(const std::string& path) { } } +bool IsFilesystemSupported(const std::string& fsType) { + std::string supported; + if (!ReadFileToString(kProcFilesystems, &supported)) { + PLOG(ERROR) << "Failed to read supported filesystems"; + return false; + } + return supported.find(fsType + "\n") != std::string::npos; +} + +status_t WipeBlockDevice(const std::string& path) { + status_t res = -1; + const char* c_path = path.c_str(); + unsigned long nr_sec = 0; + unsigned long long range[2]; + + int fd = TEMP_FAILURE_RETRY(open(c_path, O_RDWR | O_CLOEXEC)); + if (fd == -1) { + PLOG(ERROR) << "Failed to open " << path; + goto done; + } + + if ((ioctl(fd, BLKGETSIZE, nr_sec)) == -1) { + PLOG(ERROR) << "Failed to determine size of " << path; + goto done; + } + + range[0] = 0; + range[1] = (unsigned long long) nr_sec * 512; + + LOG(INFO) << "About to discard " << range[1] << " on " << path; + if (ioctl(fd, BLKDISCARD, &range) == 0) { + LOG(INFO) << "Discard success on " << path; + res = 0; + } else { + PLOG(ERROR) << "Discard failure on " << path; + } + +done: + close(fd); + return res; +} + } // namespace vold } // namespace android diff --git a/Utils.h b/Utils.h index 6ad87ae..ab151aa 100644 --- a/Utils.h +++ b/Utils.h @@ -81,6 +81,11 @@ status_t StrToHex(const std::string& str, std::string& hex); uint64_t GetFreeBytes(const std::string& path); uint64_t GetTreeBytes(const std::string& path); +bool IsFilesystemSupported(const std::string& fsType); + +/* Wipes contents of block device at given path */ +status_t WipeBlockDevice(const std::string& path); + } // namespace vold } // namespace android diff --git a/VolumeBase.cpp b/VolumeBase.cpp index ca056a4..05a61ed 100644 --- a/VolumeBase.cpp +++ b/VolumeBase.cpp @@ -222,7 +222,7 @@ status_t VolumeBase::unmount() { return res; } -status_t VolumeBase::format() { +status_t VolumeBase::format(const std::string& fsType) { if (mState == State::kMounted) { unmount(); } @@ -233,12 +233,12 @@ status_t VolumeBase::format() { } setState(State::kFormatting); - status_t res = doFormat(); + status_t res = doFormat(fsType); setState(State::kUnmounted); return res; } -status_t VolumeBase::doFormat() { +status_t VolumeBase::doFormat(const std::string& fsType) { return -ENOTSUP; } diff --git a/VolumeBase.h b/VolumeBase.h index a9975f8..42b4d65 100644 --- a/VolumeBase.h +++ b/VolumeBase.h @@ -97,7 +97,7 @@ public: status_t destroy(); status_t mount(); status_t unmount(); - status_t format(); + status_t format(const std::string& fsType); protected: explicit VolumeBase(Type type); @@ -106,7 +106,7 @@ protected: virtual status_t doDestroy(); virtual status_t doMount() = 0; virtual status_t doUnmount() = 0; - virtual status_t doFormat(); + virtual status_t doFormat(const std::string& fsType); status_t setId(const std::string& id); status_t setPath(const std::string& path); diff --git a/VolumeManager.cpp b/VolumeManager.cpp index c34f169..9306363 100755 --- a/VolumeManager.cpp +++ b/VolumeManager.cpp @@ -51,8 +51,8 @@ #include "NetlinkManager.h" #include "ResponseCode.h" #include "Loop.h" -#include "Ext4.h" -#include "Fat.h" +#include "fs/Ext4.h" +#include "fs/Vfat.h" #include "Utils.h" #include "Devmapper.h" #include "Process.h" @@ -725,9 +725,9 @@ int VolumeManager::createAsec(const char *id, unsigned int numSectors, const cha } if (usingExt4) { - formatStatus = Ext4::format(dmDevice, numImgSectors, mountPoint); + formatStatus = android::vold::ext4::Format(dmDevice, numImgSectors, mountPoint); } else { - formatStatus = Fat::format(dmDevice, numImgSectors, 0); + formatStatus = android::vold::vfat::Format(dmDevice, numImgSectors); } if (formatStatus < 0) { @@ -754,10 +754,11 @@ int VolumeManager::createAsec(const char *id, unsigned int numSectors, const cha int mountStatus; if (usingExt4) { - mountStatus = Ext4::doMount(dmDevice, mountPoint, false, false, false); + mountStatus = android::vold::ext4::Mount(dmDevice, mountPoint, + false, false, false); } else { - mountStatus = Fat::doMount(dmDevice, mountPoint, false, false, false, ownerUid, 0, 0000, - false); + mountStatus = android::vold::vfat::Mount(dmDevice, mountPoint, + false, false, false, ownerUid, 0, 0000, false); } if (mountStatus) { @@ -916,7 +917,7 @@ int VolumeManager::resizeAsec(const char *id, unsigned numSectors, const char *k */ waitForDevMapper(dmDevice); - if (Ext4::resize(dmDevice, numImgSectors)) { + if (android::vold::ext4::Resize(dmDevice, numImgSectors)) { SLOGE("Unable to resize %s (%s)", id, strerror(errno)); if (cleanupDm) { Devmapper::destroy(idHash); @@ -973,9 +974,11 @@ 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 = android::vold::ext4::Mount(loopDevice, mountPoint, + true, true, true); } else { - result = Fat::doMount(loopDevice, mountPoint, true, true, true, 0, 0, 0227, false); + result = android::vold::vfat::Mount(loopDevice, mountPoint, + true, true, true, 0, 0, 0227, false); } if (result) { @@ -1039,7 +1042,7 @@ int VolumeManager::fixupAsecPermissions(const char *id, gid_t gid, const char* f return 0; } - int ret = Ext4::doMount(loopDevice, mountPoint, + int ret = android::vold::ext4::Mount(loopDevice, mountPoint, false /* read-only */, true /* remount */, false /* executable */); @@ -1101,7 +1104,7 @@ int VolumeManager::fixupAsecPermissions(const char *id, gid_t gid, const char* f result |= -1; } - result |= Ext4::doMount(loopDevice, mountPoint, + result |= android::vold::ext4::Mount(loopDevice, mountPoint, true /* read-only */, true /* remount */, true /* execute */); @@ -1537,9 +1540,11 @@ 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 = android::vold::ext4::Mount(dmDevice, mountPoint, + readOnly, false, readOnly); } else { - result = Fat::doMount(dmDevice, mountPoint, readOnly, false, readOnly, ownerUid, 0, 0222, false); + result = android::vold::vfat::Mount(dmDevice, mountPoint, + readOnly, false, readOnly, ownerUid, 0, 0222, false); } if (result) { @@ -1628,8 +1633,8 @@ int VolumeManager::mountObb(const char *img, const char *key, int ownerGid) { */ waitForDevMapper(dmDevice); - if (Fat::doMount(dmDevice, mountPoint, true, false, true, 0, ownerGid, - 0227, false)) { + if (android::vold::vfat::Mount(dmDevice, mountPoint, + true, false, true, 0, ownerGid, 0227, false)) { SLOGE("Image mount failed (%s)", strerror(errno)); if (cleanupDm) { Devmapper::destroy(idHash); diff --git a/Ext4.cpp b/fs/Ext4.cpp similarity index 72% rename from Ext4.cpp rename to fs/Ext4.cpp index a208eb5..3ae4159 100644 --- a/Ext4.cpp +++ b/fs/Ext4.cpp @@ -50,16 +50,26 @@ using android::base::StringPrintf; +namespace android { +namespace vold { +namespace ext4 { + static const char* kResizefsPath = "/system/bin/resize2fs"; static const char* kMkfsPath = "/system/bin/make_ext4fs"; static const char* kFsckPath = "/system/bin/e2fsck"; -int Ext4::check(const char *fsPath, const char *mountPoint) { +bool IsSupported() { + return access(kMkfsPath, X_OK) == 0 + && access(kFsckPath, X_OK) == 0 + && IsFilesystemSupported("ext4"); +} + +status_t Check(const std::string& source, const std::string& target) { // The following is shamelessly borrowed from fs_mgr.c, so it should be // kept in sync with any changes over there. - char* blk_device = (char*) fsPath; - char* target = (char*) mountPoint; + const char* c_source = source.c_str(); + const char* c_target = target.c_str(); int status; int ret; @@ -79,17 +89,17 @@ int Ext4::check(const char *fsPath, const char *mountPoint) { * filesytsem due to an error, e2fsck is still run to do a full check * fix the filesystem. */ - ret = mount(blk_device, target, "ext4", tmpmnt_flags, tmpmnt_opts); + ret = mount(c_source, c_target, "ext4", tmpmnt_flags, tmpmnt_opts); if (!ret) { int i; for (i = 0; i < 5; i++) { // Try to umount 5 times before continuing on. // Should we try rebooting if all attempts fail? - int result = umount(target); + int result = umount(c_target); if (result == 0) { break; } - ALOGW("%s(): umount(%s)=%d: %s\n", __func__, target, result, strerror(errno)); + ALOGW("%s(): umount(%s)=%d: %s\n", __func__, c_target, result, strerror(errno)); sleep(1); } } @@ -100,61 +110,65 @@ int Ext4::check(const char *fsPath, const char *mountPoint) { */ if (access(kFsckPath, X_OK)) { ALOGD("Not running %s on %s (executable not in system image)\n", - kFsckPath, blk_device); + kFsckPath, c_source); } else { - ALOGD("Running %s on %s\n", kFsckPath, blk_device); + ALOGD("Running %s on %s\n", kFsckPath, c_source); std::vector cmd; cmd.push_back(kFsckPath); cmd.push_back("-y"); - cmd.push_back(blk_device); + cmd.push_back(c_source); - // Ext4 devices are currently always trusted - return android::vold::ForkExecvp(cmd, android::vold::sFsckContext); + // ext4 devices are currently always trusted + return ForkExecvp(cmd, sFsckContext); } return 0; } -int Ext4::doMount(const char *fsPath, const char *mountPoint, bool ro, bool remount, - bool executable) { +status_t Mount(const std::string& source, const std::string& target, bool ro, + bool remount, bool executable) { int rc; unsigned long flags; + const char* c_source = source.c_str(); + const char* c_target = target.c_str(); + flags = MS_NOATIME | MS_NODEV | MS_NOSUID | MS_DIRSYNC; flags |= (executable ? 0 : MS_NOEXEC); flags |= (ro ? MS_RDONLY : 0); flags |= (remount ? MS_REMOUNT : 0); - rc = mount(fsPath, mountPoint, "ext4", flags, NULL); + rc = mount(c_source, c_target, "ext4", flags, NULL); if (rc && errno == EROFS) { - SLOGE("%s appears to be a read only filesystem - retrying mount RO", fsPath); + SLOGE("%s appears to be a read only filesystem - retrying mount RO", c_source); flags |= MS_RDONLY; - rc = mount(fsPath, mountPoint, "ext4", flags, NULL); + rc = mount(c_source, c_target, "ext4", flags, NULL); } return rc; } -int Ext4::resize(const char *fspath, unsigned int numSectors) { +status_t Resize(const std::string& source, unsigned int numSectors) { std::vector cmd; cmd.push_back(kResizefsPath); cmd.push_back("-f"); - cmd.push_back(fspath); + cmd.push_back(source); cmd.push_back(StringPrintf("%u", numSectors)); - return android::vold::ForkExecvp(cmd); + return ForkExecvp(cmd); } -int Ext4::format(const char *fsPath, unsigned int numSectors, const char *mountpoint) { +status_t Format(const std::string& source, unsigned int numSectors, + const std::string& target) { std::vector cmd; cmd.push_back(kMkfsPath); cmd.push_back("-J"); cmd.push_back("-a"); - cmd.push_back(mountpoint); + cmd.push_back(target); if (numSectors) { cmd.push_back("-l"); @@ -163,7 +177,11 @@ int Ext4::format(const char *fsPath, unsigned int numSectors, const char *mountp // Always generate a real UUID cmd.push_back("-u"); - cmd.push_back(fsPath); + cmd.push_back(source); - return android::vold::ForkExecvp(cmd); + return ForkExecvp(cmd); } + +} // namespace ext4 +} // namespace vold +} // namespace android diff --git a/fs/Ext4.h b/fs/Ext4.h new file mode 100644 index 0000000..a5efa74 --- /dev/null +++ b/fs/Ext4.h @@ -0,0 +1,41 @@ +/* + * 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 ANDROID_VOLD_EXT4_H +#define ANDROID_VOLD_EXT4_H + +#include + +#include + +namespace android { +namespace vold { +namespace ext4 { + +bool IsSupported(); + +status_t Check(const std::string& source, const std::string& target); +status_t Mount(const std::string& source, const std::string& target, bool ro, + bool remount, bool executable); +status_t Format(const std::string& source, unsigned int numSectors, + const std::string& target); +status_t Resize(const std::string& source, unsigned int numSectors); + +} // namespace ext4 +} // namespace vold +} // namespace android + +#endif diff --git a/fs/F2fs.cpp b/fs/F2fs.cpp new file mode 100644 index 0000000..b947822 --- /dev/null +++ b/fs/F2fs.cpp @@ -0,0 +1,82 @@ +/* + * 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 "F2fs.h" +#include "Utils.h" + +#include +#include + +#include +#include + +#include + +using android::base::StringPrintf; + +namespace android { +namespace vold { +namespace f2fs { + +static const char* kMkfsPath = "/system/bin/make_f2fs"; +static const char* kFsckPath = "/system/bin/fsck.f2fs"; + +bool IsSupported() { + return access(kMkfsPath, X_OK) == 0 + && access(kFsckPath, X_OK) == 0 + && IsFilesystemSupported("f2fs"); +} + +status_t Check(const std::string& source) { + std::vector cmd; + cmd.push_back(kFsckPath); + cmd.push_back("-f"); + cmd.push_back(source); + + // f2fs devices are currently always trusted + return ForkExecvp(cmd, sFsckContext); +} + +status_t Mount(const std::string& source, const std::string& target) { + 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; + + int res = mount(c_source, c_target, "f2fs", flags, NULL); + if (res != 0) { + PLOG(ERROR) << "Failed to mount " << source; + if (errno == EROFS) { + res = mount(c_source, c_target, "f2fs", flags | MS_RDONLY, NULL); + if (res != 0) { + PLOG(ERROR) << "Failed to mount read-only " << source; + } + } + } + + return res; +} + +status_t Format(const std::string& source) { + std::vector cmd; + cmd.push_back(kMkfsPath); + cmd.push_back(source); + + return ForkExecvp(cmd); +} + +} // namespace f2fs +} // namespace vold +} // namespace android diff --git a/Ext4.h b/fs/F2fs.h similarity index 54% rename from Ext4.h rename to fs/F2fs.h index 55672af..f710212 100644 --- a/Ext4.h +++ b/fs/F2fs.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 The Android Open Source Project + * 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. @@ -14,18 +14,25 @@ * limitations under the License. */ -#ifndef _EXT4_H -#define _EXT4_H +#ifndef ANDROID_VOLD_F2FS_H +#define ANDROID_VOLD_F2FS_H -#include +#include -class Ext4 { -public: - static int check(const char *fsPath, const char *mountPoint); - static int doMount(const char *fsPath, const char *mountPoint, bool ro, bool remount, - bool executable); - static int format(const char *fsPath, unsigned int numSectors, const char *mountpoint); - static int resize(const char *fsPath, unsigned int numSectors); -}; +#include + +namespace android { +namespace vold { +namespace f2fs { + +bool IsSupported(); + +status_t Check(const std::string& source); +status_t Mount(const std::string& source, const std::string& target); +status_t Format(const std::string& source); + +} // namespace f2fs +} // namespace vold +} // namespace android #endif diff --git a/Fat.cpp b/fs/Vfat.cpp similarity index 73% rename from Fat.cpp rename to fs/Vfat.cpp index 873088d..faff763 100644 --- a/Fat.cpp +++ b/fs/Vfat.cpp @@ -45,16 +45,26 @@ #include -#include "Fat.h" +#include "Vfat.h" #include "Utils.h" #include "VoldUtil.h" using android::base::StringPrintf; +namespace android { +namespace vold { +namespace vfat { + static const char* kMkfsPath = "/system/bin/newfs_msdos"; static const char* kFsckPath = "/system/bin/fsck_msdos"; -int Fat::check(const char *fsPath) { +bool IsSupported() { + return access(kMkfsPath, X_OK) == 0 + && access(kFsckPath, X_OK) == 0 + && IsFilesystemSupported("vfat"); +} + +status_t Check(const std::string& source) { if (access(kFsckPath, X_OK)) { SLOGW("Skipping fs checks\n"); return 0; @@ -67,10 +77,10 @@ int Fat::check(const char *fsPath) { cmd.push_back(kFsckPath); cmd.push_back("-p"); cmd.push_back("-f"); - cmd.push_back(fsPath); + cmd.push_back(source); // Fat devices are currently always untrusted - rc = android::vold::ForkExecvp(cmd, android::vold::sFsckUntrustedContext); + rc = ForkExecvp(cmd, sFsckUntrustedContext); if (rc < 0) { SLOGE("Filesystem check failed due to logwrap error"); @@ -108,13 +118,16 @@ int Fat::check(const char *fsPath) { return 0; } -int Fat::doMount(const char *fsPath, const char *mountPoint, - bool ro, bool remount, bool executable, - int ownerUid, int ownerGid, int permMask, bool createLost) { +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) { int rc; unsigned long flags; char mountData[255]; + const char* c_source = source.c_str(); + const char* c_target = target.c_str(); + flags = MS_NODEV | MS_NOSUID | MS_DIRSYNC; flags |= (executable ? 0 : MS_NOEXEC); @@ -139,17 +152,17 @@ int Fat::doMount(const char *fsPath, const char *mountPoint, "utf8,uid=%d,gid=%d,fmask=%o,dmask=%o,shortname=mixed", ownerUid, ownerGid, permMask, permMask); - rc = mount(fsPath, mountPoint, "vfat", flags, mountData); + rc = mount(c_source, c_target, "vfat", flags, mountData); if (rc && errno == EROFS) { - SLOGE("%s appears to be a read only filesystem - retrying mount RO", fsPath); + SLOGE("%s appears to be a read only filesystem - retrying mount RO", c_source); flags |= MS_RDONLY; - rc = mount(fsPath, mountPoint, "vfat", flags, mountData); + rc = mount(c_source, c_target, "vfat", flags, mountData); } if (rc == 0 && createLost) { char *lost_path; - asprintf(&lost_path, "%s/LOST.DIR", mountPoint); + asprintf(&lost_path, "%s/LOST.DIR", c_target); if (access(lost_path, F_OK)) { /* * Create a LOST.DIR in the root so we have somewhere to put @@ -165,11 +178,7 @@ int Fat::doMount(const char *fsPath, const char *mountPoint, return rc; } -int Fat::format(const char *fsPath, unsigned int numSectors, bool wipe) { - if (wipe) { - Fat::wipe(fsPath, numSectors); - } - +status_t Format(const std::string& source, unsigned int numSectors) { std::vector cmd; cmd.push_back(kMkfsPath); cmd.push_back("-F"); @@ -185,9 +194,9 @@ int Fat::format(const char *fsPath, unsigned int numSectors, bool wipe) { cmd.push_back(StringPrintf("%u", numSectors)); } - cmd.push_back(fsPath); + cmd.push_back(source); - int rc = android::vold::ForkExecvp(cmd); + int rc = ForkExecvp(cmd); if (rc < 0) { SLOGE("Filesystem format failed due to logwrap error"); errno = EIO; @@ -205,36 +214,6 @@ int Fat::format(const char *fsPath, unsigned int numSectors, bool wipe) { return 0; } -void Fat::wipe(const char *fsPath, unsigned int numSectors) { - unsigned long long range[2]; - - int fd = open(fsPath, O_RDWR | O_CLOEXEC); - if (fd == -1) { - SLOGE("Fat wipe failed to open device %s", fsPath); - return; - } - - if (numSectors == 0) { - unsigned long nr_sec; - get_blkdev_size(fd, &nr_sec); - if (nr_sec > UINT32_MAX) { - SLOGE("Too many sectors for FAT: %ld", nr_sec); - close(fd); - return; - } - numSectors = nr_sec; - } - if (numSectors == 0) { - SLOGE("Fat wipe failed to determine size of %s", fsPath); - close(fd); - return; - } - range[0] = 0; - range[1] = (unsigned long long)numSectors * 512; - if (ioctl(fd, BLKDISCARD, &range) < 0) { - SLOGE("Fat wipe failed to discard blocks on %s", fsPath); - } else { - SLOGI("Fat wipe %d sectors on %s succeeded", numSectors, fsPath); - } - close(fd); -} +} // namespace vfat +} // namespace vold +} // namespace android diff --git a/Fat.h b/fs/Vfat.h similarity index 54% rename from Fat.h rename to fs/Vfat.h index 19614d1..306c7db 100644 --- a/Fat.h +++ b/fs/Vfat.h @@ -14,22 +14,27 @@ * limitations under the License. */ -#ifndef _FAT_H -#define _FAT_H - -#include - -class Fat { -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, unsigned int numSectors, bool wipe); - -private: - static void wipe(const char *fsPath, unsigned int numSectors); -}; +#ifndef ANDROID_VOLD_VFAT_H +#define ANDROID_VOLD_VFAT_H + +#include + +#include + +namespace android { +namespace vold { +namespace vfat { + +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, unsigned int numSectors); + +} // namespace vfat +} // namespace vold +} // namespace android #endif diff --git a/main.cpp b/main.cpp index 290093f..abdff9f 100644 --- a/main.cpp +++ b/main.cpp @@ -55,6 +55,11 @@ int main(int argc, char** argv) { LOG(INFO) << "Vold 3.0 (the awakening) firing up"; + LOG(VERBOSE) << "Detected support for:" + << (android::vold::IsFilesystemSupported("ext4") ? " ext4" : "") + << (android::vold::IsFilesystemSupported("f2fs") ? " f2fs" : "") + << (android::vold::IsFilesystemSupported("vfat") ? " vfat" : ""); + VolumeManager *vm; CommandListener *cl; CryptCommandListener *ccl;