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