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 <stdlib.h>
     18 #include <string.h>
     19 #include <dirent.h>
     20 #include <errno.h>
     21 #include <fcntl.h>
     22 
     23 #include <sys/types.h>
     24 #include <sys/stat.h>
     25 #include <sys/types.h>
     26 #include <sys/mman.h>
     27 #include <sys/mount.h>
     28 #include <sys/param.h>
     29 
     30 #include <linux/kdev_t.h>
     31 
     32 #include <cutils/properties.h>
     33 
     34 #include <diskconfig/diskconfig.h>
     35 
     36 #include <private/android_filesystem_config.h>
     37 
     38 #define LOG_TAG "Vold"
     39 
     40 #include <cutils/log.h>
     41 
     42 #include "Volume.h"
     43 #include "VolumeManager.h"
     44 #include "ResponseCode.h"
     45 #include "Fat.h"
     46 #include "Process.h"
     47 #include "cryptfs.h"
     48 
     49 extern "C" void dos_partition_dec(void const *pp, struct dos_partition *d);
     50 extern "C" void dos_partition_enc(void *pp, struct dos_partition *d);
     51 
     52 
     53 /*
     54  * Secure directory - stuff that only root can see
     55  */
     56 const char *Volume::SECDIR            = "/mnt/secure";
     57 
     58 /*
     59  * Secure staging directory - where media is mounted for preparation
     60  */
     61 const char *Volume::SEC_STGDIR        = "/mnt/secure/staging";
     62 
     63 /*
     64  * Path to the directory on the media which contains publicly accessable
     65  * asec imagefiles. This path will be obscured before the mount is
     66  * exposed to non priviledged users.
     67  */
     68 const char *Volume::SEC_STG_SECIMGDIR = "/mnt/secure/staging/.android_secure";
     69 
     70 /*
     71  * Path to external storage where *only* root can access ASEC image files
     72  */
     73 const char *Volume::SEC_ASECDIR_EXT   = "/mnt/secure/asec";
     74 
     75 /*
     76  * Path to internal storage where *only* root can access ASEC image files
     77  */
     78 const char *Volume::SEC_ASECDIR_INT   = "/data/app-asec";
     79 /*
     80  * Path to where secure containers are mounted
     81  */
     82 const char *Volume::ASECDIR           = "/mnt/asec";
     83 
     84 /*
     85  * Path to where OBBs are mounted
     86  */
     87 const char *Volume::LOOPDIR           = "/mnt/obb";
     88 
     89 static const char *stateToStr(int state) {
     90     if (state == Volume::State_Init)
     91         return "Initializing";
     92     else if (state == Volume::State_NoMedia)
     93         return "No-Media";
     94     else if (state == Volume::State_Idle)
     95         return "Idle-Unmounted";
     96     else if (state == Volume::State_Pending)
     97         return "Pending";
     98     else if (state == Volume::State_Mounted)
     99         return "Mounted";
    100     else if (state == Volume::State_Unmounting)
    101         return "Unmounting";
    102     else if (state == Volume::State_Checking)
    103         return "Checking";
    104     else if (state == Volume::State_Formatting)
    105         return "Formatting";
    106     else if (state == Volume::State_Shared)
    107         return "Shared-Unmounted";
    108     else if (state == Volume::State_SharedMnt)
    109         return "Shared-Mounted";
    110     else
    111         return "Unknown-Error";
    112 }
    113 
    114 Volume::Volume(VolumeManager *vm, const char *label, const char *mount_point) {
    115     mVm = vm;
    116     mDebug = false;
    117     mLabel = strdup(label);
    118     mMountpoint = strdup(mount_point);
    119     mState = Volume::State_Init;
    120     mCurrentlyMountedKdev = -1;
    121     mPartIdx = -1;
    122     mRetryMount = false;
    123 }
    124 
    125 Volume::~Volume() {
    126     free(mLabel);
    127     free(mMountpoint);
    128 }
    129 
    130 void Volume::protectFromAutorunStupidity() {
    131     char filename[255];
    132 
    133     snprintf(filename, sizeof(filename), "%s/autorun.inf", SEC_STGDIR);
    134     if (!access(filename, F_OK)) {
    135         SLOGW("Volume contains an autorun.inf! - removing");
    136         /*
    137          * Ensure the filename is all lower-case so
    138          * the process killer can find the inode.
    139          * Probably being paranoid here but meh.
    140          */
    141         rename(filename, filename);
    142         Process::killProcessesWithOpenFiles(filename, 2);
    143         if (unlink(filename)) {
    144             SLOGE("Failed to remove %s (%s)", filename, strerror(errno));
    145         }
    146     }
    147 }
    148 
    149 void Volume::setDebug(bool enable) {
    150     mDebug = enable;
    151 }
    152 
    153 dev_t Volume::getDiskDevice() {
    154     return MKDEV(0, 0);
    155 };
    156 
    157 dev_t Volume::getShareDevice() {
    158     return getDiskDevice();
    159 }
    160 
    161 void Volume::handleVolumeShared() {
    162 }
    163 
    164 void Volume::handleVolumeUnshared() {
    165 }
    166 
    167 int Volume::handleBlockEvent(NetlinkEvent *evt) {
    168     errno = ENOSYS;
    169     return -1;
    170 }
    171 
    172 void Volume::setState(int state) {
    173     char msg[255];
    174     int oldState = mState;
    175 
    176     if (oldState == state) {
    177         SLOGW("Duplicate state (%d)\n", state);
    178         return;
    179     }
    180 
    181     if ((oldState == Volume::State_Pending) && (state != Volume::State_Idle)) {
    182         mRetryMount = false;
    183     }
    184 
    185     mState = state;
    186 
    187     SLOGD("Volume %s state changing %d (%s) -> %d (%s)", mLabel,
    188          oldState, stateToStr(oldState), mState, stateToStr(mState));
    189     snprintf(msg, sizeof(msg),
    190              "Volume %s %s state changed from %d (%s) to %d (%s)", getLabel(),
    191              getMountpoint(), oldState, stateToStr(oldState), mState,
    192              stateToStr(mState));
    193 
    194     mVm->getBroadcaster()->sendBroadcast(ResponseCode::VolumeStateChange,
    195                                          msg, false);
    196 }
    197 
    198 int Volume::createDeviceNode(const char *path, int major, int minor) {
    199     mode_t mode = 0660 | S_IFBLK;
    200     dev_t dev = (major << 8) | minor;
    201     if (mknod(path, mode, dev) < 0) {
    202         if (errno != EEXIST) {
    203             return -1;
    204         }
    205     }
    206     return 0;
    207 }
    208 
    209 int Volume::formatVol() {
    210 
    211     if (getState() == Volume::State_NoMedia) {
    212         errno = ENODEV;
    213         return -1;
    214     } else if (getState() != Volume::State_Idle) {
    215         errno = EBUSY;
    216         return -1;
    217     }
    218 
    219     if (isMountpointMounted(getMountpoint())) {
    220         SLOGW("Volume is idle but appears to be mounted - fixing");
    221         setState(Volume::State_Mounted);
    222         // mCurrentlyMountedKdev = XXX
    223         errno = EBUSY;
    224         return -1;
    225     }
    226 
    227     bool formatEntireDevice = (mPartIdx == -1);
    228     char devicePath[255];
    229     dev_t diskNode = getDiskDevice();
    230     dev_t partNode = MKDEV(MAJOR(diskNode), (formatEntireDevice ? 1 : mPartIdx));
    231 
    232     setState(Volume::State_Formatting);
    233 
    234     int ret = -1;
    235     // Only initialize the MBR if we are formatting the entire device
    236     if (formatEntireDevice) {
    237         sprintf(devicePath, "/dev/block/vold/%d:%d",
    238                 MAJOR(diskNode), MINOR(diskNode));
    239 
    240         if (initializeMbr(devicePath)) {
    241             SLOGE("Failed to initialize MBR (%s)", strerror(errno));
    242             goto err;
    243         }
    244     }
    245 
    246     sprintf(devicePath, "/dev/block/vold/%d:%d",
    247             MAJOR(partNode), MINOR(partNode));
    248 
    249     if (mDebug) {
    250         SLOGI("Formatting volume %s (%s)", getLabel(), devicePath);
    251     }
    252 
    253     if (Fat::format(devicePath, 0)) {
    254         SLOGE("Failed to format (%s)", strerror(errno));
    255         goto err;
    256     }
    257 
    258     ret = 0;
    259 
    260 err:
    261     setState(Volume::State_Idle);
    262     return ret;
    263 }
    264 
    265 bool Volume::isMountpointMounted(const char *path) {
    266     char device[256];
    267     char mount_path[256];
    268     char rest[256];
    269     FILE *fp;
    270     char line[1024];
    271 
    272     if (!(fp = fopen("/proc/mounts", "r"))) {
    273         SLOGE("Error opening /proc/mounts (%s)", strerror(errno));
    274         return false;
    275     }
    276 
    277     while(fgets(line, sizeof(line), fp)) {
    278         line[strlen(line)-1] = '\0';
    279         sscanf(line, "%255s %255s %255s\n", device, mount_path, rest);
    280         if (!strcmp(mount_path, path)) {
    281             fclose(fp);
    282             return true;
    283         }
    284 
    285     }
    286 
    287     fclose(fp);
    288     return false;
    289 }
    290 
    291 int Volume::mountVol() {
    292     dev_t deviceNodes[4];
    293     int n, i, rc = 0;
    294     char errmsg[255];
    295     const char* externalStorage = getenv("EXTERNAL_STORAGE");
    296     bool primaryStorage = externalStorage && !strcmp(getMountpoint(), externalStorage);
    297     char decrypt_state[PROPERTY_VALUE_MAX];
    298     char crypto_state[PROPERTY_VALUE_MAX];
    299     char encrypt_progress[PROPERTY_VALUE_MAX];
    300     int flags;
    301 
    302     property_get("vold.decrypt", decrypt_state, "");
    303     property_get("vold.encrypt_progress", encrypt_progress, "");
    304 
    305     /* Don't try to mount the volumes if we have not yet entered the disk password
    306      * or are in the process of encrypting.
    307      */
    308     if ((getState() == Volume::State_NoMedia) ||
    309         ((!strcmp(decrypt_state, "1") || encrypt_progress[0]) && primaryStorage)) {
    310         snprintf(errmsg, sizeof(errmsg),
    311                  "Volume %s %s mount failed - no media",
    312                  getLabel(), getMountpoint());
    313         mVm->getBroadcaster()->sendBroadcast(
    314                                          ResponseCode::VolumeMountFailedNoMedia,
    315                                          errmsg, false);
    316         errno = ENODEV;
    317         return -1;
    318     } else if (getState() != Volume::State_Idle) {
    319         errno = EBUSY;
    320         if (getState() == Volume::State_Pending) {
    321             mRetryMount = true;
    322         }
    323         return -1;
    324     }
    325 
    326     if (isMountpointMounted(getMountpoint())) {
    327         SLOGW("Volume is idle but appears to be mounted - fixing");
    328         setState(Volume::State_Mounted);
    329         // mCurrentlyMountedKdev = XXX
    330         return 0;
    331     }
    332 
    333     n = getDeviceNodes((dev_t *) &deviceNodes, 4);
    334     if (!n) {
    335         SLOGE("Failed to get device nodes (%s)\n", strerror(errno));
    336         return -1;
    337     }
    338 
    339     /* If we're running encrypted, and the volume is marked as encryptable and nonremovable,
    340      * and vold is asking to mount the primaryStorage device, then we need to decrypt
    341      * that partition, and update the volume object to point to it's new decrypted
    342      * block device
    343      */
    344     property_get("ro.crypto.state", crypto_state, "");
    345     flags = getFlags();
    346     if (primaryStorage &&
    347         ((flags & (VOL_NONREMOVABLE | VOL_ENCRYPTABLE))==(VOL_NONREMOVABLE | VOL_ENCRYPTABLE)) &&
    348         !strcmp(crypto_state, "encrypted") && !isDecrypted()) {
    349        char new_sys_path[MAXPATHLEN];
    350        char nodepath[256];
    351        int new_major, new_minor;
    352 
    353        if (n != 1) {
    354            /* We only expect one device node returned when mounting encryptable volumes */
    355            SLOGE("Too many device nodes returned when mounting %d\n", getMountpoint());
    356            return -1;
    357        }
    358 
    359        if (cryptfs_setup_volume(getLabel(), MAJOR(deviceNodes[0]), MINOR(deviceNodes[0]),
    360                                 new_sys_path, sizeof(new_sys_path),
    361                                 &new_major, &new_minor)) {
    362            SLOGE("Cannot setup encryption mapping for %d\n", getMountpoint());
    363            return -1;
    364        }
    365        /* We now have the new sysfs path for the decrypted block device, and the
    366         * majore and minor numbers for it.  So, create the device, update the
    367         * path to the new sysfs path, and continue.
    368         */
    369         snprintf(nodepath,
    370                  sizeof(nodepath), "/dev/block/vold/%d:%d",
    371                  new_major, new_minor);
    372         if (createDeviceNode(nodepath, new_major, new_minor)) {
    373             SLOGE("Error making device node '%s' (%s)", nodepath,
    374                                                        strerror(errno));
    375         }
    376 
    377         // Todo: Either create sys filename from nodepath, or pass in bogus path so
    378         //       vold ignores state changes on this internal device.
    379         updateDeviceInfo(nodepath, new_major, new_minor);
    380 
    381         /* Get the device nodes again, because they just changed */
    382         n = getDeviceNodes((dev_t *) &deviceNodes, 4);
    383         if (!n) {
    384             SLOGE("Failed to get device nodes (%s)\n", strerror(errno));
    385             return -1;
    386         }
    387     }
    388 
    389     for (i = 0; i < n; i++) {
    390         char devicePath[255];
    391 
    392         sprintf(devicePath, "/dev/block/vold/%d:%d", MAJOR(deviceNodes[i]),
    393                 MINOR(deviceNodes[i]));
    394 
    395         SLOGI("%s being considered for volume %s\n", devicePath, getLabel());
    396 
    397         errno = 0;
    398         setState(Volume::State_Checking);
    399 
    400         if (Fat::check(devicePath)) {
    401             if (errno == ENODATA) {
    402                 SLOGW("%s does not contain a FAT filesystem\n", devicePath);
    403                 continue;
    404             }
    405             errno = EIO;
    406             /* Badness - abort the mount */
    407             SLOGE("%s failed FS checks (%s)", devicePath, strerror(errno));
    408             setState(Volume::State_Idle);
    409             return -1;
    410         }
    411 
    412         /*
    413          * Mount the device on our internal staging mountpoint so we can
    414          * muck with it before exposing it to non priviledged users.
    415          */
    416         errno = 0;
    417         int gid;
    418 
    419         if (primaryStorage) {
    420             // Special case the primary SD card.
    421             // For this we grant write access to the SDCARD_RW group.
    422             gid = AID_SDCARD_RW;
    423         } else {
    424             // For secondary external storage we keep things locked up.
    425             gid = AID_MEDIA_RW;
    426         }
    427         if (Fat::doMount(devicePath, "/mnt/secure/staging", false, false, false,
    428                 AID_SYSTEM, gid, 0702, true)) {
    429             SLOGE("%s failed to mount via VFAT (%s)\n", devicePath, strerror(errno));
    430             continue;
    431         }
    432 
    433         SLOGI("Device %s, target %s mounted @ /mnt/secure/staging", devicePath, getMountpoint());
    434 
    435         protectFromAutorunStupidity();
    436 
    437         // only create android_secure on primary storage
    438         if (primaryStorage && createBindMounts()) {
    439             SLOGE("Failed to create bindmounts (%s)", strerror(errno));
    440             umount("/mnt/secure/staging");
    441             setState(Volume::State_Idle);
    442             return -1;
    443         }
    444 
    445         /*
    446          * Now that the bindmount trickery is done, atomically move the
    447          * whole subtree to expose it to non priviledged users.
    448          */
    449         if (doMoveMount("/mnt/secure/staging", getMountpoint(), false)) {
    450             SLOGE("Failed to move mount (%s)", strerror(errno));
    451             umount("/mnt/secure/staging");
    452             setState(Volume::State_Idle);
    453             return -1;
    454         }
    455         setState(Volume::State_Mounted);
    456         mCurrentlyMountedKdev = deviceNodes[i];
    457         return 0;
    458     }
    459 
    460     SLOGE("Volume %s found no suitable devices for mounting :(\n", getLabel());
    461     setState(Volume::State_Idle);
    462 
    463     return -1;
    464 }
    465 
    466 int Volume::createBindMounts() {
    467     unsigned long flags;
    468 
    469     /*
    470      * Rename old /android_secure -> /.android_secure
    471      */
    472     if (!access("/mnt/secure/staging/android_secure", R_OK | X_OK) &&
    473          access(SEC_STG_SECIMGDIR, R_OK | X_OK)) {
    474         if (rename("/mnt/secure/staging/android_secure", SEC_STG_SECIMGDIR)) {
    475             SLOGE("Failed to rename legacy asec dir (%s)", strerror(errno));
    476         }
    477     }
    478 
    479     /*
    480      * Ensure that /android_secure exists and is a directory
    481      */
    482     if (access(SEC_STG_SECIMGDIR, R_OK | X_OK)) {
    483         if (errno == ENOENT) {
    484             if (mkdir(SEC_STG_SECIMGDIR, 0777)) {
    485                 SLOGE("Failed to create %s (%s)", SEC_STG_SECIMGDIR, strerror(errno));
    486                 return -1;
    487             }
    488         } else {
    489             SLOGE("Failed to access %s (%s)", SEC_STG_SECIMGDIR, strerror(errno));
    490             return -1;
    491         }
    492     } else {
    493         struct stat sbuf;
    494 
    495         if (stat(SEC_STG_SECIMGDIR, &sbuf)) {
    496             SLOGE("Failed to stat %s (%s)", SEC_STG_SECIMGDIR, strerror(errno));
    497             return -1;
    498         }
    499         if (!S_ISDIR(sbuf.st_mode)) {
    500             SLOGE("%s is not a directory", SEC_STG_SECIMGDIR);
    501             errno = ENOTDIR;
    502             return -1;
    503         }
    504     }
    505 
    506     /*
    507      * Bind mount /mnt/secure/staging/android_secure -> /mnt/secure/asec so we'll
    508      * have a root only accessable mountpoint for it.
    509      */
    510     if (mount(SEC_STG_SECIMGDIR, SEC_ASECDIR_EXT, "", MS_BIND, NULL)) {
    511         SLOGE("Failed to bind mount points %s -> %s (%s)",
    512                 SEC_STG_SECIMGDIR, SEC_ASECDIR_EXT, strerror(errno));
    513         return -1;
    514     }
    515 
    516     /*
    517      * Mount a read-only, zero-sized tmpfs  on <mountpoint>/android_secure to
    518      * obscure the underlying directory from everybody - sneaky eh? ;)
    519      */
    520     if (mount("tmpfs", SEC_STG_SECIMGDIR, "tmpfs", MS_RDONLY, "size=0,mode=000,uid=0,gid=0")) {
    521         SLOGE("Failed to obscure %s (%s)", SEC_STG_SECIMGDIR, strerror(errno));
    522         umount("/mnt/asec_secure");
    523         return -1;
    524     }
    525 
    526     return 0;
    527 }
    528 
    529 int Volume::doMoveMount(const char *src, const char *dst, bool force) {
    530     unsigned int flags = MS_MOVE;
    531     int retries = 5;
    532 
    533     while(retries--) {
    534         if (!mount(src, dst, "", flags, NULL)) {
    535             if (mDebug) {
    536                 SLOGD("Moved mount %s -> %s sucessfully", src, dst);
    537             }
    538             return 0;
    539         } else if (errno != EBUSY) {
    540             SLOGE("Failed to move mount %s -> %s (%s)", src, dst, strerror(errno));
    541             return -1;
    542         }
    543         int action = 0;
    544 
    545         if (force) {
    546             if (retries == 1) {
    547                 action = 2; // SIGKILL
    548             } else if (retries == 2) {
    549                 action = 1; // SIGHUP
    550             }
    551         }
    552         SLOGW("Failed to move %s -> %s (%s, retries %d, action %d)",
    553                 src, dst, strerror(errno), retries, action);
    554         Process::killProcessesWithOpenFiles(src, action);
    555         usleep(1000*250);
    556     }
    557 
    558     errno = EBUSY;
    559     SLOGE("Giving up on move %s -> %s (%s)", src, dst, strerror(errno));
    560     return -1;
    561 }
    562 
    563 int Volume::doUnmount(const char *path, bool force) {
    564     int retries = 10;
    565 
    566     if (mDebug) {
    567         SLOGD("Unmounting {%s}, force = %d", path, force);
    568     }
    569 
    570     while (retries--) {
    571         if (!umount(path) || errno == EINVAL || errno == ENOENT) {
    572             SLOGI("%s sucessfully unmounted", path);
    573             return 0;
    574         }
    575 
    576         int action = 0;
    577 
    578         if (force) {
    579             if (retries == 1) {
    580                 action = 2; // SIGKILL
    581             } else if (retries == 2) {
    582                 action = 1; // SIGHUP
    583             }
    584         }
    585 
    586         SLOGW("Failed to unmount %s (%s, retries %d, action %d)",
    587                 path, strerror(errno), retries, action);
    588 
    589         Process::killProcessesWithOpenFiles(path, action);
    590         usleep(1000*1000);
    591     }
    592     errno = EBUSY;
    593     SLOGE("Giving up on unmount %s (%s)", path, strerror(errno));
    594     return -1;
    595 }
    596 
    597 int Volume::unmountVol(bool force, bool revert) {
    598     int i, rc;
    599 
    600     if (getState() != Volume::State_Mounted) {
    601         SLOGE("Volume %s unmount request when not mounted", getLabel());
    602         errno = EINVAL;
    603         return UNMOUNT_NOT_MOUNTED_ERR;
    604     }
    605 
    606     setState(Volume::State_Unmounting);
    607     usleep(1000 * 1000); // Give the framework some time to react
    608 
    609     /*
    610      * Remove the bindmount we were using to keep a reference to
    611      * the previously obscured directory.
    612      */
    613     if (doUnmount(Volume::SEC_ASECDIR_EXT, force)) {
    614         SLOGE("Failed to remove bindmount on %s (%s)", SEC_ASECDIR_EXT, strerror(errno));
    615         goto fail_remount_tmpfs;
    616     }
    617 
    618     /*
    619      * Unmount the tmpfs which was obscuring the asec image directory
    620      * from non root users
    621      */
    622     char secure_dir[PATH_MAX];
    623     snprintf(secure_dir, PATH_MAX, "%s/.android_secure", getMountpoint());
    624     if (doUnmount(secure_dir, force)) {
    625         SLOGE("Failed to unmount tmpfs on %s (%s)", secure_dir, strerror(errno));
    626         goto fail_republish;
    627     }
    628 
    629     /*
    630      * Finally, unmount the actual block device from the staging dir
    631      */
    632     if (doUnmount(getMountpoint(), force)) {
    633         SLOGE("Failed to unmount %s (%s)", SEC_STGDIR, strerror(errno));
    634         goto fail_recreate_bindmount;
    635     }
    636 
    637     SLOGI("%s unmounted sucessfully", getMountpoint());
    638 
    639     /* If this is an encrypted volume, and we've been asked to undo
    640      * the crypto mapping, then revert the dm-crypt mapping, and revert
    641      * the device info to the original values.
    642      */
    643     if (revert && isDecrypted()) {
    644         cryptfs_revert_volume(getLabel());
    645         revertDeviceInfo();
    646         SLOGI("Encrypted volume %s reverted successfully", getMountpoint());
    647     }
    648 
    649     setState(Volume::State_Idle);
    650     mCurrentlyMountedKdev = -1;
    651     return 0;
    652 
    653     /*
    654      * Failure handling - try to restore everything back the way it was
    655      */
    656 fail_recreate_bindmount:
    657     if (mount(SEC_STG_SECIMGDIR, SEC_ASECDIR_EXT, "", MS_BIND, NULL)) {
    658         SLOGE("Failed to restore bindmount after failure! - Storage will appear offline!");
    659         goto out_nomedia;
    660     }
    661 fail_remount_tmpfs:
    662     if (mount("tmpfs", SEC_STG_SECIMGDIR, "tmpfs", MS_RDONLY, "size=0,mode=0,uid=0,gid=0")) {
    663         SLOGE("Failed to restore tmpfs after failure! - Storage will appear offline!");
    664         goto out_nomedia;
    665     }
    666 fail_republish:
    667     if (doMoveMount(SEC_STGDIR, getMountpoint(), force)) {
    668         SLOGE("Failed to republish mount after failure! - Storage will appear offline!");
    669         goto out_nomedia;
    670     }
    671 
    672     setState(Volume::State_Mounted);
    673     return -1;
    674 
    675 out_nomedia:
    676     setState(Volume::State_NoMedia);
    677     return -1;
    678 }
    679 int Volume::initializeMbr(const char *deviceNode) {
    680     struct disk_info dinfo;
    681 
    682     memset(&dinfo, 0, sizeof(dinfo));
    683 
    684     if (!(dinfo.part_lst = (struct part_info *) malloc(MAX_NUM_PARTS * sizeof(struct part_info)))) {
    685         SLOGE("Failed to malloc prt_lst");
    686         return -1;
    687     }
    688 
    689     memset(dinfo.part_lst, 0, MAX_NUM_PARTS * sizeof(struct part_info));
    690     dinfo.device = strdup(deviceNode);
    691     dinfo.scheme = PART_SCHEME_MBR;
    692     dinfo.sect_size = 512;
    693     dinfo.skip_lba = 2048;
    694     dinfo.num_lba = 0;
    695     dinfo.num_parts = 1;
    696 
    697     struct part_info *pinfo = &dinfo.part_lst[0];
    698 
    699     pinfo->name = strdup("android_sdcard");
    700     pinfo->flags |= PART_ACTIVE_FLAG;
    701     pinfo->type = PC_PART_TYPE_FAT32;
    702     pinfo->len_kb = -1;
    703 
    704     int rc = apply_disk_config(&dinfo, 0);
    705 
    706     if (rc) {
    707         SLOGE("Failed to apply disk configuration (%d)", rc);
    708         goto out;
    709     }
    710 
    711  out:
    712     free(pinfo->name);
    713     free(dinfo.device);
    714     free(dinfo.part_lst);
    715 
    716     return rc;
    717 }
    718