blob: 5308724bb0df551b3e7d3ccae7ec31824213e0db [file] [log] [blame]
Jeff Sharkeydeb24052015-03-02 21:01:40 -08001/*
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
Jeff Sharkeydeb24052015-03-02 21:01:40 -080017#include "PublicVolume.h"
18#include "Utils.h"
Jeff Sharkey36801cc2015-03-13 16:09:20 -070019#include "VolumeManager.h"
Jeff Sharkey37ba1252018-01-19 10:55:18 +090020#include "fs/Exfat.h"
Dan Pasanencb16b162015-10-27 22:52:37 -050021#include "fs/Ext4.h"
22#include "fs/F2fs.h"
23#include "fs/Ntfs.h"
Jeff Sharkey37ba1252018-01-19 10:55:18 +090024#include "fs/Vfat.h"
Jeff Sharkeydeb24052015-03-02 21:01:40 -080025
Elliott Hughes7e128fb2015-12-04 15:50:53 -080026#include <android-base/logging.h>
Sudheer Shanka40ab6742018-09-18 13:07:45 -070027#include <android-base/properties.h>
Paul Crowleyedf7a4e2018-09-18 15:14:18 -070028#include <android-base/stringprintf.h>
Jeff Sharkeydeb24052015-03-02 21:01:40 -080029#include <cutils/fs.h>
Jeff Sharkeydeb24052015-03-02 21:01:40 -080030#include <private/android_filesystem_config.h>
Jeff Sharkey7bdf4d52017-09-18 14:47:10 -060031#include <utils/Timers.h>
Jeff Sharkeydeb24052015-03-02 21:01:40 -080032
33#include <fcntl.h>
34#include <stdlib.h>
35#include <sys/mount.h>
36#include <sys/stat.h>
Elliott Hughes0e08e842017-05-18 09:08:24 -070037#include <sys/sysmacros.h>
Paul Crowleyedf7a4e2018-09-18 15:14:18 -070038#include <sys/types.h>
Jeff Sharkeydeb24052015-03-02 21:01:40 -080039#include <sys/wait.h>
40
Sudheer Shanka40ab6742018-09-18 13:07:45 -070041using android::base::GetBoolProperty;
Dan Albertae9e8902015-03-16 10:35:17 -070042using android::base::StringPrintf;
43
Jeff Sharkeydeb24052015-03-02 21:01:40 -080044namespace android {
45namespace vold {
46
Jeff Sharkeydeb24052015-03-02 21:01:40 -080047static const char* kFusePath = "/system/bin/sdcard";
48
Jeff Sharkey36801cc2015-03-13 16:09:20 -070049static const char* kAsecPath = "/mnt/secure/asec";
Jeff Sharkeydeb24052015-03-02 21:01:40 -080050
Tom Marshall8b768982015-11-05 11:20:54 -080051PublicVolume::PublicVolume(dev_t device, const std::string& fstype /* = "" */,
52 const std::string& mntopts /* = "" */)
53 : VolumeBase(Type::kPublic), mDevice(device), mFusePid(0),
54 mFsType(fstype), mMntOpts(mntopts) {
Jeff Sharkey36801cc2015-03-13 16:09:20 -070055 setId(StringPrintf("public:%u,%u", major(device), minor(device)));
56 mDevPath = StringPrintf("/dev/block/vold/%s", getId().c_str());
Jeff Sharkeydeb24052015-03-02 21:01:40 -080057}
58
Paul Crowleyedf7a4e2018-09-18 15:14:18 -070059PublicVolume::~PublicVolume() {}
Jeff Sharkeydeb24052015-03-02 21:01:40 -080060
61status_t PublicVolume::readMetadata() {
Jeff Sharkey3472e522017-10-06 18:02:53 -060062 status_t res = ReadMetadataUntrusted(mDevPath, &mFsType, &mFsUuid, &mFsLabel);
Jeff Sharkeycbe69fc2017-09-15 16:50:28 -060063
Jeff Sharkey814e9d32017-09-13 11:49:44 -060064 auto listener = getListener();
65 if (listener) listener->onVolumeMetadataChanged(getId(), mFsType, mFsUuid, mFsLabel);
Jeff Sharkeycbe69fc2017-09-15 16:50:28 -060066
Jeff Sharkey36801cc2015-03-13 16:09:20 -070067 return res;
Jeff Sharkeydeb24052015-03-02 21:01:40 -080068}
69
70status_t PublicVolume::initAsecStage() {
71 std::string legacyPath(mRawPath + "/android_secure");
72 std::string securePath(mRawPath + "/.android_secure");
73
74 // Recover legacy secure path
Paul Crowleyedf7a4e2018-09-18 15:14:18 -070075 if (!access(legacyPath.c_str(), R_OK | X_OK) && access(securePath.c_str(), R_OK | X_OK)) {
Jeff Sharkeydeb24052015-03-02 21:01:40 -080076 if (rename(legacyPath.c_str(), securePath.c_str())) {
Jeff Sharkey9c484982015-03-31 10:35:33 -070077 PLOG(WARNING) << getId() << " failed to rename legacy ASEC dir";
Jeff Sharkeydeb24052015-03-02 21:01:40 -080078 }
79 }
80
Jeff Sharkey36801cc2015-03-13 16:09:20 -070081 if (TEMP_FAILURE_RETRY(mkdir(securePath.c_str(), 0700))) {
82 if (errno != EEXIST) {
Jeff Sharkey9c484982015-03-31 10:35:33 -070083 PLOG(WARNING) << getId() << " creating ASEC stage failed";
Jeff Sharkey36801cc2015-03-13 16:09:20 -070084 return -errno;
85 }
Jeff Sharkeydeb24052015-03-02 21:01:40 -080086 }
87
Jeff Sharkey36801cc2015-03-13 16:09:20 -070088 BindMount(securePath, kAsecPath);
89
Jeff Sharkeydeb24052015-03-02 21:01:40 -080090 return OK;
91}
92
Jeff Sharkey9c484982015-03-31 10:35:33 -070093status_t PublicVolume::doCreate() {
94 return CreateDeviceNode(mDevPath, mDevice);
95}
96
97status_t PublicVolume::doDestroy() {
98 return DestroyDeviceNode(mDevPath);
99}
100
Jeff Sharkeydeb24052015-03-02 21:01:40 -0800101status_t PublicVolume::doMount() {
Jeff Sharkey9c484982015-03-31 10:35:33 -0700102 readMetadata();
103
Dan Pasanencb16b162015-10-27 22:52:37 -0500104 if (!IsFilesystemSupported(mFsType)) {
Makoto Onukic82c9ce2015-06-24 13:30:45 -0700105 LOG(ERROR) << getId() << " unsupported filesystem " << mFsType;
106 return -EIO;
107 }
108
Jeff Sharkey36801cc2015-03-13 16:09:20 -0700109 // Use UUID as stable name, if available
110 std::string stableName = getId();
111 if (!mFsUuid.empty()) {
Jeff Sharkeyf0121c52015-04-06 14:08:45 -0700112 stableName = mFsUuid;
Jeff Sharkey36801cc2015-03-13 16:09:20 -0700113 }
114
115 mRawPath = StringPrintf("/mnt/media_rw/%s", stableName.c_str());
Jeff Sharkey36801cc2015-03-13 16:09:20 -0700116
Jeff Sharkey1bd078f2015-08-06 11:40:00 -0700117 mFuseDefault = StringPrintf("/mnt/runtime/default/%s", stableName.c_str());
118 mFuseRead = StringPrintf("/mnt/runtime/read/%s", stableName.c_str());
119 mFuseWrite = StringPrintf("/mnt/runtime/write/%s", stableName.c_str());
Sudheer Shankadd4bb172019-01-16 23:35:49 -0800120 mFuseFull = StringPrintf("/mnt/runtime/full/%s", stableName.c_str());
Jeff Sharkey66270a22015-06-24 11:49:24 -0700121
122 setInternalPath(mRawPath);
Jeff Sharkey8474ee32015-07-30 16:54:23 -0700123 if (getMountFlags() & MountFlags::kVisible) {
124 setPath(StringPrintf("/storage/%s", stableName.c_str()));
125 } else {
126 setPath(mRawPath);
127 }
Jeff Sharkey66270a22015-06-24 11:49:24 -0700128
Qin Chaoe0074f12015-12-15 15:20:41 +0800129 if (fs_prepare_dir(mRawPath.c_str(), 0700, AID_ROOT, AID_ROOT)) {
Jeff Sharkey66270a22015-06-24 11:49:24 -0700130 PLOG(ERROR) << getId() << " failed to create mount points";
Jeff Sharkeydeb24052015-03-02 21:01:40 -0800131 return -errno;
132 }
133
Dan Pasanencb16b162015-10-27 22:52:37 -0500134 int ret = 0;
135 if (mFsType == "exfat") {
136 ret = exfat::Check(mDevPath);
137 } else if (mFsType == "ext4") {
Michael Bestas86918bf2015-12-06 23:53:55 +0200138 ret = ext4::Check(mDevPath, mRawPath, false);
Dan Pasanencb16b162015-10-27 22:52:37 -0500139 } else if (mFsType == "f2fs") {
Michael Bestas86918bf2015-12-06 23:53:55 +0200140 ret = f2fs::Check(mDevPath, false);
Dan Pasanencb16b162015-10-27 22:52:37 -0500141 } else if (mFsType == "ntfs") {
142 ret = ntfs::Check(mDevPath);
143 } else if (mFsType == "vfat") {
144 ret = vfat::Check(mDevPath);
145 } else {
146 LOG(WARNING) << getId() << " unsupported filesystem check, skipping";
147 }
148 if (ret) {
149 LOG(ERROR) << getId() << " failed filesystem check";
150 return -EIO;
151 }
152
153 if (mFsType == "exfat") {
154 ret = exfat::Mount(mDevPath, mRawPath, AID_MEDIA_RW, AID_MEDIA_RW, 0007);
155 } else if (mFsType == "ext4") {
Sam Mortimer09aef342015-11-27 15:27:03 -0800156 ret = ext4::Mount(mDevPath, mRawPath, false, false, true, mMntOpts,
157 false, true);
Dan Pasanencb16b162015-10-27 22:52:37 -0500158 } else if (mFsType == "f2fs") {
Sam Mortimer09aef342015-11-27 15:27:03 -0800159 ret = f2fs::Mount(mDevPath, mRawPath, mMntOpts, false, true);
Dan Pasanencb16b162015-10-27 22:52:37 -0500160 } else if (mFsType == "ntfs") {
161 ret = ntfs::Mount(mDevPath, mRawPath, AID_MEDIA_RW, AID_MEDIA_RW, 0007);
162 } else if (mFsType == "vfat") {
163 ret = vfat::Mount(mDevPath, mRawPath, false, false, false,
164 AID_MEDIA_RW, AID_MEDIA_RW, 0007, true);
165 } else {
166 ret = ::mount(mDevPath.c_str(), mRawPath.c_str(), mFsType.c_str(), 0, NULL);
167 }
168 if (ret) {
169 PLOG(ERROR) << getId() << " failed to mount " << mDevPath;
170 return -EIO;
Jeff Sharkeydeb24052015-03-02 21:01:40 -0800171 }
172
Jeff Sharkeyf1b996d2015-04-17 17:35:20 -0700173 if (getMountFlags() & MountFlags::kPrimary) {
Jeff Sharkey36801cc2015-03-13 16:09:20 -0700174 initAsecStage();
175 }
176
Jeff Sharkeyc7b5b572015-06-30 15:54:17 -0700177 if (!(getMountFlags() & MountFlags::kVisible)) {
178 // Not visible to apps, so no need to spin up FUSE
179 return OK;
180 }
181
Qin Chaoe0074f12015-12-15 15:20:41 +0800182 if (fs_prepare_dir(mFuseDefault.c_str(), 0700, AID_ROOT, AID_ROOT) ||
Paul Crowleyedf7a4e2018-09-18 15:14:18 -0700183 fs_prepare_dir(mFuseRead.c_str(), 0700, AID_ROOT, AID_ROOT) ||
Sudheer Shankadd4bb172019-01-16 23:35:49 -0800184 fs_prepare_dir(mFuseWrite.c_str(), 0700, AID_ROOT, AID_ROOT) ||
185 fs_prepare_dir(mFuseFull.c_str(), 0700, AID_ROOT, AID_ROOT)) {
Qin Chaoe0074f12015-12-15 15:20:41 +0800186 PLOG(ERROR) << getId() << " failed to create FUSE mount points";
187 return -errno;
188 }
189
Sudheer Shankadd4bb172019-01-16 23:35:49 -0800190 dev_t before = GetDevice(mFuseFull);
Jeff Sharkey66270a22015-06-24 11:49:24 -0700191
Jeff Sharkeydeb24052015-03-02 21:01:40 -0800192 if (!(mFusePid = fork())) {
Jeff Sharkeyc7b5b572015-06-30 15:54:17 -0700193 if (getMountFlags() & MountFlags::kPrimary) {
Paul Crowleyedf7a4e2018-09-18 15:14:18 -0700194 // clang-format off
Jeff Sharkey36801cc2015-03-13 16:09:20 -0700195 if (execl(kFusePath, kFusePath,
Jeff Sharkeydeb24052015-03-02 21:01:40 -0800196 "-u", "1023", // AID_MEDIA_RW
197 "-g", "1023", // AID_MEDIA_RW
Jeff Sharkey20642ae2015-07-28 10:57:29 -0700198 "-U", std::to_string(getMountUserId()).c_str(),
Jeff Sharkey66270a22015-06-24 11:49:24 -0700199 "-w",
Jeff Sharkeydeb24052015-03-02 21:01:40 -0800200 mRawPath.c_str(),
Jeff Sharkey66270a22015-06-24 11:49:24 -0700201 stableName.c_str(),
Jeff Sharkey36801cc2015-03-13 16:09:20 -0700202 NULL)) {
Paul Crowleyedf7a4e2018-09-18 15:14:18 -0700203 // clang-format on
Jeff Sharkey36801cc2015-03-13 16:09:20 -0700204 PLOG(ERROR) << "Failed to exec";
Jeff Sharkeydeb24052015-03-02 21:01:40 -0800205 }
206 } else {
Paul Crowleyedf7a4e2018-09-18 15:14:18 -0700207 // clang-format off
Sudheer Shanka55049012019-01-09 12:15:15 -0800208 if (execl(kFusePath, kFusePath,
209 "-u", "1023", // AID_MEDIA_RW
210 "-g", "1023", // AID_MEDIA_RW
211 "-U", std::to_string(getMountUserId()).c_str(),
212 mRawPath.c_str(),
213 stableName.c_str(),
214 NULL)) {
215 // clang-format on
216 PLOG(ERROR) << "Failed to exec";
Jeff Sharkeydeb24052015-03-02 21:01:40 -0800217 }
218 }
219
Jeff Sharkeyc7b5b572015-06-30 15:54:17 -0700220 LOG(ERROR) << "FUSE exiting";
Jeff Sharkeydeb24052015-03-02 21:01:40 -0800221 _exit(1);
222 }
223
224 if (mFusePid == -1) {
Jeff Sharkey9c484982015-03-31 10:35:33 -0700225 PLOG(ERROR) << getId() << " failed to fork";
Jeff Sharkeydeb24052015-03-02 21:01:40 -0800226 return -errno;
227 }
228
Jeff Sharkey7bdf4d52017-09-18 14:47:10 -0600229 nsecs_t start = systemTime(SYSTEM_TIME_BOOTTIME);
Sudheer Shankadd4bb172019-01-16 23:35:49 -0800230 while (before == GetDevice(mFuseFull)) {
Sudheer Shanka4b6ca4e2018-09-21 10:54:54 -0700231 LOG(DEBUG) << "Waiting for FUSE to spin up...";
Paul Crowleyedf7a4e2018-09-18 15:14:18 -0700232 usleep(50000); // 50ms
Jeff Sharkey7bdf4d52017-09-18 14:47:10 -0600233
234 nsecs_t now = systemTime(SYSTEM_TIME_BOOTTIME);
235 if (nanoseconds_to_milliseconds(now - start) > 5000) {
236 LOG(WARNING) << "Timed out while waiting for FUSE to spin up";
237 return -ETIMEDOUT;
238 }
Jeff Sharkey66270a22015-06-24 11:49:24 -0700239 }
Daniel Rosenberg1d79d102017-07-11 17:59:55 -0700240 /* sdcardfs will have exited already. FUSE will still be running */
Daniel Rosenberg8b9a5b32018-03-12 15:47:23 -0700241 TEMP_FAILURE_RETRY(waitpid(mFusePid, nullptr, 0));
242 mFusePid = 0;
Jeff Sharkey66270a22015-06-24 11:49:24 -0700243
Jeff Sharkeydeb24052015-03-02 21:01:40 -0800244 return OK;
245}
246
247status_t PublicVolume::doUnmount() {
John Cormie25cc7e32016-04-18 14:23:29 -0700248 // Unmount the storage before we kill the FUSE process. If we kill
249 // the FUSE process first, most file system operations will return
250 // ENOTCONN until the unmount completes. This is an exotic and unusual
251 // error code and might cause broken behaviour in applications.
Jeff Sharkey8aff8542016-03-30 20:37:28 -0600252 KillProcessesUsingPath(getPath());
253
Jeff Sharkey48d81d32015-04-12 21:50:32 -0700254 ForceUnmount(kAsecPath);
Jeff Sharkey66270a22015-06-24 11:49:24 -0700255
256 ForceUnmount(mFuseDefault);
257 ForceUnmount(mFuseRead);
258 ForceUnmount(mFuseWrite);
Sudheer Shankadd4bb172019-01-16 23:35:49 -0800259 ForceUnmount(mFuseFull);
Jeff Sharkeydeb24052015-03-02 21:01:40 -0800260 ForceUnmount(mRawPath);
261
Jeff Sharkey66270a22015-06-24 11:49:24 -0700262 rmdir(mFuseDefault.c_str());
263 rmdir(mFuseRead.c_str());
264 rmdir(mFuseWrite.c_str());
Sudheer Shankadd4bb172019-01-16 23:35:49 -0800265 rmdir(mFuseFull.c_str());
Jeff Sharkey66270a22015-06-24 11:49:24 -0700266 rmdir(mRawPath.c_str());
Jeff Sharkey36801cc2015-03-13 16:09:20 -0700267
Jeff Sharkey66270a22015-06-24 11:49:24 -0700268 mFuseDefault.clear();
269 mFuseRead.clear();
270 mFuseWrite.clear();
Sudheer Shankadd4bb172019-01-16 23:35:49 -0800271 mFuseFull.clear();
Jeff Sharkey36801cc2015-03-13 16:09:20 -0700272 mRawPath.clear();
Jeff Sharkeydeb24052015-03-02 21:01:40 -0800273
274 return OK;
275}
276
Jeff Sharkeyd0640f62015-05-21 22:35:42 -0700277status_t PublicVolume::doFormat(const std::string& fsType) {
Oleksiy Avramchenko4cff06d2018-05-23 18:59:48 +0200278 bool useVfat = vfat::IsSupported();
279 bool useExfat = exfat::IsSupported();
280 status_t res = OK;
281
282 // Resolve the target filesystem type
283 if (fsType == "auto" && useVfat && useExfat) {
284 uint64_t size = 0;
285
286 res = GetBlockDevSize(mDevPath, &size);
287 if (res != OK) {
288 LOG(ERROR) << "Couldn't get device size " << mDevPath;
289 return res;
Jeff Sharkeyd0640f62015-05-21 22:35:42 -0700290 }
Oleksiy Avramchenko4cff06d2018-05-23 18:59:48 +0200291
292 // If both vfat & exfat are supported use exfat for SDXC (>~32GiB) cards
293 if (size > 32896LL * 1024 * 1024) {
294 useVfat = false;
295 } else {
296 useExfat = false;
Jeff Sharkeyd0640f62015-05-21 22:35:42 -0700297 }
Oleksiy Avramchenko4cff06d2018-05-23 18:59:48 +0200298 } else if (fsType == "vfat") {
299 useExfat = false;
300 } else if (fsType == "exfat") {
301 useVfat = false;
302 }
303
Dan Pasanencb16b162015-10-27 22:52:37 -0500304 if (!IsFilesystemSupported(fsType) && !useVfat && !useExfat) {
Jeff Sharkeyd0640f62015-05-21 22:35:42 -0700305 LOG(ERROR) << "Unsupported filesystem " << fsType;
306 return -EINVAL;
Jeff Sharkeydeb24052015-03-02 21:01:40 -0800307 }
Jeff Sharkeyd0640f62015-05-21 22:35:42 -0700308
Oleksiy Avramchenko4cff06d2018-05-23 18:59:48 +0200309 if (WipeBlockDevice(mDevPath) != OK) {
310 LOG(WARNING) << getId() << " failed to wipe";
311 }
312
313 if (useVfat) {
314 res = vfat::Format(mDevPath, 0);
315 } else if (useExfat) {
316 res = exfat::Format(mDevPath);
Dan Pasanencb16b162015-10-27 22:52:37 -0500317 } else if (fsType == "ext4") {
318 res = ext4::Format(mDevPath, 0, mRawPath);
319 } else if (fsType == "f2fs") {
320 res = f2fs::Format(mDevPath);
321 } else if (fsType == "ntfs") {
322 res = ntfs::Format(mDevPath);
323 } else {
324 LOG(ERROR) << getId() << " unrecognized filesystem " << fsType;
325 res = -1;
326 errno = EIO;
Oleksiy Avramchenko4cff06d2018-05-23 18:59:48 +0200327 }
328
329 if (res != OK) {
330 LOG(ERROR) << getId() << " failed to format";
331 res = -errno;
332 }
333
334 return res;
Jeff Sharkeydeb24052015-03-02 21:01:40 -0800335}
336
Jeff Sharkeydeb24052015-03-02 21:01:40 -0800337} // namespace vold
338} // namespace android