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 <android-base/stringprintf.h>
     24 #include <android-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         PLOG(ERROR) << getId() << " failed to create mount points";
    128         return -errno;
    129     }
    130 
    131     if (vfat::Mount(mDevPath, mRawPath, false, false, false,
    132             AID_MEDIA_RW, AID_MEDIA_RW, 0007, true)) {
    133         PLOG(ERROR) << getId() << " failed to mount " << mDevPath;
    134         return -EIO;
    135     }
    136 
    137     if (getMountFlags() & MountFlags::kPrimary) {
    138         initAsecStage();
    139     }
    140 
    141     if (!(getMountFlags() & MountFlags::kVisible)) {
    142         // Not visible to apps, so no need to spin up FUSE
    143         return OK;
    144     }
    145 
    146     if (fs_prepare_dir(mFuseDefault.c_str(), 0700, AID_ROOT, AID_ROOT) ||
    147             fs_prepare_dir(mFuseRead.c_str(), 0700, AID_ROOT, AID_ROOT) ||
    148             fs_prepare_dir(mFuseWrite.c_str(), 0700, AID_ROOT, AID_ROOT)) {
    149         PLOG(ERROR) << getId() << " failed to create FUSE mount points";
    150         return -errno;
    151     }
    152 
    153     dev_t before = GetDevice(mFuseWrite);
    154 
    155     if (!(mFusePid = fork())) {
    156         if (getMountFlags() & MountFlags::kPrimary) {
    157             if (execl(kFusePath, kFusePath,
    158                     "-u", "1023", // AID_MEDIA_RW
    159                     "-g", "1023", // AID_MEDIA_RW
    160                     "-U", std::to_string(getMountUserId()).c_str(),
    161                     "-w",
    162                     mRawPath.c_str(),
    163                     stableName.c_str(),
    164                     NULL)) {
    165                 PLOG(ERROR) << "Failed to exec";
    166             }
    167         } else {
    168             if (execl(kFusePath, kFusePath,
    169                     "-u", "1023", // AID_MEDIA_RW
    170                     "-g", "1023", // AID_MEDIA_RW
    171                     "-U", std::to_string(getMountUserId()).c_str(),
    172                     mRawPath.c_str(),
    173                     stableName.c_str(),
    174                     NULL)) {
    175                 PLOG(ERROR) << "Failed to exec";
    176             }
    177         }
    178 
    179         LOG(ERROR) << "FUSE exiting";
    180         _exit(1);
    181     }
    182 
    183     if (mFusePid == -1) {
    184         PLOG(ERROR) << getId() << " failed to fork";
    185         return -errno;
    186     }
    187 
    188     while (before == GetDevice(mFuseWrite)) {
    189         LOG(VERBOSE) << "Waiting for FUSE to spin up...";
    190         usleep(50000); // 50ms
    191     }
    192 
    193     return OK;
    194 }
    195 
    196 status_t PublicVolume::doUnmount() {
    197     // Unmount the storage before we kill the FUSE process. If we kill
    198     // the FUSE process first, most file system operations will return
    199     // ENOTCONN until the unmount completes. This is an exotic and unusual
    200     // error code and might cause broken behaviour in applications.
    201     KillProcessesUsingPath(getPath());
    202 
    203     ForceUnmount(kAsecPath);
    204 
    205     ForceUnmount(mFuseDefault);
    206     ForceUnmount(mFuseRead);
    207     ForceUnmount(mFuseWrite);
    208     ForceUnmount(mRawPath);
    209 
    210     if (mFusePid > 0) {
    211         kill(mFusePid, SIGTERM);
    212         TEMP_FAILURE_RETRY(waitpid(mFusePid, nullptr, 0));
    213         mFusePid = 0;
    214     }
    215 
    216     rmdir(mFuseDefault.c_str());
    217     rmdir(mFuseRead.c_str());
    218     rmdir(mFuseWrite.c_str());
    219     rmdir(mRawPath.c_str());
    220 
    221     mFuseDefault.clear();
    222     mFuseRead.clear();
    223     mFuseWrite.clear();
    224     mRawPath.clear();
    225 
    226     return OK;
    227 }
    228 
    229 status_t PublicVolume::doFormat(const std::string& fsType) {
    230     if (fsType == "vfat" || fsType == "auto") {
    231         if (WipeBlockDevice(mDevPath) != OK) {
    232             LOG(WARNING) << getId() << " failed to wipe";
    233         }
    234         if (vfat::Format(mDevPath, 0)) {
    235             LOG(ERROR) << getId() << " failed to format";
    236             return -errno;
    237         }
    238     } else {
    239         LOG(ERROR) << "Unsupported filesystem " << fsType;
    240         return -EINVAL;
    241     }
    242 
    243     return OK;
    244 }
    245 
    246 }  // namespace vold
    247 }  // namespace android
    248