From 9fa9857a7514469d062335cd2dcb8c0d06eb624c Mon Sep 17 00:00:00 2001 From: "A. Wilcox" Date: Tue, 11 Feb 2020 13:41:10 -0600 Subject: Enter DiskMan --- diskman/CMakeLists.txt | 22 ++++++++++++ diskman/disk.cc | 67 +++++++++++++++++++++++++++++++++++ diskman/disk.hh | 96 ++++++++++++++++++++++++++++++++++++++++++++++++++ diskman/diskman.cc | 81 ++++++++++++++++++++++++++++++++++++++++++ diskman/diskman.hh | 44 +++++++++++++++++++++++ diskman/lvmhelp.cc | 0 diskman/lvmhelp.hh | 0 diskman/partition.cc | 0 diskman/partition.hh | 0 9 files changed, 310 insertions(+) create mode 100644 diskman/CMakeLists.txt create mode 100644 diskman/disk.cc create mode 100644 diskman/disk.hh create mode 100644 diskman/diskman.cc create mode 100644 diskman/diskman.hh create mode 100644 diskman/lvmhelp.cc create mode 100644 diskman/lvmhelp.hh create mode 100644 diskman/partition.cc create mode 100644 diskman/partition.hh (limited to 'diskman') diff --git a/diskman/CMakeLists.txt b/diskman/CMakeLists.txt new file mode 100644 index 0000000..ea0c5fe --- /dev/null +++ b/diskman/CMakeLists.txt @@ -0,0 +1,22 @@ +pkg_check_modules(FDISK REQUIRED fdisk) +find_package(Boost REQUIRED) + +set(DISKMAN_SOURCE + diskman.cc + disk.cc + lvmhelp.cc + partition.cc +) + +set(DISKMAN_INCLUDE + diskman.hh + disk.hh + partition.hh +) + +include_directories(${Boost_INCLUDE_DIRS}) +add_library(diskman ${DISKMAN_SOURCE}) +target_link_libraries(diskman ${FDISK_LIBRARIES} ${LIBUDEV_LIBRARIES}) + +install(TARGETS diskman DESTINATION lib) +install(FILES ${DISKMAN_INCLUDE} DESTINATION include/diskman) diff --git a/diskman/disk.cc b/diskman/disk.cc new file mode 100644 index 0000000..ddb357f --- /dev/null +++ b/diskman/disk.cc @@ -0,0 +1,67 @@ +/* + * disk.cc - Implementation of the Disk class + * diskman, the Disk Manipulation library for + * Project Horizon + * + * Copyright (c) 2020 Adélie Linux and contributors. All rights reserved. + * This code is licensed under the AGPL 3.0 license, as noted in the + * LICENSE-code file in the root directory of this repository. + * + * SPDX-License-Identifier: AGPL-3.0-only + */ + +#include "disk.hh" + +#include +#include + +namespace Horizon { +namespace DiskMan { + +/*! The full serial number of the disk */ +std::string _full_serial; + +#define SAFE_SET(ivar, udev_call) \ + value = udev_call;\ + if(value != nullptr) {\ + ivar = std::string(value);\ + } + +Disk::Disk(void *creation, bool partition) { + struct udev_device *device = static_cast(creation); + const char *value; + + SAFE_SET(_name, udev_device_get_sysname(device)); + SAFE_SET(_model, udev_device_get_property_value(device, "ID_MODEL")); + SAFE_SET(_node, udev_device_get_devnode(device)); + SAFE_SET(_devpath, udev_device_get_devpath(device)); + + value = udev_device_get_property_value(device, "ID_PART_TABLE_TYPE"); + if(value == nullptr) { + _has_label = false; + _label = Unknown; + } else { + _has_label = true; + if(::strcmp(value, "apm") == 0) { + _label = APM; + } else if(::strcmp(value, "dos") == 0) { + _label = MBR; + } else if(::strcmp(value, "gpt") == 0) { + _label = GPT; + } else { + _label = Unknown; + } + } + + value = udev_device_get_property_value(device, "ID_FS_TYPE"); + if(value == nullptr) { + _has_fs = false; + } else { + _has_fs = true; + _fs_type = std::string(value); + SAFE_SET(_fs_label, udev_device_get_property_value(device, "ID_FS_LABEL")); + } +} + +} +} diff --git a/diskman/disk.hh b/diskman/disk.hh new file mode 100644 index 0000000..dcb9793 --- /dev/null +++ b/diskman/disk.hh @@ -0,0 +1,96 @@ +/* + * disk.hh - Public definition of the Disk class + * diskman, the Disk Manipulation library for + * Project Horizon + * + * Copyright (c) 2020 Adélie Linux and contributors. All rights reserved. + * This code is licensed under the AGPL 3.0 license, as noted in the + * LICENSE-code file in the root directory of this repository. + * + * SPDX-License-Identifier: AGPL-3.0-only + */ + +#ifndef DISKMAN__DISK_HH +#define DISKMAN__DISK_HH + +#include +#include + +namespace Horizon { +namespace DiskMan { + +/*! Represents a fixed disk device. */ +class Disk { +public: + /*! Potential disk label types */ + enum Label { + /*! GUID Partition Table, common on x86 and POWER */ + GPT, + /*! Master Boot Record, common on x86 and ARM */ + MBR, + /*! Apple Partition Map, common on POWER */ + APM, + /*! Unknown disk label type */ + Unknown + }; + + /*! Retrieve the disk's name. For instance, "sda" or "nvme0n1". */ + const std::string name() const { return this->_name; } + /*! Retrieve the disk's model. This is specified by the vendor. */ + const std::string model() const { return this->_model; } + /*! Retrieve the disk's serial number. This may be equivalent to + * the model name, if the vendor did not specify a serial number. */ + const std::string serial() const { return this->_full_serial; } + /*! Retrieve the device node for this disk. For instance, "/dev/sda". */ + const std::string node() const { return this->_node; } + /*! Retrieve the system device path for this disk. */ + const std::string dev_path() const { return this->_devpath; } + + /*! Determine if this disk has a disk label attached. */ + bool has_label() const { return this->_has_label; } + /*! Retrieve the type of disk label in use on this disk. + * Only valid if has_label() is true. */ + enum Label label() const { return this->_label; } + + /*! Determine if this disk has a file system written to it. + * If this method returns true, the file system is directly written to + * the disk; it is not a partition inside a disklabel. */ + bool has_fs() const { return this->_has_fs; } + /*! Retrieve the type of file system written on this disk. + * Only valid if has_fs() is true. */ + const std::string fs_type() const { return this->_fs_type; } + /*! Retrieve the label of the file system written on this disk. + * Only valid if has_fs() is true. */ + const std::string fs_label() const { return this->_fs_label; } +private: + /*! The name of the disk ("sda") */ + std::string _name; + /*! The model name of the disk ("WDC WDBNCE2500PNC") */ + std::string _model; + /*! The full serial number of the disk */ + std::string _full_serial; + /*! The device node of the disk ("/dev/sda") */ + std::string _node; + /*! The device path of the disk ("/sys/devices/...") */ + std::string _devpath; + + /*! Whether this disk has a disklabel */ + bool _has_label; + /*! The type of disk label used, if +has_label+ is true */ + enum Label _label; + + /*! Whether this disk has a direct filesystem (non-labelled) */ + bool _has_fs; + /*! The type of file system in use, if +has_fs+ is true */ + std::string _fs_type; + /*! The label of the file system, if +has_fs+ is true */ + std::string _fs_label; + + Disk(void *creation, bool partition); + friend class DiskMan; +}; + +} +} + +#endif /* !DISKMAN__DISK_HH */ diff --git a/diskman/diskman.cc b/diskman/diskman.cc new file mode 100644 index 0000000..32a2c40 --- /dev/null +++ b/diskman/diskman.cc @@ -0,0 +1,81 @@ +/* + * diskman.cc - Common routines for the DiskMan library + * diskman, the Disk Manipulation library for + * Project Horizon + * + * Copyright (c) 2020 Adélie Linux and contributors. All rights reserved. + * This code is licensed under the AGPL 3.0 license, as noted in the + * LICENSE-code file in the root directory of this repository. + * + * SPDX-License-Identifier: AGPL-3.0-only + */ + +#include "diskman.hh" + +#include +#include + +namespace Horizon { +namespace DiskMan { + +struct DiskMan::impl { + struct udev *udev; + + impl() { + udev = udev_new(); + } + ~impl() { + udev_unref(udev); + } + impl(const impl &other) { + this->udev = udev_ref(other.udev); + } +}; + +DiskMan::DiskMan() : pImpl {std::make_unique()} { +} + +DiskMan::~DiskMan() = default; + +std::vector DiskMan::find_disks(bool include_part, bool include_vg, + bool include_lvm) { + struct udev_enumerate *disk_enum = udev_enumerate_new(pImpl->udev); + struct udev_list_entry *first, *item; + struct udev_device *device = nullptr; + std::vector disks; + + if(disk_enum == nullptr) { + std::cerr << "Couldn't connect to udev" << std::endl; + return {}; + } + udev_enumerate_add_match_subsystem(disk_enum, "block"); + udev_enumerate_add_match_property(disk_enum, "DEVTYPE", "disk"); + udev_enumerate_scan_devices(disk_enum); + first = udev_enumerate_get_list_entry(disk_enum); + if(first == NULL) { + std::cerr << "No block devices found" << std::endl; + return {}; + } + + udev_list_entry_foreach(item, first) { + const char *path = udev_list_entry_get_name(item); + if(device != NULL) udev_device_unref(device); + device = udev_device_new_from_syspath(pImpl->udev, path); + std::string name(udev_device_get_sysname(device)); + if(name.compare(0, 4, "loop") == 0 + || name.compare(0, 3, "ram") == 0) { + /* Don't include loop or ram devices */ + continue; + } + if(!include_lvm && name.compare(0, 3, "dm-") == 0) { + /* Skip LVM volumes if requested. */ + continue; + } + disks.push_back(Disk(device, include_part)); + } + + return disks; +} + +} +} diff --git a/diskman/diskman.hh b/diskman/diskman.hh new file mode 100644 index 0000000..ba9d4be --- /dev/null +++ b/diskman/diskman.hh @@ -0,0 +1,44 @@ +/* + * diskman.hh - Public interface for the DiskMan library + * diskman, the Disk Manipulation library for + * Project Horizon + * + * Copyright (c) 2020 Adélie Linux and contributors. All rights reserved. + * This code is licensed under the AGPL 3.0 license, as noted in the + * LICENSE-code file in the root directory of this repository. + * + * SPDX-License-Identifier: AGPL-3.0-only + */ + +#ifndef DISKMAN__DISKMAN_HH +#define DISKMAN__DISKMAN_HH + +#include +#include + +#include "disk.hh" + +namespace Horizon { +namespace DiskMan { + +class DiskMan { + struct impl; + std::unique_ptr pImpl; +public: + DiskMan(); + ~DiskMan(); + + /*! Find all available disks on this system. + * @param include_part Include partitions with disks. + * @param include_vg Include LVM volume groups as disks. + * @param include_lvm Include LVM volumes as disks. + */ + std::vector find_disks(bool include_part = true, + bool include_vg = true, + bool include_lvm = false); +}; + +} +} + +#endif /* !DISKMAN__DISKMAN_HH */ diff --git a/diskman/lvmhelp.cc b/diskman/lvmhelp.cc new file mode 100644 index 0000000..e69de29 diff --git a/diskman/lvmhelp.hh b/diskman/lvmhelp.hh new file mode 100644 index 0000000..e69de29 diff --git a/diskman/partition.cc b/diskman/partition.cc new file mode 100644 index 0000000..e69de29 diff --git a/diskman/partition.hh b/diskman/partition.hh new file mode 100644 index 0000000..e69de29 -- cgit v1.2.3-60-g2f50