Home | History | Annotate | Download | only in vold
      1 /*
      2  * Copyright (C) 2015 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 "fs/Vfat.h"
     18 #include "PublicVolume.h"
     19 #include "Utils.h"
     20 #include "VolumeManager.h"
     21 #include "ResponseCode.h"
     22 
     23 #include <base/stringprintf.h>
     24 #include <base/logging.h>
     25 #include <cutils/fs.h>
     26 #include <private/android_filesystem_config.h>
     27 
     28 #include <fcntl.h>
     29 #include <stdlib.h>
     30 #include <sys/mount.h>
     31 #include <sys/stat.h>
     32 #include <sys/types.h>
     33 #include <sys/wait.h>
     34 
     35 using android::base::StringPrintf;
     36 
     37 namespace android {
     38 namespace vold {
     39 
     40 static const char* kFusePath = "/system/bin/sdcard";
     41 
     42 static const char* kAsecPath = "/mnt/secure/asec";
     43 
     44 PublicVolume::PublicVolume(dev_t device) :
     45         VolumeBase(Type::kPublic), mDevice(device), mFusePid(0) {
     46     setId(StringPrintf("public:%u,%u", major(device), minor(device)));
     47     mDevPath = StringPrintf("/dev/block/vold/%s", getId().c_str());
     48 }
     49 
     50 PublicVolume::~PublicVolume() {
     51 }
     52 
     53 status_t PublicVolume::readMetadata() {
     54     status_t res = ReadMetadataUntrusted(mDevPath, mFsType, mFsUuid, mFsLabel);
     55     notifyEvent(ResponseCode::VolumeFsTypeChanged, mFsType);
     56     notifyEvent(ResponseCode::VolumeFsUuidChanged, mFsUuid);
     57     notifyEvent(ResponseCode::VolumeFsLabelChanged, mFsLabel);
     58     return res;
     59 }
     60 
     61 status_t PublicVolume::initAsecStage() {
     62     std::string legacyPath(mRawPath + "/android_secure");
     63     std::string securePath(mRawPath + "/.android_secure");
     64 
     65     // Recover legacy secure path
     66     if (!access(legacyPath.c_str(), R_OK | X_OK)
     67             && access(securePath.c_str(), R_OK | X_OK)) {
     68         if (rename(legacyPath.c_str(), securePath.c_str())) {
     69             PLOG(WARNING) << getId() << " failed to rename legacy ASEC dir";
     70         }
     71     }
     72 
     73     if (TEMP_FAILURE_RETRY(mkdir(securePath.c_str(), 0700))) {
     74         if (errno != EEXIST) {
     75             PLOG(WARNING) << getId() << " creating ASEC stage failed";
     76             return -errno;
     77         }
     78     }
     79 
     80     BindMount(securePath, kAsecPath);
     81 
     82     return OK;
     83 }
     84 
     85 status_t PublicVolume::doCreate() {
     86     return CreateDeviceNode(mDevPath, mDevice);
     87 }
     88 
     89 status_t PublicVolume::doDestroy() {
     90     return DestroyDeviceNode(mDevPath);
     91 }
     92 
     93 status_t PublicVolume::doMount() {
     94     // TODO: expand to support mounting other filesystems
     95     readMetadata();
     96 
     97     if (mFsType != "vfat") {
     98         LOG(ERROR) << getId() << " unsupported filesystem " << mFsType;
     99         return -EIO;
    100     }
    101 
    102     if (vfat::Check(mDevPath)) {
    103         LOG(ERROR) << getId() << " failed filesystem check";
    104         return -EIO;
    105     }
    106 
    107     // Use UUID as stable name, if available
    108     std::string stableName = getId();
    109     if (!mFsUuid.empty()) {
    110         stableName = mFsUuid;
    111     }
    112 
    113     mRawPath = StringPrintf("/mnt/media_rw/%s", stableName.c_str());
    114 
    115     mFuseDefault = StringPrintf("/mnt/runtime/default/%s", stableName.c_str());
    116     mFuseRead = StringPrintf("/mnt/runtime/read/%s", stableName.c_str());
    117     mFuseWrite = StringPrintf("/mnt/runtime/write/%s", stableName.c_str());
    118 
    119     setInternalPath(mRawPath);
    120     if (getMountFlags() & MountFlags::kVisible) {
    121         setPath(StringPrintf("/storage/%s", stableName.c_str()));
    122     } else {
    123         setPath(mRawPath);
    124     }
    125 
    126     if (fs_prepare_dir(mRawPath.c_str(), 0700, AID_ROOT, AID_ROOT) ||
    127             fs_prepare_dir(mFuseDefault.c_str(), 0700, AID_ROOT, AID_ROOT) ||
    128             fs_prepare_dir(mFuseRead.c_str(), 0700, AID_ROOT, AID_ROOT) ||
    129             fs_prepare_dir(mFuseWrite.c_str(), 0700, AID_ROOT, AID_ROOT)) {
    130         PLOG(ERROR) << getId() << " failed to create mount points";
    131         return -errno;
    132     }
    133 
    134     if (vfat::Mount(mDevPath, mRawPath, false, false, false,
    135             AID_MEDIA_RW, AID_MEDIA_RW, 0007, true)) {
    136         PLOG(ERROR) << getId() << " failed to mount " << mDevPath;
    137         return -EIO;
    138     }
    139 
    140     if (getMountFlags() & MountFlags::kPrimary) {
    141         initAsecStage();
    142     }
    143 
    144     if (!(getMountFlags() & MountFlags::kVisible)) {
    145         // Not visible to apps, so no need to spin up FUSE
    146         return OK;
    147     }
    148 
    149     dev_t before = GetDevice(mFuseWrite);
    150 
    151     if (!(mFusePid = fork())) {
    152         if (getMountFlags() & MountFlags::kPrimary) {
    153             if (execl(kFusePath, kFusePath,
    154                     "-u", "1023", // AID_MEDIA_RW
    155                     "-g", "1023", // AID_MEDIA_RW
    156                     "-U", std::to_string(getMountUserId()).c_str(),
    157                     "-w",
    158                     mRawPath.c_str(),
    159                     stableName.c_str(),
    160                     NULL)) {
    161                 PLOG(ERROR) << "Failed to exec";
    162             }
    163         } else {
    164             if (execl(kFusePath, kFusePath,
    165                     "-u", "1023", // AID_MEDIA_RW
    166                     "-g", "1023", // AID_MEDIA_RW
    167                     "-U", std::to_string(getMountUserId()).c_str(),
    168                     mRawPath.c_str(),
    169                     stableName.c_str(),
    170                     NULL)) {
    171                 PLOG(ERROR) << "Failed to exec";
    172             }
    173         }
    174 
    175         LOG(ERROR) << "FUSE exiting";
    176         _exit(1);
    177     }
    178 
    179     if (mFusePid == -1) {
    180         PLOG(ERROR) << getId() << " failed to fork";
    181         return -errno;
    182     }
    183 
    184     while (before == GetDevice(mFuseWrite)) {
    185         LOG(VERBOSE) << "Waiting for FUSE to spin up...";
    186         usleep(50000); // 50ms
    187     }
    188 
    189     return OK;
    190 }
    191 
    192 status_t PublicVolume::doUnmount() {
    193     if (mFusePid > 0) {
    194         kill(mFusePid, SIGTERM);
    195         TEMP_FAILURE_RETRY(waitpid(mFusePid, nullptr, 0));
    196         mFusePid = 0;
    197     }
    198 
    199     ForceUnmount(kAsecPath);
    200 
    201     ForceUnmount(mFuseDefault);
    202     ForceUnmount(mFuseRead);
    203     ForceUnmount(mFuseWrite);
    204     ForceUnmount(mRawPath);
    205 
    206     rmdir(mFuseDefault.c_str());
    207     rmdir(mFuseRead.c_str());
    208     rmdir(mFuseWrite.c_str());
    209     rmdir(mRawPath.c_str());
    210 
    211     mFuseDefault.clear();
    212     mFuseRead.clear();
    213     mFuseWrite.clear();
    214     mRawPath.clear();
    215 
    216     return OK;
    217 }
    218 
    219 status_t PublicVolume::doFormat(const std::string& fsType) {
    220     if (fsType == "vfat" || fsType == "auto") {
    221         if (WipeBlockDevice(mDevPath) != OK) {
    222             LOG(WARNING) << getId() << " failed to wipe";
    223         }
    224         if (vfat::Format(mDevPath, 0)) {
    225             LOG(ERROR) << getId() << " failed to format";
    226             return -errno;
    227         }
    228     } else {
    229         LOG(ERROR) << "Unsupported filesystem " << fsType;
    230         return -EINVAL;
    231     }
    232 
    233     return OK;
    234 }
    235 
    236 }  // namespace vold
    237 }  // namespace android
    238