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