d0640f6358
When formatting volumes, pass along fsType string which can be "auto" to let the volume select the best choice. For now, private volumes assume that MMC devices (like SD cards) are best off using f2fs when both kernel support and tools are present, otherwise fall back to ext4. Use blkid when mounting to pick the right set of tools. Move filesystem utility methods into namespaces and place in separate directory to be more organized. Bug: 20275581 Change-Id: Id5f82d8672dda2e9f68c35b075f28232b0b55ed4
221 lines
6.4 KiB
C++
221 lines
6.4 KiB
C++
/*
|
|
* 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 "fs/Vfat.h"
|
|
#include "PublicVolume.h"
|
|
#include "Utils.h"
|
|
#include "VolumeManager.h"
|
|
#include "ResponseCode.h"
|
|
|
|
#include <base/stringprintf.h>
|
|
#include <base/logging.h>
|
|
#include <cutils/fs.h>
|
|
#include <private/android_filesystem_config.h>
|
|
|
|
#include <fcntl.h>
|
|
#include <stdlib.h>
|
|
#include <sys/mount.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/types.h>
|
|
#include <sys/wait.h>
|
|
|
|
using android::base::StringPrintf;
|
|
|
|
namespace android {
|
|
namespace vold {
|
|
|
|
static const char* kFusePath = "/system/bin/sdcard";
|
|
|
|
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)));
|
|
mDevPath = StringPrintf("/dev/block/vold/%s", getId().c_str());
|
|
}
|
|
|
|
PublicVolume::~PublicVolume() {
|
|
}
|
|
|
|
status_t PublicVolume::readMetadata() {
|
|
status_t res = ReadMetadataUntrusted(mDevPath, mFsType, mFsUuid, mFsLabel);
|
|
notifyEvent(ResponseCode::VolumeFsTypeChanged, mFsType);
|
|
notifyEvent(ResponseCode::VolumeFsUuidChanged, mFsUuid);
|
|
notifyEvent(ResponseCode::VolumeFsLabelChanged, mFsLabel);
|
|
return res;
|
|
}
|
|
|
|
status_t PublicVolume::initAsecStage() {
|
|
std::string legacyPath(mRawPath + "/android_secure");
|
|
std::string securePath(mRawPath + "/.android_secure");
|
|
|
|
// Recover legacy secure path
|
|
if (!access(legacyPath.c_str(), R_OK | X_OK)
|
|
&& access(securePath.c_str(), R_OK | X_OK)) {
|
|
if (rename(legacyPath.c_str(), securePath.c_str())) {
|
|
PLOG(WARNING) << getId() << " failed to rename legacy ASEC dir";
|
|
}
|
|
}
|
|
|
|
if (TEMP_FAILURE_RETRY(mkdir(securePath.c_str(), 0700))) {
|
|
if (errno != EEXIST) {
|
|
PLOG(WARNING) << getId() << " creating ASEC stage failed";
|
|
return -errno;
|
|
}
|
|
}
|
|
|
|
BindMount(securePath, kAsecPath);
|
|
|
|
return OK;
|
|
}
|
|
|
|
status_t PublicVolume::doCreate() {
|
|
return CreateDeviceNode(mDevPath, mDevice);
|
|
}
|
|
|
|
status_t PublicVolume::doDestroy() {
|
|
return DestroyDeviceNode(mDevPath);
|
|
}
|
|
|
|
status_t PublicVolume::doMount() {
|
|
// TODO: expand to support mounting other filesystems
|
|
readMetadata();
|
|
|
|
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;
|
|
}
|
|
|
|
mRawPath = StringPrintf("/mnt/media_rw/%s", stableName.c_str());
|
|
mFusePath = StringPrintf("/storage/%s", stableName.c_str());
|
|
setInternalPath(mRawPath);
|
|
setPath(mFusePath);
|
|
|
|
if (fs_prepare_dir(mRawPath.c_str(), 0700, AID_ROOT, AID_ROOT)) {
|
|
PLOG(ERROR) << getId() << " failed to create mount point " << mRawPath;
|
|
return -errno;
|
|
}
|
|
if (fs_prepare_dir(mFusePath.c_str(), 0700, AID_ROOT, AID_ROOT)) {
|
|
PLOG(ERROR) << getId() << " failed to create mount point " << mFusePath;
|
|
return -errno;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
if (getMountFlags() & MountFlags::kPrimary) {
|
|
initAsecStage();
|
|
}
|
|
|
|
// TODO: teach FUSE daemon to protect itself with user-specific GID
|
|
if (!(mFusePid = fork())) {
|
|
if (!(getMountFlags() & MountFlags::kVisible)) {
|
|
// TODO: mount so that only system apps can access
|
|
if (execl(kFusePath, kFusePath,
|
|
"-u", "1023", // AID_MEDIA_RW
|
|
"-g", "1023", // AID_MEDIA_RW
|
|
mRawPath.c_str(),
|
|
mFusePath.c_str(),
|
|
NULL)) {
|
|
PLOG(ERROR) << "Failed to exec";
|
|
}
|
|
} else if (getMountFlags() & MountFlags::kPrimary) {
|
|
if (execl(kFusePath, kFusePath,
|
|
"-u", "1023", // AID_MEDIA_RW
|
|
"-g", "1023", // AID_MEDIA_RW
|
|
"-d",
|
|
mRawPath.c_str(),
|
|
mFusePath.c_str(),
|
|
NULL)) {
|
|
PLOG(ERROR) << "Failed to exec";
|
|
}
|
|
} else {
|
|
if (execl(kFusePath, kFusePath,
|
|
"-u", "1023", // AID_MEDIA_RW
|
|
"-g", "1023", // AID_MEDIA_RW
|
|
"-w", "1023", // AID_MEDIA_RW
|
|
"-d",
|
|
mRawPath.c_str(),
|
|
mFusePath.c_str(),
|
|
NULL)) {
|
|
PLOG(ERROR) << "Failed to exec";
|
|
}
|
|
}
|
|
|
|
PLOG(DEBUG) << "FUSE exiting";
|
|
_exit(1);
|
|
}
|
|
|
|
if (mFusePid == -1) {
|
|
PLOG(ERROR) << getId() << " failed to fork";
|
|
return -errno;
|
|
}
|
|
|
|
return OK;
|
|
}
|
|
|
|
status_t PublicVolume::doUnmount() {
|
|
if (mFusePid > 0) {
|
|
kill(mFusePid, SIGTERM);
|
|
TEMP_FAILURE_RETRY(waitpid(mFusePid, nullptr, 0));
|
|
mFusePid = 0;
|
|
}
|
|
|
|
ForceUnmount(kAsecPath);
|
|
ForceUnmount(mFusePath);
|
|
ForceUnmount(mRawPath);
|
|
|
|
if (TEMP_FAILURE_RETRY(rmdir(mRawPath.c_str()))) {
|
|
PLOG(ERROR) << getId() << " failed to rmdir mount point " << mRawPath;
|
|
}
|
|
if (TEMP_FAILURE_RETRY(rmdir(mFusePath.c_str()))) {
|
|
PLOG(ERROR) << getId() << " failed to rmdir mount point " << mFusePath;
|
|
}
|
|
|
|
mFusePath.clear();
|
|
mRawPath.clear();
|
|
|
|
return OK;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
} // namespace vold
|
|
} // namespace android
|