Merge changes from topic "libdm"

am: b066bbebd1

Change-Id: I2e7c1c71c9c7e25797a79702ceeafe756f457d26
This commit is contained in:
Sandeep Patil 2018-06-13 16:41:51 -07:00 committed by android-build-merger
commit ee888fe1d3
10 changed files with 903 additions and 0 deletions

View file

@ -56,12 +56,15 @@ cc_library_static {
"libselinux",
"libavb",
"libfstab",
"libdm",
],
export_static_lib_headers: [
"libfstab",
"libdm",
],
whole_static_libs: [
"liblogwrap",
"libdm",
"libfstab",
],
cppflags: [

37
fs_mgr/libdm/Android.bp Normal file
View file

@ -0,0 +1,37 @@
//
// Copyright (C) 2018 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.
//
cc_library_static {
name: "libdm",
recovery_available: true,
export_include_dirs: ["include"],
cflags: [
// TODO(b/110035986): Allows us to create a skeleton of required classes
"-Wno-unused-private-field",
],
srcs: [
"dm_table.cpp",
"dm_target.cpp",
"dm.cpp"
],
header_libs: [
"libbase_headers",
"liblog_headers",
],
}

270
fs_mgr/libdm/dm.cpp Normal file
View file

@ -0,0 +1,270 @@
/*
* Copyright (C) 2018 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 <errno.h>
#include <fcntl.h>
#include <linux/dm-ioctl.h>
#include <stdint.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <unistd.h>
#include <memory>
#include <string>
#include <vector>
#include <android-base/logging.h>
#include <android-base/macros.h>
#include <android-base/unique_fd.h>
#include "dm.h"
namespace android {
namespace dm {
DeviceMapper& DeviceMapper::Instance() {
static DeviceMapper instance;
return instance;
}
// Creates a new device mapper device
bool DeviceMapper::CreateDevice(const std::string& name) {
if (name.empty()) {
LOG(ERROR) << "Unnamed device mapper device creation is not supported";
return false;
}
if (name.size() >= DM_NAME_LEN) {
LOG(ERROR) << "[" << name << "] is too long to be device mapper name";
return false;
}
std::unique_ptr<struct dm_ioctl, decltype(&free)> io(
static_cast<struct dm_ioctl*>(malloc(sizeof(struct dm_ioctl))), free);
if (io == nullptr) {
LOG(ERROR) << "Failed to allocate dm_ioctl";
return false;
}
InitIo(io.get(), name);
if (ioctl(fd_, DM_DEV_CREATE, io.get())) {
PLOG(ERROR) << "DM_DEV_CREATE failed to create [" << name << "]";
return false;
}
// Check to make sure the newly created device doesn't already have targets
// added or opened by someone
CHECK(io->target_count == 0) << "Unexpected targets for newly created [" << name << "] device";
CHECK(io->open_count == 0) << "Unexpected opens for newly created [" << name << "] device";
// Creates a new device mapper device with the name passed in
return true;
}
bool DeviceMapper::DeleteDevice(const std::string& name) {
if (name.empty()) {
LOG(ERROR) << "Unnamed device mapper device creation is not supported";
return false;
}
if (name.size() >= DM_NAME_LEN) {
LOG(ERROR) << "[" << name << "] is too long to be device mapper name";
return false;
}
std::unique_ptr<struct dm_ioctl, decltype(&free)> io(
static_cast<struct dm_ioctl*>(malloc(sizeof(struct dm_ioctl))), free);
if (io == nullptr) {
LOG(ERROR) << "Failed to allocate dm_ioctl";
return false;
}
InitIo(io.get(), name);
if (ioctl(fd_, DM_DEV_REMOVE, io.get())) {
PLOG(ERROR) << "DM_DEV_REMOVE failed to create [" << name << "]";
return false;
}
// Check to make sure appropriate uevent is generated so ueventd will
// do the right thing and remove the corresponding device node and symlinks.
CHECK(io->flags & DM_UEVENT_GENERATED_FLAG)
<< "Didn't generate uevent for [" << name << "] removal";
return true;
}
const std::unique_ptr<DmTable> DeviceMapper::table(const std::string& /* name */) const {
// TODO(b/110035986): Return the table, as read from the kernel instead
return nullptr;
}
DmDeviceState DeviceMapper::state(const std::string& /* name */) const {
// TODO(b/110035986): Return the state, as read from the kernel instead
return DmDeviceState::INVALID;
}
bool DeviceMapper::LoadTableAndActivate(const std::string& /* name */, const DmTable& /* table */) {
return false;
}
// Reads all the available device mapper targets and their corresponding
// versions from the kernel and returns in a vector
bool DeviceMapper::GetAvailableTargets(std::vector<DmTarget>* targets) {
targets->clear();
// calculate the space needed to read a maximum of kMaxPossibleDmTargets
uint32_t payload_size = sizeof(struct dm_target_versions);
payload_size += DM_MAX_TYPE_NAME;
// device mapper wants every target spec to be aligned at 8-byte boundary
payload_size = DM_ALIGN(payload_size);
payload_size *= kMaxPossibleDmTargets;
uint32_t data_size = sizeof(struct dm_ioctl) + payload_size;
auto buffer = std::unique_ptr<void, void (*)(void*)>(calloc(1, data_size), free);
if (buffer == nullptr) {
LOG(ERROR) << "failed to allocate memory";
return false;
}
// Sets appropriate data size and data_start to make sure we tell kernel
// about the total size of the buffer we are passing and where to start
// writing the list of targets.
struct dm_ioctl* io = reinterpret_cast<struct dm_ioctl*>(buffer.get());
InitIo(io);
io->data_size = data_size;
io->data_start = sizeof(*io);
if (ioctl(fd_, DM_LIST_VERSIONS, io)) {
PLOG(ERROR) << "Failed to get DM_LIST_VERSIONS from kernel";
return false;
}
// If the provided buffer wasn't enough to list all targets, note that
// any data beyond sizeof(*io) must not be read in this case
if (io->flags & DM_BUFFER_FULL_FLAG) {
LOG(INFO) << data_size << " is not enough memory to list all dm targets";
return false;
}
// if there are no targets registered, return success with empty vector
if (io->data_size == sizeof(*io)) {
return true;
}
// Parse each target and list the name and version
// TODO(b/110035986): Templatize this
uint32_t next = sizeof(*io);
data_size = io->data_size - next;
struct dm_target_versions* vers =
reinterpret_cast<struct dm_target_versions*>(static_cast<char*>(buffer.get()) + next);
while (next && data_size) {
targets->emplace_back((vers));
if (vers->next == 0) {
break;
}
next += vers->next;
data_size -= vers->next;
vers = reinterpret_cast<struct dm_target_versions*>(static_cast<char*>(buffer.get()) + next);
}
return true;
}
bool DeviceMapper::GetAvailableDevices(std::vector<DmBlockDevice>* devices) {
devices->clear();
// calculate the space needed to read a maximum of 256 targets, each with
// name with maximum length of 16 bytes
uint32_t payload_size = sizeof(struct dm_name_list);
// 128-bytes for the name
payload_size += DM_NAME_LEN;
// dm wants every device spec to be aligned at 8-byte boundary
payload_size = DM_ALIGN(payload_size);
payload_size *= kMaxPossibleDmDevices;
uint32_t data_size = sizeof(struct dm_ioctl) + payload_size;
auto buffer = std::unique_ptr<void, void (*)(void*)>(calloc(1, data_size), free);
if (buffer == nullptr) {
LOG(ERROR) << "failed to allocate memory";
return false;
}
// Sets appropriate data size and data_start to make sure we tell kernel
// about the total size of the buffer we are passing and where to start
// writing the list of targets.
struct dm_ioctl* io = reinterpret_cast<struct dm_ioctl*>(buffer.get());
InitIo(io);
io->data_size = data_size;
io->data_start = sizeof(*io);
if (ioctl(fd_, DM_LIST_DEVICES, io)) {
PLOG(ERROR) << "Failed to get DM_LIST_DEVICES from kernel";
return false;
}
// If the provided buffer wasn't enough to list all devices any data
// beyond sizeof(*io) must not be read.
if (io->flags & DM_BUFFER_FULL_FLAG) {
LOG(INFO) << data_size << " is not enough memory to list all dm devices";
return false;
}
// if there are no devices created yet, return success with empty vector
if (io->data_size == sizeof(*io)) {
return true;
}
// Parse each device and add a new DmBlockDevice to the vector
// created from the kernel data.
uint32_t next = sizeof(*io);
data_size = io->data_size - next;
struct dm_name_list* dm_dev =
reinterpret_cast<struct dm_name_list*>(static_cast<char*>(buffer.get()) + next);
while (next && data_size) {
devices->emplace_back((dm_dev));
if (dm_dev->next == 0) {
break;
}
next += dm_dev->next;
data_size -= dm_dev->next;
dm_dev = reinterpret_cast<struct dm_name_list*>(static_cast<char*>(buffer.get()) + next);
}
return true;
}
// Accepts a device mapper device name (like system_a, vendor_b etc) and
// returns the path to it's device node (or symlink to the device node)
std::string DeviceMapper::GetDmDevicePathByName(const std::string& /* name */) {
return "";
}
// private methods of DeviceMapper
void DeviceMapper::InitIo(struct dm_ioctl* io, const std::string& name) const {
CHECK(io != nullptr) << "nullptr passed to dm_ioctl initialization";
memset(io, 0, sizeof(*io));
io->version[0] = DM_VERSION0;
io->version[1] = DM_VERSION1;
io->version[2] = DM_VERSION2;
io->data_size = sizeof(*io);
io->data_start = 0;
if (!name.empty()) {
strlcpy(io->name, name.c_str(), sizeof(io->name));
}
}
} // namespace dm
} // namespace android

