recovery: Implement a volume manager

This is a copy of the pre-binderized vold which has been converted to
use direct calls instead of sockets and stripped down to only what is
needed to support recovery.

Change-Id: Ic82d929e052b5ba70ecf7b475e0a223d77d9687e
diff --git a/volume_manager/VolumeBase.cpp b/volume_manager/VolumeBase.cpp
new file mode 100644
index 0000000..0c8e73b
--- /dev/null
+++ b/volume_manager/VolumeBase.cpp
@@ -0,0 +1,189 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ * Copyright (C) 2019 The LineageOS 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 "VolumeBase.h"
+#include <volume_manager/VolumeManager.h>
+#include "ResponseCode.h"
+#include "Utils.h"
+
+#include <android-base/logging.h>
+#include <android-base/stringprintf.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 volmgr {
+
+VolumeBase::VolumeBase(Type type)
+    : mType(type), mMountFlags(0), mCreated(false), mState(State::kUnmounted), mSilent(false) {}
+
+VolumeBase::~VolumeBase() {
+    CHECK(!mCreated);
+}
+
+void VolumeBase::setState(State state) {
+    mState = state;
+    VolumeManager::Instance()->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::setPartLabel(const std::string& partLabel) {
+    if ((mState != State::kUnmounted) && (mState != State::kUnmountable)) {
+        LOG(WARNING) << getId() << " partLabel change requires state unmounted or unmountable";
+        LOG(WARNING) << getId() << " state=" << (int)mState;
+    }
+
+    mPartLabel = partLabel;
+    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::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) {
+    mPath = path;
+    VolumeManager::Instance()->notifyEvent(ResponseCode::VolumePathChanged, mPath);
+    return OK;
+}
+
+status_t VolumeBase::create() {
+    if (mCreated) {
+        return BAD_VALUE;
+    }
+
+    mCreated = true;
+    std::vector<std::string> argv;
+    argv.push_back(StringPrintf("%d", mType));
+    argv.push_back(mDiskId);
+    argv.push_back(mPartGuid);
+    status_t res = doCreate();
+    if (res == OK) {
+        VolumeManager::Instance()->notifyEvent(ResponseCode::VolumeCreated, argv);
+        if (mPartLabel.size() > 0) {
+            VolumeManager::Instance()->notifyEvent(ResponseCode::VolumeFsLabelChanged, mPartLabel);
+        }
+    }
+    setState(State::kUnmounted);
+    return res;
+}
+
+status_t VolumeBase::doCreate() {
+    return OK;
+}
+
+status_t VolumeBase::destroy() {
+    if (!mCreated) {
+        return NO_INIT;
+    }
+
+    if (mState == State::kMounted) {
+        unmount(true /* detatch */);
+        setState(State::kBadRemoval);
+    } else {
+        setState(State::kRemoved);
+    }
+
+    VolumeManager::Instance()->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(bool detach /* = false */) {
+    setState(State::kEjecting);
+
+    status_t res = doUnmount(detach);
+    setState(State::kUnmounted);
+    return res;
+}
+
+}  // namespace volmgr
+}  // namespace android