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 <sys/stat.h>
     23 #include <sys/types.h>
     24 #include <sys/mount.h>
     25 
     26 #include <linux/kdev_t.h>
     27 
     28 #define LOG_TAG "Vold"
     29 
     30 #include <openssl/md5.h>
     31 
     32 #include <cutils/log.h>
     33 
     34 #include <sysutils/NetlinkEvent.h>
     35 
     36 #include "VolumeManager.h"
     37 #include "DirectVolume.h"
     38 #include "ResponseCode.h"
     39 #include "Loop.h"
     40 #include "Fat.h"
     41 #include "Devmapper.h"
     42 #include "Process.h"
     43 #include "Asec.h"
     44 #include "cryptfs.h"
     45 
     46 #define MASS_STORAGE_FILE_PATH  "/sys/class/android_usb/android0/f_mass_storage/lun/file"
     47 
     48 VolumeManager *VolumeManager::sInstance = NULL;
     49 
     50 VolumeManager *VolumeManager::Instance() {
     51     if (!sInstance)
     52         sInstance = new VolumeManager();
     53     return sInstance;
     54 }
     55 
     56 VolumeManager::VolumeManager() {
     57     mDebug = false;
     58     mVolumes = new VolumeCollection();
     59     mActiveContainers = new AsecIdCollection();
     60     mBroadcaster = NULL;
     61     mUmsSharingCount = 0;
     62     mSavedDirtyRatio = -1;
     63     // set dirty ratio to 0 when UMS is active
     64     mUmsDirtyRatio = 0;
     65     mVolManagerDisabled = 0;
     66 }
     67 
     68 VolumeManager::~VolumeManager() {
     69     delete mVolumes;
     70     delete mActiveContainers;
     71 }
     72 
     73 char *VolumeManager::asecHash(const char *id, char *buffer, size_t len) {
     74     static const char* digits = "0123456789abcdef";
     75 
     76     unsigned char sig[MD5_DIGEST_LENGTH];
     77 
     78     if (buffer == NULL) {
     79         SLOGE("Destination buffer is NULL");
     80         errno = ESPIPE;
     81         return NULL;
     82     } else if (id == NULL) {
     83         SLOGE("Source buffer is NULL");
     84         errno = ESPIPE;
     85         return NULL;
     86     } else if (len < MD5_ASCII_LENGTH_PLUS_NULL) {
     87         SLOGE("Target hash buffer size < %d bytes (%d)",
     88                 MD5_ASCII_LENGTH_PLUS_NULL, len);
     89         errno = ESPIPE;
     90         return NULL;
     91     }
     92 
     93     MD5(reinterpret_cast<const unsigned char*>(id), strlen(id), sig);
     94 
     95     char *p = buffer;
     96     for (int i = 0; i < MD5_DIGEST_LENGTH; i++) {
     97         *p++ = digits[sig[i] >> 4];
     98         *p++ = digits[sig[i] & 0x0F];
     99     }
    100     *p = '\0';
    101 
    102     return buffer;
    103 }
    104 
    105 void VolumeManager::setDebug(bool enable) {
    106     mDebug = enable;
    107     VolumeCollection::iterator it;
    108     for (it = mVolumes->begin(); it != mVolumes->end(); ++it) {
    109         (*it)->setDebug(enable);
    110     }
    111 }
    112 
    113 int VolumeManager::start() {
    114     return 0;
    115 }
    116 
    117 int VolumeManager::stop() {
    118     return 0;
    119 }
    120 
    121 int VolumeManager::addVolume(Volume *v) {
    122     mVolumes->push_back(v);
    123     return 0;
    124 }
    125 
    126 void VolumeManager::handleBlockEvent(NetlinkEvent *evt) {
    127     const char *devpath = evt->findParam("DEVPATH");
    128 
    129     /* Lookup a volume to handle this device */
    130     VolumeCollection::iterator it;
    131     bool hit = false;
    132     for (it = mVolumes->begin(); it != mVolumes->end(); ++it) {
    133         if (!(*it)->handleBlockEvent(evt)) {
    134 #ifdef NETLINK_DEBUG
    135             SLOGD("Device '%s' event handled by volume %s\n", devpath, (*it)->getLabel());
    136 #endif
    137             hit = true;
    138             break;
    139         }
    140     }
    141 
    142     if (!hit) {
    143 #ifdef NETLINK_DEBUG
    144         SLOGW("No volumes handled block event for '%s'", devpath);
    145 #endif
    146     }
    147 }
    148 
    149 int VolumeManager::listVolumes(SocketClient *cli) {
    150     VolumeCollection::iterator i;
    151 
    152     for (i = mVolumes->begin(); i != mVolumes->end(); ++i) {
    153         char *buffer;
    154         asprintf(&buffer, "%s %s %d",
    155                  (*i)->getLabel(), (*i)->getMountpoint(),
    156                  (*i)->getState());
    157         cli->sendMsg(ResponseCode::VolumeListResult, buffer, false);
    158         free(buffer);
    159     }
    160     cli->sendMsg(ResponseCode::CommandOkay, "Volumes listed.", false);
    161     return 0;
    162 }
    163 
    164 int VolumeManager::formatVolume(const char *label) {
    165     Volume *v = lookupVolume(label);
    166 
    167     if (!v) {
    168         errno = ENOENT;
    169         return -1;
    170     }
    171 
    172     if (mVolManagerDisabled) {
    173         errno = EBUSY;
    174         return -1;
    175     }
    176 
    177     return v->formatVol();
    178 }
    179 
    180 int VolumeManager::getObbMountPath(const char *sourceFile, char *mountPath, int mountPathLen) {
    181     char idHash[33];
    182     if (!asecHash(sourceFile, idHash, sizeof(idHash))) {
    183         SLOGE("Hash of '%s' failed (%s)", sourceFile, strerror(errno));
    184         return -1;
    185     }
    186 
    187     memset(mountPath, 0, mountPathLen);
    188     snprintf(mountPath, mountPathLen, "%s/%s", Volume::LOOPDIR, idHash);
    189 
    190     if (access(mountPath, F_OK)) {
    191         errno = ENOENT;
    192         return -1;
    193     }
    194 
    195     return 0;
    196 }
    197 
    198 int VolumeManager::getAsecMountPath(const char *id, char *buffer, int maxlen) {
    199     char asecFileName[255];
    200     snprintf(asecFileName, sizeof(asecFileName), "%s/%s.asec", Volume::SEC_ASECDIR, id);
    201 
    202     memset(buffer, 0, maxlen);
    203     if (access(asecFileName, F_OK)) {
    204         errno = ENOENT;
    205         return -1;
    206     }
    207 
    208     snprintf(buffer, maxlen, "%s/%s", Volume::ASECDIR, id);
    209     return 0;
    210 }
    211 
    212 int VolumeManager::getAsecFilesystemPath(const char *id, char *buffer, int maxlen) {
    213     char asecFileName[255];
    214     snprintf(asecFileName, sizeof(asecFileName), "%s/%s.asec", Volume::SEC_ASECDIR, id);
    215 
    216     memset(buffer, 0, maxlen);
    217     if (access(asecFileName, F_OK)) {
    218         errno = ENOENT;
    219         return -1;
    220     }
    221 
    222     snprintf(buffer, maxlen, "%s", asecFileName);
    223     return 0;
    224 }
    225 
    226 int VolumeManager::createAsec(const char *id, unsigned int numSectors,
    227                               const char *fstype, const char *key, int ownerUid) {
    228     struct asec_superblock sb;
    229     memset(&sb, 0, sizeof(sb));
    230 
    231     sb.magic = ASEC_SB_MAGIC;
    232     sb.ver = ASEC_SB_VER;
    233 
    234     if (numSectors < ((1024*1024)/512)) {
    235         SLOGE("Invalid container size specified (%d sectors)", numSectors);
    236         errno = EINVAL;
    237         return -1;
    238     }
    239 
    240     if (lookupVolume(id)) {
    241         SLOGE("ASEC id '%s' currently exists", id);
    242         errno = EADDRINUSE;
    243         return -1;
    244     }
    245 
    246     char asecFileName[255];
    247     snprintf(asecFileName, sizeof(asecFileName), "%s/%s.asec", Volume::SEC_ASECDIR, id);
    248 
    249     if (!access(asecFileName, F_OK)) {
    250         SLOGE("ASEC file '%s' currently exists - destroy it first! (%s)",
    251              asecFileName, strerror(errno));
    252         errno = EADDRINUSE;
    253         return -1;
    254     }
    255 
    256     /*
    257      * Add some headroom
    258      */
    259     unsigned fatSize = (((numSectors * 4) / 512) + 1) * 2;
    260     unsigned numImgSectors = numSectors + fatSize + 2;
    261 
    262     if (numImgSectors % 63) {
    263         numImgSectors += (63 - (numImgSectors % 63));
    264     }
    265 
    266     // Add +1 for our superblock which is at the end
    267     if (Loop::createImageFile(asecFileName, numImgSectors + 1)) {
    268         SLOGE("ASEC image file creation failed (%s)", strerror(errno));
    269         return -1;
    270     }
    271 
    272     char idHash[33];
    273     if (!asecHash(id, idHash, sizeof(idHash))) {
    274         SLOGE("Hash of '%s' failed (%s)", id, strerror(errno));
    275         unlink(asecFileName);
    276         return -1;
    277     }
    278 
    279     char loopDevice[255];
    280     if (Loop::create(idHash, asecFileName, loopDevice, sizeof(loopDevice))) {
    281         SLOGE("ASEC loop device creation failed (%s)", strerror(errno));
    282         unlink(asecFileName);
    283         return -1;
    284     }
    285 
    286     char dmDevice[255];
    287     bool cleanupDm = false;
    288 
    289     if (strcmp(key, "none")) {
    290         // XXX: This is all we support for now
    291         sb.c_cipher = ASEC_SB_C_CIPHER_TWOFISH;
    292         if (Devmapper::create(idHash, loopDevice, key, numImgSectors, dmDevice,
    293                              sizeof(dmDevice))) {
    294             SLOGE("ASEC device mapping failed (%s)", strerror(errno));
    295             Loop::destroyByDevice(loopDevice);
    296             unlink(asecFileName);
    297             return -1;
    298         }
    299         cleanupDm = true;
    300     } else {
    301         sb.c_cipher = ASEC_SB_C_CIPHER_NONE;
    302         strcpy(dmDevice, loopDevice);
    303     }
    304 
    305     /*
    306      * Drop down the superblock at the end of the file
    307      */
    308 
    309     int sbfd = open(loopDevice, O_RDWR);
    310     if (sbfd < 0) {
    311         SLOGE("Failed to open new DM device for superblock write (%s)", strerror(errno));
    312         if (cleanupDm) {
    313             Devmapper::destroy(idHash);
    314         }
    315         Loop::destroyByDevice(loopDevice);
    316         unlink(asecFileName);
    317         return -1;
    318     }
    319 
    320     if (lseek(sbfd, (numImgSectors * 512), SEEK_SET) < 0) {
    321         close(sbfd);
    322         SLOGE("Failed to lseek for superblock (%s)", strerror(errno));
    323         if (cleanupDm) {
    324             Devmapper::destroy(idHash);
    325         }
    326         Loop::destroyByDevice(loopDevice);
    327         unlink(asecFileName);
    328         return -1;
    329     }
    330 
    331     if (write(sbfd, &sb, sizeof(sb)) != sizeof(sb)) {
    332         close(sbfd);
    333         SLOGE("Failed to write superblock (%s)", strerror(errno));
    334         if (cleanupDm) {
    335             Devmapper::destroy(idHash);
    336         }
    337         Loop::destroyByDevice(loopDevice);
    338         unlink(asecFileName);
    339         return -1;
    340     }
    341     close(sbfd);
    342 
    343     if (strcmp(fstype, "none")) {
    344         if (strcmp(fstype, "fat")) {
    345             SLOGW("Unknown fstype '%s' specified for container", fstype);
    346         }
    347 
    348         if (Fat::format(dmDevice, numImgSectors)) {
    349             SLOGE("ASEC FAT format failed (%s)", strerror(errno));
    350             if (cleanupDm) {
    351                 Devmapper::destroy(idHash);
    352             }
    353             Loop::destroyByDevice(loopDevice);
    354             unlink(asecFileName);
    355             return -1;
    356         }
    357         char mountPoint[255];
    358 
    359         snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id);
    360         if (mkdir(mountPoint, 0777)) {
    361             if (errno != EEXIST) {
    362                 SLOGE("Mountpoint creation failed (%s)", strerror(errno));
    363                 if (cleanupDm) {
    364                     Devmapper::destroy(idHash);
    365                 }
    366                 Loop::destroyByDevice(loopDevice);
    367                 unlink(asecFileName);
    368                 return -1;
    369             }
    370         }
    371 
    372         if (Fat::doMount(dmDevice, mountPoint, false, false, false, ownerUid,
    373                          0, 0000, false)) {
    374             SLOGE("ASEC FAT mount failed (%s)", strerror(errno));
    375             if (cleanupDm) {
    376                 Devmapper::destroy(idHash);
    377             }
    378             Loop::destroyByDevice(loopDevice);
    379             unlink(asecFileName);
    380             return -1;
    381         }
    382     } else {
    383         SLOGI("Created raw secure container %s (no filesystem)", id);
    384     }
    385 
    386     mActiveContainers->push_back(new ContainerData(strdup(id), ASEC));
    387     return 0;
    388 }
    389 
    390 int VolumeManager::finalizeAsec(const char *id) {
    391     char asecFileName[255];
    392     char loopDevice[255];
    393     char mountPoint[255];
    394 
    395     snprintf(asecFileName, sizeof(asecFileName), "%s/%s.asec", Volume::SEC_ASECDIR, id);
    396 
    397     char idHash[33];
    398     if (!asecHash(id, idHash, sizeof(idHash))) {
    399         SLOGE("Hash of '%s' failed (%s)", id, strerror(errno));
    400         return -1;
    401     }
    402 
    403     if (Loop::lookupActive(idHash, loopDevice, sizeof(loopDevice))) {
    404         SLOGE("Unable to finalize %s (%s)", id, strerror(errno));
    405         return -1;
    406     }
    407 
    408     snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id);
    409     // XXX:
    410     if (Fat::doMount(loopDevice, mountPoint, true, true, true, 0, 0, 0227, false)) {
    411         SLOGE("ASEC finalize mount failed (%s)", strerror(errno));
    412         return -1;
    413     }
    414 
    415     if (mDebug) {
    416         SLOGD("ASEC %s finalized", id);
    417     }
    418     return 0;
    419 }
    420 
    421 int VolumeManager::renameAsec(const char *id1, const char *id2) {
    422     char *asecFilename1;
    423     char *asecFilename2;
    424     char mountPoint[255];
    425 
    426     asprintf(&asecFilename1, "%s/%s.asec", Volume::SEC_ASECDIR, id1);
    427     asprintf(&asecFilename2, "%s/%s.asec", Volume::SEC_ASECDIR, id2);
    428 
    429     snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id1);
    430     if (isMountpointMounted(mountPoint)) {
    431         SLOGW("Rename attempt when src mounted");
    432         errno = EBUSY;
    433         goto out_err;
    434     }
    435 
    436     snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id2);
    437     if (isMountpointMounted(mountPoint)) {
    438         SLOGW("Rename attempt when dst mounted");
    439         errno = EBUSY;
    440         goto out_err;
    441     }
    442 
    443     if (!access(asecFilename2, F_OK)) {
    444         SLOGE("Rename attempt when dst exists");
    445         errno = EADDRINUSE;
    446         goto out_err;
    447     }
    448 
    449     if (rename(asecFilename1, asecFilename2)) {
    450         SLOGE("Rename of '%s' to '%s' failed (%s)", asecFilename1, asecFilename2, strerror(errno));
    451         goto out_err;
    452     }
    453 
    454     free(asecFilename1);
    455     free(asecFilename2);
    456     return 0;
    457 
    458 out_err:
    459     free(asecFilename1);
    460     free(asecFilename2);
    461     return -1;
    462 }
    463 
    464 #define UNMOUNT_RETRIES 5
    465 #define UNMOUNT_SLEEP_BETWEEN_RETRY_MS (1000 * 1000)
    466 int VolumeManager::unmountAsec(const char *id, bool force) {
    467     char asecFileName[255];
    468     char mountPoint[255];
    469 
    470     snprintf(asecFileName, sizeof(asecFileName), "%s/%s.asec", Volume::SEC_ASECDIR, id);
    471     snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id);
    472 
    473     char idHash[33];
    474     if (!asecHash(id, idHash, sizeof(idHash))) {
    475         SLOGE("Hash of '%s' failed (%s)", id, strerror(errno));
    476         return -1;
    477     }
    478 
    479     return unmountLoopImage(id, idHash, asecFileName, mountPoint, force);
    480 }
    481 
    482 int VolumeManager::unmountObb(const char *fileName, bool force) {
    483     char mountPoint[255];
    484 
    485     char idHash[33];
    486     if (!asecHash(fileName, idHash, sizeof(idHash))) {
    487         SLOGE("Hash of '%s' failed (%s)", fileName, strerror(errno));
    488         return -1;
    489     }
    490 
    491     snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::LOOPDIR, idHash);
    492 
    493     return unmountLoopImage(fileName, idHash, fileName, mountPoint, force);
    494 }
    495 
    496 int VolumeManager::unmountLoopImage(const char *id, const char *idHash,
    497         const char *fileName, const char *mountPoint, bool force) {
    498     if (!isMountpointMounted(mountPoint)) {
    499         SLOGE("Unmount request for %s when not mounted", id);
    500         errno = ENOENT;
    501         return -1;
    502     }
    503 
    504     int i, rc;
    505     for (i = 1; i <= UNMOUNT_RETRIES; i++) {
    506         rc = umount(mountPoint);
    507         if (!rc) {
    508             break;
    509         }
    510         if (rc && (errno == EINVAL || errno == ENOENT)) {
    511             SLOGI("Container %s unmounted OK", id);
    512             rc = 0;
    513             break;
    514         }
    515         SLOGW("%s unmount attempt %d failed (%s)",
    516               id, i, strerror(errno));
    517 
    518         int action = 0; // default is to just complain
    519 
    520         if (force) {
    521             if (i > (UNMOUNT_RETRIES - 2))
    522                 action = 2; // SIGKILL
    523             else if (i > (UNMOUNT_RETRIES - 3))
    524                 action = 1; // SIGHUP
    525         }
    526 
    527         Process::killProcessesWithOpenFiles(mountPoint, action);
    528         usleep(UNMOUNT_SLEEP_BETWEEN_RETRY_MS);
    529     }
    530 
    531     if (rc) {
    532         errno = EBUSY;
    533         SLOGE("Failed to unmount container %s (%s)", id, strerror(errno));
    534         return -1;
    535     }
    536 
    537     int retries = 10;
    538 
    539     while(retries--) {
    540         if (!rmdir(mountPoint)) {
    541             break;
    542         }
    543 
    544         SLOGW("Failed to rmdir %s (%s)", mountPoint, strerror(errno));
    545         usleep(UNMOUNT_SLEEP_BETWEEN_RETRY_MS);
    546     }
    547 
    548     if (!retries) {
    549         SLOGE("Timed out trying to rmdir %s (%s)", mountPoint, strerror(errno));
    550     }
    551 
    552     if (Devmapper::destroy(idHash) && errno != ENXIO) {
    553         SLOGE("Failed to destroy devmapper instance (%s)", strerror(errno));
    554     }
    555 
    556     char loopDevice[255];
    557     if (!Loop::lookupActive(idHash, loopDevice, sizeof(loopDevice))) {
    558         Loop::destroyByDevice(loopDevice);
    559     } else {
    560         SLOGW("Failed to find loop device for {%s} (%s)", fileName, strerror(errno));
    561     }
    562 
    563     AsecIdCollection::iterator it;
    564     for (it = mActiveContainers->begin(); it != mActiveContainers->end(); ++it) {
    565         ContainerData* cd = *it;
    566         if (!strcmp(cd->id, id)) {
    567             free(*it);
    568             mActiveContainers->erase(it);
    569             break;
    570         }
    571     }
    572     if (it == mActiveContainers->end()) {
    573         SLOGW("mActiveContainers is inconsistent!");
    574     }
    575     return 0;
    576 }
    577 
    578 int VolumeManager::destroyAsec(const char *id, bool force) {
    579     char asecFileName[255];
    580     char mountPoint[255];
    581 
    582     snprintf(asecFileName, sizeof(asecFileName), "%s/%s.asec", Volume::SEC_ASECDIR, id);
    583     snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id);
    584 
    585     if (isMountpointMounted(mountPoint)) {
    586         if (mDebug) {
    587             SLOGD("Unmounting container before destroy");
    588         }
    589         if (unmountAsec(id, force)) {
    590             SLOGE("Failed to unmount asec %s for destroy (%s)", id, strerror(errno));
    591             return -1;
    592         }
    593     }
    594 
    595     if (unlink(asecFileName)) {
    596         SLOGE("Failed to unlink asec '%s' (%s)", asecFileName, strerror(errno));
    597         return -1;
    598     }
    599 
    600     if (mDebug) {
    601         SLOGD("ASEC %s destroyed", id);
    602     }
    603     return 0;
    604 }
    605 
    606 int VolumeManager::mountAsec(const char *id, const char *key, int ownerUid) {
    607     char asecFileName[255];
    608     char mountPoint[255];
    609 
    610     snprintf(asecFileName, sizeof(asecFileName), "%s/%s.asec", Volume::SEC_ASECDIR, id);
    611     snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id);
    612 
    613     if (isMountpointMounted(mountPoint)) {
    614         SLOGE("ASEC %s already mounted", id);
    615         errno = EBUSY;
    616         return -1;
    617     }
    618 
    619     char idHash[33];
    620     if (!asecHash(id, idHash, sizeof(idHash))) {
    621         SLOGE("Hash of '%s' failed (%s)", id, strerror(errno));
    622         return -1;
    623     }
    624 
    625     char loopDevice[255];
    626     if (Loop::lookupActive(idHash, loopDevice, sizeof(loopDevice))) {
    627         if (Loop::create(idHash, asecFileName, loopDevice, sizeof(loopDevice))) {
    628             SLOGE("ASEC loop device creation failed (%s)", strerror(errno));
    629             return -1;
    630         }
    631         if (mDebug) {
    632             SLOGD("New loop device created at %s", loopDevice);
    633         }
    634     } else {
    635         if (mDebug) {
    636             SLOGD("Found active loopback for %s at %s", asecFileName, loopDevice);
    637         }
    638     }
    639 
    640     char dmDevice[255];
    641     bool cleanupDm = false;
    642     int fd;
    643     unsigned int nr_sec = 0;
    644 
    645     if ((fd = open(loopDevice, O_RDWR)) < 0) {
    646         SLOGE("Failed to open loopdevice (%s)", strerror(errno));
    647         Loop::destroyByDevice(loopDevice);
    648         return -1;
    649     }
    650 
    651     if (ioctl(fd, BLKGETSIZE, &nr_sec)) {
    652         SLOGE("Failed to get loop size (%s)", strerror(errno));
    653         Loop::destroyByDevice(loopDevice);
    654         close(fd);
    655         return -1;
    656     }
    657 
    658     /*
    659      * Validate superblock
    660      */
    661     struct asec_superblock sb;
    662     memset(&sb, 0, sizeof(sb));
    663     if (lseek(fd, ((nr_sec-1) * 512), SEEK_SET) < 0) {
    664         SLOGE("lseek failed (%s)", strerror(errno));
    665         close(fd);
    666         Loop::destroyByDevice(loopDevice);
    667         return -1;
    668     }
    669     if (read(fd, &sb, sizeof(sb)) != sizeof(sb)) {
    670         SLOGE("superblock read failed (%s)", strerror(errno));
    671         close(fd);
    672         Loop::destroyByDevice(loopDevice);
    673         return -1;
    674     }
    675 
    676     close(fd);
    677 
    678     if (mDebug) {
    679         SLOGD("Container sb magic/ver (%.8x/%.2x)", sb.magic, sb.ver);
    680     }
    681     if (sb.magic != ASEC_SB_MAGIC || sb.ver != ASEC_SB_VER) {
    682         SLOGE("Bad container magic/version (%.8x/%.2x)", sb.magic, sb.ver);
    683         Loop::destroyByDevice(loopDevice);
    684         errno = EMEDIUMTYPE;
    685         return -1;
    686     }
    687     nr_sec--; // We don't want the devmapping to extend onto our superblock
    688 
    689     if (strcmp(key, "none")) {
    690         if (Devmapper::lookupActive(idHash, dmDevice, sizeof(dmDevice))) {
    691             if (Devmapper::create(idHash, loopDevice, key, nr_sec,
    692                                   dmDevice, sizeof(dmDevice))) {
    693                 SLOGE("ASEC device mapping failed (%s)", strerror(errno));
    694                 Loop::destroyByDevice(loopDevice);
    695                 return -1;
    696             }
    697             if (mDebug) {
    698                 SLOGD("New devmapper instance created at %s", dmDevice);
    699             }
    700         } else {
    701             if (mDebug) {
    702                 SLOGD("Found active devmapper for %s at %s", asecFileName, dmDevice);
    703             }
    704         }
    705         cleanupDm = true;
    706     } else {
    707         strcpy(dmDevice, loopDevice);
    708     }
    709 
    710     if (mkdir(mountPoint, 0777)) {
    711         if (errno != EEXIST) {
    712             SLOGE("Mountpoint creation failed (%s)", strerror(errno));
    713             if (cleanupDm) {
    714                 Devmapper::destroy(idHash);
    715             }
    716             Loop::destroyByDevice(loopDevice);
    717             return -1;
    718         }
    719     }
    720 
    721     if (Fat::doMount(dmDevice, mountPoint, true, false, true, ownerUid, 0,
    722                      0222, false)) {
    723 //                     0227, false)) {
    724         SLOGE("ASEC mount failed (%s)", strerror(errno));
    725         if (cleanupDm) {
    726             Devmapper::destroy(idHash);
    727         }
    728         Loop::destroyByDevice(loopDevice);
    729         return -1;
    730     }
    731 
    732     mActiveContainers->push_back(new ContainerData(strdup(id), ASEC));
    733     if (mDebug) {
    734         SLOGD("ASEC %s mounted", id);
    735     }
    736     return 0;
    737 }
    738 
    739 /**
    740  * Mounts an image file <code>img</code>.
    741  */
    742 int VolumeManager::mountObb(const char *img, const char *key, int ownerUid) {
    743     char mountPoint[255];
    744 
    745     char idHash[33];
    746     if (!asecHash(img, idHash, sizeof(idHash))) {
    747         SLOGE("Hash of '%s' failed (%s)", img, strerror(errno));
    748         return -1;
    749     }
    750 
    751     snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::LOOPDIR, idHash);
    752 
    753     if (isMountpointMounted(mountPoint)) {
    754         SLOGE("Image %s already mounted", img);
    755         errno = EBUSY;
    756         return -1;
    757     }
    758 
    759     char loopDevice[255];
    760     if (Loop::lookupActive(idHash, loopDevice, sizeof(loopDevice))) {
    761         if (Loop::create(idHash, img, loopDevice, sizeof(loopDevice))) {
    762             SLOGE("Image loop device creation failed (%s)", strerror(errno));
    763             return -1;
    764         }
    765         if (mDebug) {
    766             SLOGD("New loop device created at %s", loopDevice);
    767         }
    768     } else {
    769         if (mDebug) {
    770             SLOGD("Found active loopback for %s at %s", img, loopDevice);
    771         }
    772     }
    773 
    774     char dmDevice[255];
    775     bool cleanupDm = false;
    776     int fd;
    777     unsigned int nr_sec = 0;
    778 
    779     if ((fd = open(loopDevice, O_RDWR)) < 0) {
    780         SLOGE("Failed to open loopdevice (%s)", strerror(errno));
    781         Loop::destroyByDevice(loopDevice);
    782         return -1;
    783     }
    784 
    785     if (ioctl(fd, BLKGETSIZE, &nr_sec)) {
    786         SLOGE("Failed to get loop size (%s)", strerror(errno));
    787         Loop::destroyByDevice(loopDevice);
    788         close(fd);
    789         return -1;
    790     }
    791 
    792     close(fd);
    793 
    794     if (strcmp(key, "none")) {
    795         if (Devmapper::lookupActive(idHash, dmDevice, sizeof(dmDevice))) {
    796             if (Devmapper::create(idHash, loopDevice, key, nr_sec,
    797                                   dmDevice, sizeof(dmDevice))) {
    798                 SLOGE("ASEC device mapping failed (%s)", strerror(errno));
    799                 Loop::destroyByDevice(loopDevice);
    800                 return -1;
    801             }
    802             if (mDebug) {
    803                 SLOGD("New devmapper instance created at %s", dmDevice);
    804             }
    805         } else {
    806             if (mDebug) {
    807                 SLOGD("Found active devmapper for %s at %s", img, dmDevice);
    808             }
    809         }
    810         cleanupDm = true;
    811     } else {
    812         strcpy(dmDevice, loopDevice);
    813     }
    814 
    815     if (mkdir(mountPoint, 0755)) {
    816         if (errno != EEXIST) {
    817             SLOGE("Mountpoint creation failed (%s)", strerror(errno));
    818             if (cleanupDm) {
    819                 Devmapper::destroy(idHash);
    820             }
    821             Loop::destroyByDevice(loopDevice);
    822             return -1;
    823         }
    824     }
    825 
    826     if (Fat::doMount(dmDevice, mountPoint, true, false, true, ownerUid, 0,
    827                      0227, false)) {
    828         SLOGE("Image mount failed (%s)", strerror(errno));
    829         if (cleanupDm) {
    830             Devmapper::destroy(idHash);
    831         }
    832         Loop::destroyByDevice(loopDevice);
    833         return -1;
    834     }
    835 
    836     mActiveContainers->push_back(new ContainerData(strdup(img), OBB));
    837     if (mDebug) {
    838         SLOGD("Image %s mounted", img);
    839     }
    840     return 0;
    841 }
    842 
    843 int VolumeManager::mountVolume(const char *label) {
    844     Volume *v = lookupVolume(label);
    845 
    846     if (!v) {
    847         errno = ENOENT;
    848         return -1;
    849     }
    850 
    851     return v->mountVol();
    852 }
    853 
    854 int VolumeManager::listMountedObbs(SocketClient* cli) {
    855     char device[256];
    856     char mount_path[256];
    857     char rest[256];
    858     FILE *fp;
    859     char line[1024];
    860 
    861     if (!(fp = fopen("/proc/mounts", "r"))) {
    862         SLOGE("Error opening /proc/mounts (%s)", strerror(errno));
    863         return -1;
    864     }
    865 
    866     // Create a string to compare against that has a trailing slash
    867     int loopDirLen = sizeof(Volume::LOOPDIR);
    868     char loopDir[loopDirLen + 2];
    869     strcpy(loopDir, Volume::LOOPDIR);
    870     loopDir[loopDirLen++] = '/';
    871     loopDir[loopDirLen] = '\0';
    872 
    873     while(fgets(line, sizeof(line), fp)) {
    874         line[strlen(line)-1] = '\0';
    875 
    876         /*
    877          * Should look like:
    878          * /dev/block/loop0 /mnt/obb/fc99df1323fd36424f864dcb76b76d65 ...
    879          */
    880         sscanf(line, "%255s %255s %255s\n", device, mount_path, rest);
    881 
    882         if (!strncmp(mount_path, loopDir, loopDirLen)) {
    883             int fd = open(device, O_RDONLY);
    884             if (fd >= 0) {
    885                 struct loop_info64 li;
    886                 if (ioctl(fd, LOOP_GET_STATUS64, &li) >= 0) {
    887                     cli->sendMsg(ResponseCode::AsecListResult,
    888                             (const char*) li.lo_file_name, false);
    889                 }
    890                 close(fd);
    891             }
    892         }
    893     }
    894 
    895     fclose(fp);
    896     return 0;
    897 }
    898 
    899 int VolumeManager::shareEnabled(const char *label, const char *method, bool *enabled) {
    900     Volume *v = lookupVolume(label);
    901 
    902     if (!v) {
    903         errno = ENOENT;
    904         return -1;
    905     }
    906 
    907     if (strcmp(method, "ums")) {
    908         errno = ENOSYS;
    909         return -1;
    910     }
    911 
    912     if (v->getState() != Volume::State_Shared) {
    913         *enabled = false;
    914     } else {
    915         *enabled = true;
    916     }
    917     return 0;
    918 }
    919 
    920 int VolumeManager::shareVolume(const char *label, const char *method) {
    921     Volume *v = lookupVolume(label);
    922 
    923     if (!v) {
    924         errno = ENOENT;
    925         return -1;
    926     }
    927 
    928     /*
    929      * Eventually, we'll want to support additional share back-ends,
    930      * some of which may work while the media is mounted. For now,
    931      * we just support UMS
    932      */
    933     if (strcmp(method, "ums")) {
    934         errno = ENOSYS;
    935         return -1;
    936     }
    937 
    938     if (v->getState() == Volume::State_NoMedia) {
    939         errno = ENODEV;
    940         return -1;
    941     }
    942 
    943     if (v->getState() != Volume::State_Idle) {
    944         // You need to unmount manually befoe sharing
    945         errno = EBUSY;
    946         return -1;
    947     }
    948 
    949     if (mVolManagerDisabled) {
    950         errno = EBUSY;
    951         return -1;
    952     }
    953 
    954     dev_t d = v->getShareDevice();
    955     if ((MAJOR(d) == 0) && (MINOR(d) == 0)) {
    956         // This volume does not support raw disk access
    957         errno = EINVAL;
    958         return -1;
    959     }
    960 
    961     int fd;
    962     char nodepath[255];
    963     snprintf(nodepath,
    964              sizeof(nodepath), "/dev/block/vold/%d:%d",
    965              MAJOR(d), MINOR(d));
    966 
    967     if ((fd = open(MASS_STORAGE_FILE_PATH, O_WRONLY)) < 0) {
    968         SLOGE("Unable to open ums lunfile (%s)", strerror(errno));
    969         return -1;
    970     }
    971 
    972     if (write(fd, nodepath, strlen(nodepath)) < 0) {
    973         SLOGE("Unable to write to ums lunfile (%s)", strerror(errno));
    974         close(fd);
    975         return -1;
    976     }
    977 
    978     close(fd);
    979     v->handleVolumeShared();
    980     if (mUmsSharingCount++ == 0) {
    981         FILE* fp;
    982         mSavedDirtyRatio = -1; // in case we fail
    983         if ((fp = fopen("/proc/sys/vm/dirty_ratio", "r+"))) {
    984             char line[16];
    985             if (fgets(line, sizeof(line), fp) && sscanf(line, "%d", &mSavedDirtyRatio)) {
    986                 fprintf(fp, "%d\n", mUmsDirtyRatio);
    987             } else {
    988                 SLOGE("Failed to read dirty_ratio (%s)", strerror(errno));
    989             }
    990             fclose(fp);
    991         } else {
    992             SLOGE("Failed to open /proc/sys/vm/dirty_ratio (%s)", strerror(errno));
    993         }
    994     }
    995     return 0;
    996 }
    997 
    998 int VolumeManager::unshareVolume(const char *label, const char *method) {
    999     Volume *v = lookupVolume(label);
   1000 
   1001     if (!v) {
   1002         errno = ENOENT;
   1003         return -1;
   1004     }
   1005 
   1006     if (strcmp(method, "ums")) {
   1007         errno = ENOSYS;
   1008         return -1;
   1009     }
   1010 
   1011     if (v->getState() != Volume::State_Shared) {
   1012         errno = EINVAL;
   1013         return -1;
   1014     }
   1015 
   1016     int fd;
   1017     if ((fd = open(MASS_STORAGE_FILE_PATH, O_WRONLY)) < 0) {
   1018         SLOGE("Unable to open ums lunfile (%s)", strerror(errno));
   1019         return -1;
   1020     }
   1021 
   1022     char ch = 0;
   1023     if (write(fd, &ch, 1) < 0) {
   1024         SLOGE("Unable to write to ums lunfile (%s)", strerror(errno));
   1025         close(fd);
   1026         return -1;
   1027     }
   1028 
   1029     close(fd);
   1030     v->handleVolumeUnshared();
   1031     if (--mUmsSharingCount == 0 && mSavedDirtyRatio != -1) {
   1032         FILE* fp;
   1033         if ((fp = fopen("/proc/sys/vm/dirty_ratio", "r+"))) {
   1034             fprintf(fp, "%d\n", mSavedDirtyRatio);
   1035             fclose(fp);
   1036         } else {
   1037             SLOGE("Failed to open /proc/sys/vm/dirty_ratio (%s)", strerror(errno));
   1038         }
   1039         mSavedDirtyRatio = -1;
   1040     }
   1041     return 0;
   1042 }
   1043 
   1044 extern "C" int vold_disableVol(const char *label) {
   1045     VolumeManager *vm = VolumeManager::Instance();
   1046     vm->disableVolumeManager();
   1047     vm->unshareVolume(label, "ums");
   1048     return vm->unmountVolume(label, true, false);
   1049 }
   1050 
   1051 extern "C" int vold_getNumDirectVolumes(void) {
   1052     VolumeManager *vm = VolumeManager::Instance();
   1053     return vm->getNumDirectVolumes();
   1054 }
   1055 
   1056 int VolumeManager::getNumDirectVolumes(void) {
   1057     VolumeCollection::iterator i;
   1058     int n=0;
   1059 
   1060     for (i = mVolumes->begin(); i != mVolumes->end(); ++i) {
   1061         if ((*i)->getShareDevice() != (dev_t)0) {
   1062             n++;
   1063         }
   1064     }
   1065     return n;
   1066 }
   1067 
   1068 extern "C" int vold_getDirectVolumeList(struct volume_info *vol_list) {
   1069     VolumeManager *vm = VolumeManager::Instance();
   1070     return vm->getDirectVolumeList(vol_list);
   1071 }
   1072 
   1073 int VolumeManager::getDirectVolumeList(struct volume_info *vol_list) {
   1074     VolumeCollection::iterator i;
   1075     int n=0;
   1076     dev_t d;
   1077 
   1078     for (i = mVolumes->begin(); i != mVolumes->end(); ++i) {
   1079         if ((d=(*i)->getShareDevice()) != (dev_t)0) {
   1080             (*i)->getVolInfo(&vol_list[n]);
   1081             snprintf(vol_list[n].blk_dev, sizeof(vol_list[n].blk_dev),
   1082                      "/dev/block/vold/%d:%d",MAJOR(d), MINOR(d));
   1083             n++;
   1084         }
   1085     }
   1086 
   1087     return 0;
   1088 }
   1089 
   1090 int VolumeManager::unmountVolume(const char *label, bool force, bool revert) {
   1091     Volume *v = lookupVolume(label);
   1092 
   1093     if (!v) {
   1094         errno = ENOENT;
   1095         return -1;
   1096     }
   1097 
   1098     if (v->getState() == Volume::State_NoMedia) {
   1099         errno = ENODEV;
   1100         return -1;
   1101     }
   1102 
   1103     if (v->getState() != Volume::State_Mounted) {
   1104         SLOGW("Attempt to unmount volume which isn't mounted (%d)\n",
   1105              v->getState());
   1106         errno = EBUSY;
   1107         return UNMOUNT_NOT_MOUNTED_ERR;
   1108     }
   1109 
   1110     cleanupAsec(v, force);
   1111 
   1112     return v->unmountVol(force, revert);
   1113 }
   1114 
   1115 /*
   1116  * Looks up a volume by it's label or mount-point
   1117  */
   1118 Volume *VolumeManager::lookupVolume(const char *label) {
   1119     VolumeCollection::iterator i;
   1120 
   1121     for (i = mVolumes->begin(); i != mVolumes->end(); ++i) {
   1122         if (label[0] == '/') {
   1123             if (!strcmp(label, (*i)->getMountpoint()))
   1124                 return (*i);
   1125         } else {
   1126             if (!strcmp(label, (*i)->getLabel()))
   1127                 return (*i);
   1128         }
   1129     }
   1130     return NULL;
   1131 }
   1132 
   1133 bool VolumeManager::isMountpointMounted(const char *mp)
   1134 {
   1135     char device[256];
   1136     char mount_path[256];
   1137     char rest[256];
   1138     FILE *fp;
   1139     char line[1024];
   1140 
   1141     if (!(fp = fopen("/proc/mounts", "r"))) {
   1142         SLOGE("Error opening /proc/mounts (%s)", strerror(errno));
   1143         return false;
   1144     }
   1145 
   1146     while(fgets(line, sizeof(line), fp)) {
   1147         line[strlen(line)-1] = '\0';
   1148         sscanf(line, "%255s %255s %255s\n", device, mount_path, rest);
   1149         if (!strcmp(mount_path, mp)) {
   1150             fclose(fp);
   1151             return true;
   1152         }
   1153     }
   1154 
   1155     fclose(fp);
   1156     return false;
   1157 }
   1158 
   1159 int VolumeManager::cleanupAsec(Volume *v, bool force) {
   1160     while(mActiveContainers->size()) {
   1161         AsecIdCollection::iterator it = mActiveContainers->begin();
   1162         ContainerData* cd = *it;
   1163         SLOGI("Unmounting ASEC %s (dependant on %s)", cd->id, v->getMountpoint());
   1164         if (cd->type == ASEC) {
   1165             if (unmountAsec(cd->id, force)) {
   1166                 SLOGE("Failed to unmount ASEC %s (%s)", cd->id, strerror(errno));
   1167                 return -1;
   1168             }
   1169         } else if (cd->type == OBB) {
   1170             if (unmountObb(cd->id, force)) {
   1171                 SLOGE("Failed to unmount OBB %s (%s)", cd->id, strerror(errno));
   1172                 return -1;
   1173             }
   1174         } else {
   1175             SLOGE("Unknown container type %d!", cd->type);
   1176             return -1;
   1177         }
   1178     }
   1179     return 0;
   1180 }
   1181 
   1182