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 <android-base/stringprintf.h>
23 #include <android-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 
31 using android::base::StringPrintf;
32 
33 #define DEBUG 1
34 
35 namespace android {
36 namespace vold {
37 
VolumeBase(Type type)38 VolumeBase::VolumeBase(Type type) :
39         mType(type), mMountFlags(0), mMountUserId(-1), mCreated(false), mState(
40                 State::kUnmounted), mSilent(false) {
41 }
42 
~VolumeBase()43 VolumeBase::~VolumeBase() {
44     CHECK(!mCreated);
45 }
46 
setState(State state)47 void VolumeBase::setState(State state) {
48     mState = state;
49     notifyEvent(ResponseCode::VolumeStateChanged, StringPrintf("%d", mState));
50 }
51 
setDiskId(const std::string & diskId)52 status_t VolumeBase::setDiskId(const std::string& diskId) {
53     if (mCreated) {
54         LOG(WARNING) << getId() << " diskId change requires destroyed";
55         return -EBUSY;
56     }
57 
58     mDiskId = diskId;
59     return OK;
60 }
61 
setPartGuid(const std::string & partGuid)62 status_t VolumeBase::setPartGuid(const std::string& partGuid) {
63     if (mCreated) {
64         LOG(WARNING) << getId() << " partGuid change requires destroyed";
65         return -EBUSY;
66     }
67 
68     mPartGuid = partGuid;
69     return OK;
70 }
71 
setMountFlags(int mountFlags)72 status_t VolumeBase::setMountFlags(int mountFlags) {
73     if ((mState != State::kUnmounted) && (mState != State::kUnmountable)) {
74         LOG(WARNING) << getId() << " flags change requires state unmounted or unmountable";
75         return -EBUSY;
76     }
77 
78     mMountFlags = mountFlags;
79     return OK;
80 }
81 
setMountUserId(userid_t mountUserId)82 status_t VolumeBase::setMountUserId(userid_t mountUserId) {
83     if ((mState != State::kUnmounted) && (mState != State::kUnmountable)) {
84         LOG(WARNING) << getId() << " user change requires state unmounted or unmountable";
85         return -EBUSY;
86     }
87 
88     mMountUserId = mountUserId;
89     return OK;
90 }
91 
setSilent(bool silent)92 status_t VolumeBase::setSilent(bool silent) {
93     if (mCreated) {
94         LOG(WARNING) << getId() << " silence change requires destroyed";
95         return -EBUSY;
96     }
97 
98     mSilent = silent;
99     return OK;
100 }
101 
setId(const std::string & id)102 status_t VolumeBase::setId(const std::string& id) {
103     if (mCreated) {
104         LOG(WARNING) << getId() << " id change requires not created";
105         return -EBUSY;
106     }
107 
108     mId = id;
109     return OK;
110 }
111 
setPath(const std::string & path)112 status_t VolumeBase::setPath(const std::string& path) {
113     if (mState != State::kChecking) {
114         LOG(WARNING) << getId() << " path change requires state checking";
115         return -EBUSY;
116     }
117 
118     mPath = path;
119     notifyEvent(ResponseCode::VolumePathChanged, mPath);
120     return OK;
121 }
122 
setInternalPath(const std::string & internalPath)123 status_t VolumeBase::setInternalPath(const std::string& internalPath) {
124     if (mState != State::kChecking) {
125         LOG(WARNING) << getId() << " internal path change requires state checking";
126         return -EBUSY;
127     }
128 
129     mInternalPath = internalPath;
130     notifyEvent(ResponseCode::VolumeInternalPathChanged, mInternalPath);
131     return OK;
132 }
133 
notifyEvent(int event)134 void VolumeBase::notifyEvent(int event) {
135     if (mSilent) return;
136     VolumeManager::Instance()->getBroadcaster()->sendBroadcast(event,
137             getId().c_str(), false);
138 }
139 
notifyEvent(int event,const std::string & value)140 void VolumeBase::notifyEvent(int event, const std::string& value) {
141     if (mSilent) return;
142     VolumeManager::Instance()->getBroadcaster()->sendBroadcast(event,
143             StringPrintf("%s %s", getId().c_str(), value.c_str()).c_str(), false);
144 }
145 
addVolume(const std::shared_ptr<VolumeBase> & volume)146 void VolumeBase::addVolume(const std::shared_ptr<VolumeBase>& volume) {
147     mVolumes.push_back(volume);
148 }
149 
removeVolume(const std::shared_ptr<VolumeBase> & volume)150 void VolumeBase::removeVolume(const std::shared_ptr<VolumeBase>& volume) {
151     mVolumes.remove(volume);
152 }
153 
findVolume(const std::string & id)154 std::shared_ptr<VolumeBase> VolumeBase::findVolume(const std::string& id) {
155     for (auto vol : mVolumes) {
156         if (vol->getId() == id) {
157             return vol;
158         }
159     }
160     return nullptr;
161 }
162 
create()163 status_t VolumeBase::create() {
164     CHECK(!mCreated);
165 
166     mCreated = true;
167     status_t res = doCreate();
168     notifyEvent(ResponseCode::VolumeCreated,
169             StringPrintf("%d \"%s\" \"%s\"", mType, mDiskId.c_str(), mPartGuid.c_str()));
170     setState(State::kUnmounted);
171     return res;
172 }
173 
doCreate()174 status_t VolumeBase::doCreate() {
175     return OK;
176 }
177 
destroy()178 status_t VolumeBase::destroy() {
179     CHECK(mCreated);
180 
181     if (mState == State::kMounted) {
182         unmount();
183         setState(State::kBadRemoval);
184     } else {
185         setState(State::kRemoved);
186     }
187 
188     notifyEvent(ResponseCode::VolumeDestroyed);
189     status_t res = doDestroy();
190     mCreated = false;
191     return res;
192 }
193 
doDestroy()194 status_t VolumeBase::doDestroy() {
195     return OK;
196 }
197 
mount()198 status_t VolumeBase::mount() {
199     if ((mState != State::kUnmounted) && (mState != State::kUnmountable)) {
200         LOG(WARNING) << getId() << " mount requires state unmounted or unmountable";
201         return -EBUSY;
202     }
203 
204     setState(State::kChecking);
205     status_t res = doMount();
206     if (res == OK) {
207         setState(State::kMounted);
208     } else {
209         setState(State::kUnmountable);
210     }
211 
212     return res;
213 }
214 
unmount()215 status_t VolumeBase::unmount() {
216     if (mState != State::kMounted) {
217         LOG(WARNING) << getId() << " unmount requires state mounted";
218         return -EBUSY;
219     }
220 
221     setState(State::kEjecting);
222     for (auto vol : mVolumes) {
223         if (vol->destroy()) {
224             LOG(WARNING) << getId() << " failed to destroy " << vol->getId()
225                     << " stacked above";
226         }
227     }
228     mVolumes.clear();
229 
230     status_t res = doUnmount();
231     setState(State::kUnmounted);
232     return res;
233 }
234 
format(const std::string & fsType)235 status_t VolumeBase::format(const std::string& fsType) {
236     if (mState == State::kMounted) {
237         unmount();
238     }
239 
240     if ((mState != State::kUnmounted) && (mState != State::kUnmountable)) {
241         LOG(WARNING) << getId() << " format requires state unmounted or unmountable";
242         return -EBUSY;
243     }
244 
245     setState(State::kFormatting);
246     status_t res = doFormat(fsType);
247     setState(State::kUnmounted);
248     return res;
249 }
250 
doFormat(const std::string & fsType)251 status_t VolumeBase::doFormat(const std::string& fsType) {
252     return -ENOTSUP;
253 }
254 
255 }  // namespace vold
256 }  // namespace android
257