Home | History | Annotate | Download | only in vold
      1 /*
      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 
     17 #include <dirent.h>
     18 #include <errno.h>
     19 #include <fcntl.h>
     20 #include <fts.h>
     21 #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>
     27 #include <sys/stat.h>
     28 #include <sys/types.h>
     29 #include <sys/wait.h>
     30 #include <unistd.h>
     31 
     32 #include <linux/kdev_t.h>
     33 
     34 #define LOG_TAG "Vold"
     35 
     36 #include <openssl/md5.h>
     37 
     38 #include <android-base/logging.h>
     39 #include <android-base/stringprintf.h>
     40 #include <cutils/fs.h>
     41 #include <cutils/log.h>
     42 
     43 #include <selinux/android.h>
     44 
     45 #include <sysutils/NetlinkEvent.h>
     46 
     47 #include <private/android_filesystem_config.h>
     48 
     49 #include "Benchmark.h"
     50 #include "EmulatedVolume.h"
     51 #include "VolumeManager.h"
     52 #include "NetlinkManager.h"
     53 #include "ResponseCode.h"
     54 #include "Loop.h"
     55 #include "fs/Ext4.h"
     56 #include "fs/Vfat.h"
     57 #include "Utils.h"
     58 #include "Devmapper.h"
     59 #include "Process.h"
     60 #include "Asec.h"
     61 #include "VoldUtil.h"
     62 #include "cryptfs.h"
     63 
     64 #define MASS_STORAGE_FILE_PATH  "/sys/class/android_usb/android0/f_mass_storage/lun/file"
     65 
     66 #define ROUND_UP_POWER_OF_2(number, po2) (((!!((number) & ((1U << (po2)) - 1))) << (po2))\
     67                                          + ((number) & (~((1U << (po2)) - 1))))
     68 
     69 using android::base::StringPrintf;
     70 
     71 /*
     72  * Path to external storage where *only* root can access ASEC image files
     73  */
     74 const char *VolumeManager::SEC_ASECDIR_EXT   = "/mnt/secure/asec";
     75 
     76 /*
     77  * Path to internal storage where *only* root can access ASEC image files
     78  */
     79 const char *VolumeManager::SEC_ASECDIR_INT   = "/data/app-asec";
     80 
     81 /*
     82  * Path to where secure containers are mounted
     83  */
     84 const char *VolumeManager::ASECDIR           = "/mnt/asec";
     85 
     86 /*
     87  * Path to where OBBs are mounted
     88  */
     89 const char *VolumeManager::LOOPDIR           = "/mnt/obb";
     90 
     91 static const char* kPathUserMount = "/mnt/user";
     92 static const char* kPathVirtualDisk = "/data/misc/vold/virtual_disk";
     93 
     94 static const char* kPropVirtualDisk = "persist.sys.virtual_disk";
     95 
     96 /* 512MiB is large enough for testing purposes */
     97 static const unsigned int kSizeVirtualDisk = 536870912;
     98 
     99 static const unsigned int kMajorBlockMmc = 179;
    100 static const unsigned int kMajorBlockExperimentalMin = 240;
    101 static const unsigned int kMajorBlockExperimentalMax = 254;
    102 
    103 /* writes superblock at end of file or device given by name */
    104 static int writeSuperBlock(const char* name, struct asec_superblock *sb, unsigned int numImgSectors) {
    105     int sbfd = open(name, O_RDWR | O_CLOEXEC);
    106     if (sbfd < 0) {
    107         SLOGE("Failed to open %s for superblock write (%s)", name, strerror(errno));
    108         return -1;
    109     }
    110 
    111     if (lseek(sbfd, (numImgSectors * 512), SEEK_SET) < 0) {
    112         SLOGE("Failed to lseek for superblock (%s)", strerror(errno));
    113         close(sbfd);
    114         return -1;
    115     }
    116 
    117     if (write(sbfd, sb, sizeof(struct asec_superblock)) != sizeof(struct asec_superblock)) {
    118         SLOGE("Failed to write superblock (%s)", strerror(errno));
    119         close(sbfd);
    120         return -1;
    121     }
    122     close(sbfd);
    123     return 0;
    124 }
    125 
    126 static unsigned long adjustSectorNumExt4(unsigned long numSectors) {
    127     // Ext4 started to reserve 2% or 4096 clusters, whichever is smaller for
    128     // preventing costly operations or unexpected ENOSPC error.
    129     // Ext4::format() uses default block size without clustering.
    130     unsigned long clusterSectors = 4096 / 512;
    131     unsigned long reservedSectors = (numSectors * 2)/100 + (numSectors % 50 > 0);
    132     numSectors += reservedSectors > (4096 * clusterSectors) ? (4096 * clusterSectors) : reservedSectors;
    133     return ROUND_UP_POWER_OF_2(numSectors, 3);
    134 }
    135 
    136 static unsigned long adjustSectorNumFAT(unsigned long numSectors) {
    137     /*
    138     * Add some headroom
    139     */
    140     unsigned long fatSize = (((numSectors * 4) / 512) + 1) * 2;
    141     numSectors += fatSize + 2;
    142     /*
    143     * FAT is aligned to 32 kb with 512b sectors.
    144     */
    145     return ROUND_UP_POWER_OF_2(numSectors, 6);
    146 }
    147 
    148 static int setupLoopDevice(char* buffer, size_t len, const char* asecFileName, const char* idHash, bool debug) {
    149     if (Loop::lookupActive(idHash, buffer, len)) {
    150         if (Loop::create(idHash, asecFileName, buffer, len)) {
    151             SLOGE("ASEC loop device creation failed for %s (%s)", asecFileName, strerror(errno));
    152             return -1;
    153         }
    154         if (debug) {
    155             SLOGD("New loop device created at %s", buffer);
    156         }
    157     } else {
    158         if (debug) {
    159             SLOGD("Found active loopback for %s at %s", asecFileName, buffer);
    160         }
    161     }
    162     return 0;
    163 }
    164 
    165 static int setupDevMapperDevice(char* buffer, size_t len, const char* loopDevice, const char* asecFileName, const char* key, const char* idHash , unsigned long numImgSectors, bool* createdDMDevice, bool debug) {
    166     if (strcmp(key, "none")) {
    167         if (Devmapper::lookupActive(idHash, buffer, len)) {
    168             if (Devmapper::create(idHash, loopDevice, key, numImgSectors,
    169                                   buffer, len)) {
    170                 SLOGE("ASEC device mapping failed for %s (%s)", asecFileName, strerror(errno));
    171                 return -1;
    172             }
    173             if (debug) {
    174                 SLOGD("New devmapper instance created at %s", buffer);
    175             }
    176         } else {
    177             if (debug) {
    178                 SLOGD("Found active devmapper for %s at %s", asecFileName, buffer);
    179             }
    180         }
    181         *createdDMDevice = true;
    182     } else {
    183         strcpy(buffer, loopDevice);
    184         *createdDMDevice = false;
    185     }
    186     return 0;
    187 }
    188 
    189 static void waitForDevMapper(const char *dmDevice) {
    190     /*
    191      * Wait for the device mapper node to be created. Sometimes it takes a
    192      * while. Wait for up to 1 second. We could also inspect incoming uevents,
    193      * but that would take more effort.
    194      */
    195     int tries = 25;
    196     while (tries--) {
    197         if (!access(dmDevice, F_OK) || errno != ENOENT) {
    198             break;
    199         }
    200         usleep(40 * 1000);
    201     }
    202 }
    203 
    204 VolumeManager *VolumeManager::sInstance = NULL;
    205 
    206 VolumeManager *VolumeManager::Instance() {
    207     if (!sInstance)
    208         sInstance = new VolumeManager();
    209     return sInstance;
    210 }
    211 
    212 VolumeManager::VolumeManager() {
    213     mDebug = false;
    214     mActiveContainers = new AsecIdCollection();
    215     mBroadcaster = NULL;
    216     mUmsSharingCount = 0;
    217     mSavedDirtyRatio = -1;
    218     // set dirty ratio to 0 when UMS is active
    219     mUmsDirtyRatio = 0;
    220 }
    221 
    222 VolumeManager::~VolumeManager() {
    223     delete mActiveContainers;
    224 }
    225 
    226 char *VolumeManager::asecHash(const char *id, char *buffer, size_t len) {
    227     static const char* digits = "0123456789abcdef";
    228 
    229     unsigned char sig[MD5_DIGEST_LENGTH];
    230 
    231     if (buffer == NULL) {
    232         SLOGE("Destination buffer is NULL");
    233         errno = ESPIPE;
    234         return NULL;
    235     } else if (id == NULL) {
    236         SLOGE("Source buffer is NULL");
    237         errno = ESPIPE;
    238         return NULL;
    239     } else if (len < MD5_ASCII_LENGTH_PLUS_NULL) {
    240         SLOGE("Target hash buffer size < %d bytes (%zu)",
    241                 MD5_ASCII_LENGTH_PLUS_NULL, len);
    242         errno = ESPIPE;
    243         return NULL;
    244     }
    245 
    246     MD5(reinterpret_cast<const unsigned char*>(id), strlen(id), sig);
    247 
    248     char *p = buffer;
    249     for (int i = 0; i < MD5_DIGEST_LENGTH; i++) {
    250         *p++ = digits[sig[i] >> 4];
    251         *p++ = digits[sig[i] & 0x0F];
    252     }
    253     *p = '\0';
    254 
    255     return buffer;
    256 }
    257 
    258 int VolumeManager::updateVirtualDisk() {
    259     if (property_get_bool(kPropVirtualDisk, false)) {
    260         if (access(kPathVirtualDisk, F_OK) != 0) {
    261             Loop::createImageFile(kPathVirtualDisk, kSizeVirtualDisk / 512);
    262         }
    263 
    264         if (mVirtualDisk == nullptr) {
    265             if (Loop::create(kPathVirtualDisk, mVirtualDiskPath) != 0) {
    266                 LOG(ERROR) << "Failed to create virtual disk";
    267                 return -1;
    268             }
    269 
    270             struct stat buf;
    271             if (stat(mVirtualDiskPath.c_str(), &buf) < 0) {
    272                 PLOG(ERROR) << "Failed to stat " << mVirtualDiskPath;
    273                 return -1;
    274             }
    275 
    276             auto disk = new android::vold::Disk("virtual", buf.st_rdev, "virtual",
    277                     android::vold::Disk::Flags::kAdoptable | android::vold::Disk::Flags::kSd);
    278             disk->create();
    279             mVirtualDisk = std::shared_ptr<android::vold::Disk>(disk);
    280             mDisks.push_back(mVirtualDisk);
    281         }
    282     } else {
    283         if (mVirtualDisk != nullptr) {
    284             dev_t device = mVirtualDisk->getDevice();
    285 
    286             auto i = mDisks.begin();
    287             while (i != mDisks.end()) {
    288                 if ((*i)->getDevice() == device) {
    289                     (*i)->destroy();
    290                     i = mDisks.erase(i);
    291                 } else {
    292                     ++i;
    293                 }
    294             }
    295 
    296             Loop::destroyByDevice(mVirtualDiskPath.c_str());
    297             mVirtualDisk = nullptr;
    298         }
    299 
    300         if (access(kPathVirtualDisk, F_OK) == 0) {
    301             unlink(kPathVirtualDisk);
    302         }
    303     }
    304     return 0;
    305 }
    306 
    307 int VolumeManager::setDebug(bool enable) {
    308     mDebug = enable;
    309     return 0;
    310 }
    311 
    312 int VolumeManager::start() {
    313     // Always start from a clean slate by unmounting everything in
    314     // directories that we own, in case we crashed.
    315     unmountAll();
    316 
    317     // Assume that we always have an emulated volume on internal
    318     // storage; the framework will decide if it should be mounted.
    319     CHECK(mInternalEmulated == nullptr);
    320     mInternalEmulated = std::shared_ptr<android::vold::VolumeBase>(
    321             new android::vold::EmulatedVolume("/data/media"));
    322     mInternalEmulated->create();
    323 
    324     // Consider creating a virtual disk
    325     updateVirtualDisk();
    326 
    327     return 0;
    328 }
    329 
    330 int VolumeManager::stop() {
    331     CHECK(mInternalEmulated != nullptr);
    332     mInternalEmulated->destroy();
    333     mInternalEmulated = nullptr;
    334     return 0;
    335 }
    336 
    337 void VolumeManager::handleBlockEvent(NetlinkEvent *evt) {
    338     std::lock_guard<std::mutex> lock(mLock);
    339 
    340     if (mDebug) {
    341         LOG(VERBOSE) << "----------------";
    342         LOG(VERBOSE) << "handleBlockEvent with action " << (int) evt->getAction();
    343         evt->dump();
    344     }
    345 
    346     std::string eventPath(evt->findParam("DEVPATH")?evt->findParam("DEVPATH"):"");
    347     std::string devType(evt->findParam("DEVTYPE")?evt->findParam("DEVTYPE"):"");
    348 
    349     if (devType != "disk") return;
    350 
    351     int major = atoi(evt->findParam("MAJOR"));
    352     int minor = atoi(evt->findParam("MINOR"));
    353     dev_t device = makedev(major, minor);
    354 
    355     switch (evt->getAction()) {
    356     case NetlinkEvent::Action::kAdd: {
    357         for (const auto& source : mDiskSources) {
    358             if (source->matches(eventPath)) {
    359                 // For now, assume that MMC and virtio-blk (the latter is
    360                 // emulator-specific; see Disk.cpp for details) devices are SD,
    361                 // and that everything else is USB
    362                 int flags = source->getFlags();
    363                 if (major == kMajorBlockMmc
    364                     || (android::vold::IsRunningInEmulator()
    365                     && major >= (int) kMajorBlockExperimentalMin
    366                     && major <= (int) kMajorBlockExperimentalMax)) {
    367                     flags |= android::vold::Disk::Flags::kSd;
    368                 } else {
    369                     flags |= android::vold::Disk::Flags::kUsb;
    370                 }
    371 
    372                 auto disk = new android::vold::Disk(eventPath, device,
    373                         source->getNickname(), flags);
    374                 disk->create();
    375                 mDisks.push_back(std::shared_ptr<android::vold::Disk>(disk));
    376                 break;
    377             }
    378         }
    379         break;
    380     }
    381     case NetlinkEvent::Action::kChange: {
    382         LOG(DEBUG) << "Disk at " << major << ":" << minor << " changed";
    383         for (const auto& disk : mDisks) {
    384             if (disk->getDevice() == device) {
    385                 disk->readMetadata();
    386                 disk->readPartitions();
    387             }
    388         }
    389         break;
    390     }
    391     case NetlinkEvent::Action::kRemove: {
    392         auto i = mDisks.begin();
    393         while (i != mDisks.end()) {
    394             if ((*i)->getDevice() == device) {
    395                 (*i)->destroy();
    396                 i = mDisks.erase(i);
    397             } else {
    398                 ++i;
    399             }
    400         }
    401         break;
    402     }
    403     default: {
    404         LOG(WARNING) << "Unexpected block event action " << (int) evt->getAction();
    405         break;
    406     }
    407     }
    408 }
    409 
    410 void VolumeManager::addDiskSource(const std::shared_ptr<DiskSource>& diskSource) {
    411     std::lock_guard<std::mutex> lock(mLock);
    412     mDiskSources.push_back(diskSource);
    413 }
    414 
    415 std::shared_ptr<android::vold::Disk> VolumeManager::findDisk(const std::string& id) {
    416     for (auto disk : mDisks) {
    417         if (disk->getId() == id) {
    418             return disk;
    419         }
    420     }
    421     return nullptr;
    422 }
    423 
    424 std::shared_ptr<android::vold::VolumeBase> VolumeManager::findVolume(const std::string& id) {
    425     if (mInternalEmulated->getId() == id) {
    426         return mInternalEmulated;
    427     }
    428     for (const auto& disk : mDisks) {
    429         auto vol = disk->findVolume(id);
    430         if (vol != nullptr) {
    431             return vol;
    432         }
    433     }
    434     return nullptr;
    435 }
    436 
    437 void VolumeManager::listVolumes(android::vold::VolumeBase::Type type,
    438         std::list<std::string>& list) {
    439     list.clear();
    440     for (const auto& disk : mDisks) {
    441         disk->listVolumes(type, list);
    442     }
    443 }
    444 
    445 nsecs_t VolumeManager::benchmarkPrivate(const std::string& id) {
    446     std::string path;
    447     if (id == "private" || id == "null") {
    448         path = "/data";
    449     } else {
    450         auto vol = findVolume(id);
    451         if (vol != nullptr && vol->getState() == android::vold::VolumeBase::State::kMounted) {
    452             path = vol->getPath();
    453         }
    454     }
    455 
    456     if (path.empty()) {
    457         LOG(WARNING) << "Failed to find volume for " << id;
    458         return -1;
    459     }
    460 
    461     return android::vold::BenchmarkPrivate(path);
    462 }
    463 
    464 int VolumeManager::forgetPartition(const std::string& partGuid) {
    465     std::string normalizedGuid;
    466     if (android::vold::NormalizeHex(partGuid, normalizedGuid)) {
    467         LOG(WARNING) << "Invalid GUID " << partGuid;
    468         return -1;
    469     }
    470 
    471     std::string keyPath = android::vold::BuildKeyPath(normalizedGuid);
    472     if (unlink(keyPath.c_str()) != 0) {
    473         LOG(ERROR) << "Failed to unlink " << keyPath;
    474         return -1;
    475     }
    476 
    477     return 0;
    478 }
    479 
    480 int VolumeManager::linkPrimary(userid_t userId) {
    481     std::string source(mPrimary->getPath());
    482     if (mPrimary->getType() == android::vold::VolumeBase::Type::kEmulated) {
    483         source = StringPrintf("%s/%d", source.c_str(), userId);
    484         fs_prepare_dir(source.c_str(), 0755, AID_ROOT, AID_ROOT);
    485     }
    486 
    487     std::string target(StringPrintf("/mnt/user/%d/primary", userId));
    488     if (TEMP_FAILURE_RETRY(unlink(target.c_str()))) {
    489         if (errno != ENOENT) {
    490             SLOGW("Failed to unlink %s: %s", target.c_str(), strerror(errno));
    491         }
    492     }
    493     LOG(DEBUG) << "Linking " << source << " to " << target;
    494     if (TEMP_FAILURE_RETRY(symlink(source.c_str(), target.c_str()))) {
    495         SLOGW("Failed to link %s to %s: %s", source.c_str(), target.c_str(),
    496                 strerror(errno));
    497         return -errno;
    498     }
    499     return 0;
    500 }
    501 
    502 int VolumeManager::onUserAdded(userid_t userId, int userSerialNumber) {
    503     mAddedUsers[userId] = userSerialNumber;
    504     return 0;
    505 }
    506 
    507 int VolumeManager::onUserRemoved(userid_t userId) {
    508     mAddedUsers.erase(userId);
    509     return 0;
    510 }
    511 
    512 int VolumeManager::onUserStarted(userid_t userId) {
    513     // Note that sometimes the system will spin up processes from Zygote
    514     // before actually starting the user, so we're okay if Zygote
    515     // already created this directory.
    516     std::string path(StringPrintf("%s/%d", kPathUserMount, userId));
    517     fs_prepare_dir(path.c_str(), 0755, AID_ROOT, AID_ROOT);
    518 
    519     mStartedUsers.insert(userId);
    520     if (mPrimary) {
    521         linkPrimary(userId);
    522     }
    523     return 0;
    524 }
    525 
    526 int VolumeManager::onUserStopped(userid_t userId) {
    527     mStartedUsers.erase(userId);
    528     return 0;
    529 }
    530 
    531 int VolumeManager::setPrimary(const std::shared_ptr<android::vold::VolumeBase>& vol) {
    532     mPrimary = vol;
    533     for (userid_t userId : mStartedUsers) {
    534         linkPrimary(userId);
    535     }
    536     return 0;
    537 }
    538 
    539 static int unmount_tree(const char* path) {
    540     size_t path_len = strlen(path);
    541 
    542     FILE* fp = setmntent("/proc/mounts", "r");
    543     if (fp == NULL) {
    544         ALOGE("Error opening /proc/mounts: %s", strerror(errno));
    545         return -errno;
    546     }
    547 
    548     // Some volumes can be stacked on each other, so force unmount in
    549     // reverse order to give us the best chance of success.
    550     std::list<std::string> toUnmount;
    551     mntent* mentry;
    552     while ((mentry = getmntent(fp)) != NULL) {
    553         if (strncmp(mentry->mnt_dir, path, path_len) == 0) {
    554             toUnmount.push_front(std::string(mentry->mnt_dir));
    555         }
    556     }
    557     endmntent(fp);
    558 
    559     for (const auto& path : toUnmount) {
    560         if (umount2(path.c_str(), MNT_DETACH)) {
    561             ALOGW("Failed to unmount %s: %s", path.c_str(), strerror(errno));
    562         }
    563     }
    564     return 0;
    565 }
    566 
    567 int VolumeManager::remountUid(uid_t uid, const std::string& mode) {
    568     LOG(DEBUG) << "Remounting " << uid << " as mode " << mode;
    569 
    570     DIR* dir;
    571     struct dirent* de;
    572     char rootName[PATH_MAX];
    573     char pidName[PATH_MAX];
    574     int pidFd;
    575     int nsFd;
    576     struct stat sb;
    577     pid_t child;
    578 
    579     if (!(dir = opendir("/proc"))) {
    580         PLOG(ERROR) << "Failed to opendir";
    581         return -1;
    582     }
    583 
    584     // Figure out root namespace to compare against below
    585     if (android::vold::SaneReadLinkAt(dirfd(dir), "1/ns/mnt", rootName, PATH_MAX) == -1) {
    586         PLOG(ERROR) << "Failed to readlink";
    587         closedir(dir);
    588         return -1;
    589     }
    590 
    591     // Poke through all running PIDs look for apps running as UID
    592     while ((de = readdir(dir))) {
    593         pidFd = -1;
    594         nsFd = -1;
    595 
    596         pidFd = openat(dirfd(dir), de->d_name, O_RDONLY | O_DIRECTORY | O_CLOEXEC);
    597         if (pidFd < 0) {
    598             goto next;
    599         }
    600         if (fstat(pidFd, &sb) != 0) {
    601             PLOG(WARNING) << "Failed to stat " << de->d_name;
    602             goto next;
    603         }
    604         if (sb.st_uid != uid) {
    605             goto next;
    606         }
    607 
    608         // Matches so far, but refuse to touch if in root namespace
    609         LOG(DEBUG) << "Found matching PID " << de->d_name;
    610         if (android::vold::SaneReadLinkAt(pidFd, "ns/mnt", pidName, PATH_MAX) == -1) {
    611             PLOG(WARNING) << "Failed to read namespace for " << de->d_name;
    612             goto next;
    613         }
    614         if (!strcmp(rootName, pidName)) {
    615             LOG(WARNING) << "Skipping due to root namespace";
    616             goto next;
    617         }
    618 
    619         // We purposefully leave the namespace open across the fork
    620         nsFd = openat(pidFd, "ns/mnt", O_RDONLY); // not O_CLOEXEC
    621         if (nsFd < 0) {
    622             PLOG(WARNING) << "Failed to open namespace for " << de->d_name;
    623             goto next;
    624         }
    625 
    626         if (!(child = fork())) {
    627             if (setns(nsFd, CLONE_NEWNS) != 0) {
    628                 PLOG(ERROR) << "Failed to setns for " << de->d_name;
    629                 _exit(1);
    630             }
    631 
    632             unmount_tree("/storage");
    633 
    634             std::string storageSource;
    635             if (mode == "default") {
    636                 storageSource = "/mnt/runtime/default";
    637             } else if (mode == "read") {
    638                 storageSource = "/mnt/runtime/read";
    639             } else if (mode == "write") {
    640                 storageSource = "/mnt/runtime/write";
    641             } else {
    642                 // Sane default of no storage visible
    643                 _exit(0);
    644             }
    645             if (TEMP_FAILURE_RETRY(mount(storageSource.c_str(), "/storage",
    646                     NULL, MS_BIND | MS_REC, NULL)) == -1) {
    647                 PLOG(ERROR) << "Failed to mount " << storageSource << " for "
    648                         << de->d_name;
    649                 _exit(1);
    650             }
    651             if (TEMP_FAILURE_RETRY(mount(NULL, "/storage", NULL,
    652                     MS_REC | MS_SLAVE, NULL)) == -1) {
    653                 PLOG(ERROR) << "Failed to set MS_SLAVE to /storage for "
    654                         << de->d_name;
    655                 _exit(1);
    656             }
    657 
    658             // Mount user-specific symlink helper into place
    659             userid_t user_id = multiuser_get_user_id(uid);
    660             std::string userSource(StringPrintf("/mnt/user/%d", user_id));
    661             if (TEMP_FAILURE_RETRY(mount(userSource.c_str(), "/storage/self",
    662                     NULL, MS_BIND, NULL)) == -1) {
    663                 PLOG(ERROR) << "Failed to mount " << userSource << " for "
    664                         << de->d_name;
    665                 _exit(1);
    666             }
    667 
    668             _exit(0);
    669         }
    670 
    671         if (child == -1) {
    672             PLOG(ERROR) << "Failed to fork";
    673             goto next;
    674         } else {
    675             TEMP_FAILURE_RETRY(waitpid(child, nullptr, 0));
    676         }
    677 
    678 next:
    679         close(nsFd);
    680         close(pidFd);
    681     }
    682     closedir(dir);
    683     return 0;
    684 }
    685 
    686 int VolumeManager::reset() {
    687     // Tear down all existing disks/volumes and start from a blank slate so
    688     // newly connected framework hears all events.
    689     mInternalEmulated->destroy();
    690     mInternalEmulated->create();
    691     for (const auto& disk : mDisks) {
    692         disk->destroy();
    693         disk->create();
    694     }
    695     updateVirtualDisk();
    696     mAddedUsers.clear();
    697     mStartedUsers.clear();
    698     return 0;
    699 }
    700 
    701 // Can be called twice (sequentially) during shutdown. should be safe for that.
    702 int VolumeManager::shutdown() {
    703     if (mInternalEmulated == nullptr) {
    704         return 0; // already shutdown
    705     }
    706     mInternalEmulated->destroy();
    707     mInternalEmulated = nullptr;
    708     for (const auto& disk : mDisks) {
    709         disk->destroy();
    710     }
    711     mDisks.clear();
    712     return 0;
    713 }
    714 
    715 int VolumeManager::unmountAll() {
    716     std::lock_guard<std::mutex> lock(mLock);
    717 
    718     // First, try gracefully unmounting all known devices
    719     if (mInternalEmulated != nullptr) {
    720         mInternalEmulated->unmount();
    721     }
    722     for (const auto& disk : mDisks) {
    723         disk->unmountAll();
    724     }
    725 
    726     // Worst case we might have some stale mounts lurking around, so
    727     // force unmount those just to be safe.
    728     FILE* fp = setmntent("/proc/mounts", "r");
    729     if (fp == NULL) {
    730         SLOGE("Error opening /proc/mounts: %s", strerror(errno));
    731         return -errno;
    732     }
    733 
    734     // Some volumes can be stacked on each other, so force unmount in
    735     // reverse order to give us the best chance of success.
    736     std::list<std::string> toUnmount;
    737     mntent* mentry;
    738     while ((mentry = getmntent(fp)) != NULL) {
    739         if (strncmp(mentry->mnt_dir, "/mnt/", 5) == 0
    740                 || strncmp(mentry->mnt_dir, "/storage/", 9) == 0) {
    741             toUnmount.push_front(std::string(mentry->mnt_dir));
    742         }
    743     }
    744     endmntent(fp);
    745 
    746     for (const auto& path : toUnmount) {
    747         SLOGW("Tearing down stale mount %s", path.c_str());
    748         android::vold::ForceUnmount(path);
    749     }
    750 
    751     return 0;
    752 }
    753 
    754 int VolumeManager::getObbMountPath(const char *sourceFile, char *mountPath, int mountPathLen) {
    755     char idHash[33];
    756     if (!asecHash(sourceFile, idHash, sizeof(idHash))) {
    757         SLOGE("Hash of '%s' failed (%s)", sourceFile, strerror(errno));
    758         return -1;
    759     }
    760 
    761     memset(mountPath, 0, mountPathLen);
    762     int written = snprintf(mountPath, mountPathLen, "%s/%s", VolumeManager::LOOPDIR, idHash);
    763     if ((written < 0) || (written >= mountPathLen)) {
    764         errno = EINVAL;
    765         return -1;
    766     }
    767 
    768     if (access(mountPath, F_OK)) {
    769         errno = ENOENT;
    770         return -1;
    771     }
    772 
    773     return 0;
    774 }
    775 
    776 int VolumeManager::getAsecMountPath(const char *id, char *buffer, int maxlen) {
    777     char asecFileName[255];
    778 
    779     if (!isLegalAsecId(id)) {
    780         SLOGE("getAsecMountPath: Invalid asec id \"%s\"", id);
    781         errno = EINVAL;
    782         return -1;
    783     }
    784 
    785     if (findAsec(id, asecFileName, sizeof(asecFileName))) {
    786         SLOGE("Couldn't find ASEC %s", id);
    787         return -1;
    788     }
    789 
    790     memset(buffer, 0, maxlen);
    791     if (access(asecFileName, F_OK)) {
    792         errno = ENOENT;
    793         return -1;
    794     }
    795 
    796     int written = snprintf(buffer, maxlen, "%s/%s", VolumeManager::ASECDIR, id);
    797     if ((written < 0) || (written >= maxlen)) {
    798         SLOGE("getAsecMountPath failed for %s: couldn't construct path in buffer", id);
    799         errno = EINVAL;
    800         return -1;
    801     }
    802 
    803     return 0;
    804 }
    805 
    806 int VolumeManager::getAsecFilesystemPath(const char *id, char *buffer, int maxlen) {
    807     char asecFileName[255];
    808 
    809     if (!isLegalAsecId(id)) {
    810         SLOGE("getAsecFilesystemPath: Invalid asec id \"%s\"", id);
    811         errno = EINVAL;
    812         return -1;
    813     }
    814 
    815     if (findAsec(id, asecFileName, sizeof(asecFileName))) {
    816         SLOGE("Couldn't find ASEC %s", id);
    817         return -1;
    818     }
    819 
    820     memset(buffer, 0, maxlen);
    821     if (access(asecFileName, F_OK)) {
    822         errno = ENOENT;
    823         return -1;
    824     }
    825 
    826     int written = snprintf(buffer, maxlen, "%s", asecFileName);
    827     if ((written < 0) || (written >= maxlen)) {
    828         errno = EINVAL;
    829         return -1;
    830     }
    831 
    832     return 0;
    833 }
    834 
    835 int VolumeManager::createAsec(const char *id, unsigned long numSectors, const char *fstype,
    836         const char *key, const int ownerUid, bool isExternal) {
    837     struct asec_superblock sb;
    838     memset(&sb, 0, sizeof(sb));
    839 
    840     if (!isLegalAsecId(id)) {
    841         SLOGE("createAsec: Invalid asec id \"%s\"", id);
    842         errno = EINVAL;
    843         return -1;
    844     }
    845 
    846     const bool wantFilesystem = strcmp(fstype, "none");
    847     bool usingExt4 = false;
    848     if (wantFilesystem) {
    849         usingExt4 = !strcmp(fstype, "ext4");
    850         if (usingExt4) {
    851             sb.c_opts |= ASEC_SB_C_OPTS_EXT4;
    852         } else if (strcmp(fstype, "fat")) {
    853             SLOGE("Invalid filesystem type %s", fstype);
    854             errno = EINVAL;
    855             return -1;
    856         }
    857     }
    858 
    859     sb.magic = ASEC_SB_MAGIC;
    860     sb.ver = ASEC_SB_VER;
    861 
    862     if (numSectors < ((1024*1024)/512)) {
    863         SLOGE("Invalid container size specified (%lu sectors)", numSectors);
    864         errno = EINVAL;
    865         return -1;
    866     }
    867 
    868     char asecFileName[255];
    869 
    870     if (!findAsec(id, asecFileName, sizeof(asecFileName))) {
    871         SLOGE("ASEC file '%s' currently exists - destroy it first! (%s)",
    872                 asecFileName, strerror(errno));
    873         errno = EADDRINUSE;
    874         return -1;
    875     }
    876 
    877     const char *asecDir = isExternal ? VolumeManager::SEC_ASECDIR_EXT : VolumeManager::SEC_ASECDIR_INT;
    878 
    879     int written = snprintf(asecFileName, sizeof(asecFileName), "%s/%s.asec", asecDir, id);
    880     if ((written < 0) || (size_t(written) >= sizeof(asecFileName))) {
    881         errno = EINVAL;
    882         return -1;
    883     }
    884 
    885     if (!access(asecFileName, F_OK)) {
    886         SLOGE("ASEC file '%s' currently exists - destroy it first! (%s)",
    887                 asecFileName, strerror(errno));
    888         errno = EADDRINUSE;
    889         return -1;
    890     }
    891 
    892     unsigned long numImgSectors;
    893     if (usingExt4)
    894         numImgSectors = adjustSectorNumExt4(numSectors);
    895     else
    896         numImgSectors = adjustSectorNumFAT(numSectors);
    897 
    898     // Add +1 for our superblock which is at the end
    899     if (Loop::createImageFile(asecFileName, numImgSectors + 1)) {
    900         SLOGE("ASEC image file creation failed (%s)", strerror(errno));
    901         return -1;
    902     }
    903 
    904     char idHash[33];
    905     if (!asecHash(id, idHash, sizeof(idHash))) {
    906         SLOGE("Hash of '%s' failed (%s)", id, strerror(errno));
    907         unlink(asecFileName);
    908         return -1;
    909     }
    910 
    911     char loopDevice[255];
    912     if (Loop::create(idHash, asecFileName, loopDevice, sizeof(loopDevice))) {
    913         SLOGE("ASEC loop device creation failed (%s)", strerror(errno));
    914         unlink(asecFileName);
    915         return -1;
    916     }
    917 
    918     char dmDevice[255];
    919     bool cleanupDm = false;
    920 
    921     if (strcmp(key, "none")) {
    922         // XXX: This is all we support for now
    923         sb.c_cipher = ASEC_SB_C_CIPHER_TWOFISH;
    924         if (Devmapper::create(idHash, loopDevice, key, numImgSectors, dmDevice,
    925                              sizeof(dmDevice))) {
    926             SLOGE("ASEC device mapping failed (%s)", strerror(errno));
    927             Loop::destroyByDevice(loopDevice);
    928             unlink(asecFileName);
    929             return -1;
    930         }
    931         cleanupDm = true;
    932     } else {
    933         sb.c_cipher = ASEC_SB_C_CIPHER_NONE;
    934         strcpy(dmDevice, loopDevice);
    935     }
    936 
    937     /*
    938      * Drop down the superblock at the end of the file
    939      */
    940     if (writeSuperBlock(loopDevice, &sb, numImgSectors)) {
    941         if (cleanupDm) {
    942             Devmapper::destroy(idHash);
    943         }
    944         Loop::destroyByDevice(loopDevice);
    945         unlink(asecFileName);
    946         return -1;
    947     }
    948 
    949     if (wantFilesystem) {
    950         int formatStatus;
    951         char mountPoint[255];
    952 
    953         int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", VolumeManager::ASECDIR, id);
    954         if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) {
    955             SLOGE("ASEC fs format failed: couldn't construct mountPoint");
    956             if (cleanupDm) {
    957                 Devmapper::destroy(idHash);
    958             }
    959             Loop::destroyByDevice(loopDevice);
    960             unlink(asecFileName);
    961             return -1;
    962         }
    963 
    964         if (usingExt4) {
    965             formatStatus = android::vold::ext4::Format(dmDevice, numImgSectors, mountPoint);
    966         } else {
    967             formatStatus = android::vold::vfat::Format(dmDevice, numImgSectors);
    968         }
    969 
    970         if (formatStatus < 0) {
    971             SLOGE("ASEC fs format failed (%s)", strerror(errno));
    972             if (cleanupDm) {
    973                 Devmapper::destroy(idHash);
    974             }
    975             Loop::destroyByDevice(loopDevice);
    976             unlink(asecFileName);
    977             return -1;
    978         }
    979 
    980         if (mkdir(mountPoint, 0000)) {
    981             if (errno != EEXIST) {
    982                 SLOGE("Mountpoint creation failed (%s)", strerror(errno));
    983                 if (cleanupDm) {
    984                     Devmapper::destroy(idHash);
    985                 }
    986                 Loop::destroyByDevice(loopDevice);
    987                 unlink(asecFileName);
    988                 return -1;
    989             }
    990         }
    991 
    992         int mountStatus;
    993         if (usingExt4) {
    994             mountStatus = android::vold::ext4::Mount(dmDevice, mountPoint,
    995                     false, false, false);
    996         } else {
    997             mountStatus = android::vold::vfat::Mount(dmDevice, mountPoint,
    998                     false, false, false, ownerUid, 0, 0000, false);
    999         }
   1000 
   1001         if (mountStatus) {
   1002             SLOGE("ASEC FAT mount failed (%s)", strerror(errno));
   1003             if (cleanupDm) {
   1004                 Devmapper::destroy(idHash);
   1005             }
   1006             Loop::destroyByDevice(loopDevice);
   1007             unlink(asecFileName);
   1008             return -1;
   1009         }
   1010 
   1011         if (usingExt4) {
   1012             int dirfd = open(mountPoint, O_DIRECTORY | O_CLOEXEC);
   1013             if (dirfd >= 0) {
   1014                 if (fchown(dirfd, ownerUid, AID_SYSTEM)
   1015                         || fchmod(dirfd, S_IRUSR | S_IWUSR | S_IXUSR | S_ISGID | S_IRGRP | S_IXGRP)) {
   1016                     SLOGI("Cannot chown/chmod new ASEC mount point %s", mountPoint);
   1017                 }
   1018                 close(dirfd);
   1019             }
   1020         }
   1021     } else {
   1022         SLOGI("Created raw secure container %s (no filesystem)", id);
   1023     }
   1024 
   1025     mActiveContainers->push_back(new ContainerData(strdup(id), ASEC));
   1026     return 0;
   1027 }
   1028 
   1029 int VolumeManager::resizeAsec(const char *id, unsigned long numSectors, const char *key) {
   1030     char asecFileName[255];
   1031     char mountPoint[255];
   1032     bool cleanupDm = false;
   1033 
   1034     if (!isLegalAsecId(id)) {
   1035         SLOGE("resizeAsec: Invalid asec id \"%s\"", id);
   1036         errno = EINVAL;
   1037         return -1;
   1038     }
   1039 
   1040     if (findAsec(id, asecFileName, sizeof(asecFileName))) {
   1041         SLOGE("Couldn't find ASEC %s", id);
   1042         return -1;
   1043     }
   1044 
   1045     int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", VolumeManager::ASECDIR, id);
   1046     if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) {
   1047        SLOGE("ASEC resize failed for %s: couldn't construct mountpoint", id);
   1048        return -1;
   1049     }
   1050 
   1051     if (isMountpointMounted(mountPoint)) {
   1052        SLOGE("ASEC %s mounted. Unmount before resizing", id);
   1053        errno = EBUSY;
   1054        return -1;
   1055     }
   1056 
   1057     struct asec_superblock sb;
   1058     int fd;
   1059     unsigned long oldNumSec = 0;
   1060 
   1061     if ((fd = open(asecFileName, O_RDONLY | O_CLOEXEC)) < 0) {
   1062         SLOGE("Failed to open ASEC file (%s)", strerror(errno));
   1063         return -1;
   1064     }
   1065 
   1066     struct stat info;
   1067     if (fstat(fd, &info) < 0) {
   1068         SLOGE("Failed to get file size (%s)", strerror(errno));
   1069         close(fd);
   1070         return -1;
   1071     }
   1072 
   1073     oldNumSec = info.st_size / 512;
   1074 
   1075     /*
   1076      * Try to read superblock.
   1077      */
   1078     memset(&sb, 0, sizeof(struct asec_superblock));
   1079     if (lseek(fd, ((oldNumSec - 1) * 512), SEEK_SET) < 0) {
   1080         SLOGE("lseek failed (%s)", strerror(errno));
   1081         close(fd);
   1082         return -1;
   1083     }
   1084     if (read(fd, &sb, sizeof(struct asec_superblock)) != sizeof(struct asec_superblock)) {
   1085         SLOGE("superblock read failed (%s)", strerror(errno));
   1086         close(fd);
   1087         return -1;
   1088     }
   1089     close(fd);
   1090 
   1091     if (mDebug) {
   1092         SLOGD("Container sb magic/ver (%.8x/%.2x)", sb.magic, sb.ver);
   1093     }
   1094     if (sb.magic != ASEC_SB_MAGIC || sb.ver != ASEC_SB_VER) {
   1095         SLOGE("Bad container magic/version (%.8x/%.2x)", sb.magic, sb.ver);
   1096         errno = EMEDIUMTYPE;
   1097         return -1;
   1098     }
   1099 
   1100     unsigned long numImgSectors;
   1101     if (!(sb.c_opts & ASEC_SB_C_OPTS_EXT4)) {
   1102         SLOGE("Only ext4 partitions are supported for resize");
   1103         errno = EINVAL;
   1104         return -1;
   1105     } else {
   1106         numImgSectors = adjustSectorNumExt4(numSectors);
   1107     }
   1108 
   1109     /*
   1110      *  add one block for the superblock
   1111      */
   1112     SLOGD("Resizing from %lu sectors to %lu sectors", oldNumSec, numImgSectors + 1);
   1113     if (oldNumSec == numImgSectors + 1) {
   1114         SLOGW("Size unchanged; ignoring resize request");
   1115         return 0;
   1116     } else if (oldNumSec > numImgSectors + 1) {
   1117         SLOGE("Only growing is currently supported.");
   1118         close(fd);
   1119         return -1;
   1120     }
   1121 
   1122     if (Loop::resizeImageFile(asecFileName, numImgSectors + 1)) {
   1123         SLOGE("Resize of ASEC image file failed. Could not resize %s", id);
   1124         return -1;
   1125     }
   1126 
   1127     /*
   1128      * Drop down a copy of the superblock at the end of the file
   1129      */
   1130     if (writeSuperBlock(asecFileName, &sb, numImgSectors))
   1131         goto fail;
   1132 
   1133     char idHash[33];
   1134     if (!asecHash(id, idHash, sizeof(idHash))) {
   1135         SLOGE("Hash of '%s' failed (%s)", id, strerror(errno));
   1136         goto fail;
   1137     }
   1138 
   1139     char loopDevice[255];
   1140     if (setupLoopDevice(loopDevice, sizeof(loopDevice), asecFileName, idHash, mDebug))
   1141         goto fail;
   1142 
   1143     char dmDevice[255];
   1144 
   1145     if (setupDevMapperDevice(dmDevice, sizeof(dmDevice), loopDevice, asecFileName, key, idHash, numImgSectors, &cleanupDm, mDebug)) {
   1146         Loop::destroyByDevice(loopDevice);
   1147         goto fail;
   1148     }
   1149 
   1150     /*
   1151      * Wait for the device mapper node to be created.
   1152      */
   1153     waitForDevMapper(dmDevice);
   1154 
   1155     if (android::vold::ext4::Resize(dmDevice, numImgSectors)) {
   1156         SLOGE("Unable to resize %s (%s)", id, strerror(errno));
   1157         if (cleanupDm) {
   1158             Devmapper::destroy(idHash);
   1159         }
   1160         Loop::destroyByDevice(loopDevice);
   1161         goto fail;
   1162     }
   1163 
   1164     return 0;
   1165 fail:
   1166     Loop::resizeImageFile(asecFileName, oldNumSec);
   1167     return -1;
   1168 }
   1169 
   1170 int VolumeManager::finalizeAsec(const char *id) {
   1171     char asecFileName[255];
   1172     char loopDevice[255];
   1173     char mountPoint[255];
   1174 
   1175     if (!isLegalAsecId(id)) {
   1176         SLOGE("finalizeAsec: Invalid asec id \"%s\"", id);
   1177         errno = EINVAL;
   1178         return -1;
   1179     }
   1180 
   1181     if (findAsec(id, asecFileName, sizeof(asecFileName))) {
   1182         SLOGE("Couldn't find ASEC %s", id);
   1183         return -1;
   1184     }
   1185 
   1186     char idHash[33];
   1187     if (!asecHash(id, idHash, sizeof(idHash))) {
   1188         SLOGE("Hash of '%s' failed (%s)", id, strerror(errno));
   1189         return -1;
   1190     }
   1191 
   1192     if (Loop::lookupActive(idHash, loopDevice, sizeof(loopDevice))) {
   1193         SLOGE("Unable to finalize %s (%s)", id, strerror(errno));
   1194         return -1;
   1195     }
   1196 
   1197     unsigned long nr_sec = 0;
   1198     struct asec_superblock sb;
   1199 
   1200     if (Loop::lookupInfo(loopDevice, &sb, &nr_sec)) {
   1201         return -1;
   1202     }
   1203 
   1204     int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", VolumeManager::ASECDIR, id);
   1205     if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) {
   1206         SLOGE("ASEC finalize failed: couldn't construct mountPoint");
   1207         return -1;
   1208     }
   1209 
   1210     int result = 0;
   1211     if (sb.c_opts & ASEC_SB_C_OPTS_EXT4) {
   1212         result = android::vold::ext4::Mount(loopDevice, mountPoint,
   1213                 true, true, true);
   1214     } else {
   1215         result = android::vold::vfat::Mount(loopDevice, mountPoint,
   1216                 true, true, true, 0, 0, 0227, false);
   1217     }
   1218 
   1219     if (result) {
   1220         SLOGE("ASEC finalize mount failed (%s)", strerror(errno));
   1221         return -1;
   1222     }
   1223 
   1224     if (mDebug) {
   1225         SLOGD("ASEC %s finalized", id);
   1226     }
   1227     return 0;
   1228 }
   1229 
   1230 int VolumeManager::fixupAsecPermissions(const char *id, gid_t gid, const char* filename) {
   1231     char asecFileName[255];
   1232     char loopDevice[255];
   1233     char mountPoint[255];
   1234 
   1235     if (gid < AID_APP) {
   1236         SLOGE("Group ID is not in application range");
   1237         return -1;
   1238     }
   1239 
   1240     if (!isLegalAsecId(id)) {
   1241         SLOGE("fixupAsecPermissions: Invalid asec id \"%s\"", id);
   1242         errno = EINVAL;
   1243         return -1;
   1244     }
   1245 
   1246     if (findAsec(id, asecFileName, sizeof(asecFileName))) {
   1247         SLOGE("Couldn't find ASEC %s", id);
   1248         return -1;
   1249     }
   1250 
   1251     char idHash[33];
   1252     if (!asecHash(id, idHash, sizeof(idHash))) {
   1253         SLOGE("Hash of '%s' failed (%s)", id, strerror(errno));
   1254         return -1;
   1255     }
   1256 
   1257     if (Loop::lookupActive(idHash, loopDevice, sizeof(loopDevice))) {
   1258         SLOGE("Unable fix permissions during lookup on %s (%s)", id, strerror(errno));
   1259         return -1;
   1260     }
   1261 
   1262     unsigned long nr_sec = 0;
   1263     struct asec_superblock sb;
   1264 
   1265     if (Loop::lookupInfo(loopDevice, &sb, &nr_sec)) {
   1266         return -1;
   1267     }
   1268 
   1269     int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", VolumeManager::ASECDIR, id);
   1270     if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) {
   1271         SLOGE("Unable remount to fix permissions for %s: couldn't construct mountpoint", id);
   1272         return -1;
   1273     }
   1274 
   1275     int result = 0;
   1276     if ((sb.c_opts & ASEC_SB_C_OPTS_EXT4) == 0) {
   1277         return 0;
   1278     }
   1279 
   1280     int ret = android::vold::ext4::Mount(loopDevice, mountPoint,
   1281             false /* read-only */,
   1282             true  /* remount */,
   1283             false /* executable */);
   1284     if (ret) {
   1285         SLOGE("Unable remount to fix permissions for %s (%s)", id, strerror(errno));
   1286         return -1;
   1287     }
   1288 
   1289     char *paths[] = { mountPoint, NULL };
   1290 
   1291     FTS *fts = fts_open(paths, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, NULL);
   1292     if (fts) {
   1293         // Traverse the entire hierarchy and chown to system UID.
   1294         for (FTSENT *ftsent = fts_read(fts); ftsent != NULL; ftsent = fts_read(fts)) {
   1295             // We don't care about the lost+found directory.
   1296             if (!strcmp(ftsent->fts_name, "lost+found")) {
   1297                 continue;
   1298             }
   1299 
   1300             /*
   1301              * There can only be one file marked as private right now.
   1302              * This should be more robust, but it satisfies the requirements
   1303              * we have for right now.
   1304              */
   1305             const bool privateFile = !strcmp(ftsent->fts_name, filename);
   1306 
   1307             int fd = open(ftsent->fts_accpath, O_NOFOLLOW | O_CLOEXEC);
   1308             if (fd < 0) {
   1309                 SLOGE("Couldn't open file %s: %s", ftsent->fts_accpath, strerror(errno));
   1310                 result = -1;
   1311                 continue;
   1312             }
   1313 
   1314             result |= fchown(fd, AID_SYSTEM, privateFile? gid : AID_SYSTEM);
   1315 
   1316             if (ftsent->fts_info & FTS_D) {
   1317                 result |= fchmod(fd, 0755);
   1318             } else if (ftsent->fts_info & FTS_F) {
   1319                 result |= fchmod(fd, privateFile ? 0640 : 0644);
   1320             }
   1321 
   1322             if (selinux_android_restorecon(ftsent->fts_path, 0) < 0) {
   1323                 SLOGE("restorecon failed for %s: %s\n", ftsent->fts_path, strerror(errno));
   1324                 result |= -1;
   1325             }
   1326 
   1327             close(fd);
   1328         }
   1329         fts_close(fts);
   1330 
   1331         // Finally make the directory readable by everyone.
   1332         int dirfd = open(mountPoint, O_DIRECTORY | O_CLOEXEC);
   1333         if (dirfd < 0 || fchmod(dirfd, 0755)) {
   1334             SLOGE("Couldn't change owner of existing directory %s: %s", mountPoint, strerror(errno));
   1335             result |= -1;
   1336         }
   1337         close(dirfd);
   1338     } else {
   1339         result |= -1;
   1340     }
   1341 
   1342     result |= android::vold::ext4::Mount(loopDevice, mountPoint,
   1343             true /* read-only */,
   1344             true /* remount */,
   1345             true /* execute */);
   1346 
   1347     if (result) {
   1348         SLOGE("ASEC fix permissions failed (%s)", strerror(errno));
   1349         return -1;
   1350     }
   1351 
   1352     if (mDebug) {
   1353         SLOGD("ASEC %s permissions fixed", id);
   1354     }
   1355     return 0;
   1356 }
   1357 
   1358 int VolumeManager::renameAsec(const char *id1, const char *id2) {
   1359     char asecFilename1[255];
   1360     char *asecFilename2;
   1361     char mountPoint[255];
   1362 
   1363     const char *dir;
   1364 
   1365     if (!isLegalAsecId(id1)) {
   1366         SLOGE("renameAsec: Invalid asec id1 \"%s\"", id1);
   1367         errno = EINVAL;
   1368         return -1;
   1369     }
   1370 
   1371     if (!isLegalAsecId(id2)) {
   1372         SLOGE("renameAsec: Invalid asec id2 \"%s\"", id2);
   1373         errno = EINVAL;
   1374         return -1;
   1375     }
   1376 
   1377     if (findAsec(id1, asecFilename1, sizeof(asecFilename1), &dir)) {
   1378         SLOGE("Couldn't find ASEC %s", id1);
   1379         return -1;
   1380     }
   1381 
   1382     asprintf(&asecFilename2, "%s/%s.asec", dir, id2);
   1383 
   1384     int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", VolumeManager::ASECDIR, id1);
   1385     if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) {
   1386         SLOGE("Rename failed: couldn't construct mountpoint");
   1387         goto out_err;
   1388     }
   1389 
   1390     if (isMountpointMounted(mountPoint)) {
   1391         SLOGW("Rename attempt when src mounted");
   1392         errno = EBUSY;
   1393         goto out_err;
   1394     }
   1395 
   1396     written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", VolumeManager::ASECDIR, id2);
   1397     if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) {
   1398         SLOGE("Rename failed: couldn't construct mountpoint2");
   1399         goto out_err;
   1400     }
   1401 
   1402     if (isMountpointMounted(mountPoint)) {
   1403         SLOGW("Rename attempt when dst mounted");
   1404         errno = EBUSY;
   1405         goto out_err;
   1406     }
   1407 
   1408     if (!access(asecFilename2, F_OK)) {
   1409         SLOGE("Rename attempt when dst exists");
   1410         errno = EADDRINUSE;
   1411         goto out_err;
   1412     }
   1413 
   1414     if (rename(asecFilename1, asecFilename2)) {
   1415         SLOGE("Rename of '%s' to '%s' failed (%s)", asecFilename1, asecFilename2, strerror(errno));
   1416         goto out_err;
   1417     }
   1418 
   1419     free(asecFilename2);
   1420     return 0;
   1421 
   1422 out_err:
   1423     free(asecFilename2);
   1424     return -1;
   1425 }
   1426 
   1427 #define UNMOUNT_RETRIES 5
   1428 #define UNMOUNT_SLEEP_BETWEEN_RETRY_MS (1000 * 1000)
   1429 int VolumeManager::unmountAsec(const char *id, bool force) {
   1430     char asecFileName[255];
   1431     char mountPoint[255];
   1432 
   1433     if (!isLegalAsecId(id)) {
   1434         SLOGE("unmountAsec: Invalid asec id \"%s\"", id);
   1435         errno = EINVAL;
   1436         return -1;
   1437     }
   1438 
   1439     if (findAsec(id, asecFileName, sizeof(asecFileName))) {
   1440         SLOGE("Couldn't find ASEC %s", id);
   1441         return -1;
   1442     }
   1443 
   1444     int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", VolumeManager::ASECDIR, id);
   1445     if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) {
   1446         SLOGE("ASEC unmount failed for %s: couldn't construct mountpoint", id);
   1447         return -1;
   1448     }
   1449 
   1450     char idHash[33];
   1451     if (!asecHash(id, idHash, sizeof(idHash))) {
   1452         SLOGE("Hash of '%s' failed (%s)", id, strerror(errno));
   1453         return -1;
   1454     }
   1455 
   1456     return unmountLoopImage(id, idHash, asecFileName, mountPoint, force);
   1457 }
   1458 
   1459 int VolumeManager::unmountObb(const char *fileName, bool force) {
   1460     char mountPoint[255];
   1461 
   1462     char idHash[33];
   1463     if (!asecHash(fileName, idHash, sizeof(idHash))) {
   1464         SLOGE("Hash of '%s' failed (%s)", fileName, strerror(errno));
   1465         return -1;
   1466     }
   1467 
   1468     int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", VolumeManager::LOOPDIR, idHash);
   1469     if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) {
   1470         SLOGE("OBB unmount failed for %s: couldn't construct mountpoint", fileName);
   1471         return -1;
   1472     }
   1473 
   1474     return unmountLoopImage(fileName, idHash, fileName, mountPoint, force);
   1475 }
   1476 
   1477 int VolumeManager::unmountLoopImage(const char *id, const char *idHash,
   1478         const char *fileName, const char *mountPoint, bool force) {
   1479     if (!isMountpointMounted(mountPoint)) {
   1480         SLOGE("Unmount request for %s when not mounted", id);
   1481         errno = ENOENT;
   1482         return -1;
   1483     }
   1484 
   1485     int i, rc;
   1486     for (i = 1; i <= UNMOUNT_RETRIES; i++) {
   1487         rc = umount(mountPoint);
   1488         if (!rc) {
   1489             break;
   1490         }
   1491         if (rc && (errno == EINVAL || errno == ENOENT)) {
   1492             SLOGI("Container %s unmounted OK", id);
   1493             rc = 0;
   1494             break;
   1495         }
   1496         SLOGW("%s unmount attempt %d failed (%s)",
   1497               id, i, strerror(errno));
   1498 
   1499         int signal = 0; // default is to just complain
   1500 
   1501         if (force) {
   1502             if (i > (UNMOUNT_RETRIES - 2))
   1503                 signal = SIGKILL;
   1504             else if (i > (UNMOUNT_RETRIES - 3))
   1505                 signal = SIGTERM;
   1506         }
   1507 
   1508         Process::killProcessesWithOpenFiles(mountPoint, signal);
   1509         usleep(UNMOUNT_SLEEP_BETWEEN_RETRY_MS);
   1510     }
   1511 
   1512     if (rc) {
   1513         errno = EBUSY;
   1514         SLOGE("Failed to unmount container %s (%s)", id, strerror(errno));
   1515         return -1;
   1516     }
   1517 
   1518     int retries = 10;
   1519 
   1520     while(retries--) {
   1521         if (!rmdir(mountPoint)) {
   1522             break;
   1523         }
   1524 
   1525         SLOGW("Failed to rmdir %s (%s)", mountPoint, strerror(errno));
   1526         usleep(UNMOUNT_SLEEP_BETWEEN_RETRY_MS);
   1527     }
   1528 
   1529     if (!retries) {
   1530         SLOGE("Timed out trying to rmdir %s (%s)", mountPoint, strerror(errno));
   1531     }
   1532 
   1533     for (i=1; i <= UNMOUNT_RETRIES; i++) {
   1534         if (Devmapper::destroy(idHash) && errno != ENXIO) {
   1535             SLOGE("Failed to destroy devmapper instance (%s)", strerror(errno));
   1536             usleep(UNMOUNT_SLEEP_BETWEEN_RETRY_MS);
   1537             continue;
   1538         } else {
   1539           break;
   1540         }
   1541     }
   1542 
   1543     char loopDevice[255];
   1544     if (!Loop::lookupActive(idHash, loopDevice, sizeof(loopDevice))) {
   1545         Loop::destroyByDevice(loopDevice);
   1546     } else {
   1547         SLOGW("Failed to find loop device for {%s} (%s)", fileName, strerror(errno));
   1548     }
   1549 
   1550     AsecIdCollection::iterator it;
   1551     for (it = mActiveContainers->begin(); it != mActiveContainers->end(); ++it) {
   1552         ContainerData* cd = *it;
   1553         if (!strcmp(cd->id, id)) {
   1554             free(*it);
   1555             mActiveContainers->erase(it);
   1556             break;
   1557         }
   1558     }
   1559     if (it == mActiveContainers->end()) {
   1560         SLOGW("mActiveContainers is inconsistent!");
   1561     }
   1562     return 0;
   1563 }
   1564 
   1565 int VolumeManager::destroyAsec(const char *id, bool force) {
   1566     char asecFileName[255];
   1567     char mountPoint[255];
   1568 
   1569     if (!isLegalAsecId(id)) {
   1570         SLOGE("destroyAsec: Invalid asec id \"%s\"", id);
   1571         errno = EINVAL;
   1572         return -1;
   1573     }
   1574 
   1575     if (findAsec(id, asecFileName, sizeof(asecFileName))) {
   1576         SLOGE("Couldn't find ASEC %s", id);
   1577         return -1;
   1578     }
   1579 
   1580     int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", VolumeManager::ASECDIR, id);
   1581     if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) {
   1582         SLOGE("ASEC destroy failed for %s: couldn't construct mountpoint", id);
   1583         return -1;
   1584     }
   1585 
   1586     if (isMountpointMounted(mountPoint)) {
   1587         if (mDebug) {
   1588             SLOGD("Unmounting container before destroy");
   1589         }
   1590         if (unmountAsec(id, force)) {
   1591             SLOGE("Failed to unmount asec %s for destroy (%s)", id, strerror(errno));
   1592             return -1;
   1593         }
   1594     }
   1595 
   1596     if (unlink(asecFileName)) {
   1597         SLOGE("Failed to unlink asec '%s' (%s)", asecFileName, strerror(errno));
   1598         return -1;
   1599     }
   1600 
   1601     if (mDebug) {
   1602         SLOGD("ASEC %s destroyed", id);
   1603     }
   1604     return 0;
   1605 }
   1606 
   1607 /*
   1608  * Legal ASEC ids consist of alphanumeric characters, '-',
   1609  * '_', or '.'. ".." is not allowed. The first or last character
   1610  * of the ASEC id cannot be '.' (dot).
   1611  */
   1612 bool VolumeManager::isLegalAsecId(const char *id) const {
   1613     size_t i;
   1614     size_t len = strlen(id);
   1615 
   1616     if (len == 0) {
   1617         return false;
   1618     }
   1619     if ((id[0] == '.') || (id[len - 1] == '.')) {
   1620         return false;
   1621     }
   1622 
   1623     for (i = 0; i < len; i++) {
   1624         if (id[i] == '.') {
   1625             // i=0 is guaranteed never to have a dot. See above.
   1626             if (id[i-1] == '.') return false;
   1627             continue;
   1628         }
   1629         if (id[i] == '_' || id[i] == '-') continue;
   1630         if (id[i] >= 'a' && id[i] <= 'z') continue;
   1631         if (id[i] >= 'A' && id[i] <= 'Z') continue;
   1632         if (id[i] >= '0' && id[i] <= '9') continue;
   1633         return false;
   1634     }
   1635 
   1636     return true;
   1637 }
   1638 
   1639 bool VolumeManager::isAsecInDirectory(const char *dir, const char *asecName) const {
   1640     int dirfd = open(dir, O_DIRECTORY | O_CLOEXEC);
   1641     if (dirfd < 0) {
   1642         SLOGE("Couldn't open internal ASEC dir (%s)", strerror(errno));
   1643         return false;
   1644     }
   1645 
   1646     struct stat sb;
   1647     bool ret = (fstatat(dirfd, asecName, &sb, AT_SYMLINK_NOFOLLOW) == 0)
   1648         && S_ISREG(sb.st_mode);
   1649 
   1650     close(dirfd);
   1651 
   1652     return ret;
   1653 }
   1654 
   1655 int VolumeManager::findAsec(const char *id, char *asecPath, size_t asecPathLen,
   1656         const char **directory) const {
   1657     char *asecName;
   1658 
   1659     if (!isLegalAsecId(id)) {
   1660         SLOGE("findAsec: Invalid asec id \"%s\"", id);
   1661         errno = EINVAL;
   1662         return -1;
   1663     }
   1664 
   1665     if (asprintf(&asecName, "%s.asec", id) < 0) {
   1666         SLOGE("Couldn't allocate string to write ASEC name");
   1667         return -1;
   1668     }
   1669 
   1670     const char *dir;
   1671     if (isAsecInDirectory(VolumeManager::SEC_ASECDIR_INT, asecName)) {
   1672         dir = VolumeManager::SEC_ASECDIR_INT;
   1673     } else if (isAsecInDirectory(VolumeManager::SEC_ASECDIR_EXT, asecName)) {
   1674         dir = VolumeManager::SEC_ASECDIR_EXT;
   1675     } else {
   1676         free(asecName);
   1677         return -1;
   1678     }
   1679 
   1680     if (directory != NULL) {
   1681         *directory = dir;
   1682     }
   1683 
   1684     if (asecPath != NULL) {
   1685         int written = snprintf(asecPath, asecPathLen, "%s/%s", dir, asecName);
   1686         if ((written < 0) || (size_t(written) >= asecPathLen)) {
   1687             SLOGE("findAsec failed for %s: couldn't construct ASEC path", id);
   1688             free(asecName);
   1689             return -1;
   1690         }
   1691     }
   1692 
   1693     free(asecName);
   1694     return 0;
   1695 }
   1696 
   1697 int VolumeManager::mountAsec(const char *id, const char *key, int ownerUid, bool readOnly) {
   1698     char asecFileName[255];
   1699     char mountPoint[255];
   1700 
   1701     if (!isLegalAsecId(id)) {
   1702         SLOGE("mountAsec: Invalid asec id \"%s\"", id);
   1703         errno = EINVAL;
   1704         return -1;
   1705     }
   1706 
   1707     if (findAsec(id, asecFileName, sizeof(asecFileName))) {
   1708         SLOGE("Couldn't find ASEC %s", id);
   1709         return -1;
   1710     }
   1711 
   1712     int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", VolumeManager::ASECDIR, id);
   1713     if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) {
   1714         SLOGE("ASEC mount failed for %s: couldn't construct mountpoint", id);
   1715         return -1;
   1716     }
   1717 
   1718     if (isMountpointMounted(mountPoint)) {
   1719         SLOGE("ASEC %s already mounted", id);
   1720         errno = EBUSY;
   1721         return -1;
   1722     }
   1723 
   1724     char idHash[33];
   1725     if (!asecHash(id, idHash, sizeof(idHash))) {
   1726         SLOGE("Hash of '%s' failed (%s)", id, strerror(errno));
   1727         return -1;
   1728     }
   1729 
   1730     char loopDevice[255];
   1731     if (setupLoopDevice(loopDevice, sizeof(loopDevice), asecFileName, idHash, mDebug))
   1732         return -1;
   1733 
   1734     char dmDevice[255];
   1735     bool cleanupDm = false;
   1736 
   1737     unsigned long nr_sec = 0;
   1738     struct asec_superblock sb;
   1739 
   1740     if (Loop::lookupInfo(loopDevice, &sb, &nr_sec)) {
   1741         return -1;
   1742     }
   1743 
   1744     if (mDebug) {
   1745         SLOGD("Container sb magic/ver (%.8x/%.2x)", sb.magic, sb.ver);
   1746     }
   1747     if (sb.magic != ASEC_SB_MAGIC || sb.ver != ASEC_SB_VER) {
   1748         SLOGE("Bad container magic/version (%.8x/%.2x)", sb.magic, sb.ver);
   1749         Loop::destroyByDevice(loopDevice);
   1750         errno = EMEDIUMTYPE;
   1751         return -1;
   1752     }
   1753     nr_sec--; // We don't want the devmapping to extend onto our superblock
   1754 
   1755     if (setupDevMapperDevice(dmDevice, sizeof(dmDevice), loopDevice, asecFileName, key, idHash , nr_sec, &cleanupDm, mDebug)) {
   1756         Loop::destroyByDevice(loopDevice);
   1757         return -1;
   1758     }
   1759 
   1760     if (mkdir(mountPoint, 0000)) {
   1761         if (errno != EEXIST) {
   1762             SLOGE("Mountpoint creation failed (%s)", strerror(errno));
   1763             if (cleanupDm) {
   1764                 Devmapper::destroy(idHash);
   1765             }
   1766             Loop::destroyByDevice(loopDevice);
   1767             return -1;
   1768         }
   1769     }
   1770 
   1771     /*
   1772      * Wait for the device mapper node to be created.
   1773      */
   1774     waitForDevMapper(dmDevice);
   1775 
   1776     int result;
   1777     if (sb.c_opts & ASEC_SB_C_OPTS_EXT4) {
   1778         result = android::vold::ext4::Mount(dmDevice, mountPoint,
   1779                 readOnly, false, readOnly);
   1780     } else {
   1781         result = android::vold::vfat::Mount(dmDevice, mountPoint,
   1782                 readOnly, false, readOnly, ownerUid, 0, 0222, false);
   1783     }
   1784 
   1785     if (result) {
   1786         SLOGE("ASEC mount failed (%s)", strerror(errno));
   1787         if (cleanupDm) {
   1788             Devmapper::destroy(idHash);
   1789         }
   1790         Loop::destroyByDevice(loopDevice);
   1791         return -1;
   1792     }
   1793 
   1794     mActiveContainers->push_back(new ContainerData(strdup(id), ASEC));
   1795     if (mDebug) {
   1796         SLOGD("ASEC %s mounted", id);
   1797     }
   1798     return 0;
   1799 }
   1800 
   1801 /**
   1802  * Mounts an image file <code>img</code>.
   1803  */
   1804 int VolumeManager::mountObb(const char *img, const char *key, int ownerGid) {
   1805     char mountPoint[255];
   1806 
   1807     char idHash[33];
   1808     if (!asecHash(img, idHash, sizeof(idHash))) {
   1809         SLOGE("Hash of '%s' failed (%s)", img, strerror(errno));
   1810         return -1;
   1811     }
   1812 
   1813     int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", VolumeManager::LOOPDIR, idHash);
   1814     if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) {
   1815         SLOGE("OBB mount failed for %s: couldn't construct mountpoint", img);
   1816         return -1;
   1817     }
   1818 
   1819     if (isMountpointMounted(mountPoint)) {
   1820         SLOGE("Image %s already mounted", img);
   1821         errno = EBUSY;
   1822         return -1;
   1823     }
   1824 
   1825     char loopDevice[255];
   1826     if (setupLoopDevice(loopDevice, sizeof(loopDevice), img, idHash, mDebug))
   1827         return -1;
   1828 
   1829     char dmDevice[255];
   1830     bool cleanupDm = false;
   1831     int fd;
   1832     unsigned long nr_sec = 0;
   1833 
   1834     if ((fd = open(loopDevice, O_RDWR | O_CLOEXEC)) < 0) {
   1835         SLOGE("Failed to open loopdevice (%s)", strerror(errno));
   1836         Loop::destroyByDevice(loopDevice);
   1837         return -1;
   1838     }
   1839 
   1840     get_blkdev_size(fd, &nr_sec);
   1841     if (nr_sec == 0) {
   1842         SLOGE("Failed to get loop size (%s)", strerror(errno));
   1843         Loop::destroyByDevice(loopDevice);
   1844         close(fd);
   1845         return -1;
   1846     }
   1847 
   1848     close(fd);
   1849 
   1850     if (setupDevMapperDevice(dmDevice, sizeof(loopDevice), loopDevice, img,key, idHash, nr_sec, &cleanupDm, mDebug)) {
   1851         Loop::destroyByDevice(loopDevice);
   1852         return -1;
   1853     }
   1854 
   1855     if (mkdir(mountPoint, 0755)) {
   1856         if (errno != EEXIST) {
   1857             SLOGE("Mountpoint creation failed (%s)", strerror(errno));
   1858             if (cleanupDm) {
   1859                 Devmapper::destroy(idHash);
   1860             }
   1861             Loop::destroyByDevice(loopDevice);
   1862             return -1;
   1863         }
   1864     }
   1865 
   1866     /*
   1867      * Wait for the device mapper node to be created.
   1868      */
   1869     waitForDevMapper(dmDevice);
   1870 
   1871     if (android::vold::vfat::Mount(dmDevice, mountPoint,
   1872             true, false, true, 0, ownerGid, 0227, false)) {
   1873         SLOGE("Image mount failed (%s)", strerror(errno));
   1874         if (cleanupDm) {
   1875             Devmapper::destroy(idHash);
   1876         }
   1877         Loop::destroyByDevice(loopDevice);
   1878         return -1;
   1879     }
   1880 
   1881     mActiveContainers->push_back(new ContainerData(strdup(img), OBB));
   1882     if (mDebug) {
   1883         SLOGD("Image %s mounted", img);
   1884     }
   1885     return 0;
   1886 }
   1887 
   1888 int VolumeManager::listMountedObbs(SocketClient* cli) {
   1889     FILE *fp = setmntent("/proc/mounts", "r");
   1890     if (fp == NULL) {
   1891         SLOGE("Error opening /proc/mounts (%s)", strerror(errno));
   1892         return -1;
   1893     }
   1894 
   1895     // Create a string to compare against that has a trailing slash
   1896     int loopDirLen = strlen(VolumeManager::LOOPDIR);
   1897     char loopDir[loopDirLen + 2];
   1898     strcpy(loopDir, VolumeManager::LOOPDIR);
   1899     loopDir[loopDirLen++] = '/';
   1900     loopDir[loopDirLen] = '\0';
   1901 
   1902     mntent* mentry;
   1903     while ((mentry = getmntent(fp)) != NULL) {
   1904         if (!strncmp(mentry->mnt_dir, loopDir, loopDirLen)) {
   1905             int fd = open(mentry->mnt_fsname, O_RDONLY | O_CLOEXEC);
   1906             if (fd >= 0) {
   1907                 struct loop_info64 li;
   1908                 if (ioctl(fd, LOOP_GET_STATUS64, &li) >= 0) {
   1909                     cli->sendMsg(ResponseCode::AsecListResult,
   1910                             (const char*) li.lo_file_name, false);
   1911                 }
   1912                 close(fd);
   1913             }
   1914         }
   1915     }
   1916     endmntent(fp);
   1917     return 0;
   1918 }
   1919 
   1920 extern "C" int vold_unmountAll(void) {
   1921     VolumeManager *vm = VolumeManager::Instance();
   1922     return vm->unmountAll();
   1923 }
   1924 
   1925 bool VolumeManager::isMountpointMounted(const char *mp)
   1926 {
   1927     FILE *fp = setmntent("/proc/mounts", "r");
   1928     if (fp == NULL) {
   1929         SLOGE("Error opening /proc/mounts (%s)", strerror(errno));
   1930         return false;
   1931     }
   1932 
   1933     bool found_mp = false;
   1934     mntent* mentry;
   1935     while ((mentry = getmntent(fp)) != NULL) {
   1936         if (strcmp(mentry->mnt_dir, mp) == 0) {
   1937             found_mp = true;
   1938             break;
   1939         }
   1940     }
   1941     endmntent(fp);
   1942     return found_mp;
   1943 }
   1944 
   1945 int VolumeManager::mkdirs(char* path) {
   1946     // Only offer to create directories for paths managed by vold
   1947     if (strncmp(path, "/storage/", 9) == 0) {
   1948         // fs_mkdirs() does symlink checking and relative path enforcement
   1949         return fs_mkdirs(path, 0700);
   1950     } else {
   1951         SLOGE("Failed to find mounted volume for %s", path);
   1952         return -EINVAL;
   1953     }
   1954 }
   1955