summaryrefslogtreecommitdiff
path: root/PublicVolume.cpp (plain)
blob: a38999312f5b30ee7da0b866da319c762a14e60e
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 "fs/Vfat.h"
18#include "fs/Ntfs.h"
19#include "fs/Exfat.h"
20#include "fs/Hfsplus.h"
21#include "fs/Iso9660.h"
22#include "fs/Ext4.h"
23#include "fs/Sdcardfs.h"
24#include "PublicVolume.h"
25#include "Utils.h"
26#include "VolumeManager.h"
27#include "ResponseCode.h"
28
29#include <android-base/stringprintf.h>
30#include <android-base/logging.h>
31#include <cutils/fs.h>
32#include <private/android_filesystem_config.h>
33
34#include <fcntl.h>
35#include <stdlib.h>
36#include <sys/mount.h>
37#include <sys/stat.h>
38#include <sys/types.h>
39#include <sys/wait.h>
40#include <sys/sysmacros.h>
41
42using android::base::StringPrintf;
43
44namespace android {
45namespace droidvold {
46
47static const char* kChownPath = "/system/bin/chown";
48
49PublicVolume::PublicVolume(const std::string& physicalDevName, const bool isPhysical) :
50 VolumeBase(Type::kPublic), mJustPhysicalDev(isPhysical) {
51 setId(physicalDevName);
52 mDevPath = StringPrintf("/dev/block/%s", getId().c_str());
53}
54
55PublicVolume::~PublicVolume() {
56}
57
58status_t PublicVolume::readMetadata() {
59 status_t res = ReadPartMetadata(mDevPath, mFsType, mFsUuid, mFsLabel);
60
61 if (VolumeManager::Instance()->getDebug())
62 LOG(DEBUG) << "blkid get devPath=" << mDevPath << " fsType= " << mFsType;
63
64 notifyEvent(ResponseCode::VolumeFsTypeChanged, mFsType);
65
66 // TODO: find the Uuid of srdisk
67 // If mFsUuid of publicVolume is empty,
68 // it will cause systemUi crash when it is mounted
69 if (mFsUuid.empty()) {
70 if (major(mDevice) == 11)
71 mFsUuid = "sr0";
72 else
73 mFsUuid = "fakeUuid";
74 }
75
76 notifyEvent(ResponseCode::VolumeFsUuidChanged, mFsUuid);
77 notifyEvent(ResponseCode::VolumeFsLabelChanged, mFsLabel);
78
79 return OK;
80}
81
82status_t PublicVolume::doCreate() {
83 return 0;
84}
85
86status_t PublicVolume::doDestroy() {
87 return 0;
88}
89
90status_t PublicVolume::doMount() {
91 // TODO: expand to support mounting other filesystems
92 readMetadata();
93
94 if (mFsType != "vfat" &&
95 mFsType != "ntfs" &&
96 mFsType != "exfat" &&
97 strncmp(mFsType.c_str(), "ext", 3) &&
98 mFsType != "hfs" &&
99 mFsType != "iso9660" &&
100 mFsType != "udf") {
101 LOG(ERROR) << getId() << " unsupported filesystem " << mFsType;
102 return -EIO;
103 }
104
105 // Use UUID as stable name, if available
106 std::string stableName = getId();
107 if (!mFsUuid.empty()) {
108 stableName = mFsUuid;
109 }
110 mRawPath = StringPrintf("/mnt/media_rw/%s", stableName.c_str());
111
112 mFuseDefault = StringPrintf("/mnt/runtime/default/%s", stableName.c_str());
113 mFuseRead = StringPrintf("/mnt/runtime/read/%s", stableName.c_str());
114 mFuseWrite = StringPrintf("/mnt/runtime/write/%s", stableName.c_str());
115
116
117 VolumeManager *vm = VolumeManager::Instance();
118
119 if (mFsType == "vfat") {
120#ifdef HAS_VFAT
121 sleep(5);
122 if (vm->isMountpointMounted(mRawPath.c_str())) {
123 LOG(DEBUG) << getId() << " vfat will handle by vold";
124 return 0;
125 }
126#else
127 LOG(DEBUG) << getId() << " vfat will handle by vold";
128 return 0;
129#endif
130 }
131
132 if (vm->isMountpointMounted(mRawPath.c_str())) {
133 LOG(ERROR) << " path:" << mRawPath << " is already mounted";
134 return -EIO;
135 }
136
137 setInternalPath(mRawPath);
138
139 if (getMountFlags() & MountFlags::kVisible) {
140 setPath(StringPrintf("/storage/%s", stableName.c_str()));
141 } else {
142 setPath(mRawPath);
143 }
144
145 if (prepareDir(mRawPath, 0700, AID_ROOT, AID_ROOT)) {
146 PLOG(ERROR) << getId() << " failed to create mount points";
147 return -errno;
148 }
149
150 if (prepareDir(mFuseDefault.c_str(), 0700, AID_ROOT, AID_ROOT) ||
151 prepareDir(mFuseRead.c_str(), 0700, AID_ROOT, AID_ROOT) ||
152 prepareDir(mFuseWrite.c_str(), 0700, AID_ROOT, AID_ROOT)) {
153 rmdir(mRawPath.c_str());
154 PLOG(ERROR) << getId() << " failed to create FUSE mount points";
155 return -errno;
156 }
157
158
159 // Mount device
160 status_t mountStatus = -1;
161
162 if (mFsType == "vfat") {
163 mountStatus = vfat::Mount(mDevPath, mRawPath, false, false, false,
164 AID_MEDIA_RW, AID_MEDIA_RW, 0007, true);
165 } else if (mFsType == "ntfs") {
166 mountStatus = ntfs::Mount(mDevPath.c_str(), mRawPath.c_str(), false, false,
167 AID_MEDIA_RW, AID_MEDIA_RW, 0007, true);
168 } else if (mFsType == "exfat") {
169 mountStatus = exfat::Mount(mDevPath.c_str(), mRawPath.c_str(), false, false,
170 AID_MEDIA_RW, AID_MEDIA_RW, 0007, true);
171 } else if (!strncmp(mFsType.c_str(), "ext", 3)) {
172 mountStatus = ext4::Mount(mDevPath, mRawPath, false, false, true, mFsType);
173 } else if (mFsType == "hfs") {
174 mountStatus = hfsplus::Mount(mDevPath.c_str(), mRawPath.c_str(), false, false,
175 AID_MEDIA_RW, AID_MEDIA_RW, 0007, true);
176 } else if (mFsType == "iso9660" || mFsType == "udf") {
177 if ((mountStatus = iso9660::Mount(mDevPath.c_str(), mRawPath.c_str(), false, false,
178 AID_MEDIA_RW, AID_MEDIA_RW, 0007, true)) == 0)
179 mSrMounted = true;
180 }
181
182 if (mountStatus) {
183 PLOG(ERROR) << " failed to mount " << mDevPath << " as " << mFsType;
184 rmdir(mRawPath.c_str());
185 return -EIO;
186 } else {
187 LOG(INFO) << "successfully mount " << mDevPath << " as " << mFsType;
188 }
189
190 if (!strncmp(mFsType.c_str(), "ext", 3)) {
191 std::vector<std::string> cmd;
192 cmd.push_back(kChownPath);
193 cmd.push_back("-R");
194 cmd.push_back("media_rw:media_rw");
195 cmd.push_back(mRawPath);
196
197 std::vector<std::string> output;
198 status_t res = ForkExecvp(cmd, output);
199 if (res != OK) {
200 LOG(WARNING) << "chown failed " << mRawPath;
201 return res;
202 }
203
204 RestoreconRecursive(mRawPath);
205
206 LOG(VERBOSE) << "Finished restorecon of " << mRawPath;
207 }
208
209
210 // mount sdcardfs
211 if (getMountFlags() & MountFlags::kPrimary) {
212 sdcardfs::run_sdcardfs(mRawPath, stableName,
213 1023, 1023, getMountUserId(), false, true);
214 } else {
215 sdcardfs::run_sdcardfs(mRawPath, stableName,
216 1023, 1023, getMountUserId(), false, false);
217 }
218
219 return OK;
220}
221
222status_t PublicVolume::doUnmount() {
223 // Unmount the storage before we kill the FUSE process. If we kill
224 // the FUSE process first, most file system operations will return
225 // ENOTCONN until the unmount completes. This is an exotic and unusual
226 // error code and might cause broken behaviour in applications.
227 KillProcessesUsingPath(getPath());
228
229#ifdef HAS_VIRTUAL_CDROM
230 std::string stableName = getId();
231 if (!mFsUuid.empty()) {
232 stableName = mFsUuid;
233 }
234
235 VolumeManager *vm = VolumeManager::Instance();
236 vm->unmountLoopIfNeed(stableName.c_str());
237#endif
238
239 ForceUnmount(mFuseDefault);
240 ForceUnmount(mFuseRead);
241 ForceUnmount(mFuseWrite);
242 ForceUnmount(mRawPath);
243
244 rmdir(mFuseDefault.c_str());
245 rmdir(mFuseRead.c_str());
246 rmdir(mFuseWrite.c_str());
247 rmdir(mRawPath.c_str());
248
249 mFuseDefault.clear();
250 mFuseRead.clear();
251 mFuseWrite.clear();
252 mRawPath.clear();
253
254 return OK;
255}
256
257status_t PublicVolume::doFormat(const std::string& fsType) {
258 if (fsType == "vfat" || fsType == "auto") {
259 if (WipeBlockDevice(mDevPath) != OK) {
260 LOG(WARNING) << getId() << " failed to wipe";
261 }
262 if (vfat::Format(mDevPath, 0)) {
263 LOG(ERROR) << getId() << " failed to format";
264 return -errno;
265 }
266 } else {
267 LOG(ERROR) << "Unsupported filesystem " << fsType;
268 return -EINVAL;
269 }
270
271 return OK;
272}
273
274status_t PublicVolume::prepareDir(const std::string& path,
275 mode_t mode, uid_t uid, gid_t gid) {
276 if (fs_prepare_dir(path.c_str(), 0700, AID_ROOT, AID_ROOT)) {
277 if (errno == ENOTCONN) { // Transport endpoint is not connected
278 LOG(ERROR) << getId() << " failed to create mount point";
279 LOG(INFO) << "umount " << path << " and try again";
280 // lazy umount
281 if (!umount2(path.c_str(), MNT_DETACH) || errno == EINVAL || errno == ENOENT) {
282 if (fs_prepare_dir(path.c_str(), 0700, AID_ROOT, AID_ROOT)) {
283 return -1;
284 }
285 return OK;
286 }
287 PLOG(ERROR) << " failed to umount " << path;
288 return -1;
289 }
290 return -1;
291 }
292
293 return OK;
294}
295
296} // namespace vold
297} // namespace android
298