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 "PublicVolume.h" 18#include "Utils.h" 19#include "VolumeManager.h" 20#include "fs/Exfat.h" 21#include "fs/Vfat.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#include <utils/Timers.h> 28 29#include <fcntl.h> 30#include <stdlib.h> 31#include <sys/mount.h> 32#include <sys/stat.h> 33#include <sys/types.h> 34#include <sys/sysmacros.h> 35#include <sys/wait.h> 36 37using android::base::StringPrintf; 38 39namespace android { 40namespace vold { 41 42static const char* kFusePath = "/system/bin/sdcard"; 43 44static const char* kAsecPath = "/mnt/secure/asec"; 45 46PublicVolume::PublicVolume(dev_t device) : 47 VolumeBase(Type::kPublic), mDevice(device), mFusePid(0) { 48 setId(StringPrintf("public:%u,%u", major(device), minor(device))); 49 mDevPath = StringPrintf("/dev/block/vold/%s", getId().c_str()); 50} 51 52PublicVolume::~PublicVolume() { 53} 54 55status_t PublicVolume::readMetadata() { 56 status_t res = ReadMetadataUntrusted(mDevPath, &mFsType, &mFsUuid, &mFsLabel); 57 58 auto listener = getListener(); 59 if (listener) listener->onVolumeMetadataChanged(getId(), mFsType, mFsUuid, mFsLabel); 60 61 return res; 62} 63 64status_t PublicVolume::initAsecStage() { 65 std::string legacyPath(mRawPath + "/android_secure"); 66 std::string securePath(mRawPath + "/.android_secure"); 67 68 // Recover legacy secure path 69 if (!access(legacyPath.c_str(), R_OK | X_OK) 70 && access(securePath.c_str(), R_OK | X_OK)) { 71 if (rename(legacyPath.c_str(), securePath.c_str())) { 72 PLOG(WARNING) << getId() << " failed to rename legacy ASEC dir"; 73 } 74 } 75 76 if (TEMP_FAILURE_RETRY(mkdir(securePath.c_str(), 0700))) { 77 if (errno != EEXIST) { 78 PLOG(WARNING) << getId() << " creating ASEC stage failed"; 79 return -errno; 80 } 81 } 82 83 BindMount(securePath, kAsecPath); 84 85 return OK; 86} 87 88status_t PublicVolume::doCreate() { 89 return CreateDeviceNode(mDevPath, mDevice); 90} 91 92status_t PublicVolume::doDestroy() { 93 return DestroyDeviceNode(mDevPath); 94} 95 96status_t PublicVolume::doMount() { 97 readMetadata(); 98 99 if (mFsType == "vfat" && vfat::IsSupported()) { 100 if (vfat::Check(mDevPath)) { 101 LOG(ERROR) << getId() << " failed filesystem check"; 102 return -EIO; 103 } 104 } else if (mFsType == "exfat" && exfat::IsSupported()) { 105 if (exfat::Check(mDevPath)) { 106 LOG(ERROR) << getId() << " failed filesystem check"; 107 return -EIO; 108 } 109 } else { 110 LOG(ERROR) << getId() << " unsupported filesystem " << mFsType; 111 return -EIO; 112 } 113 114 // Use UUID as stable name, if available 115 std::string stableName = getId(); 116 if (!mFsUuid.empty()) { 117 stableName = mFsUuid; 118 } 119 120 mRawPath = StringPrintf("/mnt/media_rw/%s", stableName.c_str()); 121 122 mFuseDefault = StringPrintf("/mnt/runtime/default/%s", stableName.c_str()); 123 mFuseRead = StringPrintf("/mnt/runtime/read/%s", stableName.c_str()); 124 mFuseWrite = StringPrintf("/mnt/runtime/write/%s", stableName.c_str()); 125 126 setInternalPath(mRawPath); 127 if (getMountFlags() & MountFlags::kVisible) { 128 setPath(StringPrintf("/storage/%s", stableName.c_str())); 129 } else { 130 setPath(mRawPath); 131 } 132 133 if (fs_prepare_dir(mRawPath.c_str(), 0700, AID_ROOT, AID_ROOT)) { 134 PLOG(ERROR) << getId() << " failed to create mount points"; 135 return -errno; 136 } 137 138 if (mFsType == "vfat") { 139 if (vfat::Mount(mDevPath, mRawPath, false, false, false, AID_MEDIA_RW, AID_MEDIA_RW, 0007, 140 true)) { 141 PLOG(ERROR) << getId() << " failed to mount " << mDevPath; 142 return -EIO; 143 } 144 } else if (mFsType == "exfat") { 145 if (exfat::Mount(mDevPath, mRawPath, AID_MEDIA_RW, AID_MEDIA_RW, 0007)) { 146 PLOG(ERROR) << getId() << " failed to mount " << mDevPath; 147 return -EIO; 148 } 149 } 150 151 if (getMountFlags() & MountFlags::kPrimary) { 152 initAsecStage(); 153 } 154 155 if (!(getMountFlags() & MountFlags::kVisible)) { 156 // Not visible to apps, so no need to spin up FUSE 157 return OK; 158 } 159 160 if (fs_prepare_dir(mFuseDefault.c_str(), 0700, AID_ROOT, AID_ROOT) || 161 fs_prepare_dir(mFuseRead.c_str(), 0700, AID_ROOT, AID_ROOT) || 162 fs_prepare_dir(mFuseWrite.c_str(), 0700, AID_ROOT, AID_ROOT)) { 163 PLOG(ERROR) << getId() << " failed to create FUSE mount points"; 164 return -errno; 165 } 166 167 dev_t before = GetDevice(mFuseWrite); 168 169 if (!(mFusePid = fork())) { 170 if (getMountFlags() & MountFlags::kPrimary) { 171 if (execl(kFusePath, kFusePath, 172 "-u", "1023", // AID_MEDIA_RW 173 "-g", "1023", // AID_MEDIA_RW 174 "-U", std::to_string(getMountUserId()).c_str(), 175 "-w", 176 mRawPath.c_str(), 177 stableName.c_str(), 178 NULL)) { 179 PLOG(ERROR) << "Failed to exec"; 180 } 181 } else { 182 if (execl(kFusePath, kFusePath, 183 "-u", "1023", // AID_MEDIA_RW 184 "-g", "1023", // AID_MEDIA_RW 185 "-U", std::to_string(getMountUserId()).c_str(), 186 mRawPath.c_str(), 187 stableName.c_str(), 188 NULL)) { 189 PLOG(ERROR) << "Failed to exec"; 190 } 191 } 192 193 LOG(ERROR) << "FUSE exiting"; 194 _exit(1); 195 } 196 197 if (mFusePid == -1) { 198 PLOG(ERROR) << getId() << " failed to fork"; 199 return -errno; 200 } 201 202 nsecs_t start = systemTime(SYSTEM_TIME_BOOTTIME); 203 while (before == GetDevice(mFuseWrite)) { 204 LOG(VERBOSE) << "Waiting for FUSE to spin up..."; 205 usleep(50000); // 50ms 206 207 nsecs_t now = systemTime(SYSTEM_TIME_BOOTTIME); 208 if (nanoseconds_to_milliseconds(now - start) > 5000) { 209 LOG(WARNING) << "Timed out while waiting for FUSE to spin up"; 210 return -ETIMEDOUT; 211 } 212 } 213 /* sdcardfs will have exited already. FUSE will still be running */ 214 if (TEMP_FAILURE_RETRY(waitpid(mFusePid, nullptr, WNOHANG)) == mFusePid) 215 mFusePid = 0; 216 217 return OK; 218} 219 220status_t PublicVolume::doUnmount() { 221 // Unmount the storage before we kill the FUSE process. If we kill 222 // the FUSE process first, most file system operations will return 223 // ENOTCONN until the unmount completes. This is an exotic and unusual 224 // error code and might cause broken behaviour in applications. 225 KillProcessesUsingPath(getPath()); 226 227 ForceUnmount(kAsecPath); 228 229 ForceUnmount(mFuseDefault); 230 ForceUnmount(mFuseRead); 231 ForceUnmount(mFuseWrite); 232 ForceUnmount(mRawPath); 233 234 if (mFusePid > 0) { 235 kill(mFusePid, SIGTERM); 236 TEMP_FAILURE_RETRY(waitpid(mFusePid, nullptr, 0)); 237 mFusePid = 0; 238 } 239 240 rmdir(mFuseDefault.c_str()); 241 rmdir(mFuseRead.c_str()); 242 rmdir(mFuseWrite.c_str()); 243 rmdir(mRawPath.c_str()); 244 245 mFuseDefault.clear(); 246 mFuseRead.clear(); 247 mFuseWrite.clear(); 248 mRawPath.clear(); 249 250 return OK; 251} 252 253status_t PublicVolume::doFormat(const std::string& fsType) { 254 if ((fsType == "vfat" || fsType == "auto") && vfat::IsSupported()) { 255 if (WipeBlockDevice(mDevPath) != OK) { 256 LOG(WARNING) << getId() << " failed to wipe"; 257 } 258 if (vfat::Format(mDevPath, 0)) { 259 LOG(ERROR) << getId() << " failed to format"; 260 return -errno; 261 } 262 } else if ((fsType == "exfat" || fsType == "auto") && exfat::IsSupported()) { 263 if (WipeBlockDevice(mDevPath) != OK) { 264 LOG(WARNING) << getId() << " failed to wipe"; 265 } 266 if (exfat::Format(mDevPath)) { 267 LOG(ERROR) << getId() << " failed to format"; 268 return -errno; 269 } 270 } else { 271 LOG(ERROR) << "Unsupported filesystem " << fsType; 272 return -EINVAL; 273 } 274 275 return OK; 276} 277 278} // namespace vold 279} // namespace android 280