diff --git a/fastboot/device/commands.cpp b/fastboot/device/commands.cpp index eb18141c5e140d2b944a37f08f3e70fa1a97b752..b1c2958fef5c1a425a3234cd5f8d41938a24c773 100644 --- a/fastboot/device/commands.cpp +++ b/fastboot/device/commands.cpp @@ -42,26 +42,66 @@ using ::android::hardware::boot::V1_0::CommandResult; using ::android::hardware::boot::V1_0::Slot; using namespace android::fs_mgr; +struct VariableHandlers { + // Callback to retrieve the value of a single variable. + std::function<bool(FastbootDevice*, const std::vector<std::string>&, std::string*)> get; + // Callback to retrieve all possible argument combinations, for getvar all. + std::function<std::vector<std::vector<std::string>>(FastbootDevice*)> get_all_args; +}; + +static void GetAllVars(FastbootDevice* device, const std::string& name, + const VariableHandlers& handlers) { + if (!handlers.get_all_args) { + std::string message; + if (!handlers.get(device, std::vector<std::string>(), &message)) { + return; + } + device->WriteInfo(android::base::StringPrintf("%s:%s", name.c_str(), message.c_str())); + return; + } + + auto all_args = handlers.get_all_args(device); + for (const auto& args : all_args) { + std::string message; + if (!handlers.get(device, args, &message)) { + continue; + } + std::string arg_string = android::base::Join(args, ":"); + device->WriteInfo(android::base::StringPrintf("%s:%s:%s", name.c_str(), arg_string.c_str(), + message.c_str())); + } +} + bool GetVarHandler(FastbootDevice* device, const std::vector<std::string>& args) { - using VariableHandler = - std::function<bool(FastbootDevice*, const std::vector<std::string>&, std::string*)>; - const std::unordered_map<std::string, VariableHandler> kVariableMap = { - {FB_VAR_VERSION, GetVersion}, - {FB_VAR_VERSION_BOOTLOADER, GetBootloaderVersion}, - {FB_VAR_VERSION_BASEBAND, GetBasebandVersion}, - {FB_VAR_PRODUCT, GetProduct}, - {FB_VAR_SERIALNO, GetSerial}, - {FB_VAR_SECURE, GetSecure}, - {FB_VAR_UNLOCKED, GetUnlocked}, - {FB_VAR_MAX_DOWNLOAD_SIZE, GetMaxDownloadSize}, - {FB_VAR_CURRENT_SLOT, ::GetCurrentSlot}, - {FB_VAR_SLOT_COUNT, GetSlotCount}, - {FB_VAR_HAS_SLOT, GetHasSlot}, - {FB_VAR_SLOT_SUCCESSFUL, GetSlotSuccessful}, - {FB_VAR_SLOT_UNBOOTABLE, GetSlotUnbootable}, - {FB_VAR_PARTITION_SIZE, GetPartitionSize}, - {FB_VAR_IS_LOGICAL, GetPartitionIsLogical}, - {FB_VAR_IS_USERSPACE, GetIsUserspace}}; + const std::unordered_map<std::string, VariableHandlers> kVariableMap = { + {FB_VAR_VERSION, {GetVersion, nullptr}}, + {FB_VAR_VERSION_BOOTLOADER, {GetBootloaderVersion, nullptr}}, + {FB_VAR_VERSION_BASEBAND, {GetBasebandVersion, nullptr}}, + {FB_VAR_PRODUCT, {GetProduct, nullptr}}, + {FB_VAR_SERIALNO, {GetSerial, nullptr}}, + {FB_VAR_SECURE, {GetSecure, nullptr}}, + {FB_VAR_UNLOCKED, {GetUnlocked, nullptr}}, + {FB_VAR_MAX_DOWNLOAD_SIZE, {GetMaxDownloadSize, nullptr}}, + {FB_VAR_CURRENT_SLOT, {::GetCurrentSlot, nullptr}}, + {FB_VAR_SLOT_COUNT, {GetSlotCount, nullptr}}, + {FB_VAR_HAS_SLOT, {GetHasSlot, GetAllPartitionArgsNoSlot}}, + {FB_VAR_SLOT_SUCCESSFUL, {GetSlotSuccessful, nullptr}}, + {FB_VAR_SLOT_UNBOOTABLE, {GetSlotUnbootable, nullptr}}, + {FB_VAR_PARTITION_SIZE, {GetPartitionSize, GetAllPartitionArgsWithSlot}}, + {FB_VAR_IS_LOGICAL, {GetPartitionIsLogical, GetAllPartitionArgsWithSlot}}, + {FB_VAR_IS_USERSPACE, {GetIsUserspace, nullptr}}}; + + if (args.size() < 2) { + return device->WriteFail("Missing argument"); + } + + // Special case: return all variables that we can. + if (args[1] == "all") { + for (const auto& [name, handlers] : kVariableMap) { + GetAllVars(device, name, handlers); + } + return device->WriteOkay(""); + } // args[0] is command name, args[1] is variable. auto found_variable = kVariableMap.find(args[1]); @@ -71,7 +111,7 @@ bool GetVarHandler(FastbootDevice* device, const std::vector<std::string>& args) std::string message; std::vector<std::string> getvar_args(args.begin() + 2, args.end()); - if (!found_variable->second(device, getvar_args, &message)) { + if (!found_variable->second.get(device, getvar_args, &message)) { return device->WriteFail(message); } return device->WriteOkay(message); diff --git a/fastboot/device/fastboot_device.cpp b/fastboot/device/fastboot_device.cpp index 6ed6d32900f9964eab474e12c131f1130a021e49..55aca9ccda2fffe03d2416f2a6439b4cb04acbfa 100644 --- a/fastboot/device/fastboot_device.cpp +++ b/fastboot/device/fastboot_device.cpp @@ -137,3 +137,7 @@ bool FastbootDevice::WriteOkay(const std::string& message) { bool FastbootDevice::WriteFail(const std::string& message) { return WriteStatus(FastbootResult::FAIL, message); } + +bool FastbootDevice::WriteInfo(const std::string& message) { + return WriteStatus(FastbootResult::INFO, message); +} diff --git a/fastboot/device/fastboot_device.h b/fastboot/device/fastboot_device.h index addc2eff78ceb91d4b78398df7e034c152d5a8d3..171e7ae3bf02ddb8bd15ae844632744c58526ba8 100644 --- a/fastboot/device/fastboot_device.h +++ b/fastboot/device/fastboot_device.h @@ -39,9 +39,10 @@ class FastbootDevice { bool HandleData(bool read, std::vector<char>* data); std::string GetCurrentSlot(); - // Shortcuts for writing OKAY and FAIL status results. + // Shortcuts for writing status results. bool WriteOkay(const std::string& message); bool WriteFail(const std::string& message); + bool WriteInfo(const std::string& message); std::vector<char>& download_data() { return download_data_; } Transport* get_transport() { return transport_.get(); } diff --git a/fastboot/device/utility.cpp b/fastboot/device/utility.cpp index ec84576ced85e8a035ae4b8824af5aca3a3861f8..0157e7fd450e3f604c5d8060194891ed0d6070fc 100644 --- a/fastboot/device/utility.cpp +++ b/fastboot/device/utility.cpp @@ -16,6 +16,11 @@ #include "utility.h" +#include <dirent.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <unistd.h> + #include <android-base/logging.h> #include <fs_mgr_dm_linear.h> #include <liblp/liblp.h> @@ -123,3 +128,33 @@ bool GetSlotNumber(const std::string& slot, Slot* number) { *number = slot[0] - 'a'; return true; } + +std::vector<std::string> ListPartitions(FastbootDevice* device) { + std::vector<std::string> partitions; + + // First get physical partitions. + struct dirent* de; + std::unique_ptr<DIR, decltype(&closedir)> by_name(opendir("/dev/block/by-name"), closedir); + while ((de = readdir(by_name.get())) != nullptr) { + if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..")) { + continue; + } + struct stat s; + std::string path = "/dev/block/by-name/" + std::string(de->d_name); + if (!stat(path.c_str(), &s) && S_ISBLK(s.st_mode)) { + partitions.emplace_back(de->d_name); + } + } + + // Next get logical partitions. + if (auto path = FindPhysicalPartition(LP_METADATA_PARTITION_NAME)) { + uint32_t slot_number = SlotNumberForSlotSuffix(device->GetCurrentSlot()); + if (auto metadata = ReadMetadata(path->c_str(), slot_number)) { + for (const auto& partition : metadata->partitions) { + std::string partition_name = GetPartitionName(partition); + partitions.emplace_back(partition_name); + } + } + } + return partitions; +} diff --git a/fastboot/device/utility.h b/fastboot/device/utility.h index 0931fc31308d3468450d8efc3bd578f1eb5eeffc..4f0d0791e9643ad4e506b84423936b470fbef3f0 100644 --- a/fastboot/device/utility.h +++ b/fastboot/device/utility.h @@ -56,5 +56,5 @@ std::optional<std::string> FindPhysicalPartition(const std::string& name); bool LogicalPartitionExists(const std::string& name, const std::string& slot_suffix, bool* is_zero_length = nullptr); bool OpenPartition(FastbootDevice* device, const std::string& name, PartitionHandle* handle); - bool GetSlotNumber(const std::string& slot, android::hardware::boot::V1_0::Slot* number); +std::vector<std::string> ListPartitions(FastbootDevice* device); diff --git a/fastboot/device/variables.cpp b/fastboot/device/variables.cpp index 8eeda98f7104a648b0173f9400c3b3d752ececec..9f3fa7597d98f0150b65063ce29d8ee5f1ba4a12 100644 --- a/fastboot/device/variables.cpp +++ b/fastboot/device/variables.cpp @@ -222,3 +222,37 @@ bool GetIsUserspace(FastbootDevice* /* device */, const std::vector<std::string> *message = "yes"; return true; } + +std::vector<std::vector<std::string>> GetAllPartitionArgsWithSlot(FastbootDevice* device) { + std::vector<std::vector<std::string>> args; + auto partitions = ListPartitions(device); + for (const auto& partition : partitions) { + args.emplace_back(std::initializer_list<std::string>{partition}); + } + return args; +} + +std::vector<std::vector<std::string>> GetAllPartitionArgsNoSlot(FastbootDevice* device) { + auto partitions = ListPartitions(device); + + std::string slot_suffix = device->GetCurrentSlot(); + if (!slot_suffix.empty()) { + auto names = std::move(partitions); + for (const auto& name : names) { + std::string slotless_name = name; + if (android::base::EndsWith(name, "_a") || android::base::EndsWith(name, "_b")) { + slotless_name = name.substr(0, name.rfind("_")); + } + if (std::find(partitions.begin(), partitions.end(), slotless_name) == + partitions.end()) { + partitions.emplace_back(slotless_name); + } + } + } + + std::vector<std::vector<std::string>> args; + for (const auto& partition : partitions) { + args.emplace_back(std::initializer_list<std::string>{partition}); + } + return args; +} diff --git a/fastboot/device/variables.h b/fastboot/device/variables.h index b643bbdf8921a8beee1b5f688a36b315dc96d8bf..c3a64cfab8035a6bd2a545da08a635fc093d8189 100644 --- a/fastboot/device/variables.h +++ b/fastboot/device/variables.h @@ -48,3 +48,7 @@ bool GetPartitionIsLogical(FastbootDevice* device, const std::vector<std::string std::string* message); bool GetIsUserspace(FastbootDevice* device, const std::vector<std::string>& args, std::string* message); + +// Helpers for getvar all. +std::vector<std::vector<std::string>> GetAllPartitionArgsWithSlot(FastbootDevice* device); +std::vector<std::vector<std::string>> GetAllPartitionArgsNoSlot(FastbootDevice* device);