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