55
fs_mgr/libdm/dm_table.cpp Normal file
View file

@ -0,0 +1,55 @@
/*
* Copyright (C) 2018 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 <android-base/logging.h>
#include <android-base/macros.h>
#include <string>
#include <vector>
#include "dm_table.h"
namespace android {
namespace dm {
bool DmTable::AddTarget(std::unique_ptr<DmTarget>&& /* target */) {
return true;
}
bool DmTable::RemoveTarget(std::unique_ptr<DmTarget>&& /* target */) {
return true;
}
bool DmTable::valid() const {
return true;
}
uint64_t DmTable::size() const {
return valid() ? size_ : 0;
}
// Returns a string represnetation of the table that is ready to be passed
// down to the kernel for loading
//
// Implementation must verify there are no gaps in the table, table starts
// with sector == 0, and iterate over each target to get its table
// serialized.
std::string DmTable::Serialize() const {
return "";
}
} // namespace dm
} // namespace android

View file

@ -0,0 +1,29 @@
/*
* Copyright (C) 2018 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 <android-base/logging.h>
#include <android-base/macros.h>
#include <stdint.h>
#include <string>
#include <vector>
#include "dm_target.h"
namespace android {
namespace dm {} // namespace dm
} // namespace android

152
fs_mgr/libdm/include/dm.h Normal file
View file

@ -0,0 +1,152 @@
/*
* Copyright 2018 Google, Inc
*
* 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.
*/
#ifndef _LIBDM_DM_H_
#define _LIBDM_DM_H_
#include <errno.h>
#include <fcntl.h>
#include <linux/dm-ioctl.h>
#include <linux/kdev_t.h>
#include <sys/sysmacros.h>
#include <unistd.h>
#include <memory>
#include <android-base/logging.h>
#include <dm_table.h>
// The minimum expected device mapper major.minor version
#define DM_VERSION0 (4)
#define DM_VERSION1 (0)
#define DM_VERSION2 (0)
#define DM_ALIGN_MASK (7)
#define DM_ALIGN(x) ((x + DM_ALIGN_MASK) & ~DM_ALIGN_MASK)
namespace android {
namespace dm {
enum class DmDeviceState { INVALID, SUSPENDED, ACTIVE };
class DeviceMapper final {
public:
class DmBlockDevice final {
public:
// only allow creating this with dm_name_list
DmBlockDevice() = delete;
explicit DmBlockDevice(struct dm_name_list* d) : name_(d->name), dev_(d->dev){};
// Returs device mapper name associated with the block device
const std::string& name() const { return name_; }
// Return major number for the block device
uint32_t Major() const { return major(dev_); }
// Return minor number for the block device
uint32_t Minor() const { return minor(dev_); }
~DmBlockDevice() = default;
private:
std::string name_;
uint64_t dev_;
};
// Creates a device mapper device with given name.
// Return 'true' on success and 'false' on failure to
// create OR if a device mapper device with the same name already
// exists.
// TODO(b/110035986): Make this method private and to be only
// called through LoadTableAndActivate() below.
bool CreateDevice(const std::string& name);
// Removes a device mapper device with the given name.
// Returns 'true' on success, false otherwise.
bool DeleteDevice(const std::string& name);
// Reads the device mapper table from the device with given anme and
// returns it in a DmTable object.
const std::unique_ptr<DmTable> table(const std::string& name) const;
// Returns the current state of the underlying device mapper device
// with given name.
// One of INVALID, SUSPENDED or ACTIVE.
DmDeviceState state(const std::string& name) const;
// Loads the device mapper table from parameter into the underlying
// device mapper device with given name and activate / resumes the device in the process.
// If a device mapper device with the 'name', doesn't exist, it will be created.
// Returns 'true' on success, false otherwise.
bool LoadTableAndActivate(const std::string& name, const DmTable& table);
// Returns true if a list of available device mapper targets registered in the kernel was
// successfully read and stored in 'targets'. Returns 'false' otherwise.
bool GetAvailableTargets(std::vector<DmTarget>* targets);
// Return 'true' if it can successfully read the list of device mapper block devices
// currently created. 'devices' will be empty if the kernel interactions
// were successful and there are no block devices at the moment. Returns
// 'false' in case of any failure along the way.
bool GetAvailableDevices(std::vector<DmBlockDevice>* devices);
// Returns the path to the device mapper device node in '/dev' corresponding to
// 'name'.
std::string GetDmDevicePathByName(const std::string& name);
// The only way to create a DeviceMapper object.
static DeviceMapper& Instance();
~DeviceMapper() {
if (fd_ != -1) {
::close(fd_);
}
}
private:
// Maximum possible device mapper targets registered in the kernel.
// This is only used to read the list of targets from kernel so we allocate
// a finite amount of memory. This limit is in no way enforced by the kernel.
static constexpr uint32_t kMaxPossibleDmTargets = 256;
// Maximum possible device mapper created block devices. Note that this is restricted by
// the minor numbers (that used to be 8 bits) that can be range from 0 to 2^20-1 in newer
// kernels. In Android systems however, we never expect these to grow beyond the artificial
// limit we are imposing here of 256.
static constexpr uint32_t kMaxPossibleDmDevices = 256;
void InitIo(struct dm_ioctl* io, const std::string& name = std::string()) const;
DeviceMapper() : fd_(-1) {
fd_ = TEMP_FAILURE_RETRY(open("/dev/device-mapper", O_RDWR | O_CLOEXEC));
if (fd_ < 0) {
PLOG(ERROR) << "Failed to open device-mapper";
}
}
int fd_;
// Non-copyable & Non-movable
DeviceMapper(const DeviceMapper&) = delete;
DeviceMapper& operator=(const DeviceMapper&) = delete;
DeviceMapper& operator=(DeviceMapper&&) = delete;
DeviceMapper(DeviceMapper&&) = delete;
};
} // namespace dm
} // namespace android
#endif /* _LIBDM_DM_H_ */

