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