1 // Copyright 2018 The Fuchsia Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #pragma once 6 7 #include <fbl/array.h> 8 #include <fbl/unique_fd.h> 9 #include <fbl/vector.h> 10 #include <fvm/fvm.h> 11 #include <stdarg.h> 12 #include <stdlib.h> 13 14 #include <utility> 15 16 namespace fvm { 17 18 // Checker defines a class which may be used to validate an FVM 19 // (provided as either a regular file or a raw block device). 20 class Checker { 21 public: 22 Checker(); 23 Checker(fbl::unique_fd fd, uint32_t block_size, bool silent); 24 ~Checker(); 25 26 // Sets the path of the block device / image to read the FVM from. SetDevice(fbl::unique_fd fd)27 void SetDevice(fbl::unique_fd fd) { 28 fd_ = std::move(fd); 29 } 30 31 // Sets the block size of the provided device. Not automatically queried from the underlying 32 // device, since this checker may operate on a regular file, which does not have an 33 // attached block size. SetBlockSize(uint32_t block_size)34 void SetBlockSize(uint32_t block_size) { 35 block_size_ = block_size; 36 } 37 38 // Toggles the output of future calls to |Log|. SetSilent(bool silent)39 void SetSilent(bool silent) { 40 logger_.SetSilent(silent); 41 } 42 43 // Read from and validate the provided device, logging information if requested. 44 bool Validate() const; 45 46 private: 47 class Logger { 48 public: Logger()49 Logger() : silent_(false) {}; Logger(bool silent)50 explicit Logger(bool silent) : silent_(silent) {}; 51 52 // Toggles the output of future calls to |Log|. SetSilent(bool silent)53 void SetSilent(bool silent) { 54 silent_ = silent; 55 } 56 57 // Prints the format string and arguments to stderr. Error(const char * format,...)58 void Error(const char* format, ...) const { 59 va_list arg; 60 va_start(arg, format); 61 vprintf(format, arg); 62 va_end(arg); 63 } 64 65 // Prints the format string and arguments to stdout, unless explicitly silenced. Log(const char * format,...)66 void Log(const char* format, ...) const { 67 va_list arg; 68 if (!silent_) { 69 va_start(arg, format); 70 vprintf(format, arg); 71 va_end(arg); 72 } 73 } 74 75 private: 76 bool silent_; 77 }; 78 79 // Cached information from loading and validating the FVM. 80 struct FvmInfo { 81 // Contains both copies of metadata. 82 fbl::Array<uint8_t> metadata; 83 size_t valid_metadata_offset; 84 const uint8_t* valid_metadata; 85 const uint8_t* invalid_metadata; 86 size_t block_size; 87 size_t block_count; 88 size_t device_size; 89 size_t slice_size; 90 }; 91 92 struct Slice { 93 uint64_t virtual_partition; 94 uint64_t virtual_slice; 95 uint64_t physical_slice; 96 }; 97 98 struct Partition { AllocatedPartition99 bool Allocated() const { return entry != nullptr; } 100 101 const fvm::vpart_entry_t* entry = nullptr; 102 fbl::Vector<Slice> slices; 103 }; 104 105 106 // Parses the FVM info from the device, and validate it (minimally). 107 bool LoadFVM(FvmInfo* out) const; 108 109 // Outputs and checks information about the FVM, optionally logging parsed information. 110 bool CheckFVM(const FvmInfo& info) const; 111 112 // Acquires a list of slices and partitions while parsing the FVM. 113 // 114 // Returns false if the FVM contains contradictory or invalid data. 115 bool LoadPartitions(const size_t slice_count, const fvm::slice_entry_t* slice_table, 116 const fvm::vpart_entry_t* vpart_table, fbl::Vector<Slice>* out_slices, 117 fbl::Array<Partition>* out_partitions) const; 118 119 // Displays information about |slices|, assuming they are sorted in physical slice order. 120 void DumpSlices(const fbl::Vector<Slice>& slices) const; 121 122 // Confirms the Checker has received necessary arguments before beginning validation. 123 bool ValidateOptions() const; 124 125 fbl::unique_fd fd_; 126 uint32_t block_size_ = 512; 127 Logger logger_; 128 }; 129 130 } // namespace fvm 131