2015-03-03 06:01:40 +01:00
|
|
|
/*
|
|
|
|
* Copyright (C) 2015 The Android Open Source Project
|
|
|
|
*
|
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
* you may not use this file except in compliance with the License.
|
|
|
|
* You may obtain a copy of the License at
|
|
|
|
*
|
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
*
|
|
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
* See the License for the specific language governing permissions and
|
|
|
|
* limitations under the License.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "Disk.h"
|
|
|
|
#include "PublicVolume.h"
|
2015-03-31 19:35:33 +02:00
|
|
|
#include "PrivateVolume.h"
|
2015-03-03 06:01:40 +01:00
|
|
|
#include "Utils.h"
|
|
|
|
#include "VolumeBase.h"
|
2015-03-14 00:09:20 +01:00
|
|
|
#include "VolumeManager.h"
|
|
|
|
#include "ResponseCode.h"
|
2016-08-23 21:48:50 +02:00
|
|
|
#include "Ext4Crypt.h"
|
2015-03-03 06:01:40 +01:00
|
|
|
|
2015-12-05 00:50:53 +01:00
|
|
|
#include <android-base/file.h>
|
Progress towards FBE and adoptable storage.
Offer to adopt storage devices on FBE devices, but keep it guarded
behind a system property for now, since we still need to work out key
storage details.
When migrating shared storage, leave user-specific /data/media
directories in place, since they already have the needed crypto
policies defined.
Enable journaling, quotas, and encrypt options when formatting
newly adopted devices. installd already gracefully handles older
partitions without quota enabled.
Test: cts-tradefed run commandAndExit cts-dev --abi armeabi-v7a -m CtsAppSecurityHostTestCases -t android.appsecurity.cts.AdoptableHostTest
Bug: 62290006, 36757864, 29117062, 37395736
Bug: 29923055, 25861755, 30230655, 37436961
Change-Id: Ibbeb6ec9db2394a279bbac221a2b20711d65494e
2017-06-21 21:52:23 +02:00
|
|
|
#include <android-base/properties.h>
|
2015-12-05 00:50:53 +01:00
|
|
|
#include <android-base/stringprintf.h>
|
|
|
|
#include <android-base/logging.h>
|
2015-03-03 06:01:40 +01:00
|
|
|
#include <diskconfig/diskconfig.h>
|
|
|
|
|
2015-03-31 19:35:33 +02:00
|
|
|
#include <vector>
|
2015-03-03 06:01:40 +01:00
|
|
|
#include <fcntl.h>
|
2015-03-31 06:22:07 +02:00
|
|
|
#include <inttypes.h>
|
2015-03-03 06:01:40 +01:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/stat.h>
|
2017-05-18 18:08:24 +02:00
|
|
|
#include <sys/sysmacros.h>
|
2015-03-03 06:01:40 +01:00
|
|
|
#include <sys/mount.h>
|
|
|
|
|
2015-03-16 18:35:17 +01:00
|
|
|
using android::base::ReadFileToString;
|
2015-03-31 19:35:33 +02:00
|
|
|
using android::base::WriteStringToFile;
|
2015-03-16 18:35:17 +01:00
|
|
|
using android::base::StringPrintf;
|
|
|
|
|
2015-03-03 06:01:40 +01:00
|
|
|
namespace android {
|
|
|
|
namespace vold {
|
|
|
|
|
|
|
|
static const char* kSgdiskPath = "/system/bin/sgdisk";
|
|
|
|
static const char* kSgdiskToken = " \t\n";
|
|
|
|
|
2017-03-26 06:49:13 +02:00
|
|
|
static const char* kSysfsLoopMaxMinors = "/sys/module/loop/parameters/max_part";
|
2015-03-03 06:01:40 +01:00
|
|
|
static const char* kSysfsMmcMaxMinors = "/sys/module/mmcblk/parameters/perdev_minors";
|
|
|
|
|
2017-03-26 06:49:13 +02:00
|
|
|
static const unsigned int kMajorBlockLoop = 7;
|
2015-04-20 00:55:42 +02:00
|
|
|
static const unsigned int kMajorBlockScsiA = 8;
|
|
|
|
static const unsigned int kMajorBlockScsiB = 65;
|
|
|
|
static const unsigned int kMajorBlockScsiC = 66;
|
|
|
|
static const unsigned int kMajorBlockScsiD = 67;
|
|
|
|
static const unsigned int kMajorBlockScsiE = 68;
|
|
|
|
static const unsigned int kMajorBlockScsiF = 69;
|
|
|
|
static const unsigned int kMajorBlockScsiG = 70;
|
|
|
|
static const unsigned int kMajorBlockScsiH = 71;
|
|
|
|
static const unsigned int kMajorBlockScsiI = 128;
|
|
|
|
static const unsigned int kMajorBlockScsiJ = 129;
|
|
|
|
static const unsigned int kMajorBlockScsiK = 130;
|
|
|
|
static const unsigned int kMajorBlockScsiL = 131;
|
|
|
|
static const unsigned int kMajorBlockScsiM = 132;
|
|
|
|
static const unsigned int kMajorBlockScsiN = 133;
|
|
|
|
static const unsigned int kMajorBlockScsiO = 134;
|
|
|
|
static const unsigned int kMajorBlockScsiP = 135;
|
2015-03-03 06:01:40 +01:00
|
|
|
static const unsigned int kMajorBlockMmc = 179;
|
2016-01-08 10:36:47 +01:00
|
|
|
static const unsigned int kMajorBlockExperimentalMin = 240;
|
|
|
|
static const unsigned int kMajorBlockExperimentalMax = 254;
|
2015-03-03 06:01:40 +01:00
|
|
|
|
|
|
|
static const char* kGptBasicData = "EBD0A0A2-B9E5-4433-87C0-68B6B72699C7";
|
|
|
|
static const char* kGptAndroidMeta = "19A710A2-B3CA-11E4-B026-10604B889DCF";
|
2015-04-09 06:07:21 +02:00
|
|
|
static const char* kGptAndroidExpand = "193D1EA4-B3CA-11E4-B075-10604B889DCF";
|
2015-03-03 06:01:40 +01:00
|
|
|
|
|
|
|
enum class Table {
|
|
|
|
kUnknown,
|
|
|
|
kMbr,
|
|
|
|
kGpt,
|
|
|
|
};
|
|
|
|
|
2016-01-08 10:36:47 +01:00
|
|
|
static bool isVirtioBlkDevice(unsigned int major) {
|
|
|
|
/*
|
|
|
|
* The new emulator's "ranchu" virtual board no longer includes a goldfish
|
|
|
|
* MMC-based SD card device; instead, it emulates SD cards with virtio-blk,
|
|
|
|
* which has been supported by upstream kernel and QEMU for quite a while.
|
|
|
|
* Unfortunately, the virtio-blk block device driver does not use a fixed
|
|
|
|
* major number, but relies on the kernel to assign one from a specific
|
|
|
|
* range of block majors, which are allocated for "LOCAL/EXPERIMENAL USE"
|
|
|
|
* per Documentation/devices.txt. This is true even for the latest Linux
|
|
|
|
* kernel (4.4; see init() in drivers/block/virtio_blk.c).
|
|
|
|
*
|
|
|
|
* This makes it difficult for vold to detect a virtio-blk based SD card.
|
|
|
|
* The current solution checks two conditions (both must be met):
|
|
|
|
*
|
|
|
|
* a) If the running environment is the emulator;
|
|
|
|
* b) If the major number is an experimental block device major number (for
|
|
|
|
* x86/x86_64 3.10 ranchu kernels, virtio-blk always gets major number
|
|
|
|
* 253, but it is safer to match the range than just one value).
|
|
|
|
*
|
|
|
|
* Other conditions could be used, too, e.g. the hardware name should be
|
|
|
|
* "ranchu", the device's sysfs path should end with "/block/vd[d-z]", etc.
|
|
|
|
* But just having a) and b) is enough for now.
|
|
|
|
*/
|
|
|
|
return IsRunningInEmulator() && major >= kMajorBlockExperimentalMin
|
|
|
|
&& major <= kMajorBlockExperimentalMax;
|
|
|
|
}
|
|
|
|
|
2015-04-09 06:07:21 +02:00
|
|
|
Disk::Disk(const std::string& eventPath, dev_t device,
|
|
|
|
const std::string& nickname, int flags) :
|
|
|
|
mDevice(device), mSize(-1), mNickname(nickname), mFlags(flags), mCreated(
|
|
|
|
false), mJustPartitioned(false) {
|
2015-03-14 00:09:20 +01:00
|
|
|
mId = StringPrintf("disk:%u,%u", major(device), minor(device));
|
|
|
|
mEventPath = eventPath;
|
2015-03-03 06:01:40 +01:00
|
|
|
mSysPath = StringPrintf("/sys/%s", eventPath.c_str());
|
2015-03-14 00:09:20 +01:00
|
|
|
mDevPath = StringPrintf("/dev/block/vold/%s", mId.c_str());
|
2015-03-03 06:01:40 +01:00
|
|
|
CreateDeviceNode(mDevPath, mDevice);
|
|
|
|
}
|
|
|
|
|
|
|
|
Disk::~Disk() {
|
2015-03-14 00:09:20 +01:00
|
|
|
CHECK(!mCreated);
|
2015-03-03 06:01:40 +01:00
|
|
|
DestroyDeviceNode(mDevPath);
|
|
|
|
}
|
|
|
|
|
|
|
|
std::shared_ptr<VolumeBase> Disk::findVolume(const std::string& id) {
|
2015-03-14 00:09:20 +01:00
|
|
|
for (auto vol : mVolumes) {
|
|
|
|
if (vol->getId() == id) {
|
|
|
|
return vol;
|
|
|
|
}
|
|
|
|
auto stackedVol = vol->findVolume(id);
|
|
|
|
if (stackedVol != nullptr) {
|
|
|
|
return stackedVol;
|
2015-03-03 06:01:40 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2015-06-26 23:02:09 +02:00
|
|
|
void Disk::listVolumes(VolumeBase::Type type, std::list<std::string>& list) {
|
2016-07-27 23:11:02 +02:00
|
|
|
for (const auto& vol : mVolumes) {
|
2015-06-26 23:02:09 +02:00
|
|
|
if (vol->getType() == type) {
|
|
|
|
list.push_back(vol->getId());
|
|
|
|
}
|
|
|
|
// TODO: consider looking at stacked volumes
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-03-14 00:09:20 +01:00
|
|
|
status_t Disk::create() {
|
|
|
|
CHECK(!mCreated);
|
|
|
|
mCreated = true;
|
2015-04-09 06:07:21 +02:00
|
|
|
notifyEvent(ResponseCode::DiskCreated, StringPrintf("%d", mFlags));
|
2015-03-14 00:09:20 +01:00
|
|
|
readMetadata();
|
|
|
|
readPartitions();
|
|
|
|
return OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
status_t Disk::destroy() {
|
|
|
|
CHECK(mCreated);
|
|
|
|
destroyAllVolumes();
|
|
|
|
mCreated = false;
|
2015-04-09 06:07:21 +02:00
|
|
|
notifyEvent(ResponseCode::DiskDestroyed);
|
2015-03-14 00:09:20 +01:00
|
|
|
return OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Disk::createPublicVolume(dev_t device) {
|
2015-03-31 19:35:33 +02:00
|
|
|
auto vol = std::shared_ptr<VolumeBase>(new PublicVolume(device));
|
2015-04-09 06:07:21 +02:00
|
|
|
if (mJustPartitioned) {
|
|
|
|
LOG(DEBUG) << "Device just partitioned; silently formatting";
|
|
|
|
vol->setSilent(true);
|
|
|
|
vol->create();
|
2015-05-22 07:35:42 +02:00
|
|
|
vol->format("auto");
|
2015-04-09 06:07:21 +02:00
|
|
|
vol->destroy();
|
|
|
|
vol->setSilent(false);
|
|
|
|
}
|
2015-03-14 00:09:20 +01:00
|
|
|
|
2015-03-31 19:35:33 +02:00
|
|
|
mVolumes.push_back(vol);
|
2015-04-18 02:35:20 +02:00
|
|
|
vol->setDiskId(getId());
|
2015-04-09 06:07:21 +02:00
|
|
|
vol->create();
|
2015-03-14 00:09:20 +01:00
|
|
|
}
|
|
|
|
|
2015-03-31 19:35:33 +02:00
|
|
|
void Disk::createPrivateVolume(dev_t device, const std::string& partGuid) {
|
|
|
|
std::string normalizedGuid;
|
2015-06-18 23:25:08 +02:00
|
|
|
if (NormalizeHex(partGuid, normalizedGuid)) {
|
2015-03-31 19:35:33 +02:00
|
|
|
LOG(WARNING) << "Invalid GUID " << partGuid;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string keyRaw;
|
|
|
|
if (!ReadFileToString(BuildKeyPath(normalizedGuid), &keyRaw)) {
|
|
|
|
PLOG(ERROR) << "Failed to load key for GUID " << normalizedGuid;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
LOG(DEBUG) << "Found key for GUID " << normalizedGuid;
|
|
|
|
|
|
|
|
auto vol = std::shared_ptr<VolumeBase>(new PrivateVolume(device, keyRaw));
|
2015-04-09 06:07:21 +02:00
|
|
|
if (mJustPartitioned) {
|
|
|
|
LOG(DEBUG) << "Device just partitioned; silently formatting";
|
|
|
|
vol->setSilent(true);
|
|
|
|
vol->create();
|
2015-05-22 07:35:42 +02:00
|
|
|
vol->format("auto");
|
2015-04-09 06:07:21 +02:00
|
|
|
vol->destroy();
|
|
|
|
vol->setSilent(false);
|
|
|
|
}
|
2015-03-31 19:35:33 +02:00
|
|
|
|
|
|
|
mVolumes.push_back(vol);
|
2015-04-18 02:35:20 +02:00
|
|
|
vol->setDiskId(getId());
|
2015-06-18 23:25:08 +02:00
|
|
|
vol->setPartGuid(partGuid);
|
2015-04-09 06:07:21 +02:00
|
|
|
vol->create();
|
2015-03-14 00:09:20 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void Disk::destroyAllVolumes() {
|
2016-07-27 23:11:02 +02:00
|
|
|
for (const auto& vol : mVolumes) {
|
2015-03-14 00:09:20 +01:00
|
|
|
vol->destroy();
|
|
|
|
}
|
|
|
|
mVolumes.clear();
|
|
|
|
}
|
|
|
|
|
2015-03-03 06:01:40 +01:00
|
|
|
status_t Disk::readMetadata() {
|
|
|
|
mSize = -1;
|
2015-03-14 00:09:20 +01:00
|
|
|
mLabel.clear();
|
2015-03-03 06:01:40 +01:00
|
|
|
|
2015-04-09 06:07:21 +02:00
|
|
|
int fd = open(mDevPath.c_str(), O_RDONLY | O_CLOEXEC);
|
2015-03-14 00:09:20 +01:00
|
|
|
if (fd != -1) {
|
|
|
|
if (ioctl(fd, BLKGETSIZE64, &mSize)) {
|
|
|
|
mSize = -1;
|
2015-03-03 06:01:40 +01:00
|
|
|
}
|
2015-03-14 00:09:20 +01:00
|
|
|
close(fd);
|
2015-03-03 06:01:40 +01:00
|
|
|
}
|
|
|
|
|
2016-01-08 10:36:47 +01:00
|
|
|
unsigned int majorId = major(mDevice);
|
|
|
|
switch (majorId) {
|
2017-03-26 06:49:13 +02:00
|
|
|
case kMajorBlockLoop: {
|
|
|
|
mLabel = "Virtual";
|
|
|
|
break;
|
|
|
|
}
|
2015-04-20 00:55:42 +02:00
|
|
|
case kMajorBlockScsiA: case kMajorBlockScsiB: case kMajorBlockScsiC: case kMajorBlockScsiD:
|
|
|
|
case kMajorBlockScsiE: case kMajorBlockScsiF: case kMajorBlockScsiG: case kMajorBlockScsiH:
|
|
|
|
case kMajorBlockScsiI: case kMajorBlockScsiJ: case kMajorBlockScsiK: case kMajorBlockScsiL:
|
|
|
|
case kMajorBlockScsiM: case kMajorBlockScsiN: case kMajorBlockScsiO: case kMajorBlockScsiP: {
|
2015-03-03 06:01:40 +01:00
|
|
|
std::string path(mSysPath + "/device/vendor");
|
|
|
|
std::string tmp;
|
|
|
|
if (!ReadFileToString(path, &tmp)) {
|
2015-03-14 00:09:20 +01:00
|
|
|
PLOG(WARNING) << "Failed to read vendor from " << path;
|
2015-03-03 06:01:40 +01:00
|
|
|
return -errno;
|
|
|
|
}
|
|
|
|
mLabel = tmp;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case kMajorBlockMmc: {
|
|
|
|
std::string path(mSysPath + "/device/manfid");
|
|
|
|
std::string tmp;
|
|
|
|
if (!ReadFileToString(path, &tmp)) {
|
2015-03-14 00:09:20 +01:00
|
|
|
PLOG(WARNING) << "Failed to read manufacturer from " << path;
|
2015-03-03 06:01:40 +01:00
|
|
|
return -errno;
|
|
|
|
}
|
|
|
|
uint64_t manfid = strtoll(tmp.c_str(), nullptr, 16);
|
|
|
|
// Our goal here is to give the user a meaningful label, ideally
|
|
|
|
// matching whatever is silk-screened on the card. To reduce
|
|
|
|
// user confusion, this list doesn't contain white-label manfid.
|
|
|
|
switch (manfid) {
|
|
|
|
case 0x000003: mLabel = "SanDisk"; break;
|
|
|
|
case 0x00001b: mLabel = "Samsung"; break;
|
|
|
|
case 0x000028: mLabel = "Lexar"; break;
|
|
|
|
case 0x000074: mLabel = "Transcend"; break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
default: {
|
2016-01-08 10:36:47 +01:00
|
|
|
if (isVirtioBlkDevice(majorId)) {
|
|
|
|
LOG(DEBUG) << "Recognized experimental block major ID " << majorId
|
|
|
|
<< " as virtio-blk (emulator's virtual SD card device)";
|
|
|
|
mLabel = "Virtual";
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
LOG(WARNING) << "Unsupported block major type " << majorId;
|
2015-03-03 06:01:40 +01:00
|
|
|
return -ENOTSUP;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-03-10 20:11:09 +01:00
|
|
|
notifyEvent(ResponseCode::DiskSizeChanged, StringPrintf("%" PRIu64, mSize));
|
2015-04-09 06:07:21 +02:00
|
|
|
notifyEvent(ResponseCode::DiskLabelChanged, mLabel);
|
2015-06-26 23:02:09 +02:00
|
|
|
notifyEvent(ResponseCode::DiskSysPathChanged, mSysPath);
|
2015-03-03 06:01:40 +01:00
|
|
|
return OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
status_t Disk::readPartitions() {
|
|
|
|
int8_t maxMinors = getMaxMinors();
|
|
|
|
if (maxMinors < 0) {
|
|
|
|
return -ENOTSUP;
|
|
|
|
}
|
|
|
|
|
2015-03-14 00:09:20 +01:00
|
|
|
destroyAllVolumes();
|
2015-03-03 06:01:40 +01:00
|
|
|
|
|
|
|
// Parse partition table
|
2015-04-09 06:07:21 +02:00
|
|
|
|
|
|
|
std::vector<std::string> cmd;
|
|
|
|
cmd.push_back(kSgdiskPath);
|
|
|
|
cmd.push_back("--android-dump");
|
|
|
|
cmd.push_back(mDevPath);
|
|
|
|
|
|
|
|
std::vector<std::string> output;
|
|
|
|
status_t res = ForkExecvp(cmd, output);
|
|
|
|
if (res != OK) {
|
|
|
|
LOG(WARNING) << "sgdisk failed to scan " << mDevPath;
|
2015-04-29 06:17:43 +02:00
|
|
|
notifyEvent(ResponseCode::DiskScanned);
|
2015-04-09 06:07:21 +02:00
|
|
|
mJustPartitioned = false;
|
|
|
|
return res;
|
2015-03-03 06:01:40 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
Table table = Table::kUnknown;
|
2015-03-14 00:09:20 +01:00
|
|
|
bool foundParts = false;
|
2016-07-27 23:11:02 +02:00
|
|
|
for (const auto& line : output) {
|
2015-04-09 06:07:21 +02:00
|
|
|
char* cline = (char*) line.c_str();
|
|
|
|
char* token = strtok(cline, kSgdiskToken);
|
2015-03-14 00:09:20 +01:00
|
|
|
if (token == nullptr) continue;
|
|
|
|
|
2015-03-03 06:01:40 +01:00
|
|
|
if (!strcmp(token, "DISK")) {
|
|
|
|
const char* type = strtok(nullptr, kSgdiskToken);
|
|
|
|
if (!strcmp(type, "mbr")) {
|
|
|
|
table = Table::kMbr;
|
|
|
|
} else if (!strcmp(type, "gpt")) {
|
|
|
|
table = Table::kGpt;
|
|
|
|
}
|
|
|
|
} else if (!strcmp(token, "PART")) {
|
2015-03-14 00:09:20 +01:00
|
|
|
foundParts = true;
|
2015-03-03 06:01:40 +01:00
|
|
|
int i = strtol(strtok(nullptr, kSgdiskToken), nullptr, 10);
|
|
|
|
if (i <= 0 || i > maxMinors) {
|
2015-03-14 00:09:20 +01:00
|
|
|
LOG(WARNING) << mId << " is ignoring partition " << i
|
|
|
|
<< " beyond max supported devices";
|
2015-03-03 06:01:40 +01:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
dev_t partDevice = makedev(major(mDevice), minor(mDevice) + i);
|
|
|
|
|
|
|
|
if (table == Table::kMbr) {
|
|
|
|
const char* type = strtok(nullptr, kSgdiskToken);
|
|
|
|
|
|
|
|
switch (strtol(type, nullptr, 16)) {
|
|
|
|
case 0x06: // FAT16
|
|
|
|
case 0x0b: // W95 FAT32 (LBA)
|
|
|
|
case 0x0c: // W95 FAT32 (LBA)
|
|
|
|
case 0x0e: // W95 FAT16 (LBA)
|
2015-03-14 00:09:20 +01:00
|
|
|
createPublicVolume(partDevice);
|
2015-03-03 06:01:40 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
} else if (table == Table::kGpt) {
|
|
|
|
const char* typeGuid = strtok(nullptr, kSgdiskToken);
|
|
|
|
const char* partGuid = strtok(nullptr, kSgdiskToken);
|
|
|
|
|
|
|
|
if (!strcasecmp(typeGuid, kGptBasicData)) {
|
2015-03-14 00:09:20 +01:00
|
|
|
createPublicVolume(partDevice);
|
2015-04-09 06:07:21 +02:00
|
|
|
} else if (!strcasecmp(typeGuid, kGptAndroidExpand)) {
|
2015-03-31 19:35:33 +02:00
|
|
|
createPrivateVolume(partDevice, partGuid);
|
2015-03-03 06:01:40 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Ugly last ditch effort, treat entire disk as partition
|
2015-03-14 00:09:20 +01:00
|
|
|
if (table == Table::kUnknown || !foundParts) {
|
|
|
|
LOG(WARNING) << mId << " has unknown partition table; trying entire device";
|
2015-06-26 20:16:14 +02:00
|
|
|
|
|
|
|
std::string fsType;
|
|
|
|
std::string unused;
|
|
|
|
if (ReadMetadataUntrusted(mDevPath, fsType, unused, unused) == OK) {
|
|
|
|
createPublicVolume(mDevice);
|
|
|
|
} else {
|
|
|
|
LOG(WARNING) << mId << " failed to identify, giving up";
|
|
|
|
}
|
2015-03-03 06:01:40 +01:00
|
|
|
}
|
2015-04-18 02:35:20 +02:00
|
|
|
|
2015-04-19 23:57:55 +02:00
|
|
|
notifyEvent(ResponseCode::DiskScanned);
|
2015-04-09 06:07:21 +02:00
|
|
|
mJustPartitioned = false;
|
2015-03-03 06:01:40 +01:00
|
|
|
return OK;
|
|
|
|
}
|
|
|
|
|
2015-03-31 19:35:33 +02:00
|
|
|
status_t Disk::unmountAll() {
|
2016-07-27 23:11:02 +02:00
|
|
|
for (const auto& vol : mVolumes) {
|
2015-03-31 19:35:33 +02:00
|
|
|
vol->unmount();
|
|
|
|
}
|
|
|
|
return OK;
|
|
|
|
}
|
|
|
|
|
2015-03-03 06:01:40 +01:00
|
|
|
status_t Disk::partitionPublic() {
|
2015-09-23 23:13:45 +02:00
|
|
|
int res;
|
|
|
|
|
2015-03-03 06:01:40 +01:00
|
|
|
// TODO: improve this code
|
2015-03-14 00:09:20 +01:00
|
|
|
destroyAllVolumes();
|
2015-04-09 06:07:21 +02:00
|
|
|
mJustPartitioned = true;
|
2015-03-03 06:01:40 +01:00
|
|
|
|
2015-09-23 23:13:45 +02:00
|
|
|
// First nuke any existing partition table
|
|
|
|
std::vector<std::string> cmd;
|
|
|
|
cmd.push_back(kSgdiskPath);
|
|
|
|
cmd.push_back("--zap-all");
|
|
|
|
cmd.push_back(mDevPath);
|
|
|
|
|
|
|
|
// Zap sometimes returns an error when it actually succeeded, so
|
|
|
|
// just log as warning and keep rolling forward.
|
|
|
|
if ((res = ForkExecvp(cmd)) != 0) {
|
|
|
|
LOG(WARNING) << "Failed to zap; status " << res;
|
|
|
|
}
|
|
|
|
|
2015-03-03 06:01:40 +01:00
|
|
|
struct disk_info dinfo;
|
|
|
|
memset(&dinfo, 0, sizeof(dinfo));
|
|
|
|
|
|
|
|
if (!(dinfo.part_lst = (struct part_info *) malloc(
|
|
|
|
MAX_NUM_PARTS * sizeof(struct part_info)))) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
memset(dinfo.part_lst, 0, MAX_NUM_PARTS * sizeof(struct part_info));
|
|
|
|
dinfo.device = strdup(mDevPath.c_str());
|
|
|
|
dinfo.scheme = PART_SCHEME_MBR;
|
|
|
|
dinfo.sect_size = 512;
|
|
|
|
dinfo.skip_lba = 2048;
|
|
|
|
dinfo.num_lba = 0;
|
|
|
|
dinfo.num_parts = 1;
|
|
|
|
|
|
|
|
struct part_info *pinfo = &dinfo.part_lst[0];
|
|
|
|
|
|
|
|
pinfo->name = strdup("android_sdcard");
|
|
|
|
pinfo->flags |= PART_ACTIVE_FLAG;
|
|
|
|
pinfo->type = PC_PART_TYPE_FAT32;
|
|
|
|
pinfo->len_kb = -1;
|
|
|
|
|
|
|
|
int rc = apply_disk_config(&dinfo, 0);
|
|
|
|
if (rc) {
|
2015-03-14 00:09:20 +01:00
|
|
|
LOG(ERROR) << "Failed to apply disk configuration: " << rc;
|
2015-03-03 06:01:40 +01:00
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
out:
|
|
|
|
free(pinfo->name);
|
|
|
|
free(dinfo.device);
|
|
|
|
free(dinfo.part_lst);
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
status_t Disk::partitionPrivate() {
|
2015-03-31 19:35:33 +02:00
|
|
|
return partitionMixed(0);
|
2015-03-03 06:01:40 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
status_t Disk::partitionMixed(int8_t ratio) {
|
2015-04-09 06:07:21 +02:00
|
|
|
int res;
|
2015-03-31 19:35:33 +02:00
|
|
|
|
Progress towards FBE and adoptable storage.
Offer to adopt storage devices on FBE devices, but keep it guarded
behind a system property for now, since we still need to work out key
storage details.
When migrating shared storage, leave user-specific /data/media
directories in place, since they already have the needed crypto
policies defined.
Enable journaling, quotas, and encrypt options when formatting
newly adopted devices. installd already gracefully handles older
partitions without quota enabled.
Test: cts-tradefed run commandAndExit cts-dev --abi armeabi-v7a -m CtsAppSecurityHostTestCases -t android.appsecurity.cts.AdoptableHostTest
Bug: 62290006, 36757864, 29117062, 37395736
Bug: 29923055, 25861755, 30230655, 37436961
Change-Id: Ibbeb6ec9db2394a279bbac221a2b20711d65494e
2017-06-21 21:52:23 +02:00
|
|
|
if (e4crypt_is_native()
|
|
|
|
&& !android::base::GetBoolProperty("persist.sys.adoptable_fbe", false)) {
|
2016-08-23 21:48:50 +02:00
|
|
|
LOG(ERROR) << "Private volumes not yet supported on FBE devices";
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
2015-03-14 00:09:20 +01:00
|
|
|
destroyAllVolumes();
|
2015-04-09 06:07:21 +02:00
|
|
|
mJustPartitioned = true;
|
2015-03-31 19:35:33 +02:00
|
|
|
|
|
|
|
// First nuke any existing partition table
|
|
|
|
std::vector<std::string> cmd;
|
|
|
|
cmd.push_back(kSgdiskPath);
|
|
|
|
cmd.push_back("--zap-all");
|
|
|
|
cmd.push_back(mDevPath);
|
|
|
|
|
2015-04-15 07:22:34 +02:00
|
|
|
// Zap sometimes returns an error when it actually succeeded, so
|
|
|
|
// just log as warning and keep rolling forward.
|
2015-04-09 06:07:21 +02:00
|
|
|
if ((res = ForkExecvp(cmd)) != 0) {
|
2015-04-15 07:22:34 +02:00
|
|
|
LOG(WARNING) << "Failed to zap; status " << res;
|
2015-03-31 19:35:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// We've had some success above, so generate both the private partition
|
|
|
|
// GUID and encryption key and persist them.
|
|
|
|
std::string partGuidRaw;
|
Progress towards FBE and adoptable storage.
Offer to adopt storage devices on FBE devices, but keep it guarded
behind a system property for now, since we still need to work out key
storage details.
When migrating shared storage, leave user-specific /data/media
directories in place, since they already have the needed crypto
policies defined.
Enable journaling, quotas, and encrypt options when formatting
newly adopted devices. installd already gracefully handles older
partitions without quota enabled.
Test: cts-tradefed run commandAndExit cts-dev --abi armeabi-v7a -m CtsAppSecurityHostTestCases -t android.appsecurity.cts.AdoptableHostTest
Bug: 62290006, 36757864, 29117062, 37395736
Bug: 29923055, 25861755, 30230655, 37436961
Change-Id: Ibbeb6ec9db2394a279bbac221a2b20711d65494e
2017-06-21 21:52:23 +02:00
|
|
|
if (GenerateRandomUuid(partGuidRaw) != OK) {
|
|
|
|
LOG(ERROR) << "Failed to generate GUID";
|
|
|
|
return -EIO;
|
|
|
|
}
|
|
|
|
|
2015-03-31 19:35:33 +02:00
|
|
|
std::string keyRaw;
|
Progress towards FBE and adoptable storage.
Offer to adopt storage devices on FBE devices, but keep it guarded
behind a system property for now, since we still need to work out key
storage details.
When migrating shared storage, leave user-specific /data/media
directories in place, since they already have the needed crypto
policies defined.
Enable journaling, quotas, and encrypt options when formatting
newly adopted devices. installd already gracefully handles older
partitions without quota enabled.
Test: cts-tradefed run commandAndExit cts-dev --abi armeabi-v7a -m CtsAppSecurityHostTestCases -t android.appsecurity.cts.AdoptableHostTest
Bug: 62290006, 36757864, 29117062, 37395736
Bug: 29923055, 25861755, 30230655, 37436961
Change-Id: Ibbeb6ec9db2394a279bbac221a2b20711d65494e
2017-06-21 21:52:23 +02:00
|
|
|
if (ReadRandomBytes(16, keyRaw) != OK) {
|
|
|
|
LOG(ERROR) << "Failed to generate key";
|
2015-03-31 19:35:33 +02:00
|
|
|
return -EIO;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string partGuid;
|
|
|
|
StrToHex(partGuidRaw, partGuid);
|
|
|
|
|
|
|
|
if (!WriteStringToFile(keyRaw, BuildKeyPath(partGuid))) {
|
|
|
|
LOG(ERROR) << "Failed to persist key";
|
|
|
|
return -EIO;
|
|
|
|
} else {
|
|
|
|
LOG(DEBUG) << "Persisted key for GUID " << partGuid;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Now let's build the new GPT table. We heavily rely on sgdisk to
|
|
|
|
// force optimal alignment on the created partitions.
|
|
|
|
cmd.clear();
|
|
|
|
cmd.push_back(kSgdiskPath);
|
|
|
|
|
|
|
|
// If requested, create a public partition first. Mixed-mode partitioning
|
|
|
|
// like this is an experimental feature.
|
|
|
|
if (ratio > 0) {
|
|
|
|
if (ratio < 10 || ratio > 90) {
|
|
|
|
LOG(ERROR) << "Mixed partition ratio must be between 10-90%";
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint64_t splitMb = ((mSize / 100) * ratio) / 1024 / 1024;
|
|
|
|
cmd.push_back(StringPrintf("--new=0:0:+%" PRId64 "M", splitMb));
|
|
|
|
cmd.push_back(StringPrintf("--typecode=0:%s", kGptBasicData));
|
|
|
|
cmd.push_back("--change-name=0:shared");
|
|
|
|
}
|
|
|
|
|
|
|
|
// Define a metadata partition which is designed for future use; there
|
|
|
|
// should only be one of these per physical device, even if there are
|
|
|
|
// multiple private volumes.
|
|
|
|
cmd.push_back("--new=0:0:+16M");
|
|
|
|
cmd.push_back(StringPrintf("--typecode=0:%s", kGptAndroidMeta));
|
|
|
|
cmd.push_back("--change-name=0:android_meta");
|
|
|
|
|
|
|
|
// Define a single private partition filling the rest of disk.
|
|
|
|
cmd.push_back("--new=0:0:-0");
|
2015-04-09 06:07:21 +02:00
|
|
|
cmd.push_back(StringPrintf("--typecode=0:%s", kGptAndroidExpand));
|
2015-03-31 19:35:33 +02:00
|
|
|
cmd.push_back(StringPrintf("--partition-guid=0:%s", partGuid.c_str()));
|
2015-04-09 06:07:21 +02:00
|
|
|
cmd.push_back("--change-name=0:android_expand");
|
2015-03-31 19:35:33 +02:00
|
|
|
|
|
|
|
cmd.push_back(mDevPath);
|
|
|
|
|
2015-04-09 06:07:21 +02:00
|
|
|
if ((res = ForkExecvp(cmd)) != 0) {
|
|
|
|
LOG(ERROR) << "Failed to partition; status " << res;
|
|
|
|
return res;
|
2015-03-31 19:35:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return OK;
|
2015-03-03 06:01:40 +01:00
|
|
|
}
|
|
|
|
|
2015-04-09 06:07:21 +02:00
|
|
|
void Disk::notifyEvent(int event) {
|
|
|
|
VolumeManager::Instance()->getBroadcaster()->sendBroadcast(event,
|
|
|
|
getId().c_str(), false);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Disk::notifyEvent(int event, const std::string& value) {
|
|
|
|
VolumeManager::Instance()->getBroadcaster()->sendBroadcast(event,
|
|
|
|
StringPrintf("%s %s", getId().c_str(), value.c_str()).c_str(), false);
|
|
|
|
}
|
|
|
|
|
2015-03-03 06:01:40 +01:00
|
|
|
int Disk::getMaxMinors() {
|
|
|
|
// Figure out maximum partition devices supported
|
2016-01-08 10:36:47 +01:00
|
|
|
unsigned int majorId = major(mDevice);
|
|
|
|
switch (majorId) {
|
2017-03-26 06:49:13 +02:00
|
|
|
case kMajorBlockLoop: {
|
|
|
|
std::string tmp;
|
|
|
|
if (!ReadFileToString(kSysfsLoopMaxMinors, &tmp)) {
|
|
|
|
LOG(ERROR) << "Failed to read max minors";
|
|
|
|
return -errno;
|
|
|
|
}
|
|
|
|
return atoi(tmp.c_str());
|
|
|
|
}
|
2015-04-20 00:55:42 +02:00
|
|
|
case kMajorBlockScsiA: case kMajorBlockScsiB: case kMajorBlockScsiC: case kMajorBlockScsiD:
|
|
|
|
case kMajorBlockScsiE: case kMajorBlockScsiF: case kMajorBlockScsiG: case kMajorBlockScsiH:
|
|
|
|
case kMajorBlockScsiI: case kMajorBlockScsiJ: case kMajorBlockScsiK: case kMajorBlockScsiL:
|
|
|
|
case kMajorBlockScsiM: case kMajorBlockScsiN: case kMajorBlockScsiO: case kMajorBlockScsiP: {
|
2015-03-03 06:01:40 +01:00
|
|
|
// Per Documentation/devices.txt this is static
|
|
|
|
return 15;
|
|
|
|
}
|
|
|
|
case kMajorBlockMmc: {
|
|
|
|
// Per Documentation/devices.txt this is dynamic
|
|
|
|
std::string tmp;
|
|
|
|
if (!ReadFileToString(kSysfsMmcMaxMinors, &tmp)) {
|
2015-03-14 00:09:20 +01:00
|
|
|
LOG(ERROR) << "Failed to read max minors";
|
2015-03-03 06:01:40 +01:00
|
|
|
return -errno;
|
|
|
|
}
|
|
|
|
return atoi(tmp.c_str());
|
|
|
|
}
|
2016-01-08 10:36:47 +01:00
|
|
|
default: {
|
|
|
|
if (isVirtioBlkDevice(majorId)) {
|
|
|
|
// drivers/block/virtio_blk.c has "#define PART_BITS 4", so max is
|
|
|
|
// 2^4 - 1 = 15
|
|
|
|
return 15;
|
|
|
|
}
|
|
|
|
}
|
2015-03-03 06:01:40 +01:00
|
|
|
}
|
|
|
|
|
2016-01-08 10:36:47 +01:00
|
|
|
LOG(ERROR) << "Unsupported block major type " << majorId;
|
2015-03-03 06:01:40 +01:00
|
|
|
return -ENOTSUP;
|
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace vold
|
|
|
|
} // namespace android
|