View file

@ -0,0 +1,75 @@
/*
* Copyright 2018 Google, Inc
*
* 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.
*/
#ifndef _LIBDM_DMTABLE_H_
#define _LIBDM_DMTABLE_H_
#include <stdint.h>
#include <memory>
#include <string>
#include <vector>
#include "dm_target.h"
namespace android {
namespace dm {
class DmTable {
public:
DmTable() : size_(0){};
// Adds a target to the device mapper table for a range specified in the target object.
// The function will return 'true' if the target was successfully added and doesn't overlap with
// any of the existing targets in the table. Gaps are allowed. The final check, including
// overlaps and gaps are done before loading the table. Returns 'false' on failure.
bool AddTarget(std::unique_ptr<DmTarget>&& target);
// Removes a target from the table for the range specified in the target object. Returns 'false'
// if the target name doesn't match with the one in the table. Returns 'true' if target is
// successfully removed.
bool RemoveTarget(std::unique_ptr<DmTarget>&& target);
// Checks the table to make sure it is valid. i.e. Checks for range overlaps, range gaps
// and returns 'true' if the table is ready to be loaded into kernel. Returns 'false' if the
// table is malformed.
bool valid() const;
// Returns the total size represented by the table in terms of number of 512-byte sectors.
// NOTE: This function will overlook if there are any gaps in the targets added in the table.
uint64_t size() const;
// Returns the string represntation of the table that is ready to be passed into the kernel
// as part of the DM_TABLE_LOAD ioctl.
std::string Serialize() const;
~DmTable() = default;
private:
// list of targets defined in this table sorted by
// their start and end sectors.
// Note: Overlapping targets MUST never be added in this list.
std::vector<std::unique_ptr<DmTarget>> targets_;
// Total size in terms of # of sectors, as calculated by looking at the last and the first
// target in 'target_'.
uint64_t size_;
};
} // namespace dm
} // namespace android
#endif /* _LIBDM_DMTABLE_H_ */

