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