You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
254 lines
6.4 KiB
254 lines
6.4 KiB
/* |
|
* 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 "Utils.h" |
|
#include "VolumeBase.h" |
|
#include "VolumeManager.h" |
|
#include "ResponseCode.h" |
|
|
|
#include <android-base/stringprintf.h> |
|
#include <android-base/logging.h> |
|
|
|
#include <fcntl.h> |
|
#include <stdlib.h> |
|
#include <sys/mount.h> |
|
#include <sys/stat.h> |
|
#include <sys/types.h> |
|
|
|
using android::base::StringPrintf; |
|
|
|
namespace android { |
|
namespace vold { |
|
|
|
VolumeBase::VolumeBase(Type type) : |
|
mType(type), mMountFlags(0), mMountUserId(-1), mCreated(false), mState( |
|
State::kUnmounted), mSilent(false) { |
|
} |
|
|
|
VolumeBase::~VolumeBase() { |
|
CHECK(!mCreated); |
|
} |
|
|
|
void VolumeBase::setState(State state) { |
|
mState = state; |
|
notifyEvent(ResponseCode::VolumeStateChanged, StringPrintf("%d", mState)); |
|
} |
|
|
|
status_t VolumeBase::setDiskId(const std::string& diskId) { |
|
if (mCreated) { |
|
LOG(WARNING) << getId() << " diskId change requires destroyed"; |
|
return -EBUSY; |
|
} |
|
|
|
mDiskId = diskId; |
|
return OK; |
|
} |
|
|
|
status_t VolumeBase::setPartGuid(const std::string& partGuid) { |
|
if (mCreated) { |
|
LOG(WARNING) << getId() << " partGuid change requires destroyed"; |
|
return -EBUSY; |
|
} |
|
|
|
mPartGuid = partGuid; |
|
return OK; |
|
} |
|
|
|
status_t VolumeBase::setMountFlags(int mountFlags) { |
|
if ((mState != State::kUnmounted) && (mState != State::kUnmountable)) { |
|
LOG(WARNING) << getId() << " flags change requires state unmounted or unmountable"; |
|
return -EBUSY; |
|
} |
|
|
|
mMountFlags = mountFlags; |
|
return OK; |
|
} |
|
|
|
status_t VolumeBase::setMountUserId(userid_t mountUserId) { |
|
if ((mState != State::kUnmounted) && (mState != State::kUnmountable)) { |
|
LOG(WARNING) << getId() << " user change requires state unmounted or unmountable"; |
|
return -EBUSY; |
|
} |
|
|
|
mMountUserId = mountUserId; |
|
return OK; |
|
} |
|
|
|
status_t VolumeBase::setSilent(bool silent) { |
|
if (mCreated) { |
|
LOG(WARNING) << getId() << " silence change requires destroyed"; |
|
return -EBUSY; |
|
} |
|
|
|
mSilent = silent; |
|
return OK; |
|
} |
|
|
|
status_t VolumeBase::setId(const std::string& id) { |
|
if (mCreated) { |
|
LOG(WARNING) << getId() << " id change requires not created"; |
|
return -EBUSY; |
|
} |
|
|
|
mId = id; |
|
return OK; |
|
} |
|
|
|
status_t VolumeBase::setPath(const std::string& path) { |
|
if (mState != State::kChecking) { |
|
LOG(WARNING) << getId() << " path change requires state checking"; |
|
return -EBUSY; |
|
} |
|
|
|
mPath = path; |
|
notifyEvent(ResponseCode::VolumePathChanged, mPath); |
|
return OK; |
|
} |
|
|
|
status_t VolumeBase::setInternalPath(const std::string& internalPath) { |
|
if (mState != State::kChecking) { |
|
LOG(WARNING) << getId() << " internal path change requires state checking"; |
|
return -EBUSY; |
|
} |
|
|
|
mInternalPath = internalPath; |
|
notifyEvent(ResponseCode::VolumeInternalPathChanged, mInternalPath); |
|
return OK; |
|
} |
|
|
|
void VolumeBase::notifyEvent(int event) { |
|
if (mSilent) return; |
|
VolumeManager::Instance()->getBroadcaster()->sendBroadcast(event, |
|
getId().c_str(), false); |
|
} |
|
|
|
void VolumeBase::notifyEvent(int event, const std::string& value) { |
|
if (mSilent) return; |
|
VolumeManager::Instance()->getBroadcaster()->sendBroadcast(event, |
|
StringPrintf("%s %s", getId().c_str(), value.c_str()).c_str(), false); |
|
} |
|
|
|
void VolumeBase::addVolume(const std::shared_ptr<VolumeBase>& volume) { |
|
mVolumes.push_back(volume); |
|
} |
|
|
|
void VolumeBase::removeVolume(const std::shared_ptr<VolumeBase>& volume) { |
|
mVolumes.remove(volume); |
|
} |
|
|
|
std::shared_ptr<VolumeBase> VolumeBase::findVolume(const std::string& id) { |
|
for (auto vol : mVolumes) { |
|
if (vol->getId() == id) { |
|
return vol; |
|
} |
|
} |
|
return nullptr; |
|
} |
|
|
|
status_t VolumeBase::create() { |
|
CHECK(!mCreated); |
|
|
|
mCreated = true; |
|
status_t res = doCreate(); |
|
notifyEvent(ResponseCode::VolumeCreated, |
|
StringPrintf("%d \"%s\" \"%s\"", mType, mDiskId.c_str(), mPartGuid.c_str())); |
|
setState(State::kUnmounted); |
|
return res; |
|
} |
|
|
|
status_t VolumeBase::doCreate() { |
|
return OK; |
|
} |
|
|
|
status_t VolumeBase::destroy() { |
|
CHECK(mCreated); |
|
|
|
if (mState == State::kMounted) { |
|
unmount(); |
|
setState(State::kBadRemoval); |
|
} else { |
|
setState(State::kRemoved); |
|
} |
|
|
|
notifyEvent(ResponseCode::VolumeDestroyed); |
|
status_t res = doDestroy(); |
|
mCreated = false; |
|
return res; |
|
} |
|
|
|
status_t VolumeBase::doDestroy() { |
|
return OK; |
|
} |
|
|
|
status_t VolumeBase::mount() { |
|
if ((mState != State::kUnmounted) && (mState != State::kUnmountable)) { |
|
LOG(WARNING) << getId() << " mount requires state unmounted or unmountable"; |
|
return -EBUSY; |
|
} |
|
|
|
setState(State::kChecking); |
|
status_t res = doMount(); |
|
if (res == OK) { |
|
setState(State::kMounted); |
|
} else { |
|
setState(State::kUnmountable); |
|
} |
|
|
|
return res; |
|
} |
|
|
|
status_t VolumeBase::unmount() { |
|
if (mState != State::kMounted) { |
|
LOG(WARNING) << getId() << " unmount requires state mounted"; |
|
return -EBUSY; |
|
} |
|
|
|
setState(State::kEjecting); |
|
for (const auto& vol : mVolumes) { |
|
if (vol->destroy()) { |
|
LOG(WARNING) << getId() << " failed to destroy " << vol->getId() |
|
<< " stacked above"; |
|
} |
|
} |
|
mVolumes.clear(); |
|
|
|
status_t res = doUnmount(); |
|
setState(State::kUnmounted); |
|
return res; |
|
} |
|
|
|
status_t VolumeBase::format(const std::string& fsType) { |
|
if (mState == State::kMounted) { |
|
unmount(); |
|
} |
|
|
|
if ((mState != State::kUnmounted) && (mState != State::kUnmountable)) { |
|
LOG(WARNING) << getId() << " format requires state unmounted or unmountable"; |
|
return -EBUSY; |
|
} |
|
|
|
setState(State::kFormatting); |
|
status_t res = doFormat(fsType); |
|
setState(State::kUnmounted); |
|
return res; |
|
} |
|
|
|
status_t VolumeBase::doFormat(const std::string& fsType) { |
|
return -ENOTSUP; |
|
} |
|
|
|
} // namespace vold |
|
} // namespace android
|
|
|