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 | |
42 | using android::base::StringPrintf; |
43 | |
44 | namespace android { |
45 | namespace droidvold { |
46 | |
47 | static const char* kChownPath = "/system/bin/chown"; |
48 | |
49 | PublicVolume::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 | |
55 | PublicVolume::~PublicVolume() { |
56 | } |
57 | |
58 | status_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 | |
82 | status_t PublicVolume::doCreate() { |
83 | return 0; |
84 | } |
85 | |
86 | status_t PublicVolume::doDestroy() { |
87 | return 0; |
88 | } |
89 | |
90 | status_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 | |
222 | status_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 | |
257 | status_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 | |
274 | status_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 |