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