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 35using android::base::StringPrintf; 36 37namespace android { 38namespace vold { 39 40static const char* kFusePath = "/system/bin/sdcard"; 41 42static const char* kAsecPath = "/mnt/secure/asec"; 43 44PublicVolume::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 50PublicVolume::~PublicVolume() { 51} 52 53status_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 61status_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 85status_t PublicVolume::doCreate() { 86 return CreateDeviceNode(mDevPath, mDevice); 87} 88 89status_t PublicVolume::doDestroy() { 90 return DestroyDeviceNode(mDevPath); 91} 92 93status_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 196status_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 229status_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