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