View file

@ -0,0 +1,77 @@
/*
* Copyright 2018 Google, Inc
*
* 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.
*/
#ifndef _LIBDM_DMTARGET_H_
#define _LIBDM_DMTARGET_H_
#include <linux/dm-ioctl.h>
#include <stdint.h>
#include <android-base/logging.h>
#include <string>
namespace android {
namespace dm {
class DmTarget {
public:
DmTarget(const std::string& name, uint64_t start = 0, uint64_t length = 0)
: name_(name), v0_(0), v1_(0), v2_(0), start_(start), length_(length){};
// Creates a DmTarget object from dm_target_version as read from kernel
// with DM_LIST_VERSION ioctl.
DmTarget(const struct dm_target_versions* vers) : start_(0), length_(0) {
CHECK(vers != nullptr) << "Can't create DmTarget with dm_target_versions set to nullptr";
v0_ = vers->version[0];
v1_ = vers->version[1];
v2_ = vers->version[2];
name_ = vers->name;
}
virtual ~DmTarget() = default;
// Returns name of the target.
const std::string& name() const { return name_; }
// Returns size in number of sectors when this target is part of
// a DmTable, return 0 otherwise.
uint64_t size() const { return length_; }
// Return string representation of the device mapper target version.
std::string version() const {
return std::to_string(v0_) + "." + std::to_string(v1_) + "." + std::to_string(v2_);
}
// Function that converts this object to a string of arguments that can
// be passed to the kernel for adding this target in a table. Each target (e.g. verity, linear)
// must implement this, for it to be used on a device.
virtual std::string Serialize() const { return ""; }
private:
// Name of the target.
std::string name_;
// Target version.
uint32_t v0_, v1_, v2_;
// logical sector number start and total length (in terms of 512-byte sectors) represented
// by this target within a DmTable.
uint64_t start_, length_;
};
} // namespace dm
} // namespace android
#endif /* _LIBDM_DMTARGET_H_ */

