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