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