blob: d1a0b2fdf16764314ab43bd9b84fd031910906e8 [file] [log] [blame]
San Mehatf1b736b2009-10-10 17:22:08 -07001/*
2 * Copyright (C) 2008 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
Yabin Cuid1104f72015-01-02 13:28:28 -080017#include <dirent.h>
San Mehatf1b736b2009-10-10 17:22:08 -070018#include <errno.h>
San Mehata2677e42009-12-13 10:40:18 -080019#include <fcntl.h>
Kenny Root344ca102012-04-03 17:23:01 -070020#include <fts.h>
Yabin Cuid1104f72015-01-02 13:28:28 -080021#include <mntent.h>
22#include <stdio.h>
23#include <stdlib.h>
24#include <string.h>
25#include <sys/ioctl.h>
26#include <sys/mount.h>
San Mehata19b2502010-01-06 10:33:53 -080027#include <sys/stat.h>
28#include <sys/types.h>
Jeff Sharkey66270a22015-06-24 11:49:24 -070029#include <sys/wait.h>
Yabin Cuid1104f72015-01-02 13:28:28 -080030#include <unistd.h>
San Mehata19b2502010-01-06 10:33:53 -080031
San Mehata2677e42009-12-13 10:40:18 -080032#include <linux/kdev_t.h>
San Mehatf1b736b2009-10-10 17:22:08 -070033
34#define LOG_TAG "Vold"
35
Kenny Root7b18a7b2010-03-15 13:13:41 -070036#include <openssl/md5.h>
37
Jeff Sharkey36801cc2015-03-13 16:09:20 -070038#include <base/logging.h>
39#include <base/stringprintf.h>
Jeff Sharkey71ebe152013-09-17 17:24:38 -070040#include <cutils/fs.h>
San Mehatf1b736b2009-10-10 17:22:08 -070041#include <cutils/log.h>
42
Robert Craigb9e3ba52014-02-04 10:53:00 -050043#include <selinux/android.h>
44
San Mehatfd7f5872009-10-12 11:32:47 -070045#include <sysutils/NetlinkEvent.h>
46
Kenny Root344ca102012-04-03 17:23:01 -070047#include <private/android_filesystem_config.h>
48
Jeff Sharkey5a6bfca2015-05-14 20:33:55 -070049#include "Benchmark.h"
Jeff Sharkey36801cc2015-03-13 16:09:20 -070050#include "EmulatedVolume.h"
San Mehatf1b736b2009-10-10 17:22:08 -070051#include "VolumeManager.h"
Jeff Sharkey36801cc2015-03-13 16:09:20 -070052#include "NetlinkManager.h"
San Mehata2677e42009-12-13 10:40:18 -080053#include "ResponseCode.h"
San Mehata19b2502010-01-06 10:33:53 -080054#include "Loop.h"
Jeff Sharkeyd0640f62015-05-21 22:35:42 -070055#include "fs/Ext4.h"
56#include "fs/Vfat.h"
Jeff Sharkey36801cc2015-03-13 16:09:20 -070057#include "Utils.h"
San Mehatb78a32c2010-01-10 13:02:12 -080058#include "Devmapper.h"
San Mehat586536c2010-02-16 17:12:00 -080059#include "Process.h"
San Mehatfcf24fe2010-03-03 12:37:32 -080060#include "Asec.h"
Hiroaki Miyazawa14eab552015-02-04 13:29:15 +090061#include "VoldUtil.h"
Ken Sumrall29d8da82011-05-18 17:20:07 -070062#include "cryptfs.h"
Jeff Sharkeybc40cc82015-06-18 14:25:08 -070063#include "fstrim.h"
San Mehat23969932010-01-09 07:08:06 -080064
Mike Lockwood97f2fc12011-06-07 10:51:38 -070065#define MASS_STORAGE_FILE_PATH "/sys/class/android_usb/android0/f_mass_storage/lun/file"
66
Daniel Rosenberg6a74dca2014-05-23 13:47:00 -070067#define ROUND_UP_POWER_OF_2(number, po2) (((!!(number & ((1U << po2) - 1))) << po2)\
68 + (number & (~((1U << po2) - 1))))
69
Jeff Sharkey36801cc2015-03-13 16:09:20 -070070using android::base::StringPrintf;
71
Jeff Sharkey9f18fe72015-04-01 23:32:18 -070072/*
73 * Path to external storage where *only* root can access ASEC image files
74 */
75const char *VolumeManager::SEC_ASECDIR_EXT = "/mnt/secure/asec";
76
77/*
78 * Path to internal storage where *only* root can access ASEC image files
79 */
80const char *VolumeManager::SEC_ASECDIR_INT = "/data/app-asec";
81
82/*
83 * Path to where secure containers are mounted
84 */
85const char *VolumeManager::ASECDIR = "/mnt/asec";
86
87/*
88 * Path to where OBBs are mounted
89 */
90const char *VolumeManager::LOOPDIR = "/mnt/obb";
91
Jeff Sharkey36801cc2015-03-13 16:09:20 -070092static const char* kUserMountPath = "/mnt/user";
93
Jeff Sharkey36801cc2015-03-13 16:09:20 -070094static const unsigned int kMajorBlockMmc = 179;
95
Daniel Rosenbergfcd34a02014-05-22 11:23:56 -070096/* writes superblock at end of file or device given by name */
97static int writeSuperBlock(const char* name, struct asec_superblock *sb, unsigned int numImgSectors) {
Jeff Sharkeyce6a9132015-04-08 21:07:21 -070098 int sbfd = open(name, O_RDWR | O_CLOEXEC);
Daniel Rosenbergfcd34a02014-05-22 11:23:56 -070099 if (sbfd < 0) {
100 SLOGE("Failed to open %s for superblock write (%s)", name, strerror(errno));
101 return -1;
102 }
103
104 if (lseek(sbfd, (numImgSectors * 512), SEEK_SET) < 0) {
105 SLOGE("Failed to lseek for superblock (%s)", strerror(errno));
106 close(sbfd);
107 return -1;
108 }
109
110 if (write(sbfd, sb, sizeof(struct asec_superblock)) != sizeof(struct asec_superblock)) {
111 SLOGE("Failed to write superblock (%s)", strerror(errno));
112 close(sbfd);
113 return -1;
114 }
115 close(sbfd);
116 return 0;
117}
118
119static int adjustSectorNumExt4(unsigned numSectors) {
Daniel Rosenberge9196fe2014-06-10 17:16:03 -0700120 // Ext4 started to reserve 2% or 4096 clusters, whichever is smaller for
121 // preventing costly operations or unexpected ENOSPC error.
122 // Ext4::format() uses default block size without clustering.
123 unsigned clusterSectors = 4096 / 512;
124 unsigned reservedSectors = (numSectors * 2)/100 + (numSectors % 50 > 0);
125 numSectors += reservedSectors > (4096 * clusterSectors) ? (4096 * clusterSectors) : reservedSectors;
Daniel Rosenbergfcd34a02014-05-22 11:23:56 -0700126 return ROUND_UP_POWER_OF_2(numSectors, 3);
127}
128
129static int adjustSectorNumFAT(unsigned numSectors) {
130 /*
131 * Add some headroom
132 */
133 unsigned fatSize = (((numSectors * 4) / 512) + 1) * 2;
134 numSectors += fatSize + 2;
135 /*
136 * FAT is aligned to 32 kb with 512b sectors.
137 */
138 return ROUND_UP_POWER_OF_2(numSectors, 6);
139}
140
141static int setupLoopDevice(char* buffer, size_t len, const char* asecFileName, const char* idHash, bool debug) {
142 if (Loop::lookupActive(idHash, buffer, len)) {
143 if (Loop::create(idHash, asecFileName, buffer, len)) {
144 SLOGE("ASEC loop device creation failed for %s (%s)", asecFileName, strerror(errno));
145 return -1;
146 }
147 if (debug) {
148 SLOGD("New loop device created at %s", buffer);
149 }
150 } else {
151 if (debug) {
152 SLOGD("Found active loopback for %s at %s", asecFileName, buffer);
153 }
154 }
155 return 0;
156}
157
158static int setupDevMapperDevice(char* buffer, size_t len, const char* loopDevice, const char* asecFileName, const char* key, const char* idHash , int numImgSectors, bool* createdDMDevice, bool debug) {
159 if (strcmp(key, "none")) {
160 if (Devmapper::lookupActive(idHash, buffer, len)) {
161 if (Devmapper::create(idHash, loopDevice, key, numImgSectors,
162 buffer, len)) {
163 SLOGE("ASEC device mapping failed for %s (%s)", asecFileName, strerror(errno));
164 return -1;
165 }
166 if (debug) {
167 SLOGD("New devmapper instance created at %s", buffer);
168 }
169 } else {
170 if (debug) {
171 SLOGD("Found active devmapper for %s at %s", asecFileName, buffer);
172 }
173 }
174 *createdDMDevice = true;
175 } else {
176 strcpy(buffer, loopDevice);
177 *createdDMDevice = false;
178 }
179 return 0;
180}
181
182static void waitForDevMapper(const char *dmDevice) {
183 /*
184 * Wait for the device mapper node to be created. Sometimes it takes a
185 * while. Wait for up to 1 second. We could also inspect incoming uevents,
186 * but that would take more effort.
187 */
188 int tries = 25;
189 while (tries--) {
190 if (!access(dmDevice, F_OK) || errno != ENOENT) {
191 break;
192 }
193 usleep(40 * 1000);
194 }
195}
196
San Mehatf1b736b2009-10-10 17:22:08 -0700197VolumeManager *VolumeManager::sInstance = NULL;
198
199VolumeManager *VolumeManager::Instance() {
200 if (!sInstance)
201 sInstance = new VolumeManager();
202 return sInstance;
203}
204
205VolumeManager::VolumeManager() {
San Mehatd9a4e352010-03-12 13:32:47 -0800206 mDebug = false;
San Mehat88705162010-01-15 09:26:28 -0800207 mActiveContainers = new AsecIdCollection();
San Mehatf1b736b2009-10-10 17:22:08 -0700208 mBroadcaster = NULL;
Mike Lockwooda28056b2010-10-28 15:21:24 -0400209 mUmsSharingCount = 0;
210 mSavedDirtyRatio = -1;
211 // set dirty ratio to 0 when UMS is active
212 mUmsDirtyRatio = 0;
San Mehatf1b736b2009-10-10 17:22:08 -0700213}
214
215VolumeManager::~VolumeManager() {
San Mehat88705162010-01-15 09:26:28 -0800216 delete mActiveContainers;
San Mehatf1b736b2009-10-10 17:22:08 -0700217}
218
Kenny Root7b18a7b2010-03-15 13:13:41 -0700219char *VolumeManager::asecHash(const char *id, char *buffer, size_t len) {
Kenny Rootacc9e7d2010-06-18 19:06:50 -0700220 static const char* digits = "0123456789abcdef";
221
Kenny Root7b18a7b2010-03-15 13:13:41 -0700222 unsigned char sig[MD5_DIGEST_LENGTH];
223
Kenny Rootacc9e7d2010-06-18 19:06:50 -0700224 if (buffer == NULL) {
225 SLOGE("Destination buffer is NULL");
226 errno = ESPIPE;
227 return NULL;
228 } else if (id == NULL) {
229 SLOGE("Source buffer is NULL");
230 errno = ESPIPE;
231 return NULL;
232 } else if (len < MD5_ASCII_LENGTH_PLUS_NULL) {
Colin Cross59846b62014-02-06 20:34:29 -0800233 SLOGE("Target hash buffer size < %d bytes (%zu)",
Kenny Rootacc9e7d2010-06-18 19:06:50 -0700234 MD5_ASCII_LENGTH_PLUS_NULL, len);
San Mehatd9a4e352010-03-12 13:32:47 -0800235 errno = ESPIPE;
236 return NULL;
237 }
Kenny Root7b18a7b2010-03-15 13:13:41 -0700238
239 MD5(reinterpret_cast<const unsigned char*>(id), strlen(id), sig);
San Mehatd9a4e352010-03-12 13:32:47 -0800240
Kenny Rootacc9e7d2010-06-18 19:06:50 -0700241 char *p = buffer;
Kenny Root7b18a7b2010-03-15 13:13:41 -0700242 for (int i = 0; i < MD5_DIGEST_LENGTH; i++) {
Kenny Rootacc9e7d2010-06-18 19:06:50 -0700243 *p++ = digits[sig[i] >> 4];
244 *p++ = digits[sig[i] & 0x0F];
San Mehatd9a4e352010-03-12 13:32:47 -0800245 }
Kenny Rootacc9e7d2010-06-18 19:06:50 -0700246 *p = '\0';
San Mehatd9a4e352010-03-12 13:32:47 -0800247
248 return buffer;
249}
250
Jeff Sharkeyf1b996d2015-04-17 17:35:20 -0700251int VolumeManager::setDebug(bool enable) {
San Mehatd9a4e352010-03-12 13:32:47 -0800252 mDebug = enable;
Jeff Sharkeyf1b996d2015-04-17 17:35:20 -0700253 return 0;
San Mehatd9a4e352010-03-12 13:32:47 -0800254}
255
San Mehatf1b736b2009-10-10 17:22:08 -0700256int VolumeManager::start() {
Jeff Sharkey36801cc2015-03-13 16:09:20 -0700257 // Always start from a clean slate by unmounting everything in
258 // directories that we own, in case we crashed.
Jeff Sharkey9c484982015-03-31 10:35:33 -0700259 unmountAll();
Jeff Sharkey36801cc2015-03-13 16:09:20 -0700260
261 // Assume that we always have an emulated volume on internal
262 // storage; the framework will decide if it should be mounted.
Jeff Sharkeyc8e04c52015-04-21 12:14:17 -0700263 CHECK(mInternalEmulated == nullptr);
Jeff Sharkey36801cc2015-03-13 16:09:20 -0700264 mInternalEmulated = std::shared_ptr<android::vold::VolumeBase>(
Jeff Sharkey3161fb32015-04-12 16:03:33 -0700265 new android::vold::EmulatedVolume("/data/media"));
Jeff Sharkey36801cc2015-03-13 16:09:20 -0700266 mInternalEmulated->create();
267
San Mehatf1b736b2009-10-10 17:22:08 -0700268 return 0;
269}
270
271int VolumeManager::stop() {
Jeff Sharkeyc8e04c52015-04-21 12:14:17 -0700272 CHECK(mInternalEmulated != nullptr);
Jeff Sharkey36801cc2015-03-13 16:09:20 -0700273 mInternalEmulated->destroy();
274 mInternalEmulated = nullptr;
San Mehatf1b736b2009-10-10 17:22:08 -0700275 return 0;
276}
277
San Mehatfd7f5872009-10-12 11:32:47 -0700278void VolumeManager::handleBlockEvent(NetlinkEvent *evt) {
Jeff Sharkeyc8e04c52015-04-21 12:14:17 -0700279 std::lock_guard<std::mutex> lock(mLock);
280
Jeff Sharkeyf1b996d2015-04-17 17:35:20 -0700281 if (mDebug) {
282 LOG(VERBOSE) << "----------------";
283 LOG(VERBOSE) << "handleBlockEvent with action " << (int) evt->getAction();
284 evt->dump();
285 }
San Mehatf1b736b2009-10-10 17:22:08 -0700286
Jeff Sharkey36801cc2015-03-13 16:09:20 -0700287 std::string eventPath(evt->findParam("DEVPATH"));
288 std::string devType(evt->findParam("DEVTYPE"));
289
290 if (devType != "disk") return;
291
292 int major = atoi(evt->findParam("MAJOR"));
293 int minor = atoi(evt->findParam("MINOR"));
294 dev_t device = makedev(major, minor);
295
296 switch (evt->getAction()) {
297 case NetlinkEvent::Action::kAdd: {
298 for (auto source : mDiskSources) {
299 if (source->matches(eventPath)) {
300 // For now, assume that MMC devices are SD, and that
301 // everything else is USB
302 int flags = source->getFlags();
303 if (major == kMajorBlockMmc) {
304 flags |= android::vold::Disk::Flags::kSd;
305 } else {
306 flags |= android::vold::Disk::Flags::kUsb;
307 }
308
309 auto disk = new android::vold::Disk(eventPath, device,
310 source->getNickname(), flags);
311 disk->create();
312 mDisks.push_back(std::shared_ptr<android::vold::Disk>(disk));
313 break;
314 }
315 }
316 break;
317 }
318 case NetlinkEvent::Action::kChange: {
Jeff Sharkey7d9d0112015-04-14 23:14:23 -0700319 LOG(DEBUG) << "Disk at " << major << ":" << minor << " changed";
Jeff Sharkey36801cc2015-03-13 16:09:20 -0700320 for (auto disk : mDisks) {
321 if (disk->getDevice() == device) {
322 disk->readMetadata();
323 disk->readPartitions();
324 }
325 }
326 break;
327 }
328 case NetlinkEvent::Action::kRemove: {
329 auto i = mDisks.begin();
330 while (i != mDisks.end()) {
331 if ((*i)->getDevice() == device) {
332 (*i)->destroy();
333 i = mDisks.erase(i);
334 } else {
335 ++i;
336 }
337 }
338 break;
339 }
340 default: {
341 LOG(WARNING) << "Unexpected block event action " << (int) evt->getAction();
342 break;
343 }
344 }
345}
346
347void VolumeManager::addDiskSource(const std::shared_ptr<DiskSource>& diskSource) {
348 mDiskSources.push_back(diskSource);
349}
350
351std::shared_ptr<android::vold::Disk> VolumeManager::findDisk(const std::string& id) {
352 for (auto disk : mDisks) {
353 if (disk->getId() == id) {
354 return disk;
San Mehatf1b736b2009-10-10 17:22:08 -0700355 }
356 }
Jeff Sharkey36801cc2015-03-13 16:09:20 -0700357 return nullptr;
358}
San Mehatf1b736b2009-10-10 17:22:08 -0700359
Jeff Sharkey36801cc2015-03-13 16:09:20 -0700360std::shared_ptr<android::vold::VolumeBase> VolumeManager::findVolume(const std::string& id) {
361 if (mInternalEmulated->getId() == id) {
362 return mInternalEmulated;
San Mehatf1b736b2009-10-10 17:22:08 -0700363 }
Jeff Sharkey36801cc2015-03-13 16:09:20 -0700364 for (auto disk : mDisks) {
365 auto vol = disk->findVolume(id);
366 if (vol != nullptr) {
367 return vol;
368 }
369 }
370 return nullptr;
371}
372
Jeff Sharkey5a6bfca2015-05-14 20:33:55 -0700373nsecs_t VolumeManager::benchmarkVolume(const std::string& id) {
374 std::string path;
375 std::string sysPath;
376 auto vol = findVolume(id);
377 if (vol != nullptr) {
378 if (vol->getState() == android::vold::VolumeBase::State::kMounted) {
379 path = vol->getPath();
380 auto disk = findDisk(vol->getDiskId());
381 if (disk != nullptr) {
382 sysPath = disk->getSysPath();
383 }
384 }
385 } else {
386 path = "/data";
387 }
388
389 if (path.empty()) {
390 LOG(WARNING) << "Failed to find volume for " << id;
391 return -1;
392 }
393
394 path += "/misc";
395 if (android::vold::PrepareDir(path, 01771, AID_SYSTEM, AID_MISC)) {
396 return -1;
397 }
398 path += "/vold";
399 if (android::vold::PrepareDir(path, 0700, AID_ROOT, AID_ROOT)) {
400 return -1;
401 }
402 path += "/bench";
403 if (android::vold::PrepareDir(path, 0700, AID_ROOT, AID_ROOT)) {
404 return -1;
405 }
406
407 return android::vold::Benchmark(path, sysPath);
408}
409
Jeff Sharkeybc40cc82015-06-18 14:25:08 -0700410int VolumeManager::forgetPartition(const std::string& partGuid) {
411 std::string normalizedGuid;
412 if (android::vold::NormalizeHex(partGuid, normalizedGuid)) {
413 LOG(WARNING) << "Invalid GUID " << partGuid;
414 return -1;
415 }
416
417 std::string keyPath = android::vold::BuildKeyPath(normalizedGuid);
418 if (unlink(keyPath.c_str()) != 0) {
419 LOG(ERROR) << "Failed to unlink " << keyPath;
420 return -1;
421 }
422
423 return 0;
424}
425
Jeff Sharkey36801cc2015-03-13 16:09:20 -0700426int VolumeManager::linkPrimary(userid_t userId) {
427 std::string source(mPrimary->getPath());
428 if (mPrimary->getType() == android::vold::VolumeBase::Type::kEmulated) {
429 source = StringPrintf("%s/%d", source.c_str(), userId);
430 }
431
432 std::string target(StringPrintf("/mnt/user/%d/primary", userId));
433 if (TEMP_FAILURE_RETRY(unlink(target.c_str()))) {
434 if (errno != ENOENT) {
435 SLOGW("Failed to unlink %s: %s", target.c_str(), strerror(errno));
436 }
437 }
Jeff Sharkey1bfb3752015-04-29 15:22:23 -0700438 LOG(DEBUG) << "Linking " << source << " to " << target;
Jeff Sharkey36801cc2015-03-13 16:09:20 -0700439 if (TEMP_FAILURE_RETRY(symlink(source.c_str(), target.c_str()))) {
440 SLOGW("Failed to link %s to %s: %s", source.c_str(), target.c_str(),
441 strerror(errno));
442 return -errno;
443 }
444 return 0;
445}
446
Jeff Sharkeybd3038d2015-06-10 09:42:01 -0700447int VolumeManager::onUserAdded(userid_t userId, int userSerialNumber) {
448 mAddedUsers[userId] = userSerialNumber;
449 return 0;
450}
451
452int VolumeManager::onUserRemoved(userid_t userId) {
453 mAddedUsers.erase(userId);
454 return 0;
455}
456
457int VolumeManager::onUserStarted(userid_t userId) {
Jeff Sharkey36801cc2015-03-13 16:09:20 -0700458 // Note that sometimes the system will spin up processes from Zygote
459 // before actually starting the user, so we're okay if Zygote
460 // already created this directory.
461 std::string path(StringPrintf("%s/%d", kUserMountPath, userId));
462 fs_prepare_dir(path.c_str(), 0755, AID_ROOT, AID_ROOT);
463
Jeff Sharkeybd3038d2015-06-10 09:42:01 -0700464 mStartedUsers.insert(userId);
Jeff Sharkey36801cc2015-03-13 16:09:20 -0700465 if (mPrimary) {
466 linkPrimary(userId);
467 }
468 return 0;
469}
470
Jeff Sharkeybd3038d2015-06-10 09:42:01 -0700471int VolumeManager::onUserStopped(userid_t userId) {
472 mStartedUsers.erase(userId);
Jeff Sharkey36801cc2015-03-13 16:09:20 -0700473 return 0;
474}
475
476int VolumeManager::setPrimary(const std::shared_ptr<android::vold::VolumeBase>& vol) {
477 mPrimary = vol;
Jeff Sharkeybd3038d2015-06-10 09:42:01 -0700478 for (userid_t userId : mStartedUsers) {
Jeff Sharkey36801cc2015-03-13 16:09:20 -0700479 linkPrimary(userId);
480 }
481 return 0;
482}
483
Jeff Sharkeyc7b5b572015-06-30 15:54:17 -0700484static int sane_readlinkat(int dirfd, const char* path, char* buf, size_t bufsiz) {
485 ssize_t len = readlinkat(dirfd, path, buf, bufsiz);
486 if (len < 0) {
487 return -1;
488 } else if (len == (ssize_t) bufsiz) {
489 return -1;
490 } else {
491 buf[len] = '\0';
492 return 0;
493 }
494}
495
496static int unmount_tree(const char* path) {
497 size_t path_len = strlen(path);
498
499 FILE* fp = setmntent("/proc/mounts", "r");
500 if (fp == NULL) {
501 ALOGE("Error opening /proc/mounts: %s", strerror(errno));
502 return -errno;
503 }
504
505 // Some volumes can be stacked on each other, so force unmount in
506 // reverse order to give us the best chance of success.
507 std::list<std::string> toUnmount;
508 mntent* mentry;
509 while ((mentry = getmntent(fp)) != NULL) {
510 if (strncmp(mentry->mnt_dir, path, path_len) == 0) {
511 toUnmount.push_front(std::string(mentry->mnt_dir));
512 }
513 }
514 endmntent(fp);
515
516 for (auto path : toUnmount) {
517 if (umount2(path.c_str(), MNT_DETACH)) {
518 ALOGW("Failed to unmount %s: %s", path.c_str(), strerror(errno));
519 }
520 }
521 return 0;
522}
523
Jeff Sharkey66270a22015-06-24 11:49:24 -0700524int VolumeManager::remountUid(uid_t uid, const std::string& mode) {
525 LOG(DEBUG) << "Remounting " << uid << " as mode " << mode;
526
527 DIR* dir;
528 struct dirent* de;
529 char rootName[PATH_MAX];
530 char pidName[PATH_MAX];
531 int pidFd;
532 int nsFd;
533 struct stat sb;
534 pid_t child;
535
536 if (!(dir = opendir("/proc"))) {
537 PLOG(ERROR) << "Failed to opendir";
538 return -1;
539 }
540
541 // Figure out root namespace to compare against below
Jeff Sharkeyc7b5b572015-06-30 15:54:17 -0700542 if (sane_readlinkat(dirfd(dir), "1/ns/mnt", rootName, PATH_MAX) == -1) {
Jeff Sharkey66270a22015-06-24 11:49:24 -0700543 PLOG(ERROR) << "Failed to readlink";
544 closedir(dir);
545 return -1;
546 }
547
548 // Poke through all running PIDs look for apps running as UID
549 while ((de = readdir(dir))) {
550 pidFd = -1;
551 nsFd = -1;
552
553 pidFd = openat(dirfd(dir), de->d_name, O_RDONLY | O_DIRECTORY | O_CLOEXEC);
554 if (pidFd < 0) {
555 goto next;
556 }
557 if (fstat(pidFd, &sb) != 0) {
558 PLOG(WARNING) << "Failed to stat " << de->d_name;
559 goto next;
560 }
561 if (sb.st_uid != uid) {
562 goto next;
563 }
564
565 // Matches so far, but refuse to touch if in root namespace
566 LOG(DEBUG) << "Found matching PID " << de->d_name;
Jeff Sharkeyc7b5b572015-06-30 15:54:17 -0700567 if (sane_readlinkat(pidFd, "ns/mnt", pidName, PATH_MAX) == -1) {
Jeff Sharkey66270a22015-06-24 11:49:24 -0700568 PLOG(WARNING) << "Failed to read namespace for " << de->d_name;
569 goto next;
570 }
571 if (!strcmp(rootName, pidName)) {
572 LOG(WARNING) << "Skipping due to root namespace";
573 goto next;
574 }
575
576 // We purposefully leave the namespace open across the fork
577 nsFd = openat(pidFd, "ns/mnt", O_RDONLY);
578 if (nsFd < 0) {
Jeff Sharkeyc7b5b572015-06-30 15:54:17 -0700579 PLOG(WARNING) << "Failed to open namespace for " << de->d_name;
Jeff Sharkey66270a22015-06-24 11:49:24 -0700580 goto next;
581 }
582
583 if (!(child = fork())) {
584 if (setns(nsFd, CLONE_NEWNS) != 0) {
Jeff Sharkeyc7b5b572015-06-30 15:54:17 -0700585 PLOG(ERROR) << "Failed to setns for " << de->d_name;
Jeff Sharkey66270a22015-06-24 11:49:24 -0700586 _exit(1);
587 }
588
Jeff Sharkeyc7b5b572015-06-30 15:54:17 -0700589 unmount_tree("/storage");
Jeff Sharkey66270a22015-06-24 11:49:24 -0700590
591 std::string storageSource;
592 if (mode == "default") {
593 storageSource = "/mnt/runtime_default";
594 } else if (mode == "read") {
595 storageSource = "/mnt/runtime_read";
596 } else if (mode == "write") {
597 storageSource = "/mnt/runtime_write";
598 } else {
599 // Sane default of no storage visible
600 _exit(0);
601 }
602 if (TEMP_FAILURE_RETRY(mount(storageSource.c_str(), "/storage",
603 NULL, MS_BIND | MS_REC | MS_SLAVE, NULL)) == -1) {
Jeff Sharkeyc7b5b572015-06-30 15:54:17 -0700604 PLOG(ERROR) << "Failed to mount " << storageSource << " for "
605 << de->d_name;
606 _exit(1);
Jeff Sharkey66270a22015-06-24 11:49:24 -0700607 }
Jeff Sharkeyc7b5b572015-06-30 15:54:17 -0700608
609 // Mount user-specific symlink helper into place
610 userid_t user_id = multiuser_get_user_id(uid);
611 std::string userSource(StringPrintf("/mnt/user/%d", user_id));
612 if (TEMP_FAILURE_RETRY(mount(userSource.c_str(), "/storage/self",
613 NULL, MS_BIND, NULL)) == -1) {
614 PLOG(ERROR) << "Failed to mount " << userSource << " for "
615 << de->d_name;
616 _exit(1);
617 }
618
Jeff Sharkey66270a22015-06-24 11:49:24 -0700619 _exit(0);
620 }
621
622 if (child == -1) {
623 PLOG(ERROR) << "Failed to fork";
624 goto next;
625 } else {
626 TEMP_FAILURE_RETRY(waitpid(child, nullptr, 0));
627 }
628
629next:
630 close(nsFd);
631 close(pidFd);
632 }
633 closedir(dir);
634 return 0;
635}
636
Jeff Sharkey36801cc2015-03-13 16:09:20 -0700637int VolumeManager::reset() {
638 // Tear down all existing disks/volumes and start from a blank slate so
639 // newly connected framework hears all events.
640 mInternalEmulated->destroy();
641 mInternalEmulated->create();
642 for (auto disk : mDisks) {
643 disk->destroy();
644 disk->create();
645 }
Jeff Sharkeybd3038d2015-06-10 09:42:01 -0700646 mAddedUsers.clear();
647 mStartedUsers.clear();
Jeff Sharkey36801cc2015-03-13 16:09:20 -0700648 return 0;
649}
650
651int VolumeManager::shutdown() {
Jeff Sharkey9c484982015-03-31 10:35:33 -0700652 mInternalEmulated->destroy();
Jeff Sharkey36801cc2015-03-13 16:09:20 -0700653 for (auto disk : mDisks) {
654 disk->destroy();
655 }
656 mDisks.clear();
657 return 0;
San Mehatf1b736b2009-10-10 17:22:08 -0700658}
659
Jeff Sharkey9c484982015-03-31 10:35:33 -0700660int VolumeManager::unmountAll() {
Jeff Sharkeyc8e04c52015-04-21 12:14:17 -0700661 std::lock_guard<std::mutex> lock(mLock);
662
Jeff Sharkey9c484982015-03-31 10:35:33 -0700663 // First, try gracefully unmounting all known devices
664 if (mInternalEmulated != nullptr) {
665 mInternalEmulated->unmount();
666 }
667 for (auto disk : mDisks) {
668 disk->unmountAll();
669 }
670
671 // Worst case we might have some stale mounts lurking around, so
672 // force unmount those just to be safe.
673 FILE* fp = setmntent("/proc/mounts", "r");
674 if (fp == NULL) {
675 SLOGE("Error opening /proc/mounts: %s", strerror(errno));
676 return -errno;
677 }
678
679 // Some volumes can be stacked on each other, so force unmount in
680 // reverse order to give us the best chance of success.
681 std::list<std::string> toUnmount;
682 mntent* mentry;
683 while ((mentry = getmntent(fp)) != NULL) {
684 if (strncmp(mentry->mnt_dir, "/mnt/", 5) == 0
685 || strncmp(mentry->mnt_dir, "/storage/", 9) == 0) {
686 toUnmount.push_front(std::string(mentry->mnt_dir));
687 }
688 }
689 endmntent(fp);
690
691 for (auto path : toUnmount) {
692 SLOGW("Tearing down stale mount %s", path.c_str());
693 android::vold::ForceUnmount(path);
694 }
695
696 return 0;
697}
698
Kenny Root508c0e12010-07-12 09:59:49 -0700699int VolumeManager::getObbMountPath(const char *sourceFile, char *mountPath, int mountPathLen) {
700 char idHash[33];
701 if (!asecHash(sourceFile, idHash, sizeof(idHash))) {
702 SLOGE("Hash of '%s' failed (%s)", sourceFile, strerror(errno));
703 return -1;
704 }
705
706 memset(mountPath, 0, mountPathLen);
Jeff Sharkey9f18fe72015-04-01 23:32:18 -0700707 int written = snprintf(mountPath, mountPathLen, "%s/%s", VolumeManager::LOOPDIR, idHash);
rpcraigd1c226f2012-10-09 06:58:16 -0400708 if ((written < 0) || (written >= mountPathLen)) {
709 errno = EINVAL;
710 return -1;
711 }
Kenny Root508c0e12010-07-12 09:59:49 -0700712
713 if (access(mountPath, F_OK)) {
714 errno = ENOENT;
715 return -1;
716 }
717
718 return 0;
719}
720
San Mehata19b2502010-01-06 10:33:53 -0800721int VolumeManager::getAsecMountPath(const char *id, char *buffer, int maxlen) {
San Mehat88ac2c02010-03-23 11:15:58 -0700722 char asecFileName[255];
Kenny Root344ca102012-04-03 17:23:01 -0700723
Nick Kralevich0de7c612014-01-27 14:58:06 -0800724 if (!isLegalAsecId(id)) {
725 SLOGE("getAsecMountPath: Invalid asec id \"%s\"", id);
726 errno = EINVAL;
727 return -1;
728 }
729
Kenny Root344ca102012-04-03 17:23:01 -0700730 if (findAsec(id, asecFileName, sizeof(asecFileName))) {
731 SLOGE("Couldn't find ASEC %s", id);
732 return -1;
733 }
San Mehat88ac2c02010-03-23 11:15:58 -0700734
735 memset(buffer, 0, maxlen);
736 if (access(asecFileName, F_OK)) {
737 errno = ENOENT;
738 return -1;
739 }
San Mehata19b2502010-01-06 10:33:53 -0800740
Jeff Sharkey9f18fe72015-04-01 23:32:18 -0700741 int written = snprintf(buffer, maxlen, "%s/%s", VolumeManager::ASECDIR, id);
rpcraigd1c226f2012-10-09 06:58:16 -0400742 if ((written < 0) || (written >= maxlen)) {
743 SLOGE("getAsecMountPath failed for %s: couldn't construct path in buffer", id);
744 errno = EINVAL;
745 return -1;
746 }
747
San Mehata19b2502010-01-06 10:33:53 -0800748 return 0;
749}
750
Dianne Hackborn736910c2011-06-27 13:37:07 -0700751int VolumeManager::getAsecFilesystemPath(const char *id, char *buffer, int maxlen) {
752 char asecFileName[255];
Kenny Root344ca102012-04-03 17:23:01 -0700753
Nick Kralevich0de7c612014-01-27 14:58:06 -0800754 if (!isLegalAsecId(id)) {
755 SLOGE("getAsecFilesystemPath: Invalid asec id \"%s\"", id);
756 errno = EINVAL;
757 return -1;
758 }
759
Kenny Root344ca102012-04-03 17:23:01 -0700760 if (findAsec(id, asecFileName, sizeof(asecFileName))) {
761 SLOGE("Couldn't find ASEC %s", id);
762 return -1;
763 }
Dianne Hackborn736910c2011-06-27 13:37:07 -0700764
765 memset(buffer, 0, maxlen);
766 if (access(asecFileName, F_OK)) {
767 errno = ENOENT;
768 return -1;
769 }
770
rpcraigd1c226f2012-10-09 06:58:16 -0400771 int written = snprintf(buffer, maxlen, "%s", asecFileName);
772 if ((written < 0) || (written >= maxlen)) {
773 errno = EINVAL;
774 return -1;
775 }
776
Dianne Hackborn736910c2011-06-27 13:37:07 -0700777 return 0;
778}
779
Kenny Root344ca102012-04-03 17:23:01 -0700780int VolumeManager::createAsec(const char *id, unsigned int numSectors, const char *fstype,
781 const char *key, const int ownerUid, bool isExternal) {
San Mehatfcf24fe2010-03-03 12:37:32 -0800782 struct asec_superblock sb;
783 memset(&sb, 0, sizeof(sb));
784
Nick Kralevich0de7c612014-01-27 14:58:06 -0800785 if (!isLegalAsecId(id)) {
786 SLOGE("createAsec: Invalid asec id \"%s\"", id);
787 errno = EINVAL;
788 return -1;
789 }
790
Kenny Root344ca102012-04-03 17:23:01 -0700791 const bool wantFilesystem = strcmp(fstype, "none");
792 bool usingExt4 = false;
793 if (wantFilesystem) {
794 usingExt4 = !strcmp(fstype, "ext4");
795 if (usingExt4) {
796 sb.c_opts |= ASEC_SB_C_OPTS_EXT4;
797 } else if (strcmp(fstype, "fat")) {
798 SLOGE("Invalid filesystem type %s", fstype);
799 errno = EINVAL;
800 return -1;
801 }
802 }
803
San Mehatfcf24fe2010-03-03 12:37:32 -0800804 sb.magic = ASEC_SB_MAGIC;
805 sb.ver = ASEC_SB_VER;
San Mehata19b2502010-01-06 10:33:53 -0800806
San Mehatd31e3802010-02-18 08:37:45 -0800807 if (numSectors < ((1024*1024)/512)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700808 SLOGE("Invalid container size specified (%d sectors)", numSectors);
San Mehatd31e3802010-02-18 08:37:45 -0800809 errno = EINVAL;
810 return -1;
811 }
812
San Mehata19b2502010-01-06 10:33:53 -0800813 char asecFileName[255];
Kenny Root344ca102012-04-03 17:23:01 -0700814
815 if (!findAsec(id, asecFileName, sizeof(asecFileName))) {
816 SLOGE("ASEC file '%s' currently exists - destroy it first! (%s)",
817 asecFileName, strerror(errno));
818 errno = EADDRINUSE;
819 return -1;
820 }
821
Jeff Sharkey9f18fe72015-04-01 23:32:18 -0700822 const char *asecDir = isExternal ? VolumeManager::SEC_ASECDIR_EXT : VolumeManager::SEC_ASECDIR_INT;
Kenny Root344ca102012-04-03 17:23:01 -0700823
rpcraigd1c226f2012-10-09 06:58:16 -0400824 int written = snprintf(asecFileName, sizeof(asecFileName), "%s/%s.asec", asecDir, id);
825 if ((written < 0) || (size_t(written) >= sizeof(asecFileName))) {
826 errno = EINVAL;
827 return -1;
828 }
San Mehata19b2502010-01-06 10:33:53 -0800829
830 if (!access(asecFileName, F_OK)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700831 SLOGE("ASEC file '%s' currently exists - destroy it first! (%s)",
Kenny Root344ca102012-04-03 17:23:01 -0700832 asecFileName, strerror(errno));
San Mehata19b2502010-01-06 10:33:53 -0800833 errno = EADDRINUSE;
834 return -1;
835 }
836
Daniel Rosenbergfcd34a02014-05-22 11:23:56 -0700837 unsigned numImgSectors;
Daniel Rosenberg6a74dca2014-05-23 13:47:00 -0700838 if (usingExt4)
Daniel Rosenbergfcd34a02014-05-22 11:23:56 -0700839 numImgSectors = adjustSectorNumExt4(numSectors);
Daniel Rosenberg6a74dca2014-05-23 13:47:00 -0700840 else
Daniel Rosenbergfcd34a02014-05-22 11:23:56 -0700841 numImgSectors = adjustSectorNumFAT(numSectors);
San Mehatfcf24fe2010-03-03 12:37:32 -0800842
843 // Add +1 for our superblock which is at the end
844 if (Loop::createImageFile(asecFileName, numImgSectors + 1)) {
San Mehat97ac40e2010-03-24 10:24:19 -0700845 SLOGE("ASEC image file creation failed (%s)", strerror(errno));
San Mehata19b2502010-01-06 10:33:53 -0800846 return -1;
847 }
848
San Mehatd9a4e352010-03-12 13:32:47 -0800849 char idHash[33];
850 if (!asecHash(id, idHash, sizeof(idHash))) {
San Mehat97ac40e2010-03-24 10:24:19 -0700851 SLOGE("Hash of '%s' failed (%s)", id, strerror(errno));
San Mehatd9a4e352010-03-12 13:32:47 -0800852 unlink(asecFileName);
853 return -1;
854 }
855
San Mehata19b2502010-01-06 10:33:53 -0800856 char loopDevice[255];
San Mehatd9a4e352010-03-12 13:32:47 -0800857 if (Loop::create(idHash, asecFileName, loopDevice, sizeof(loopDevice))) {
San Mehat97ac40e2010-03-24 10:24:19 -0700858 SLOGE("ASEC loop device creation failed (%s)", strerror(errno));
San Mehata19b2502010-01-06 10:33:53 -0800859 unlink(asecFileName);
860 return -1;
861 }
862
San Mehatb78a32c2010-01-10 13:02:12 -0800863 char dmDevice[255];
864 bool cleanupDm = false;
San Mehata19b2502010-01-06 10:33:53 -0800865
San Mehatb78a32c2010-01-10 13:02:12 -0800866 if (strcmp(key, "none")) {
San Mehatfcf24fe2010-03-03 12:37:32 -0800867 // XXX: This is all we support for now
868 sb.c_cipher = ASEC_SB_C_CIPHER_TWOFISH;
San Mehatd9a4e352010-03-12 13:32:47 -0800869 if (Devmapper::create(idHash, loopDevice, key, numImgSectors, dmDevice,
San Mehatb78a32c2010-01-10 13:02:12 -0800870 sizeof(dmDevice))) {
San Mehat97ac40e2010-03-24 10:24:19 -0700871 SLOGE("ASEC device mapping failed (%s)", strerror(errno));
San Mehatb78a32c2010-01-10 13:02:12 -0800872 Loop::destroyByDevice(loopDevice);
873 unlink(asecFileName);
874 return -1;
875 }
876 cleanupDm = true;
877 } else {
San Mehatfcf24fe2010-03-03 12:37:32 -0800878 sb.c_cipher = ASEC_SB_C_CIPHER_NONE;
San Mehatb78a32c2010-01-10 13:02:12 -0800879 strcpy(dmDevice, loopDevice);
880 }
881
San Mehatfcf24fe2010-03-03 12:37:32 -0800882 /*
883 * Drop down the superblock at the end of the file
884 */
Daniel Rosenbergfcd34a02014-05-22 11:23:56 -0700885 if (writeSuperBlock(loopDevice, &sb, numImgSectors)) {
San Mehatfcf24fe2010-03-03 12:37:32 -0800886 if (cleanupDm) {
San Mehatd9a4e352010-03-12 13:32:47 -0800887 Devmapper::destroy(idHash);
San Mehatfcf24fe2010-03-03 12:37:32 -0800888 }
889 Loop::destroyByDevice(loopDevice);
890 unlink(asecFileName);
891 return -1;
892 }
893
Kenny Root344ca102012-04-03 17:23:01 -0700894 if (wantFilesystem) {
895 int formatStatus;
rpcraiga54e13a2012-09-21 14:17:08 -0400896 char mountPoint[255];
897
Jeff Sharkey9f18fe72015-04-01 23:32:18 -0700898 int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", VolumeManager::ASECDIR, id);
rpcraigd1c226f2012-10-09 06:58:16 -0400899 if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) {
900 SLOGE("ASEC fs format failed: couldn't construct mountPoint");
901 if (cleanupDm) {
902 Devmapper::destroy(idHash);
903 }
904 Loop::destroyByDevice(loopDevice);
905 unlink(asecFileName);
906 return -1;
907 }
rpcraiga54e13a2012-09-21 14:17:08 -0400908
Kenny Root344ca102012-04-03 17:23:01 -0700909 if (usingExt4) {
Jeff Sharkeyd0640f62015-05-21 22:35:42 -0700910 formatStatus = android::vold::ext4::Format(dmDevice, numImgSectors, mountPoint);
Kenny Root344ca102012-04-03 17:23:01 -0700911 } else {
Jeff Sharkeyd0640f62015-05-21 22:35:42 -0700912 formatStatus = android::vold::vfat::Format(dmDevice, numImgSectors);
San Mehatb78a32c2010-01-10 13:02:12 -0800913 }
San Mehata19b2502010-01-06 10:33:53 -0800914
Kenny Root344ca102012-04-03 17:23:01 -0700915 if (formatStatus < 0) {
916 SLOGE("ASEC fs format failed (%s)", strerror(errno));
San Mehatb78a32c2010-01-10 13:02:12 -0800917 if (cleanupDm) {
San Mehatd9a4e352010-03-12 13:32:47 -0800918 Devmapper::destroy(idHash);
San Mehatb78a32c2010-01-10 13:02:12 -0800919 }
San Mehateb13a902010-01-07 12:12:50 -0800920 Loop::destroyByDevice(loopDevice);
921 unlink(asecFileName);
922 return -1;
923 }
Kenny Root344ca102012-04-03 17:23:01 -0700924
Kenny Root344ca102012-04-03 17:23:01 -0700925 if (mkdir(mountPoint, 0000)) {
San Mehata1091cb2010-02-28 20:17:20 -0800926 if (errno != EEXIST) {
San Mehat97ac40e2010-03-24 10:24:19 -0700927 SLOGE("Mountpoint creation failed (%s)", strerror(errno));
San Mehata1091cb2010-02-28 20:17:20 -0800928 if (cleanupDm) {
San Mehatd9a4e352010-03-12 13:32:47 -0800929 Devmapper::destroy(idHash);
San Mehata1091cb2010-02-28 20:17:20 -0800930 }
931 Loop::destroyByDevice(loopDevice);
932 unlink(asecFileName);
933 return -1;
934 }
San Mehatb78a32c2010-01-10 13:02:12 -0800935 }
San Mehata1091cb2010-02-28 20:17:20 -0800936
Kenny Root344ca102012-04-03 17:23:01 -0700937 int mountStatus;
938 if (usingExt4) {
Jeff Sharkeyd0640f62015-05-21 22:35:42 -0700939 mountStatus = android::vold::ext4::Mount(dmDevice, mountPoint,
940 false, false, false);
Kenny Root344ca102012-04-03 17:23:01 -0700941 } else {
Jeff Sharkeyd0640f62015-05-21 22:35:42 -0700942 mountStatus = android::vold::vfat::Mount(dmDevice, mountPoint,
943 false, false, false, ownerUid, 0, 0000, false);
Kenny Root344ca102012-04-03 17:23:01 -0700944 }
945
946 if (mountStatus) {
San Mehat97ac40e2010-03-24 10:24:19 -0700947 SLOGE("ASEC FAT mount failed (%s)", strerror(errno));
San Mehata1091cb2010-02-28 20:17:20 -0800948 if (cleanupDm) {
San Mehatd9a4e352010-03-12 13:32:47 -0800949 Devmapper::destroy(idHash);
San Mehata1091cb2010-02-28 20:17:20 -0800950 }
951 Loop::destroyByDevice(loopDevice);
952 unlink(asecFileName);
953 return -1;
954 }
Kenny Root344ca102012-04-03 17:23:01 -0700955
956 if (usingExt4) {
Jeff Sharkeyce6a9132015-04-08 21:07:21 -0700957 int dirfd = open(mountPoint, O_DIRECTORY | O_CLOEXEC);
Kenny Root344ca102012-04-03 17:23:01 -0700958 if (dirfd >= 0) {
959 if (fchown(dirfd, ownerUid, AID_SYSTEM)
960 || fchmod(dirfd, S_IRUSR | S_IWUSR | S_IXUSR | S_ISGID | S_IRGRP | S_IXGRP)) {
961 SLOGI("Cannot chown/chmod new ASEC mount point %s", mountPoint);
962 }
963 close(dirfd);
964 }
965 }
San Mehata1091cb2010-02-28 20:17:20 -0800966 } else {
San Mehat97ac40e2010-03-24 10:24:19 -0700967 SLOGI("Created raw secure container %s (no filesystem)", id);
San Mehata19b2502010-01-06 10:33:53 -0800968 }
San Mehat88705162010-01-15 09:26:28 -0800969
Kenny Rootcbacf782010-09-24 15:11:48 -0700970 mActiveContainers->push_back(new ContainerData(strdup(id), ASEC));
San Mehata19b2502010-01-06 10:33:53 -0800971 return 0;
972}
973
Daniel Rosenbergfcd34a02014-05-22 11:23:56 -0700974int VolumeManager::resizeAsec(const char *id, unsigned numSectors, const char *key) {
975 char asecFileName[255];
976 char mountPoint[255];
977 bool cleanupDm = false;
978
979 if (!isLegalAsecId(id)) {
980 SLOGE("resizeAsec: Invalid asec id \"%s\"", id);
981 errno = EINVAL;
982 return -1;
983 }
984
985 if (findAsec(id, asecFileName, sizeof(asecFileName))) {
986 SLOGE("Couldn't find ASEC %s", id);
987 return -1;
988 }
989
Jeff Sharkey9f18fe72015-04-01 23:32:18 -0700990 int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", VolumeManager::ASECDIR, id);
Daniel Rosenbergfcd34a02014-05-22 11:23:56 -0700991 if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) {
992 SLOGE("ASEC resize failed for %s: couldn't construct mountpoint", id);
993 return -1;
994 }
995
996 if (isMountpointMounted(mountPoint)) {
997 SLOGE("ASEC %s mounted. Unmount before resizing", id);
998 errno = EBUSY;
999 return -1;
1000 }
1001
1002 struct asec_superblock sb;
1003 int fd;
1004 unsigned int oldNumSec = 0;
1005
Jeff Sharkeyce6a9132015-04-08 21:07:21 -07001006 if ((fd = open(asecFileName, O_RDONLY | O_CLOEXEC)) < 0) {
Daniel Rosenbergfcd34a02014-05-22 11:23:56 -07001007 SLOGE("Failed to open ASEC file (%s)", strerror(errno));
1008 return -1;
1009 }
1010
1011 struct stat info;
1012 if (fstat(fd, &info) < 0) {
1013 SLOGE("Failed to get file size (%s)", strerror(errno));
1014 close(fd);
1015 return -1;
1016 }
1017
1018 oldNumSec = info.st_size / 512;
1019
1020 unsigned numImgSectors;
1021 if (sb.c_opts & ASEC_SB_C_OPTS_EXT4)
1022 numImgSectors = adjustSectorNumExt4(numSectors);
1023 else
1024 numImgSectors = adjustSectorNumFAT(numSectors);
1025 /*
1026 * add one block for the superblock
1027 */
1028 SLOGD("Resizing from %d sectors to %d sectors", oldNumSec, numImgSectors + 1);
Jeff Sharkey43ed1232014-08-22 12:29:05 -07001029 if (oldNumSec == numImgSectors + 1) {
1030 SLOGW("Size unchanged; ignoring resize request");
1031 return 0;
1032 } else if (oldNumSec > numImgSectors + 1) {
Daniel Rosenbergfcd34a02014-05-22 11:23:56 -07001033 SLOGE("Only growing is currently supported.");
1034 close(fd);
1035 return -1;
1036 }
1037
1038 /*
1039 * Try to read superblock.
1040 */
1041 memset(&sb, 0, sizeof(struct asec_superblock));
1042 if (lseek(fd, ((oldNumSec - 1) * 512), SEEK_SET) < 0) {
1043 SLOGE("lseek failed (%s)", strerror(errno));
1044 close(fd);
1045 return -1;
1046 }
1047 if (read(fd, &sb, sizeof(struct asec_superblock)) != sizeof(struct asec_superblock)) {
1048 SLOGE("superblock read failed (%s)", strerror(errno));
1049 close(fd);
1050 return -1;
1051 }
1052 close(fd);
1053
1054 if (mDebug) {
1055 SLOGD("Container sb magic/ver (%.8x/%.2x)", sb.magic, sb.ver);
1056 }
1057 if (sb.magic != ASEC_SB_MAGIC || sb.ver != ASEC_SB_VER) {
1058 SLOGE("Bad container magic/version (%.8x/%.2x)", sb.magic, sb.ver);
1059 errno = EMEDIUMTYPE;
1060 return -1;
1061 }
1062
1063 if (!(sb.c_opts & ASEC_SB_C_OPTS_EXT4)) {
1064 SLOGE("Only ext4 partitions are supported for resize");
1065 errno = EINVAL;
1066 return -1;
1067 }
1068
1069 if (Loop::resizeImageFile(asecFileName, numImgSectors + 1)) {
1070 SLOGE("Resize of ASEC image file failed. Could not resize %s", id);
1071 return -1;
1072 }
1073
1074 /*
1075 * Drop down a copy of the superblock at the end of the file
1076 */
1077 if (writeSuperBlock(asecFileName, &sb, numImgSectors))
1078 goto fail;
1079
1080 char idHash[33];
1081 if (!asecHash(id, idHash, sizeof(idHash))) {
1082 SLOGE("Hash of '%s' failed (%s)", id, strerror(errno));
1083 goto fail;
1084 }
1085
1086 char loopDevice[255];
1087 if (setupLoopDevice(loopDevice, sizeof(loopDevice), asecFileName, idHash, mDebug))
1088 goto fail;
1089
1090 char dmDevice[255];
1091
1092 if (setupDevMapperDevice(dmDevice, sizeof(dmDevice), loopDevice, asecFileName, key, idHash, numImgSectors, &cleanupDm, mDebug)) {
1093 Loop::destroyByDevice(loopDevice);
1094 goto fail;
1095 }
1096
1097 /*
1098 * Wait for the device mapper node to be created.
1099 */
1100 waitForDevMapper(dmDevice);
1101
Jeff Sharkeyd0640f62015-05-21 22:35:42 -07001102 if (android::vold::ext4::Resize(dmDevice, numImgSectors)) {
Daniel Rosenbergfcd34a02014-05-22 11:23:56 -07001103 SLOGE("Unable to resize %s (%s)", id, strerror(errno));
1104 if (cleanupDm) {
1105 Devmapper::destroy(idHash);
1106 }
1107 Loop::destroyByDevice(loopDevice);
1108 goto fail;
1109 }
1110
1111 return 0;
1112fail:
1113 Loop::resizeImageFile(asecFileName, oldNumSec);
1114 return -1;
1115}
1116
San Mehata19b2502010-01-06 10:33:53 -08001117int VolumeManager::finalizeAsec(const char *id) {
1118 char asecFileName[255];
1119 char loopDevice[255];
1120 char mountPoint[255];
1121
Nick Kralevich0de7c612014-01-27 14:58:06 -08001122 if (!isLegalAsecId(id)) {
1123 SLOGE("finalizeAsec: Invalid asec id \"%s\"", id);
1124 errno = EINVAL;
1125 return -1;
1126 }
1127
Kenny Root344ca102012-04-03 17:23:01 -07001128 if (findAsec(id, asecFileName, sizeof(asecFileName))) {
1129 SLOGE("Couldn't find ASEC %s", id);
1130 return -1;
1131 }
San Mehata19b2502010-01-06 10:33:53 -08001132
San Mehatd9a4e352010-03-12 13:32:47 -08001133 char idHash[33];
1134 if (!asecHash(id, idHash, sizeof(idHash))) {
San Mehat97ac40e2010-03-24 10:24:19 -07001135 SLOGE("Hash of '%s' failed (%s)", id, strerror(errno));
San Mehatd9a4e352010-03-12 13:32:47 -08001136 return -1;
1137 }
1138
1139 if (Loop::lookupActive(idHash, loopDevice, sizeof(loopDevice))) {
San Mehat97ac40e2010-03-24 10:24:19 -07001140 SLOGE("Unable to finalize %s (%s)", id, strerror(errno));
San Mehata19b2502010-01-06 10:33:53 -08001141 return -1;
1142 }
1143
Hiroaki Miyazawa14eab552015-02-04 13:29:15 +09001144 unsigned long nr_sec = 0;
Kenny Root344ca102012-04-03 17:23:01 -07001145 struct asec_superblock sb;
1146
1147 if (Loop::lookupInfo(loopDevice, &sb, &nr_sec)) {
1148 return -1;
1149 }
1150
Jeff Sharkey9f18fe72015-04-01 23:32:18 -07001151 int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", VolumeManager::ASECDIR, id);
rpcraigd1c226f2012-10-09 06:58:16 -04001152 if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) {
1153 SLOGE("ASEC finalize failed: couldn't construct mountPoint");
1154 return -1;
1155 }
Kenny Root344ca102012-04-03 17:23:01 -07001156
1157 int result = 0;
1158 if (sb.c_opts & ASEC_SB_C_OPTS_EXT4) {
Jeff Sharkeyd0640f62015-05-21 22:35:42 -07001159 result = android::vold::ext4::Mount(loopDevice, mountPoint,
1160 true, true, true);
Kenny Root344ca102012-04-03 17:23:01 -07001161 } else {
Jeff Sharkeyd0640f62015-05-21 22:35:42 -07001162 result = android::vold::vfat::Mount(loopDevice, mountPoint,
1163 true, true, true, 0, 0, 0227, false);
Kenny Root344ca102012-04-03 17:23:01 -07001164 }
1165
1166 if (result) {
San Mehat97ac40e2010-03-24 10:24:19 -07001167 SLOGE("ASEC finalize mount failed (%s)", strerror(errno));
San Mehata19b2502010-01-06 10:33:53 -08001168 return -1;
1169 }
1170
San Mehatd9a4e352010-03-12 13:32:47 -08001171 if (mDebug) {
San Mehat97ac40e2010-03-24 10:24:19 -07001172 SLOGD("ASEC %s finalized", id);
San Mehatd9a4e352010-03-12 13:32:47 -08001173 }
San Mehata19b2502010-01-06 10:33:53 -08001174 return 0;
1175}
1176
Kenny Root344ca102012-04-03 17:23:01 -07001177int VolumeManager::fixupAsecPermissions(const char *id, gid_t gid, const char* filename) {
1178 char asecFileName[255];
1179 char loopDevice[255];
1180 char mountPoint[255];
1181
1182 if (gid < AID_APP) {
1183 SLOGE("Group ID is not in application range");
1184 return -1;
1185 }
1186
Nick Kralevich0de7c612014-01-27 14:58:06 -08001187 if (!isLegalAsecId(id)) {
1188 SLOGE("fixupAsecPermissions: Invalid asec id \"%s\"", id);
1189 errno = EINVAL;
1190 return -1;
1191 }
1192
Kenny Root344ca102012-04-03 17:23:01 -07001193 if (findAsec(id, asecFileName, sizeof(asecFileName))) {
1194 SLOGE("Couldn't find ASEC %s", id);
1195 return -1;
1196 }
1197
1198 char idHash[33];
1199 if (!asecHash(id, idHash, sizeof(idHash))) {
1200 SLOGE("Hash of '%s' failed (%s)", id, strerror(errno));
1201 return -1;
1202 }
1203
1204 if (Loop::lookupActive(idHash, loopDevice, sizeof(loopDevice))) {
1205 SLOGE("Unable fix permissions during lookup on %s (%s)", id, strerror(errno));
1206 return -1;
1207 }
1208
Hiroaki Miyazawa14eab552015-02-04 13:29:15 +09001209 unsigned long nr_sec = 0;
Kenny Root344ca102012-04-03 17:23:01 -07001210 struct asec_superblock sb;
1211
1212 if (Loop::lookupInfo(loopDevice, &sb, &nr_sec)) {
1213 return -1;
1214 }
1215
Jeff Sharkey9f18fe72015-04-01 23:32:18 -07001216 int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", VolumeManager::ASECDIR, id);
rpcraigd1c226f2012-10-09 06:58:16 -04001217 if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) {
1218 SLOGE("Unable remount to fix permissions for %s: couldn't construct mountpoint", id);
1219 return -1;
1220 }
Kenny Root344ca102012-04-03 17:23:01 -07001221
1222 int result = 0;
1223 if ((sb.c_opts & ASEC_SB_C_OPTS_EXT4) == 0) {
1224 return 0;
1225 }
1226
Jeff Sharkeyd0640f62015-05-21 22:35:42 -07001227 int ret = android::vold::ext4::Mount(loopDevice, mountPoint,
Kenny Root344ca102012-04-03 17:23:01 -07001228 false /* read-only */,
1229 true /* remount */,
1230 false /* executable */);
1231 if (ret) {
1232 SLOGE("Unable remount to fix permissions for %s (%s)", id, strerror(errno));
1233 return -1;
1234 }
1235
1236 char *paths[] = { mountPoint, NULL };
1237
1238 FTS *fts = fts_open(paths, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, NULL);
1239 if (fts) {
1240 // Traverse the entire hierarchy and chown to system UID.
1241 for (FTSENT *ftsent = fts_read(fts); ftsent != NULL; ftsent = fts_read(fts)) {
1242 // We don't care about the lost+found directory.
1243 if (!strcmp(ftsent->fts_name, "lost+found")) {
1244 continue;
1245 }
1246
1247 /*
1248 * There can only be one file marked as private right now.
1249 * This should be more robust, but it satisfies the requirements
1250 * we have for right now.
1251 */
1252 const bool privateFile = !strcmp(ftsent->fts_name, filename);
1253
Jeff Sharkeyce6a9132015-04-08 21:07:21 -07001254 int fd = open(ftsent->fts_accpath, O_NOFOLLOW | O_CLOEXEC);
Kenny Root344ca102012-04-03 17:23:01 -07001255 if (fd < 0) {
1256 SLOGE("Couldn't open file %s: %s", ftsent->fts_accpath, strerror(errno));
1257 result = -1;
1258 continue;
1259 }
1260
1261 result |= fchown(fd, AID_SYSTEM, privateFile? gid : AID_SYSTEM);
1262
1263 if (ftsent->fts_info & FTS_D) {
Kenny Root1a673c82012-05-10 16:45:29 -07001264 result |= fchmod(fd, 0755);
Kenny Root348c8ab2012-05-10 15:39:53 -07001265 } else if (ftsent->fts_info & FTS_F) {
Kenny Root344ca102012-04-03 17:23:01 -07001266 result |= fchmod(fd, privateFile ? 0640 : 0644);
1267 }
Robert Craigb9e3ba52014-02-04 10:53:00 -05001268
Stephen Smalley5093e612014-02-12 09:43:08 -05001269 if (selinux_android_restorecon(ftsent->fts_path, 0) < 0) {
Robert Craigb9e3ba52014-02-04 10:53:00 -05001270 SLOGE("restorecon failed for %s: %s\n", ftsent->fts_path, strerror(errno));
1271 result |= -1;
1272 }
1273
Kenny Root344ca102012-04-03 17:23:01 -07001274 close(fd);
1275 }
1276 fts_close(fts);
1277
1278 // Finally make the directory readable by everyone.
Jeff Sharkeyce6a9132015-04-08 21:07:21 -07001279 int dirfd = open(mountPoint, O_DIRECTORY | O_CLOEXEC);
Kenny Root344ca102012-04-03 17:23:01 -07001280 if (dirfd < 0 || fchmod(dirfd, 0755)) {
1281 SLOGE("Couldn't change owner of existing directory %s: %s", mountPoint, strerror(errno));
1282 result |= -1;
1283 }
1284 close(dirfd);
1285 } else {
1286 result |= -1;
1287 }
1288
Jeff Sharkeyd0640f62015-05-21 22:35:42 -07001289 result |= android::vold::ext4::Mount(loopDevice, mountPoint,
Kenny Root344ca102012-04-03 17:23:01 -07001290 true /* read-only */,
1291 true /* remount */,
1292 true /* execute */);
1293
1294 if (result) {
1295 SLOGE("ASEC fix permissions failed (%s)", strerror(errno));
1296 return -1;
1297 }
1298
1299 if (mDebug) {
1300 SLOGD("ASEC %s permissions fixed", id);
1301 }
1302 return 0;
1303}
1304
San Mehat048b0802010-01-23 08:17:06 -08001305int VolumeManager::renameAsec(const char *id1, const char *id2) {
Kenny Root344ca102012-04-03 17:23:01 -07001306 char asecFilename1[255];
San Mehat048b0802010-01-23 08:17:06 -08001307 char *asecFilename2;
1308 char mountPoint[255];
1309
Kenny Root344ca102012-04-03 17:23:01 -07001310 const char *dir;
1311
Nick Kralevich0de7c612014-01-27 14:58:06 -08001312 if (!isLegalAsecId(id1)) {
1313 SLOGE("renameAsec: Invalid asec id1 \"%s\"", id1);
1314 errno = EINVAL;
1315 return -1;
1316 }
1317
1318 if (!isLegalAsecId(id2)) {
1319 SLOGE("renameAsec: Invalid asec id2 \"%s\"", id2);
1320 errno = EINVAL;
1321 return -1;
1322 }
1323
Kenny Root344ca102012-04-03 17:23:01 -07001324 if (findAsec(id1, asecFilename1, sizeof(asecFilename1), &dir)) {
1325 SLOGE("Couldn't find ASEC %s", id1);
1326 return -1;
1327 }
1328
1329 asprintf(&asecFilename2, "%s/%s.asec", dir, id2);
San Mehat048b0802010-01-23 08:17:06 -08001330
Jeff Sharkey9f18fe72015-04-01 23:32:18 -07001331 int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", VolumeManager::ASECDIR, id1);
rpcraigd1c226f2012-10-09 06:58:16 -04001332 if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) {
1333 SLOGE("Rename failed: couldn't construct mountpoint");
1334 goto out_err;
1335 }
1336
San Mehat048b0802010-01-23 08:17:06 -08001337 if (isMountpointMounted(mountPoint)) {
San Mehat97ac40e2010-03-24 10:24:19 -07001338 SLOGW("Rename attempt when src mounted");
San Mehat048b0802010-01-23 08:17:06 -08001339 errno = EBUSY;
1340 goto out_err;
1341 }
1342
Jeff Sharkey9f18fe72015-04-01 23:32:18 -07001343 written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", VolumeManager::ASECDIR, id2);
rpcraigd1c226f2012-10-09 06:58:16 -04001344 if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) {
1345 SLOGE("Rename failed: couldn't construct mountpoint2");
1346 goto out_err;
1347 }
1348
San Mehat96956ed2010-02-24 08:42:51 -08001349 if (isMountpointMounted(mountPoint)) {
San Mehat97ac40e2010-03-24 10:24:19 -07001350 SLOGW("Rename attempt when dst mounted");
San Mehat96956ed2010-02-24 08:42:51 -08001351 errno = EBUSY;
1352 goto out_err;
1353 }
1354
San Mehat048b0802010-01-23 08:17:06 -08001355 if (!access(asecFilename2, F_OK)) {
San Mehat97ac40e2010-03-24 10:24:19 -07001356 SLOGE("Rename attempt when dst exists");
San Mehat048b0802010-01-23 08:17:06 -08001357 errno = EADDRINUSE;
1358 goto out_err;
1359 }
1360
1361 if (rename(asecFilename1, asecFilename2)) {
San Mehat97ac40e2010-03-24 10:24:19 -07001362 SLOGE("Rename of '%s' to '%s' failed (%s)", asecFilename1, asecFilename2, strerror(errno));
San Mehat048b0802010-01-23 08:17:06 -08001363 goto out_err;
1364 }
1365
San Mehat048b0802010-01-23 08:17:06 -08001366 free(asecFilename2);
1367 return 0;
1368
1369out_err:
San Mehat048b0802010-01-23 08:17:06 -08001370 free(asecFilename2);
1371 return -1;
1372}
1373
Kenny Rootfb7c4d52010-06-30 18:48:41 -07001374#define UNMOUNT_RETRIES 5
1375#define UNMOUNT_SLEEP_BETWEEN_RETRY_MS (1000 * 1000)
San Mehat4ba89482010-02-18 09:00:18 -08001376int VolumeManager::unmountAsec(const char *id, bool force) {
San Mehata19b2502010-01-06 10:33:53 -08001377 char asecFileName[255];
1378 char mountPoint[255];
1379
Nick Kralevich0de7c612014-01-27 14:58:06 -08001380 if (!isLegalAsecId(id)) {
1381 SLOGE("unmountAsec: Invalid asec id \"%s\"", id);
1382 errno = EINVAL;
1383 return -1;
1384 }
1385
Kenny Root344ca102012-04-03 17:23:01 -07001386 if (findAsec(id, asecFileName, sizeof(asecFileName))) {
1387 SLOGE("Couldn't find ASEC %s", id);
1388 return -1;
1389 }
1390
Jeff Sharkey9f18fe72015-04-01 23:32:18 -07001391 int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", VolumeManager::ASECDIR, id);
rpcraigd1c226f2012-10-09 06:58:16 -04001392 if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) {
1393 SLOGE("ASEC unmount failed for %s: couldn't construct mountpoint", id);
1394 return -1;
1395 }
San Mehata19b2502010-01-06 10:33:53 -08001396
San Mehatd9a4e352010-03-12 13:32:47 -08001397 char idHash[33];
1398 if (!asecHash(id, idHash, sizeof(idHash))) {
San Mehat97ac40e2010-03-24 10:24:19 -07001399 SLOGE("Hash of '%s' failed (%s)", id, strerror(errno));
San Mehatd9a4e352010-03-12 13:32:47 -08001400 return -1;
1401 }
1402
Kenny Rootfb7c4d52010-06-30 18:48:41 -07001403 return unmountLoopImage(id, idHash, asecFileName, mountPoint, force);
1404}
1405
Kenny Root508c0e12010-07-12 09:59:49 -07001406int VolumeManager::unmountObb(const char *fileName, bool force) {
Kenny Rootfb7c4d52010-06-30 18:48:41 -07001407 char mountPoint[255];
1408
1409 char idHash[33];
1410 if (!asecHash(fileName, idHash, sizeof(idHash))) {
1411 SLOGE("Hash of '%s' failed (%s)", fileName, strerror(errno));
1412 return -1;
1413 }
1414
Jeff Sharkey9f18fe72015-04-01 23:32:18 -07001415 int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", VolumeManager::LOOPDIR, idHash);
rpcraigd1c226f2012-10-09 06:58:16 -04001416 if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) {
1417 SLOGE("OBB unmount failed for %s: couldn't construct mountpoint", fileName);
1418 return -1;
1419 }
Kenny Rootfb7c4d52010-06-30 18:48:41 -07001420
1421 return unmountLoopImage(fileName, idHash, fileName, mountPoint, force);
1422}
1423
1424int VolumeManager::unmountLoopImage(const char *id, const char *idHash,
1425 const char *fileName, const char *mountPoint, bool force) {
San Mehat0586d542010-01-12 15:38:59 -08001426 if (!isMountpointMounted(mountPoint)) {
Kenny Rootfb7c4d52010-06-30 18:48:41 -07001427 SLOGE("Unmount request for %s when not mounted", id);
Kenny Root918e5f92010-09-30 18:00:52 -07001428 errno = ENOENT;
San Mehatb78a32c2010-01-10 13:02:12 -08001429 return -1;
1430 }
San Mehat23969932010-01-09 07:08:06 -08001431
San Mehatb78a32c2010-01-10 13:02:12 -08001432 int i, rc;
Kenny Rootfb7c4d52010-06-30 18:48:41 -07001433 for (i = 1; i <= UNMOUNT_RETRIES; i++) {
San Mehatb78a32c2010-01-10 13:02:12 -08001434 rc = umount(mountPoint);
1435 if (!rc) {
1436 break;
San Mehata19b2502010-01-06 10:33:53 -08001437 }
San Mehatb78a32c2010-01-10 13:02:12 -08001438 if (rc && (errno == EINVAL || errno == ENOENT)) {
Kenny Rootfb7c4d52010-06-30 18:48:41 -07001439 SLOGI("Container %s unmounted OK", id);
San Mehatb78a32c2010-01-10 13:02:12 -08001440 rc = 0;
1441 break;
San Mehata19b2502010-01-06 10:33:53 -08001442 }
Kenny Rootfb7c4d52010-06-30 18:48:41 -07001443 SLOGW("%s unmount attempt %d failed (%s)",
San Mehat8c940ef2010-02-13 14:19:53 -08001444 id, i, strerror(errno));
San Mehatb78a32c2010-01-10 13:02:12 -08001445
Jeff Sharkey36801cc2015-03-13 16:09:20 -07001446 int signal = 0; // default is to just complain
San Mehat4ba89482010-02-18 09:00:18 -08001447
1448 if (force) {
Kenny Rootfb7c4d52010-06-30 18:48:41 -07001449 if (i > (UNMOUNT_RETRIES - 2))
Jeff Sharkey36801cc2015-03-13 16:09:20 -07001450 signal = SIGKILL;
Kenny Rootfb7c4d52010-06-30 18:48:41 -07001451 else if (i > (UNMOUNT_RETRIES - 3))
Jeff Sharkey36801cc2015-03-13 16:09:20 -07001452 signal = SIGTERM;
San Mehat4ba89482010-02-18 09:00:18 -08001453 }
San Mehat8c940ef2010-02-13 14:19:53 -08001454
Jeff Sharkey36801cc2015-03-13 16:09:20 -07001455 Process::killProcessesWithOpenFiles(mountPoint, signal);
Kenny Rootfb7c4d52010-06-30 18:48:41 -07001456 usleep(UNMOUNT_SLEEP_BETWEEN_RETRY_MS);
San Mehatb78a32c2010-01-10 13:02:12 -08001457 }
1458
1459 if (rc) {
San Mehat4ba89482010-02-18 09:00:18 -08001460 errno = EBUSY;
San Mehat97ac40e2010-03-24 10:24:19 -07001461 SLOGE("Failed to unmount container %s (%s)", id, strerror(errno));
San Mehatb78a32c2010-01-10 13:02:12 -08001462 return -1;
1463 }
1464
San Mehat12f4b892010-02-24 11:43:22 -08001465 int retries = 10;
1466
1467 while(retries--) {
1468 if (!rmdir(mountPoint)) {
1469 break;
1470 }
1471
San Mehat97ac40e2010-03-24 10:24:19 -07001472 SLOGW("Failed to rmdir %s (%s)", mountPoint, strerror(errno));
Kenny Rootfb7c4d52010-06-30 18:48:41 -07001473 usleep(UNMOUNT_SLEEP_BETWEEN_RETRY_MS);
San Mehat12f4b892010-02-24 11:43:22 -08001474 }
1475
1476 if (!retries) {
San Mehat97ac40e2010-03-24 10:24:19 -07001477 SLOGE("Timed out trying to rmdir %s (%s)", mountPoint, strerror(errno));
San Mehatf5c61982010-02-03 11:04:46 -08001478 }
San Mehat88705162010-01-15 09:26:28 -08001479
Paul Lawrence60dec162014-09-02 10:52:15 -07001480 for (i=1; i <= UNMOUNT_RETRIES; i++) {
1481 if (Devmapper::destroy(idHash) && errno != ENXIO) {
1482 SLOGE("Failed to destroy devmapper instance (%s)", strerror(errno));
1483 usleep(UNMOUNT_SLEEP_BETWEEN_RETRY_MS);
1484 continue;
1485 } else {
1486 break;
1487 }
San Mehata19b2502010-01-06 10:33:53 -08001488 }
1489
1490 char loopDevice[255];
San Mehatd9a4e352010-03-12 13:32:47 -08001491 if (!Loop::lookupActive(idHash, loopDevice, sizeof(loopDevice))) {
San Mehata19b2502010-01-06 10:33:53 -08001492 Loop::destroyByDevice(loopDevice);
San Mehatd9a4e352010-03-12 13:32:47 -08001493 } else {
Kenny Rootfb7c4d52010-06-30 18:48:41 -07001494 SLOGW("Failed to find loop device for {%s} (%s)", fileName, strerror(errno));
San Mehata19b2502010-01-06 10:33:53 -08001495 }
San Mehat88705162010-01-15 09:26:28 -08001496
1497 AsecIdCollection::iterator it;
1498 for (it = mActiveContainers->begin(); it != mActiveContainers->end(); ++it) {
Kenny Rootcbacf782010-09-24 15:11:48 -07001499 ContainerData* cd = *it;
1500 if (!strcmp(cd->id, id)) {
San Mehat88705162010-01-15 09:26:28 -08001501 free(*it);
1502 mActiveContainers->erase(it);
1503 break;
1504 }
1505 }
1506 if (it == mActiveContainers->end()) {
San Mehat97ac40e2010-03-24 10:24:19 -07001507 SLOGW("mActiveContainers is inconsistent!");
San Mehat88705162010-01-15 09:26:28 -08001508 }
San Mehatb78a32c2010-01-10 13:02:12 -08001509 return 0;
1510}
1511
San Mehat4ba89482010-02-18 09:00:18 -08001512int VolumeManager::destroyAsec(const char *id, bool force) {
San Mehatb78a32c2010-01-10 13:02:12 -08001513 char asecFileName[255];
1514 char mountPoint[255];
1515
Nick Kralevich0de7c612014-01-27 14:58:06 -08001516 if (!isLegalAsecId(id)) {
1517 SLOGE("destroyAsec: Invalid asec id \"%s\"", id);
1518 errno = EINVAL;
1519 return -1;
1520 }
1521
Kenny Root344ca102012-04-03 17:23:01 -07001522 if (findAsec(id, asecFileName, sizeof(asecFileName))) {
1523 SLOGE("Couldn't find ASEC %s", id);
1524 return -1;
1525 }
1526
Jeff Sharkey9f18fe72015-04-01 23:32:18 -07001527 int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", VolumeManager::ASECDIR, id);
rpcraigd1c226f2012-10-09 06:58:16 -04001528 if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) {
1529 SLOGE("ASEC destroy failed for %s: couldn't construct mountpoint", id);
1530 return -1;
1531 }
San Mehatb78a32c2010-01-10 13:02:12 -08001532
San Mehat0586d542010-01-12 15:38:59 -08001533 if (isMountpointMounted(mountPoint)) {
San Mehatd9a4e352010-03-12 13:32:47 -08001534 if (mDebug) {
San Mehat97ac40e2010-03-24 10:24:19 -07001535 SLOGD("Unmounting container before destroy");
San Mehatd9a4e352010-03-12 13:32:47 -08001536 }
San Mehat4ba89482010-02-18 09:00:18 -08001537 if (unmountAsec(id, force)) {
San Mehat97ac40e2010-03-24 10:24:19 -07001538 SLOGE("Failed to unmount asec %s for destroy (%s)", id, strerror(errno));
San Mehat0586d542010-01-12 15:38:59 -08001539 return -1;
1540 }
1541 }
San Mehata19b2502010-01-06 10:33:53 -08001542
San Mehat0586d542010-01-12 15:38:59 -08001543 if (unlink(asecFileName)) {
San Mehat97ac40e2010-03-24 10:24:19 -07001544 SLOGE("Failed to unlink asec '%s' (%s)", asecFileName, strerror(errno));
San Mehat0586d542010-01-12 15:38:59 -08001545 return -1;
1546 }
San Mehata19b2502010-01-06 10:33:53 -08001547
San Mehatd9a4e352010-03-12 13:32:47 -08001548 if (mDebug) {
San Mehat97ac40e2010-03-24 10:24:19 -07001549 SLOGD("ASEC %s destroyed", id);
San Mehatd9a4e352010-03-12 13:32:47 -08001550 }
San Mehata19b2502010-01-06 10:33:53 -08001551 return 0;
1552}
1553
Nick Kralevich0de7c612014-01-27 14:58:06 -08001554/*
1555 * Legal ASEC ids consist of alphanumeric characters, '-',
1556 * '_', or '.'. ".." is not allowed. The first or last character
1557 * of the ASEC id cannot be '.' (dot).
1558 */
1559bool VolumeManager::isLegalAsecId(const char *id) const {
1560 size_t i;
1561 size_t len = strlen(id);
1562
1563 if (len == 0) {
1564 return false;
1565 }
1566 if ((id[0] == '.') || (id[len - 1] == '.')) {
1567 return false;
1568 }
1569
1570 for (i = 0; i < len; i++) {
1571 if (id[i] == '.') {
1572 // i=0 is guaranteed never to have a dot. See above.
1573 if (id[i-1] == '.') return false;
1574 continue;
1575 }
1576 if (id[i] == '_' || id[i] == '-') continue;
1577 if (id[i] >= 'a' && id[i] <= 'z') continue;
1578 if (id[i] >= 'A' && id[i] <= 'Z') continue;
1579 if (id[i] >= '0' && id[i] <= '9') continue;
1580 return false;
1581 }
1582
1583 return true;
1584}
1585
Kenny Root344ca102012-04-03 17:23:01 -07001586bool VolumeManager::isAsecInDirectory(const char *dir, const char *asecName) const {
Jeff Sharkeyce6a9132015-04-08 21:07:21 -07001587 int dirfd = open(dir, O_DIRECTORY | O_CLOEXEC);
Kenny Root344ca102012-04-03 17:23:01 -07001588 if (dirfd < 0) {
1589 SLOGE("Couldn't open internal ASEC dir (%s)", strerror(errno));
Nick Kralevich25e581a2015-02-06 08:55:08 -08001590 return false;
Kenny Root344ca102012-04-03 17:23:01 -07001591 }
1592
Nick Kralevich25e581a2015-02-06 08:55:08 -08001593 struct stat sb;
1594 bool ret = (fstatat(dirfd, asecName, &sb, AT_SYMLINK_NOFOLLOW) == 0)
1595 && S_ISREG(sb.st_mode);
Kenny Root344ca102012-04-03 17:23:01 -07001596
1597 close(dirfd);
1598
1599 return ret;
1600}
1601
1602int VolumeManager::findAsec(const char *id, char *asecPath, size_t asecPathLen,
1603 const char **directory) const {
Kenny Root344ca102012-04-03 17:23:01 -07001604 char *asecName;
1605
Nick Kralevich0de7c612014-01-27 14:58:06 -08001606 if (!isLegalAsecId(id)) {
1607 SLOGE("findAsec: Invalid asec id \"%s\"", id);
1608 errno = EINVAL;
1609 return -1;
1610 }
1611
Kenny Root344ca102012-04-03 17:23:01 -07001612 if (asprintf(&asecName, "%s.asec", id) < 0) {
1613 SLOGE("Couldn't allocate string to write ASEC name");
1614 return -1;
1615 }
1616
1617 const char *dir;
Jeff Sharkey9f18fe72015-04-01 23:32:18 -07001618 if (isAsecInDirectory(VolumeManager::SEC_ASECDIR_INT, asecName)) {
1619 dir = VolumeManager::SEC_ASECDIR_INT;
1620 } else if (isAsecInDirectory(VolumeManager::SEC_ASECDIR_EXT, asecName)) {
1621 dir = VolumeManager::SEC_ASECDIR_EXT;
Kenny Root344ca102012-04-03 17:23:01 -07001622 } else {
1623 free(asecName);
1624 return -1;
1625 }
1626
1627 if (directory != NULL) {
1628 *directory = dir;
1629 }
1630
1631 if (asecPath != NULL) {
1632 int written = snprintf(asecPath, asecPathLen, "%s/%s", dir, asecName);
rpcraigd1c226f2012-10-09 06:58:16 -04001633 if ((written < 0) || (size_t(written) >= asecPathLen)) {
1634 SLOGE("findAsec failed for %s: couldn't construct ASEC path", id);
Kenny Root344ca102012-04-03 17:23:01 -07001635 free(asecName);
1636 return -1;
1637 }
1638 }
1639
1640 free(asecName);
1641 return 0;
1642}
1643
Jeff Sharkey43ed1232014-08-22 12:29:05 -07001644int VolumeManager::mountAsec(const char *id, const char *key, int ownerUid, bool readOnly) {
San Mehata19b2502010-01-06 10:33:53 -08001645 char asecFileName[255];
1646 char mountPoint[255];
1647
Nick Kralevich0de7c612014-01-27 14:58:06 -08001648 if (!isLegalAsecId(id)) {
1649 SLOGE("mountAsec: Invalid asec id \"%s\"", id);
1650 errno = EINVAL;
1651 return -1;
1652 }
1653
Kenny Root344ca102012-04-03 17:23:01 -07001654 if (findAsec(id, asecFileName, sizeof(asecFileName))) {
1655 SLOGE("Couldn't find ASEC %s", id);
1656 return -1;
1657 }
1658
Jeff Sharkey9f18fe72015-04-01 23:32:18 -07001659 int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", VolumeManager::ASECDIR, id);
rpcraigd1c226f2012-10-09 06:58:16 -04001660 if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) {
Colin Cross59846b62014-02-06 20:34:29 -08001661 SLOGE("ASEC mount failed for %s: couldn't construct mountpoint", id);
rpcraigd1c226f2012-10-09 06:58:16 -04001662 return -1;
1663 }
San Mehata19b2502010-01-06 10:33:53 -08001664
1665 if (isMountpointMounted(mountPoint)) {
San Mehat97ac40e2010-03-24 10:24:19 -07001666 SLOGE("ASEC %s already mounted", id);
San Mehata19b2502010-01-06 10:33:53 -08001667 errno = EBUSY;
1668 return -1;
1669 }
1670
San Mehatd9a4e352010-03-12 13:32:47 -08001671 char idHash[33];
1672 if (!asecHash(id, idHash, sizeof(idHash))) {
San Mehat97ac40e2010-03-24 10:24:19 -07001673 SLOGE("Hash of '%s' failed (%s)", id, strerror(errno));
San Mehatd9a4e352010-03-12 13:32:47 -08001674 return -1;
1675 }
Kenny Root7b18a7b2010-03-15 13:13:41 -07001676
San Mehata19b2502010-01-06 10:33:53 -08001677 char loopDevice[255];
Daniel Rosenbergfcd34a02014-05-22 11:23:56 -07001678 if (setupLoopDevice(loopDevice, sizeof(loopDevice), asecFileName, idHash, mDebug))
1679 return -1;
San Mehatb78a32c2010-01-10 13:02:12 -08001680
1681 char dmDevice[255];
1682 bool cleanupDm = false;
Tim Murray8439dc92014-12-15 11:56:11 -08001683
Hiroaki Miyazawa14eab552015-02-04 13:29:15 +09001684 unsigned long nr_sec = 0;
San Mehatfcf24fe2010-03-03 12:37:32 -08001685 struct asec_superblock sb;
San Mehatfcf24fe2010-03-03 12:37:32 -08001686
Kenny Root344ca102012-04-03 17:23:01 -07001687 if (Loop::lookupInfo(loopDevice, &sb, &nr_sec)) {
1688 return -1;
1689 }
San Mehatfcf24fe2010-03-03 12:37:32 -08001690
San Mehatd9a4e352010-03-12 13:32:47 -08001691 if (mDebug) {
San Mehat97ac40e2010-03-24 10:24:19 -07001692 SLOGD("Container sb magic/ver (%.8x/%.2x)", sb.magic, sb.ver);
San Mehatd9a4e352010-03-12 13:32:47 -08001693 }
San Mehatfcf24fe2010-03-03 12:37:32 -08001694 if (sb.magic != ASEC_SB_MAGIC || sb.ver != ASEC_SB_VER) {
San Mehat97ac40e2010-03-24 10:24:19 -07001695 SLOGE("Bad container magic/version (%.8x/%.2x)", sb.magic, sb.ver);
San Mehatfcf24fe2010-03-03 12:37:32 -08001696 Loop::destroyByDevice(loopDevice);
1697 errno = EMEDIUMTYPE;
1698 return -1;
1699 }
1700 nr_sec--; // We don't want the devmapping to extend onto our superblock
1701
Daniel Rosenbergfcd34a02014-05-22 11:23:56 -07001702 if (setupDevMapperDevice(dmDevice, sizeof(dmDevice), loopDevice, asecFileName, key, idHash , nr_sec, &cleanupDm, mDebug)) {
1703 Loop::destroyByDevice(loopDevice);
1704 return -1;
San Mehata19b2502010-01-06 10:33:53 -08001705 }
1706
Kenny Root344ca102012-04-03 17:23:01 -07001707 if (mkdir(mountPoint, 0000)) {
San Mehatb78a32c2010-01-10 13:02:12 -08001708 if (errno != EEXIST) {
San Mehat97ac40e2010-03-24 10:24:19 -07001709 SLOGE("Mountpoint creation failed (%s)", strerror(errno));
San Mehatb78a32c2010-01-10 13:02:12 -08001710 if (cleanupDm) {
San Mehatd9a4e352010-03-12 13:32:47 -08001711 Devmapper::destroy(idHash);
San Mehatb78a32c2010-01-10 13:02:12 -08001712 }
1713 Loop::destroyByDevice(loopDevice);
1714 return -1;
1715 }
San Mehata19b2502010-01-06 10:33:53 -08001716 }
1717
Kenny Rootcdc2a1c2012-05-03 13:49:46 -07001718 /*
Daniel Rosenbergfcd34a02014-05-22 11:23:56 -07001719 * Wait for the device mapper node to be created.
Kenny Rootcdc2a1c2012-05-03 13:49:46 -07001720 */
Daniel Rosenbergfcd34a02014-05-22 11:23:56 -07001721 waitForDevMapper(dmDevice);
Kenny Rootcdc2a1c2012-05-03 13:49:46 -07001722
Kenny Root344ca102012-04-03 17:23:01 -07001723 int result;
1724 if (sb.c_opts & ASEC_SB_C_OPTS_EXT4) {
Jeff Sharkeyd0640f62015-05-21 22:35:42 -07001725 result = android::vold::ext4::Mount(dmDevice, mountPoint,
1726 readOnly, false, readOnly);
Kenny Root344ca102012-04-03 17:23:01 -07001727 } else {
Jeff Sharkeyd0640f62015-05-21 22:35:42 -07001728 result = android::vold::vfat::Mount(dmDevice, mountPoint,
1729 readOnly, false, readOnly, ownerUid, 0, 0222, false);
Kenny Root344ca102012-04-03 17:23:01 -07001730 }
1731
1732 if (result) {
San Mehat97ac40e2010-03-24 10:24:19 -07001733 SLOGE("ASEC mount failed (%s)", strerror(errno));
San Mehatb78a32c2010-01-10 13:02:12 -08001734 if (cleanupDm) {
San Mehatd9a4e352010-03-12 13:32:47 -08001735 Devmapper::destroy(idHash);
San Mehatb78a32c2010-01-10 13:02:12 -08001736 }
1737 Loop::destroyByDevice(loopDevice);
San Mehata19b2502010-01-06 10:33:53 -08001738 return -1;
1739 }
1740
Kenny Rootcbacf782010-09-24 15:11:48 -07001741 mActiveContainers->push_back(new ContainerData(strdup(id), ASEC));
San Mehatd9a4e352010-03-12 13:32:47 -08001742 if (mDebug) {
San Mehat97ac40e2010-03-24 10:24:19 -07001743 SLOGD("ASEC %s mounted", id);
San Mehatd9a4e352010-03-12 13:32:47 -08001744 }
San Mehata19b2502010-01-06 10:33:53 -08001745 return 0;
1746}
1747
Kenny Rootfb7c4d52010-06-30 18:48:41 -07001748/**
1749 * Mounts an image file <code>img</code>.
1750 */
Jeff Sharkey69479042012-09-25 16:14:57 -07001751int VolumeManager::mountObb(const char *img, const char *key, int ownerGid) {
Kenny Rootfb7c4d52010-06-30 18:48:41 -07001752 char mountPoint[255];
1753
Kenny Rootfb7c4d52010-06-30 18:48:41 -07001754 char idHash[33];
1755 if (!asecHash(img, idHash, sizeof(idHash))) {
1756 SLOGE("Hash of '%s' failed (%s)", img, strerror(errno));
1757 return -1;
1758 }
1759
Jeff Sharkey9f18fe72015-04-01 23:32:18 -07001760 int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", VolumeManager::LOOPDIR, idHash);
rpcraigd1c226f2012-10-09 06:58:16 -04001761 if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) {
Colin Cross59846b62014-02-06 20:34:29 -08001762 SLOGE("OBB mount failed for %s: couldn't construct mountpoint", img);
rpcraigd1c226f2012-10-09 06:58:16 -04001763 return -1;
1764 }
Kenny Rootfb7c4d52010-06-30 18:48:41 -07001765
1766 if (isMountpointMounted(mountPoint)) {
1767 SLOGE("Image %s already mounted", img);
1768 errno = EBUSY;
1769 return -1;
1770 }
1771
1772 char loopDevice[255];
Daniel Rosenbergfcd34a02014-05-22 11:23:56 -07001773 if (setupLoopDevice(loopDevice, sizeof(loopDevice), img, idHash, mDebug))
1774 return -1;
Kenny Rootfb7c4d52010-06-30 18:48:41 -07001775
1776 char dmDevice[255];
1777 bool cleanupDm = false;
1778 int fd;
Hiroaki Miyazawa14eab552015-02-04 13:29:15 +09001779 unsigned long nr_sec = 0;
Kenny Rootfb7c4d52010-06-30 18:48:41 -07001780
Jeff Sharkeyce6a9132015-04-08 21:07:21 -07001781 if ((fd = open(loopDevice, O_RDWR | O_CLOEXEC)) < 0) {
Kenny Rootfb7c4d52010-06-30 18:48:41 -07001782 SLOGE("Failed to open loopdevice (%s)", strerror(errno));
1783 Loop::destroyByDevice(loopDevice);
1784 return -1;
1785 }
1786
Hiroaki Miyazawa14eab552015-02-04 13:29:15 +09001787 get_blkdev_size(fd, &nr_sec);
1788 if (nr_sec == 0) {
Kenny Rootfb7c4d52010-06-30 18:48:41 -07001789 SLOGE("Failed to get loop size (%s)", strerror(errno));
1790 Loop::destroyByDevice(loopDevice);
1791 close(fd);
1792 return -1;
1793 }
1794
1795 close(fd);
1796
Hiroaki Miyazawa14eab552015-02-04 13:29:15 +09001797 if (setupDevMapperDevice(dmDevice, sizeof(loopDevice), loopDevice, img,key, idHash, nr_sec, &cleanupDm, mDebug)) {
Daniel Rosenbergfcd34a02014-05-22 11:23:56 -07001798 Loop::destroyByDevice(loopDevice);
1799 return -1;
Kenny Rootfb7c4d52010-06-30 18:48:41 -07001800 }
1801
1802 if (mkdir(mountPoint, 0755)) {
1803 if (errno != EEXIST) {
1804 SLOGE("Mountpoint creation failed (%s)", strerror(errno));
1805 if (cleanupDm) {
1806 Devmapper::destroy(idHash);
1807 }
1808 Loop::destroyByDevice(loopDevice);
1809 return -1;
1810 }
1811 }
1812
yoshiyuki hama476a6272015-01-28 16:37:23 +09001813 /*
1814 * Wait for the device mapper node to be created.
1815 */
1816 waitForDevMapper(dmDevice);
1817
Jeff Sharkeyd0640f62015-05-21 22:35:42 -07001818 if (android::vold::vfat::Mount(dmDevice, mountPoint,
1819 true, false, true, 0, ownerGid, 0227, false)) {
Kenny Rootfb7c4d52010-06-30 18:48:41 -07001820 SLOGE("Image mount failed (%s)", strerror(errno));
1821 if (cleanupDm) {
1822 Devmapper::destroy(idHash);
1823 }
1824 Loop::destroyByDevice(loopDevice);
1825 return -1;
1826 }
1827
Kenny Rootcbacf782010-09-24 15:11:48 -07001828 mActiveContainers->push_back(new ContainerData(strdup(img), OBB));
Kenny Rootfb7c4d52010-06-30 18:48:41 -07001829 if (mDebug) {
1830 SLOGD("Image %s mounted", img);
1831 }
1832 return 0;
1833}
1834
Kenny Root508c0e12010-07-12 09:59:49 -07001835int VolumeManager::listMountedObbs(SocketClient* cli) {
Yabin Cuid1104f72015-01-02 13:28:28 -08001836 FILE *fp = setmntent("/proc/mounts", "r");
1837 if (fp == NULL) {
Kenny Root508c0e12010-07-12 09:59:49 -07001838 SLOGE("Error opening /proc/mounts (%s)", strerror(errno));
1839 return -1;
1840 }
1841
1842 // Create a string to compare against that has a trailing slash
Jeff Sharkey9f18fe72015-04-01 23:32:18 -07001843 int loopDirLen = strlen(VolumeManager::LOOPDIR);
Kenny Root508c0e12010-07-12 09:59:49 -07001844 char loopDir[loopDirLen + 2];
Jeff Sharkey9f18fe72015-04-01 23:32:18 -07001845 strcpy(loopDir, VolumeManager::LOOPDIR);
Kenny Root508c0e12010-07-12 09:59:49 -07001846 loopDir[loopDirLen++] = '/';
1847 loopDir[loopDirLen] = '\0';
1848
Yabin Cuid1104f72015-01-02 13:28:28 -08001849 mntent* mentry;
1850 while ((mentry = getmntent(fp)) != NULL) {
1851 if (!strncmp(mentry->mnt_dir, loopDir, loopDirLen)) {
Jeff Sharkeyce6a9132015-04-08 21:07:21 -07001852 int fd = open(mentry->mnt_fsname, O_RDONLY | O_CLOEXEC);
Kenny Root508c0e12010-07-12 09:59:49 -07001853 if (fd >= 0) {
1854 struct loop_info64 li;
1855 if (ioctl(fd, LOOP_GET_STATUS64, &li) >= 0) {
1856 cli->sendMsg(ResponseCode::AsecListResult,
1857 (const char*) li.lo_file_name, false);
1858 }
1859 close(fd);
1860 }
1861 }
1862 }
Yabin Cuid1104f72015-01-02 13:28:28 -08001863 endmntent(fp);
Kenny Root508c0e12010-07-12 09:59:49 -07001864 return 0;
1865}
1866
Jeff Sharkey9c484982015-03-31 10:35:33 -07001867extern "C" int vold_unmountAll(void) {
Ken Sumrall425524d2012-06-14 20:55:28 -07001868 VolumeManager *vm = VolumeManager::Instance();
Jeff Sharkey9c484982015-03-31 10:35:33 -07001869 return vm->unmountAll();
Ken Sumrall425524d2012-06-14 20:55:28 -07001870}
1871
San Mehata19b2502010-01-06 10:33:53 -08001872bool VolumeManager::isMountpointMounted(const char *mp)
1873{
Yabin Cuid1104f72015-01-02 13:28:28 -08001874 FILE *fp = setmntent("/proc/mounts", "r");
1875 if (fp == NULL) {
San Mehat97ac40e2010-03-24 10:24:19 -07001876 SLOGE("Error opening /proc/mounts (%s)", strerror(errno));
San Mehata19b2502010-01-06 10:33:53 -08001877 return false;
1878 }
1879
Yabin Cuid1104f72015-01-02 13:28:28 -08001880 bool found_mp = false;
1881 mntent* mentry;
1882 while ((mentry = getmntent(fp)) != NULL) {
1883 if (strcmp(mentry->mnt_dir, mp) == 0) {
1884 found_mp = true;
1885 break;
San Mehata19b2502010-01-06 10:33:53 -08001886 }
San Mehata19b2502010-01-06 10:33:53 -08001887 }
Yabin Cuid1104f72015-01-02 13:28:28 -08001888 endmntent(fp);
1889 return found_mp;
San Mehata19b2502010-01-06 10:33:53 -08001890}
1891
Jeff Sharkey71ebe152013-09-17 17:24:38 -07001892int VolumeManager::mkdirs(char* path) {
Jeff Sharkey36801cc2015-03-13 16:09:20 -07001893 // Only offer to create directories for paths managed by vold
1894 if (strncmp(path, "/storage/", 9) == 0) {
1895 // fs_mkdirs() does symlink checking and relative path enforcement
1896 return fs_mkdirs(path, 0700);
Jeff Sharkey71ebe152013-09-17 17:24:38 -07001897 } else {
Cylen Yao27cfee32014-05-02 19:23:42 +08001898 SLOGE("Failed to find mounted volume for %s", path);
Jeff Sharkey71ebe152013-09-17 17:24:38 -07001899 return -EINVAL;
1900 }
Jeff Sharkey71ebe152013-09-17 17:24:38 -07001901}