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/Ext4.h" 18#include "fs/F2fs.h" 19#include "PrivateVolume.h" 20#include "EmulatedVolume.h" 21#include "Utils.h" 22#include "VolumeManager.h" 23#include "ResponseCode.h" 24#include "cryptfs.h" 25 26#include <android-base/stringprintf.h> 27#include <android-base/logging.h> 28#include <cutils/fs.h> 29#include <private/android_filesystem_config.h> 30 31#include <fcntl.h> 32#include <stdlib.h> 33#include <sys/mount.h> 34#include <sys/stat.h> 35#include <sys/types.h> 36#include <sys/wait.h> 37#include <sys/param.h> 38 39using android::base::StringPrintf; 40 41namespace android { 42namespace vold { 43 44static const unsigned int kMajorBlockMmc = 179; 45 46PrivateVolume::PrivateVolume(dev_t device, const std::string& keyRaw) : 47 VolumeBase(Type::kPrivate), mRawDevice(device), mKeyRaw(keyRaw) { 48 setId(StringPrintf("private:%u,%u", major(device), minor(device))); 49 mRawDevPath = StringPrintf("/dev/block/vold/%s", getId().c_str()); 50} 51 52PrivateVolume::~PrivateVolume() { 53} 54 55status_t PrivateVolume::readMetadata() { 56 status_t res = ReadMetadata(mDmDevPath, mFsType, mFsUuid, mFsLabel); 57 notifyEvent(ResponseCode::VolumeFsTypeChanged, mFsType); 58 notifyEvent(ResponseCode::VolumeFsUuidChanged, mFsUuid); 59 notifyEvent(ResponseCode::VolumeFsLabelChanged, mFsLabel); 60 return res; 61} 62 63status_t PrivateVolume::doCreate() { 64 if (CreateDeviceNode(mRawDevPath, mRawDevice)) { 65 return -EIO; 66 } 67 68 // Recover from stale vold by tearing down any old mappings 69 cryptfs_revert_ext_volume(getId().c_str()); 70 71 // TODO: figure out better SELinux labels for private volumes 72 73 unsigned char* key = (unsigned char*) mKeyRaw.data(); 74 char crypto_blkdev[MAXPATHLEN]; 75 int res = cryptfs_setup_ext_volume(getId().c_str(), mRawDevPath.c_str(), 76 key, mKeyRaw.size(), crypto_blkdev); 77 mDmDevPath = crypto_blkdev; 78 if (res != 0) { 79 PLOG(ERROR) << getId() << " failed to setup cryptfs"; 80 return -EIO; 81 } 82 83 return OK; 84} 85 86status_t PrivateVolume::doDestroy() { 87 if (cryptfs_revert_ext_volume(getId().c_str())) { 88 LOG(ERROR) << getId() << " failed to revert cryptfs"; 89 } 90 return DestroyDeviceNode(mRawDevPath); 91} 92 93status_t PrivateVolume::doMount() { 94 if (readMetadata()) { 95 LOG(ERROR) << getId() << " failed to read metadata"; 96 return -EIO; 97 } 98 99 mPath = StringPrintf("/mnt/expand/%s", mFsUuid.c_str()); 100 setPath(mPath); 101 102 if (PrepareDir(mPath, 0700, AID_ROOT, AID_ROOT)) { 103 PLOG(ERROR) << getId() << " failed to create mount point " << mPath; 104 return -EIO; 105 } 106 107 if (mFsType == "ext4") { 108 int res = ext4::Check(mDmDevPath, mPath); 109 if (res == 0 || res == 1) { 110 LOG(DEBUG) << getId() << " passed filesystem check"; 111 } else { 112 PLOG(ERROR) << getId() << " failed filesystem check"; 113 return -EIO; 114 } 115 116 if (ext4::Mount(mDmDevPath, mPath, false, false, true)) { 117 PLOG(ERROR) << getId() << " failed to mount"; 118 return -EIO; 119 } 120 121 } else if (mFsType == "f2fs") { 122 int res = f2fs::Check(mDmDevPath); 123 if (res == 0) { 124 LOG(DEBUG) << getId() << " passed filesystem check"; 125 } else { 126 PLOG(ERROR) << getId() << " failed filesystem check"; 127 return -EIO; 128 } 129 130 if (f2fs::Mount(mDmDevPath, mPath)) { 131 PLOG(ERROR) << getId() << " failed to mount"; 132 return -EIO; 133 } 134 135 } else { 136 LOG(ERROR) << getId() << " unsupported filesystem " << mFsType; 137 return -EIO; 138 } 139 140 RestoreconRecursive(mPath); 141 142 // Verify that common directories are ready to roll 143 if (PrepareDir(mPath + "/app", 0771, AID_SYSTEM, AID_SYSTEM) || 144 PrepareDir(mPath + "/user", 0711, AID_SYSTEM, AID_SYSTEM) || 145 PrepareDir(mPath + "/user_de", 0711, AID_SYSTEM, AID_SYSTEM) || 146 PrepareDir(mPath + "/media", 0770, AID_MEDIA_RW, AID_MEDIA_RW) || 147 PrepareDir(mPath + "/media/0", 0770, AID_MEDIA_RW, AID_MEDIA_RW) || 148 PrepareDir(mPath + "/local", 0751, AID_ROOT, AID_ROOT) || 149 PrepareDir(mPath + "/local/tmp", 0771, AID_SHELL, AID_SHELL)) { 150 PLOG(ERROR) << getId() << " failed to prepare"; 151 return -EIO; 152 } 153 154 // Create a new emulated volume stacked above us, it will automatically 155 // be destroyed during unmount 156 std::string mediaPath(mPath + "/media"); 157 auto vol = std::shared_ptr<VolumeBase>( 158 new EmulatedVolume(mediaPath, mRawDevice, mFsUuid)); 159 addVolume(vol); 160 vol->create(); 161 162 return OK; 163} 164 165status_t PrivateVolume::doUnmount() { 166 ForceUnmount(mPath); 167 168 if (TEMP_FAILURE_RETRY(rmdir(mPath.c_str()))) { 169 PLOG(ERROR) << getId() << " failed to rmdir mount point " << mPath; 170 } 171 172 return OK; 173} 174 175status_t PrivateVolume::doFormat(const std::string& fsType) { 176 std::string resolvedFsType = fsType; 177 if (fsType == "auto") { 178 // For now, assume that all MMC devices are flash-based SD cards, and 179 // give everyone else ext4 because sysfs rotational isn't reliable. 180 if ((major(mRawDevice) == kMajorBlockMmc) && f2fs::IsSupported()) { 181 resolvedFsType = "f2fs"; 182 } else { 183 resolvedFsType = "ext4"; 184 } 185 LOG(DEBUG) << "Resolved auto to " << resolvedFsType; 186 } 187 188 if (resolvedFsType == "ext4") { 189 // TODO: change reported mountpoint once we have better selinux support 190 if (ext4::Format(mDmDevPath, 0, "/data")) { 191 PLOG(ERROR) << getId() << " failed to format"; 192 return -EIO; 193 } 194 } else if (resolvedFsType == "f2fs") { 195 if (f2fs::Format(mDmDevPath)) { 196 PLOG(ERROR) << getId() << " failed to format"; 197 return -EIO; 198 } 199 } else { 200 LOG(ERROR) << getId() << " unsupported filesystem " << fsType; 201 return -EINVAL; 202 } 203 204 return OK; 205} 206 207} // namespace vold 208} // namespace android 209