31
fs_mgr/tools/Android.bp Normal file
View file

@ -0,0 +1,31 @@
//
// Copyright (C) 2018 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.
//
cc_binary {
name: "dmctl",
srcs: ["dmctl.cpp"],
static_libs: [
"libfs_mgr",
],
shared_libs: [
"libbase",
"liblog",
],
cflags: ["-Werror"],
}

174
fs_mgr/tools/dmctl.cpp Normal file
View file

@ -0,0 +1,174 @@
/*
* Copyright (C) 2018 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 <errno.h>
#include <fcntl.h>
#include <getopt.h>
#include <linux/dm-ioctl.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <unistd.h>
#include <android-base/unique_fd.h>
#include <dm.h>
#include <functional>
#include <iomanip>
#include <ios>
#include <iostream>
#include <map>
#include <string>
#include <vector>
using DeviceMapper = ::android::dm::DeviceMapper;
using DmTarget = ::android::dm::DmTarget;
using DmBlockDevice = ::android::dm::DeviceMapper::DmBlockDevice;
static int Usage(void) {
std::cerr << "usage: dmctl <command> [command options]";
std::cerr << "commands:";
std::cerr << " create <dm-name> [dm-target> [-lo <filename>] <dm-target-args>]";
std::cerr, " delete <dm-name>";
std::cerr, " list <devices | targets>";
std::cerr, " help";
return -EINVAL;
}
static int DmCreateCmdHandler(int argc, char** argv) {
if (argc < 1) {
std::cerr << "DmCreateCmdHandler: atleast 'name' MUST be provided for target device";
return -EINVAL;
}
std::string name = argv[0];
DeviceMapper& dm = DeviceMapper::Instance();
if (!dm.CreateDevice(name)) {
std::cerr << "DmCreateCmdHandler: Failed to create " << name << " device";
return -EIO;
}
// if we also have target specified
if (argc > 1) {
// fall through for now. This will eventually create a DmTarget() based on the target name
// passing it the table that is specified at the command line
}
return 0;
}
static int DmDeleteCmdHandler(int argc, char** argv) {
if (argc < 1) {
std::cerr << "DmCreateCmdHandler: atleast 'name' MUST be provided for target device";
return -EINVAL;
}
std::string name = argv[0];
DeviceMapper& dm = DeviceMapper::Instance();
if (!dm.DeleteDevice(name)) {
std::cerr << "DmCreateCmdHandler: Failed to create " << name << " device";
return -EIO;
}
return 0;
}
static int DmListTargets(DeviceMapper& dm) {
std::vector<DmTarget> targets;
if (!dm.GetAvailableTargets(&targets)) {
std::cerr << "Failed to read available device mapper targets" << std::endl;
return -errno;
}
std::cout << "Available Device Mapper Targets:" << std::endl;
if (targets.empty()) {
std::cout << " <empty>" << std::endl;
return 0;
}
for (const auto& target : targets) {
std::cout << std::left << std::setw(20) << target.name() << " : " << target.version()
<< std::endl;
}
return 0;
}
static int DmListDevices(DeviceMapper& dm) {
std::vector<DmBlockDevice> devices;
if (!dm.GetAvailableDevices(&devices)) {
std::cerr << "Failed to read available device mapper devices" << std::endl;
return -errno;
}
std::cout << "Available Device Mapper Devices:" << std::endl;
if (devices.empty()) {
std::cout << " <empty>" << std::endl;
return 0;
}
for (const auto& dev : devices) {
std::cout << std::left << std::setw(20) << dev.name() << " : " << dev.Major() << ":"
<< dev.Minor() << std::endl;
}
return 0;
}
static const std::map<std::string, std::function<int(DeviceMapper&)>> listmap = {
{"targets", DmListTargets},
{"devices", DmListDevices},
};
static int DmListCmdHandler(int argc, char** argv) {
if (argc < 1) {
std::cerr << "Invalid arguments, see \'dmctl help\'" << std::endl;
return -EINVAL;
}
DeviceMapper& dm = DeviceMapper::Instance();
for (const auto& l : listmap) {
if (l.first == argv[0]) return l.second(dm);
}
std::cerr << "Invalid argument to \'dmctl list\': " << argv[0] << std::endl;
return -EINVAL;
}
static int HelpCmdHandler(int /* argc */, char** /* argv */) {
Usage();
return 0;
}
static std::map<std::string, std::function<int(int, char**)>> cmdmap = {
{"create", DmCreateCmdHandler},
{"delete", DmDeleteCmdHandler},
{"list", DmListCmdHandler},
{"help", HelpCmdHandler},
};
int main(int argc, char** argv) {
android::base::InitLogging(argv, &android::base::StderrLogger);
if (argc < 2) {
return Usage();
}
for (const auto& cmd : cmdmap) {
if (cmd.first == argv[1]) {
return cmd.second(argc - 2, argv + 2);
}
}
return Usage();
}