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