| // Copyright 2022 The ChromiumOS Authors | |
| // Use of this source code is governed by a BSD-style license that can be | |
| // found in the LICENSE file. | |
| #include <sysexits.h> | |
| #include <unistd.h> | |
| #include <cstdint> | |
| #include <iostream> | |
| #include <string> | |
| #include <base/logging.h> | |
| #include <base/json/json_writer.h> | |
| #include <base/strings/string_number_conversions.h> | |
| #include <base/strings/string_split.h> | |
| #include <base/strings/stringprintf.h> | |
| #include <base/values.h> | |
| #include <brillo/daemons/daemon.h> | |
| #include <brillo/errors/error.h> | |
| #include <brillo/flag_helper.h> | |
| #include <dbus/bus.h> | |
| #include <lvmd/proto_bindings/lvmd.pb.h> | |
| #include "lvmd/dbus-proxies.h" | |
| using org::chromium::LvmdProxy; | |
| namespace { | |
| const char kDevicePath[] = "device_path"; | |
| const char kFreeBytes[] = "free_bytes"; | |
| const char kName[] = "name"; | |
| const char kPath[] = "path"; | |
| const char kTotalBytes[] = "total_bytes"; | |
| const char kLogicalVolume[] = "logical_volume"; | |
| const char kLogicalVolumeList[] = "logical_volume_list"; | |
| const char kPhysicalVolume[] = "physical_volume"; | |
| const char kThinpool[] = "thinpool"; | |
| const char kVolumeGroup[] = "volume_group"; | |
| std::string ErrorPtrToStr(const brillo::ErrorPtr& err) { | |
| return base::StringPrintf("Domain=%s Error Code=%s Error Message=%s", | |
| err->GetDomain().c_str(), err->GetCode().c_str(), | |
| err->GetMessage().c_str()); | |
| } | |
| int PrintDict(const base::Value::Dict& dict) { | |
| std::string json; | |
| if (!base::JSONWriter::WriteWithOptions( | |
| dict, base::JSONWriter::OPTIONS_PRETTY_PRINT, &json)) { | |
| LOG(ERROR) << "Failed to write json."; | |
| return EX_SOFTWARE; | |
| } | |
| std::cout << json; | |
| return EX_OK; | |
| } | |
| base::Value::Dict Dict() { | |
| return base::Value::Dict(); | |
| } | |
| base::Value::Dict ToDict(const lvmd::PhysicalVolume& pv) { | |
| auto pv_dict = Dict().Set(kDevicePath, pv.device_path()); | |
| auto dict = Dict().Set(kPhysicalVolume, std::move(pv_dict)); | |
| return dict; | |
| } | |
| base::Value::Dict ToDict(const lvmd::VolumeGroup& vg) { | |
| auto vg_dict = Dict().Set(kName, vg.name()); | |
| auto dict = Dict().Set(kVolumeGroup, std::move(vg_dict)); | |
| return dict; | |
| } | |
| base::Value::Dict ToDict(const lvmd::Thinpool& thinpool) { | |
| auto vg_dict = ToDict(thinpool.volume_group()); | |
| auto thinpool_dict = | |
| Dict() | |
| .Set(kVolumeGroup, std::move(vg_dict)) | |
| .Set(kName, thinpool.name()) | |
| .Set(kTotalBytes, static_cast<int>(thinpool.total_bytes())) | |
| .Set(kFreeBytes, static_cast<int>(thinpool.free_bytes())); | |
| auto dict = Dict().Set(kThinpool, std::move(thinpool_dict)); | |
| return dict; | |
| } | |
| base::Value::Dict ToDict(const lvmd::LogicalVolume& lv) { | |
| auto lv_dict = Dict().Set(kName, lv.name()).Set(kPath, lv.path()); | |
| auto dict = Dict().Set(kLogicalVolume, std::move(lv_dict)); | |
| return dict; | |
| } | |
| base::Value::Dict ToDict(const lvmd::LogicalVolumeList& lvs) { | |
| auto lv_list = base::Value::List(); | |
| for (const auto& lv : lvs.logical_volume()) { | |
| lv_list.Append(ToDict(lv)); | |
| } | |
| auto dict = Dict().Set(kLogicalVolumeList, base::Value(std::move(lv_list))); | |
| return dict; | |
| } | |
| class LvmdClient : public brillo::Daemon { | |
| public: | |
| LvmdClient(int argc, const char** argv) : argc_(argc), argv_(argv) {} | |
| ~LvmdClient() override = default; | |
| // Delete copy constructor and assignment operator. | |
| LvmdClient(const LvmdClient&) = delete; | |
| LvmdClient& operator=(const LvmdClient&) = delete; | |
| int OnEventLoopStarted() override; | |
| private: | |
| // Initialize the client. | |
| int Init(); | |
| // Checks for exclusivity of boolean flags. | |
| bool CheckExclusiveFlags(const std::vector<bool>& flags); | |
| // Process flags for correctness and execute. | |
| int ProcessFlags(); | |
| // Helpers when processing given flags. | |
| // `--show` helpers: | |
| int GetPhysicalVolume(const std::string& device_path); | |
| int GetVolumeGroup(const std::string& device_path); | |
| int GetThinpool(const std::string& vg_name, const std::string& thinpool_name); | |
| int ListLogicalVolumes(const std::string& vg_name); | |
| int GetLogicalVolume(const std::string& vg_name, const std::string& lv_name); | |
| // `--create` helpers: | |
| int CreateLogicalVolume(const std::string& vg_name, | |
| const std::string& thinpool_name, | |
| const std::string& lv_name, | |
| int64_t size); | |
| int CreateLogicalVolumes(const std::string& vg_name, | |
| const std::string& thinpool_name, | |
| const std::string& lv_names, | |
| const std::string& sizes); | |
| // `--remove` helpers: | |
| int RemoveLogicalVolume(const std::string& vg_name, | |
| const std::string& lv_name); | |
| int RemoveLogicalVolumes(const std::string& vg_name, | |
| const std::string& lv_names); | |
| // `--activate` helpers: | |
| // `--deactivate` helpers: | |
| int ToggleLogicalVolumeActivation(const std::string& vg_name, | |
| const std::string& lv_name, | |
| bool activate); | |
| int ResizeLogicalVolume(const std::string& vg_name, | |
| const std::string& lv_name, | |
| int64_t size); | |
| // argc and argv passed to main(). | |
| int argc_; | |
| const char** argv_; | |
| std::unique_ptr<LvmdProxy> lvmd_proxy_; | |
| }; | |
| int LvmdClient::Init() { | |
| dbus::Bus::Options options; | |
| options.bus_type = dbus::Bus::SYSTEM; | |
| scoped_refptr<dbus::Bus> bus{new dbus::Bus{options}}; | |
| if (!bus->Connect()) { | |
| LOG(ERROR) << "Failed to connect to DBus."; | |
| return EX_UNAVAILABLE; | |
| } | |
| lvmd_proxy_ = std::make_unique<LvmdProxy>(bus); | |
| return EX_OK; | |
| } | |
| bool LvmdClient::CheckExclusiveFlags(const std::vector<bool>& flags) { | |
| return std::count(std::begin(flags), std::end(flags), true) == 1; | |
| } | |
| int LvmdClient::ProcessFlags() { | |
| // Exclusive top level lvm actions. | |
| DEFINE_bool(show, false, "Show action."); | |
| DEFINE_bool(create, false, "Create action."); | |
| DEFINE_bool(remove, false, "Remove action."); | |
| DEFINE_bool(activate, false, "Activate action."); | |
| DEFINE_bool(deactivate, false, "Deactivation action."); | |
| DEFINE_bool(resize, false, "Resize action."); | |
| // Exclusive top level lvm devices. | |
| DEFINE_bool(pv, false, "Get PhysicalVolume."); | |
| DEFINE_bool(vg, false, "Get VolumeGroup."); | |
| DEFINE_bool(thinpool, false, "Get Thinpool."); | |
| DEFINE_bool(lvs, false, "Get LogicalVolumes."); | |
| DEFINE_bool(lv, false, "Get LogicalVolume."); | |
| // Used in `--show`: | |
| // `--pv` | |
| // `--vg` | |
| DEFINE_string(device_path, "", "Path to a device."); | |
| // Used in `--show`: | |
| // `--thinpool` | |
| // `--lvs` | |
| // `--lv` | |
| // Used in `--create`: | |
| // `--lv` | |
| // Used in `--remove`: | |
| // `--lv` | |
| // Used in `--activate`: | |
| // `--lv` | |
| // Used in `--deactivate`: | |
| // `--lv` | |
| DEFINE_string(vg_name, "", "Volume Group name."); | |
| // Used in `--show`: | |
| // `--thinpool` | |
| // Used in `--create`: | |
| // `--lv` | |
| DEFINE_string(thinpool_name, "", "Thinpool name."); | |
| // Used in `--show`: | |
| // `--lv` | |
| // Used in `--create`: | |
| // `--lv` | |
| // Used in `--remove`: | |
| // `--lv` | |
| // Used in `--activate`: | |
| // `--lv` | |
| // Used in `--deactivate`: | |
| // `--lv` | |
| // Used in `--resize`: | |
| // `--lv` | |
| DEFINE_string(lv_name, "", "Logical Volume name."); | |
| // Used in `--create`: | |
| // `--lv` | |
| // Used in `--resize`: | |
| // `--lv` | |
| DEFINE_int64(size, -1, "Size in MiB."); | |
| // Used in `--create`: | |
| // `--lvs` | |
| // Used in `--remove`: | |
| // `--lvs` | |
| DEFINE_string(lv_names, "", "Logical Volume names. (comma separated)"); | |
| // Used in `--create`: | |
| // `--lvs` | |
| DEFINE_string(sizes, "", "Sizes in MiB. (comma separated)"); | |
| brillo::FlagHelper::Init(argc_, argv_, "Lvmd Client"); | |
| if (!CheckExclusiveFlags({ | |
| FLAGS_show, | |
| FLAGS_create, | |
| FLAGS_remove, | |
| FLAGS_activate, | |
| FLAGS_deactivate, | |
| FLAGS_resize, | |
| })) { | |
| LOG(ERROR) << "Please provide only one of " | |
| "`--show`" | |
| ", " | |
| "`--create`" | |
| ", " | |
| "`--remove`" | |
| ", " | |
| "`--activate`" | |
| ", " | |
| "`--deactivate`" | |
| "."; | |
| return EX_USAGE; | |
| } | |
| if (!CheckExclusiveFlags({ | |
| FLAGS_pv, | |
| FLAGS_vg, | |
| FLAGS_thinpool, | |
| FLAGS_lvs, | |
| FLAGS_lv, | |
| })) { | |
| LOG(ERROR) << "Please provide only one of " | |
| "`--pv`" | |
| ", " | |
| "`--vg`" | |
| ", " | |
| "`--thinpool`" | |
| ", " | |
| "`--lvs`" | |
| ", " | |
| "`--lv`" | |
| "."; | |
| return EX_USAGE; | |
| } | |
| if (FLAGS_show) { | |
| if (FLAGS_pv) | |
| return GetPhysicalVolume(FLAGS_device_path); | |
| if (FLAGS_vg) | |
| return GetVolumeGroup(FLAGS_device_path); | |
| if (FLAGS_thinpool) | |
| return GetThinpool(FLAGS_vg_name, FLAGS_thinpool_name); | |
| if (FLAGS_lvs) | |
| return ListLogicalVolumes(FLAGS_vg_name); | |
| if (FLAGS_lv) | |
| return GetLogicalVolume(FLAGS_vg_name, FLAGS_lv_name); | |
| LOG(ERROR) << "`--show` is not support for this LVM device."; | |
| return EX_USAGE; | |
| } | |
| if (FLAGS_create) { | |
| if (FLAGS_lv) | |
| return CreateLogicalVolume(FLAGS_vg_name, FLAGS_thinpool_name, | |
| FLAGS_lv_name, FLAGS_size); | |
| if (FLAGS_lvs) | |
| return CreateLogicalVolumes(FLAGS_vg_name, FLAGS_thinpool_name, | |
| FLAGS_lv_names, FLAGS_sizes); | |
| LOG(ERROR) << "`--create` is not support for this LVM device."; | |
| return EX_USAGE; | |
| } | |
| if (FLAGS_remove) { | |
| if (FLAGS_lv) | |
| return RemoveLogicalVolume(FLAGS_vg_name, FLAGS_lv_name); | |
| if (FLAGS_lvs) | |
| return RemoveLogicalVolumes(FLAGS_vg_name, FLAGS_lv_names); | |
| LOG(ERROR) << "`--remove` is not support for this LVM device."; | |
| return EX_USAGE; | |
| } | |
| if (FLAGS_activate) { | |
| if (FLAGS_lv) | |
| return ToggleLogicalVolumeActivation(FLAGS_vg_name, FLAGS_lv_name, | |
| /*activate=*/true); | |
| LOG(ERROR) << "`--activate` is not support for this LVM device."; | |
| return EX_USAGE; | |
| } | |
| if (FLAGS_deactivate) { | |
| if (FLAGS_lv) | |
| return ToggleLogicalVolumeActivation(FLAGS_vg_name, FLAGS_lv_name, | |
| /*activate=*/false); | |
| LOG(ERROR) << "`--deactivate` is not support for this LVM device."; | |
| return EX_USAGE; | |
| } | |
| if (FLAGS_resize) { | |
| if (FLAGS_lv) | |
| return ResizeLogicalVolume(FLAGS_vg_name, FLAGS_lv_name, FLAGS_size); | |
| LOG(ERROR) << "`--resize` is not support for this LVM device."; | |
| return EX_USAGE; | |
| } | |
| // Should never reach here. | |
| LOG(FATAL) << "Client missed handling a flag, please file a bug."; | |
| } | |
| int LvmdClient::GetPhysicalVolume(const std::string& device_path) { | |
| if (device_path.empty()) { | |
| LOG(ERROR) << "`--device_path` must be provided."; | |
| return EX_USAGE; | |
| } | |
| brillo::ErrorPtr err; | |
| lvmd::PhysicalVolume pv; | |
| if (!lvmd_proxy_->GetPhysicalVolume(device_path, &pv, &err)) { | |
| LOG(ERROR) << "Failed to get physical volume, " << ErrorPtrToStr(err); | |
| return EX_SOFTWARE; | |
| } | |
| return PrintDict(ToDict(pv)); | |
| } | |
| int LvmdClient::GetVolumeGroup(const std::string& device_path) { | |
| if (device_path.empty()) { | |
| LOG(ERROR) << "`--device_path` must be provided."; | |
| return EX_USAGE; | |
| } | |
| lvmd::PhysicalVolume pv; | |
| pv.set_device_path(device_path); | |
| brillo::ErrorPtr err; | |
| lvmd::VolumeGroup vg; | |
| if (!lvmd_proxy_->GetVolumeGroup(pv, &vg, &err)) { | |
| LOG(ERROR) << "Failed to get volume group, " << ErrorPtrToStr(err); | |
| return EX_SOFTWARE; | |
| } | |
| return PrintDict(ToDict(vg)); | |
| } | |
| int LvmdClient::GetThinpool(const std::string& vg_name, | |
| const std::string& thinpool_name) { | |
| if (vg_name.empty()) { | |
| LOG(ERROR) << "`--vg_name` must be provided."; | |
| return EX_USAGE; | |
| } | |
| if (thinpool_name.empty()) { | |
| LOG(ERROR) << "`--thinpool_name` must be provided."; | |
| return EX_USAGE; | |
| } | |
| lvmd::VolumeGroup vg; | |
| vg.set_name(vg_name); | |
| brillo::ErrorPtr err; | |
| lvmd::Thinpool thinpool; | |
| if (!lvmd_proxy_->GetThinpool(vg, thinpool_name, &thinpool, &err)) { | |
| LOG(ERROR) << "Failed to get thinpool, " << ErrorPtrToStr(err); | |
| return EX_SOFTWARE; | |
| } | |
| return PrintDict(ToDict(thinpool)); | |
| } | |
| int LvmdClient::ListLogicalVolumes(const std::string& vg_name) { | |
| if (vg_name.empty()) { | |
| LOG(ERROR) << "`--vg_name` must be provided."; | |
| return EX_USAGE; | |
| } | |
| lvmd::VolumeGroup vg; | |
| vg.set_name(vg_name); | |
| brillo::ErrorPtr err; | |
| lvmd::LogicalVolumeList lvs; | |
| if (!lvmd_proxy_->ListLogicalVolumes(vg, &lvs, &err)) { | |
| LOG(ERROR) << "Failed to list logical volumes, " << ErrorPtrToStr(err); | |
| return EX_SOFTWARE; | |
| } | |
| return PrintDict(ToDict(lvs)); | |
| } | |
| int LvmdClient::GetLogicalVolume(const std::string& vg_name, | |
| const std::string& lv_name) { | |
| if (vg_name.empty()) { | |
| LOG(ERROR) << "`--vg_name` must be provided."; | |
| return EX_USAGE; | |
| } | |
| if (lv_name.empty()) { | |
| LOG(ERROR) << "`--lv_name` must be provided."; | |
| return EX_USAGE; | |
| } | |
| lvmd::VolumeGroup vg; | |
| vg.set_name(vg_name); | |
| brillo::ErrorPtr err; | |
| lvmd::LogicalVolume lv; | |
| if (!lvmd_proxy_->GetLogicalVolume(vg, lv_name, &lv, &err)) { | |
| LOG(ERROR) << "Failed to get logical volume, " << ErrorPtrToStr(err); | |
| return EX_SOFTWARE; | |
| } | |
| return PrintDict(ToDict(lv)); | |
| } | |
| int LvmdClient::CreateLogicalVolume(const std::string& vg_name, | |
| const std::string& thinpool_name, | |
| const std::string& lv_name, | |
| int64_t size) { | |
| if (vg_name.empty()) { | |
| LOG(ERROR) << "`--vg_name` must be provided."; | |
| return EX_USAGE; | |
| } | |
| if (thinpool_name.empty()) { | |
| LOG(ERROR) << "`--thinpool_name` must be provided."; | |
| return EX_USAGE; | |
| } | |
| if (lv_name.empty()) { | |
| LOG(ERROR) << "`--lv_name` must be provided."; | |
| return EX_USAGE; | |
| } | |
| if (size < 0) { | |
| LOG(ERROR) << "`--size` must be positive."; | |
| return EX_USAGE; | |
| } | |
| lvmd::VolumeGroup vg; | |
| vg.set_name(vg_name); | |
| lvmd::Thinpool thinpool; | |
| *thinpool.mutable_volume_group() = vg; | |
| thinpool.set_name(thinpool_name); | |
| lvmd::LogicalVolumeConfiguration lv_config; | |
| lv_config.set_name(lv_name); | |
| lv_config.set_size(size); | |
| brillo::ErrorPtr err; | |
| lvmd::LogicalVolume lv; | |
| if (!lvmd_proxy_->CreateLogicalVolume(thinpool, lv_config, &lv, &err)) { | |
| LOG(ERROR) << "Failed to create logical volume, " << ErrorPtrToStr(err); | |
| return EX_SOFTWARE; | |
| } | |
| return PrintDict(ToDict(lv)); | |
| } | |
| int LvmdClient::CreateLogicalVolumes(const std::string& vg_name, | |
| const std::string& thinpool_name, | |
| const std::string& lv_names, | |
| const std::string& sizes) { | |
| if (vg_name.empty()) { | |
| LOG(ERROR) << "`--vg_name` must be provided."; | |
| return EX_USAGE; | |
| } | |
| if (thinpool_name.empty()) { | |
| LOG(ERROR) << "`--thinpool_name` must be provided."; | |
| return EX_USAGE; | |
| } | |
| if (lv_names.empty()) { | |
| LOG(ERROR) << "`--lv_names` must be provided."; | |
| return EX_USAGE; | |
| } | |
| if (sizes.empty()) { | |
| LOG(ERROR) << "`--sizes` must be provided."; | |
| return EX_USAGE; | |
| } | |
| const std::string kDelims{","}; | |
| const auto& vec_lv_names = base::SplitString( | |
| lv_names, kDelims, base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY); | |
| const auto& vec_str_sizes = base::SplitString( | |
| sizes, kDelims, base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY); | |
| if (vec_lv_names.size() != vec_str_sizes.size()) { | |
| LOG(ERROR) | |
| << "`--lv_names` and `--sizes` must have the same number of arguments."; | |
| return EX_USAGE; | |
| } | |
| const int64_t kNumLvs = vec_lv_names.size(); | |
| std::vector<int64_t> vec_sizes; | |
| vec_sizes.reserve(kNumLvs); | |
| for (const auto& str_size : vec_str_sizes) { | |
| int64_t size; | |
| if (!base::StringToInt64(str_size, &size)) { | |
| LOG(ERROR) << "`--sizes` given an invalid size: " << str_size; | |
| return EX_USAGE; | |
| } | |
| if (size < 0) { | |
| LOG(ERROR) << "`--sizes` must all be positive, given bad value: " << size; | |
| return EX_USAGE; | |
| } | |
| vec_sizes.emplace_back(size); | |
| } | |
| lvmd::VolumeGroup vg; | |
| vg.set_name(vg_name); | |
| lvmd::Thinpool thinpool; | |
| *thinpool.mutable_volume_group() = vg; | |
| thinpool.set_name(thinpool_name); | |
| lvmd::CreateLogicalVolumesRequest request; | |
| for (int i = 0; i < kNumLvs; ++i) { | |
| auto* lv_info = request.add_logical_volume_infos(); | |
| *lv_info->mutable_thinpool() = thinpool; | |
| auto* lv_config = lv_info->mutable_lv_config(); | |
| lv_config->set_name(vec_lv_names[i]); | |
| lv_config->set_size(vec_sizes[i]); | |
| } | |
| brillo::ErrorPtr err; | |
| lvmd::CreateLogicalVolumesResponse response; | |
| if (!lvmd_proxy_->CreateLogicalVolumes(request, &response, &err)) { | |
| LOG(ERROR) << "Failed to create logical volumes, " << ErrorPtrToStr(err); | |
| return EX_SOFTWARE; | |
| } | |
| return PrintDict(ToDict(response.logical_volume_list())); | |
| } | |
| int LvmdClient::RemoveLogicalVolume(const std::string& vg_name, | |
| const std::string& lv_name) { | |
| if (vg_name.empty()) { | |
| LOG(ERROR) << "`--vg_name` must be provided."; | |
| return EX_USAGE; | |
| } | |
| if (lv_name.empty()) { | |
| LOG(ERROR) << "`--lv_name` must be provided."; | |
| return EX_USAGE; | |
| } | |
| lvmd::VolumeGroup vg; | |
| vg.set_name(vg_name); | |
| lvmd::LogicalVolume lv; | |
| *lv.mutable_volume_group() = vg; | |
| lv.set_name(lv_name); | |
| brillo::ErrorPtr err; | |
| if (!lvmd_proxy_->RemoveLogicalVolume(lv, &err)) { | |
| LOG(ERROR) << "Failed to remove logical volume, " << ErrorPtrToStr(err); | |
| return EX_SOFTWARE; | |
| } | |
| return EX_OK; | |
| } | |
| int LvmdClient::RemoveLogicalVolumes(const std::string& vg_name, | |
| const std::string& lv_names) { | |
| if (vg_name.empty()) { | |
| LOG(ERROR) << "`--vg_name` must be provided."; | |
| return EX_USAGE; | |
| } | |
| if (lv_names.empty()) { | |
| LOG(ERROR) << "`--lv_names` must be provided."; | |
| return EX_USAGE; | |
| } | |
| const auto& vec_lv_names = base::SplitString( | |
| lv_names, ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY); | |
| lvmd::VolumeGroup vg; | |
| vg.set_name(vg_name); | |
| lvmd::RemoveLogicalVolumesRequest request; | |
| auto* lv_list = request.mutable_logical_volume_list(); | |
| for (const auto& lv_name : vec_lv_names) { | |
| auto* lv = lv_list->add_logical_volume(); | |
| *lv->mutable_volume_group() = vg; | |
| lv->set_name(lv_name); | |
| } | |
| brillo::ErrorPtr err; | |
| lvmd::RemoveLogicalVolumesResponse response; | |
| if (!lvmd_proxy_->RemoveLogicalVolumes(request, &response, &err)) { | |
| LOG(ERROR) << "Failed to remove logical volumes, " << ErrorPtrToStr(err); | |
| return EX_SOFTWARE; | |
| } | |
| return EX_OK; | |
| } | |
| int LvmdClient::ToggleLogicalVolumeActivation(const std::string& vg_name, | |
| const std::string& lv_name, | |
| bool activate) { | |
| if (vg_name.empty()) { | |
| LOG(ERROR) << "`--vg_name` must be provided."; | |
| return EX_USAGE; | |
| } | |
| if (lv_name.empty()) { | |
| LOG(ERROR) << "`--lv_name` must be provided."; | |
| return EX_USAGE; | |
| } | |
| lvmd::VolumeGroup vg; | |
| vg.set_name(vg_name); | |
| lvmd::LogicalVolume lv; | |
| *lv.mutable_volume_group() = vg; | |
| lv.set_name(lv_name); | |
| brillo::ErrorPtr err; | |
| if (!lvmd_proxy_->ToggleLogicalVolumeActivation(lv, activate, &err)) { | |
| LOG(ERROR) << "Failed to toggle activation for logical volume, " | |
| << ErrorPtrToStr(err); | |
| return EX_SOFTWARE; | |
| } | |
| return EX_OK; | |
| } | |
| int LvmdClient::ResizeLogicalVolume(const std::string& vg_name, | |
| const std::string& lv_name, | |
| int64_t size) { | |
| if (vg_name.empty()) { | |
| LOG(ERROR) << "`--vg_name` must be provided."; | |
| return EX_USAGE; | |
| } | |
| if (lv_name.empty()) { | |
| LOG(ERROR) << "`--lv_name` must be provided."; | |
| return EX_USAGE; | |
| } | |
| if (size < 0) { | |
| LOG(ERROR) << "`--size` must be positive."; | |
| return EX_USAGE; | |
| } | |
| lvmd::VolumeGroup vg; | |
| vg.set_name(vg_name); | |
| lvmd::LogicalVolume lv; | |
| *lv.mutable_volume_group() = vg; | |
| lv.set_name(lv_name); | |
| brillo::ErrorPtr err; | |
| if (!lvmd_proxy_->ResizeLogicalVolume(lv, size, &err)) { | |
| LOG(ERROR) << "Failed to resize logical volume, " << ErrorPtrToStr(err); | |
| return EX_SOFTWARE; | |
| } | |
| return EX_OK; | |
| } | |
| int LvmdClient::OnEventLoopStarted() { | |
| Quit(); | |
| for (auto fnc : {&LvmdClient::Init, &LvmdClient::ProcessFlags}) { | |
| if (int ret = (this->*fnc)(); ret != EX_OK) { | |
| return ret; | |
| } | |
| } | |
| return EX_OK; | |
| } | |
| } // namespace | |
| int main(int argc, const char** argv) { | |
| switch (getuid()) { | |
| case 0: | |
| break; | |
| default: | |
| LOG(ERROR) << "lvmd_client can only be run as root."; | |
| return EX_USAGE; | |
| } | |
| return LvmdClient(argc, argv).Run(); | |
| } |