| // Copyright 2021 The ChromiumOS Authors | |
| // Use of this source code is governed by a BSD-style license that can be | |
| // found in the LICENSE file. | |
| #include <stdlib.h> | |
| #include <string> | |
| #include <base/files/file_util.h> | |
| #include <base/files/scoped_temp_dir.h> | |
| #include <base/strings/stringprintf.h> | |
| #include <brillo/process/process.h> | |
| #include <gtest/gtest.h> | |
| #include <rootdev/rootdev.h> | |
| #include "init/utils.h" | |
| namespace { | |
| // Commands for disk formatting utility sfdisk. | |
| // Specify that partition table should use gpt format. | |
| constexpr char kSfdiskPartitionTableTypeCommand[] = "label: gpt\n"; | |
| // Templates for partition command (size specified in number of sectors). | |
| constexpr char kSfdiskCommandFormat[] = "size=1, type=%s, name=\"%s\"\n"; | |
| constexpr char kSfdiskCommandWithAttrsFormat[] = | |
| "size=1, type=%s, name=\"%s\", attrs=\"%s\"\n"; | |
| // UUIDs for various partition types in gpt partition tables. | |
| constexpr char kKernelPartition[] = "FE3A2A5D-4F32-41A7-B725-ACCC3285A309"; | |
| constexpr char kRootPartition[] = "3CB8E202-3B7E-47DD-8A3C-7FF2A13CFCEC"; | |
| constexpr char kDataPartition[] = "0FC63DAF-8483-4772-8E79-3D69D8477DE4"; | |
| constexpr char kReservedPartition[] = "2E0A753D-9E48-43B0-8337-B15192CB1B5E"; | |
| constexpr char kRWFWPartition[] = "CAB6E88E-ABF3-4102-A07A-D4BB9BE3C1D3"; | |
| constexpr char kEFIPartition[] = "C12A7328-F81F-11D2-BA4B-00A0C93EC93B"; | |
| } // namespace | |
| // TODO(b/286154453): Appears to fail when host OS has md array. | |
| TEST(GetRootDevice, DISABLED_NoStripPartition) { | |
| base::FilePath root_dev; | |
| char dev_path[PATH_MAX]; | |
| int ret = rootdev(dev_path, sizeof(dev_path), true, false); | |
| root_dev = utils::GetRootDevice(false); | |
| EXPECT_EQ(!!ret, root_dev.empty()); | |
| EXPECT_EQ(dev_path, root_dev.value()); | |
| } | |
| TEST(ReadFileToInt, IntContents) { | |
| base::ScopedTempDir temp_dir_; | |
| ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); | |
| base::FilePath file = temp_dir_.GetPath().Append("file"); | |
| ASSERT_TRUE(base::WriteFile(file, "1")); | |
| int output; | |
| EXPECT_EQ(utils::ReadFileToInt(file, &output), true); | |
| EXPECT_EQ(output, 1); | |
| } | |
| TEST(ReadFileToInt, StringContents) { | |
| base::ScopedTempDir temp_dir_; | |
| ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); | |
| base::FilePath file = temp_dir_.GetPath().Append("file"); | |
| ASSERT_TRUE(base::WriteFile(file, "Not an int")); | |
| int output; | |
| EXPECT_EQ(utils::ReadFileToInt(file, &output), false); | |
| } | |
| class CgptTest : public testing::Test { | |
| protected: | |
| void SetUp() override { | |
| constexpr int kSectorSize = 512; | |
| constexpr int kSectorCount = 25 * 1024; | |
| ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); | |
| test_image_path_ = temp_dir_.GetPath().Append("test.img"); | |
| base::File test_image(test_image_path_, | |
| base::File::FLAG_CREATE | base::File::FLAG_WRITE); | |
| ASSERT_TRUE(test_image.IsValid()); | |
| ASSERT_GE(test_image.SetLength(kSectorSize * kSectorCount), 0); | |
| test_image.Close(); | |
| base::FilePath sfdisk_input_path = | |
| temp_dir_.GetPath().Append("sfdisk_input"); | |
| base::File sfdisk_input(sfdisk_input_path, | |
| base::File::FLAG_CREATE | base::File::FLAG_WRITE); | |
| ASSERT_TRUE(sfdisk_input.IsValid()); | |
| std::vector<std::string> sfdisk_commands{ | |
| kSfdiskPartitionTableTypeCommand, | |
| base::StringPrintf(kSfdiskCommandFormat, kDataPartition, "STATE"), | |
| base::StringPrintf(kSfdiskCommandWithAttrsFormat, kKernelPartition, | |
| "KERN-A", "GUID:49,56"), | |
| base::StringPrintf(kSfdiskCommandFormat, kRootPartition, "ROOT-A"), | |
| base::StringPrintf(kSfdiskCommandWithAttrsFormat, kKernelPartition, | |
| "KERN-B", "GUID:48"), | |
| base::StringPrintf(kSfdiskCommandFormat, kRootPartition, "ROOT-B"), | |
| base::StringPrintf(kSfdiskCommandWithAttrsFormat, kKernelPartition, | |
| "KERN-C", "GUID:52,53,54,55"), | |
| base::StringPrintf(kSfdiskCommandFormat, kRootPartition, "ROOT-C"), | |
| base::StringPrintf(kSfdiskCommandFormat, kDataPartition, "OEM"), | |
| base::StringPrintf(kSfdiskCommandFormat, kReservedPartition, | |
| "reserved"), | |
| base::StringPrintf(kSfdiskCommandFormat, kReservedPartition, | |
| "reserved"), | |
| base::StringPrintf(kSfdiskCommandFormat, kRWFWPartition, "RWFW"), | |
| base::StringPrintf(kSfdiskCommandFormat, kEFIPartition, "EFI-SYSTEM")}; | |
| for (const std::string& command : sfdisk_commands) { | |
| EXPECT_EQ( | |
| sfdisk_input.WriteAtCurrentPos(command.c_str(), command.length()), | |
| command.length()); | |
| } | |
| sfdisk_input.Close(); | |
| // Build partition table on backing file. | |
| brillo::ProcessImpl sfdisk; | |
| sfdisk.AddArg("/sbin/sfdisk"); | |
| sfdisk.AddArg(test_image_path_.value()); | |
| sfdisk.RedirectInput(sfdisk_input_path); | |
| ASSERT_EQ(sfdisk.Run(), 0); | |
| } | |
| base::FilePath test_image_path_; | |
| private: | |
| base::ScopedTempDir temp_dir_; | |
| }; | |
| TEST_F(CgptTest, FindInvalidPartitions) { | |
| EXPECT_EQ(utils::GetPartitionNumber(test_image_path_, ""), -1); | |
| EXPECT_EQ(utils::GetPartitionNumber(test_image_path_, "NONEXISTENT"), -1); | |
| // return -1 here because there are multiple partitions labeled "reserved". | |
| EXPECT_EQ(utils::GetPartitionNumber(test_image_path_, "reserved"), -1); | |
| } | |
| TEST_F(CgptTest, FindValidPartitions) { | |
| EXPECT_EQ(utils::GetPartitionNumber(test_image_path_, "STATE"), 1); | |
| EXPECT_EQ(utils::GetPartitionNumber(test_image_path_, "KERN-A"), 2); | |
| EXPECT_EQ(utils::GetPartitionNumber(test_image_path_, "ROOT-A"), 3); | |
| EXPECT_EQ(utils::GetPartitionNumber(test_image_path_, "KERN-B"), 4); | |
| EXPECT_EQ(utils::GetPartitionNumber(test_image_path_, "ROOT-B"), 5); | |
| EXPECT_EQ(utils::GetPartitionNumber(test_image_path_, "KERN-C"), 6); | |
| EXPECT_EQ(utils::GetPartitionNumber(test_image_path_, "ROOT-C"), 7); | |
| EXPECT_EQ(utils::GetPartitionNumber(test_image_path_, "OEM"), 8); | |
| EXPECT_EQ(utils::GetPartitionNumber(test_image_path_, "RWFW"), 11); | |
| EXPECT_EQ(utils::GetPartitionNumber(test_image_path_, "EFI-SYSTEM"), 12); | |
| } | |
| TEST_F(CgptTest, ReadPartitionMetadata) { | |
| bool successful; | |
| int priority; | |
| EXPECT_TRUE(utils::ReadPartitionMetadata(test_image_path_, 2, &successful, | |
| &priority)); | |
| EXPECT_TRUE(successful); | |
| EXPECT_EQ(priority, 2); | |
| EXPECT_TRUE(utils::ReadPartitionMetadata(test_image_path_, 4, &successful, | |
| &priority)); | |
| EXPECT_FALSE(successful); | |
| EXPECT_EQ(priority, 1); | |
| EXPECT_TRUE(utils::ReadPartitionMetadata(test_image_path_, 6, &successful, | |
| &priority)); | |
| EXPECT_FALSE(successful); | |
| EXPECT_EQ(priority, 0); | |
| } | |
| TEST_F(CgptTest, EnsureKernelIsBootable) { | |
| utils::EnsureKernelIsBootable(test_image_path_, 4); | |
| bool successful; | |
| int priority; | |
| EXPECT_TRUE(utils::ReadPartitionMetadata(test_image_path_, 4, &successful, | |
| &priority)); | |
| EXPECT_TRUE(successful); | |
| EXPECT_GT(priority, 0); | |
| utils::EnsureKernelIsBootable(test_image_path_, 6); | |
| EXPECT_TRUE(utils::ReadPartitionMetadata(test_image_path_, 6, &successful, | |
| &priority)); | |
| EXPECT_TRUE(successful); | |
| EXPECT_GT(priority, 0); | |
| } | |
| TEST(GetDevicePathComponents, ErrorCases) { | |
| std::string base_device; | |
| int partition_number; | |
| EXPECT_FALSE( | |
| utils::GetDevicePathComponents(base::FilePath(""), nullptr, nullptr)); | |
| EXPECT_FALSE(utils::GetDevicePathComponents(base::FilePath(""), nullptr, | |
| &partition_number)); | |
| EXPECT_FALSE(utils::GetDevicePathComponents(base::FilePath(""), &base_device, | |
| nullptr)); | |
| EXPECT_FALSE(utils::GetDevicePathComponents(base::FilePath(""), &base_device, | |
| &partition_number)); | |
| EXPECT_FALSE(utils::GetDevicePathComponents(base::FilePath("24728"), | |
| &base_device, &partition_number)); | |
| EXPECT_FALSE(utils::GetDevicePathComponents(base::FilePath("bad_dev"), | |
| &base_device, &partition_number)); | |
| EXPECT_FALSE(utils::GetDevicePathComponents(base::FilePath("/dev/"), | |
| &base_device, &partition_number)); | |
| } | |
| TEST(GetDevicePathComponents, ValidCases) { | |
| std::string base_device; | |
| int partition_number; | |
| EXPECT_TRUE(utils::GetDevicePathComponents(base::FilePath("/dev/sda273"), | |
| &base_device, &partition_number)); | |
| EXPECT_EQ(base_device, "/dev/sda"); | |
| EXPECT_EQ(partition_number, 273); | |
| EXPECT_TRUE(utils::GetDevicePathComponents( | |
| base::FilePath("/dev/mmcblk5p193448"), &base_device, &partition_number)); | |
| EXPECT_EQ(base_device, "/dev/mmcblk5p"); | |
| EXPECT_EQ(partition_number, 193448); | |
| EXPECT_TRUE(utils::GetDevicePathComponents(base::FilePath("/dev/nvme7n2p11"), | |
| &base_device, &partition_number)); | |
| EXPECT_EQ(base_device, "/dev/nvme7n2p"); | |
| EXPECT_EQ(partition_number, 11); | |
| } |