VolumeBase.cpp revision 9c48498f4529f623650c56d03e63324c8d813032
1/*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "Utils.h"
18#include "VolumeBase.h"
19#include "VolumeManager.h"
20#include "ResponseCode.h"
21
22#include <base/stringprintf.h>
23#include <base/logging.h>
24
25#include <fcntl.h>
26#include <stdlib.h>
27#include <sys/mount.h>
28#include <sys/stat.h>
29#include <sys/types.h>
30
31using android::base::StringPrintf;
32
33#define DEBUG 1
34
35namespace android {
36namespace vold {
37
38VolumeBase::VolumeBase(Type type) :
39        mType(type), mFlags(0), mUser(-1), mCreated(false), mState(State::kUnmounted) {
40}
41
42VolumeBase::~VolumeBase() {
43    CHECK(!mCreated);
44}
45
46void VolumeBase::setState(State state) {
47    mState = state;
48
49    VolumeManager::Instance()->getBroadcaster()->sendBroadcast(
50            ResponseCode::VolumeStateChanged,
51            StringPrintf("%s %d", getId().c_str(), mState).c_str(), false);
52}
53
54status_t VolumeBase::setFlags(int flags) {
55    if (mState != State::kUnmounted) {
56        LOG(WARNING) << getId() << " flags change requires state unmounted";
57        return -EBUSY;
58    }
59
60    mFlags = flags;
61    return OK;
62}
63
64status_t VolumeBase::setUser(userid_t user) {
65    if (mState != State::kUnmounted) {
66        LOG(WARNING) << getId() << " user change requires state unmounted";
67        return -EBUSY;
68    }
69
70    mUser = user;
71    return OK;
72}
73
74status_t VolumeBase::setId(const std::string& id) {
75    if (mCreated) {
76        LOG(WARNING) << getId() << " id change requires not created";
77        return -EBUSY;
78    }
79
80    mId = id;
81    return OK;
82}
83
84status_t VolumeBase::setPath(const std::string& path) {
85    if (mState != State::kMounting) {
86        LOG(WARNING) << getId() << " path change requires state mounting";
87        return -EBUSY;
88    }
89
90    mPath = path;
91    VolumeManager::Instance()->getBroadcaster()->sendBroadcast(
92            ResponseCode::VolumePathChanged,
93            StringPrintf("%s %s", getId().c_str(), mPath.c_str()).c_str(), false);
94    return OK;
95}
96
97void VolumeBase::addVolume(const std::shared_ptr<VolumeBase>& volume) {
98    mVolumes.push_back(volume);
99}
100
101void VolumeBase::removeVolume(const std::shared_ptr<VolumeBase>& volume) {
102    mVolumes.remove(volume);
103}
104
105std::shared_ptr<VolumeBase> VolumeBase::findVolume(const std::string& id) {
106    for (auto vol : mVolumes) {
107        if (vol->getId() == id) {
108            return vol;
109        }
110    }
111    return nullptr;
112}
113
114status_t VolumeBase::create() {
115    CHECK(!mCreated);
116
117    mCreated = true;
118    status_t res = doCreate();
119    VolumeManager::Instance()->getBroadcaster()->sendBroadcast(
120            ResponseCode::VolumeCreated,
121            StringPrintf("%s %d", getId().c_str(), mType).c_str(), false);
122    return res;
123}
124
125status_t VolumeBase::doCreate() {
126    return OK;
127}
128
129status_t VolumeBase::destroy() {
130    CHECK(mCreated);
131
132    if (mState == State::kMounted) {
133        unmount();
134    }
135
136    VolumeManager::Instance()->getBroadcaster()->sendBroadcast(
137            ResponseCode::VolumeDestroyed, getId().c_str(), false);
138    status_t res = doDestroy();
139    mCreated = false;
140    return res;
141}
142
143status_t VolumeBase::doDestroy() {
144    return OK;
145}
146
147status_t VolumeBase::mount() {
148    if (mState != State::kUnmounted) {
149        LOG(WARNING) << getId() << " mount requires state unmounted";
150        return -EBUSY;
151    }
152
153    setState(State::kMounting);
154    status_t res = doMount();
155    if (res == OK) {
156        setState(State::kMounted);
157    } else {
158        setState(State::kUnmounted);
159    }
160
161    return res;
162}
163
164status_t VolumeBase::unmount() {
165    if (mState != State::kMounted) {
166        LOG(WARNING) << getId() << " unmount requires state mounted";
167        return -EBUSY;
168    }
169
170    setState(State::kUnmounting);
171
172    for (auto vol : mVolumes) {
173        if (vol->unmount()) {
174            LOG(WARNING) << getId() << " failed to unmount " << vol->getId()
175                    << " stacked above";
176        }
177    }
178    mVolumes.clear();
179
180    status_t res = doUnmount();
181    setState(State::kUnmounted);
182    return res;
183}
184
185status_t VolumeBase::format() {
186    if (mState != State::kUnmounted) {
187        LOG(WARNING) << getId() << " format requires state unmounted";
188        return -EBUSY;
189    }
190
191    setState(State::kFormatting);
192    status_t res = doFormat();
193    setState(State::kUnmounted);
194    return res;
195}
196
197status_t VolumeBase::doFormat() {
198    return -ENOTSUP;
199}
200
201}  // namespace vold
202}  // namespace android
203