xref: /aosp_15_r20/system/extras/partition_tools/lpadd.cc (revision 288bf5226967eb3dac5cce6c939ccc2a7f2b4fe5)
1*288bf522SAndroid Build Coastguard Worker // Copyright (C) 2019 The Android Open Source Project
2*288bf522SAndroid Build Coastguard Worker //
3*288bf522SAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License");
4*288bf522SAndroid Build Coastguard Worker // you may not use this file except in compliance with the License.
5*288bf522SAndroid Build Coastguard Worker // You may obtain a copy of the License at
6*288bf522SAndroid Build Coastguard Worker //
7*288bf522SAndroid Build Coastguard Worker //      http://www.apache.org/licenses/LICENSE-2.0
8*288bf522SAndroid Build Coastguard Worker //
9*288bf522SAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
10*288bf522SAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS,
11*288bf522SAndroid Build Coastguard Worker // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*288bf522SAndroid Build Coastguard Worker // See the License for the specific language governing permissions and
13*288bf522SAndroid Build Coastguard Worker // limitations under the License.
14*288bf522SAndroid Build Coastguard Worker 
15*288bf522SAndroid Build Coastguard Worker #include <getopt.h>
16*288bf522SAndroid Build Coastguard Worker #include <string.h>
17*288bf522SAndroid Build Coastguard Worker #include <sysexits.h>
18*288bf522SAndroid Build Coastguard Worker #include <unistd.h>
19*288bf522SAndroid Build Coastguard Worker 
20*288bf522SAndroid Build Coastguard Worker #include <iostream>
21*288bf522SAndroid Build Coastguard Worker #include <optional>
22*288bf522SAndroid Build Coastguard Worker 
23*288bf522SAndroid Build Coastguard Worker #include <android-base/file.h>
24*288bf522SAndroid Build Coastguard Worker #include <android-base/logging.h>
25*288bf522SAndroid Build Coastguard Worker #include <android-base/unique_fd.h>
26*288bf522SAndroid Build Coastguard Worker #include <liblp/builder.h>
27*288bf522SAndroid Build Coastguard Worker #include <sparse/sparse.h>
28*288bf522SAndroid Build Coastguard Worker 
29*288bf522SAndroid Build Coastguard Worker using android::base::borrowed_fd;
30*288bf522SAndroid Build Coastguard Worker using android::base::unique_fd;
31*288bf522SAndroid Build Coastguard Worker using android::fs_mgr::LpMetadata;
32*288bf522SAndroid Build Coastguard Worker using android::fs_mgr::MetadataBuilder;
33*288bf522SAndroid Build Coastguard Worker using android::fs_mgr::ReadMetadata;
34*288bf522SAndroid Build Coastguard Worker using android::fs_mgr::UpdatePartitionTable;
35*288bf522SAndroid Build Coastguard Worker using SparsePtr = std::unique_ptr<sparse_file, decltype(&sparse_file_destroy)>;
36*288bf522SAndroid Build Coastguard Worker 
37*288bf522SAndroid Build Coastguard Worker std::optional<TemporaryDir> gTempDir;
38*288bf522SAndroid Build Coastguard Worker 
usage(const char * program)39*288bf522SAndroid Build Coastguard Worker static int usage(const char* program) {
40*288bf522SAndroid Build Coastguard Worker     std::cerr << program << " - command-line tool for adding partitions to a super.img\n";
41*288bf522SAndroid Build Coastguard Worker     std::cerr << "\n";
42*288bf522SAndroid Build Coastguard Worker     std::cerr << "Usage:\n";
43*288bf522SAndroid Build Coastguard Worker     std::cerr << " " << program << " [options] SUPER PARTNAME PARTGROUP [IMAGE]\n";
44*288bf522SAndroid Build Coastguard Worker     std::cerr << "\n";
45*288bf522SAndroid Build Coastguard Worker     std::cerr << "  SUPER                         Path to the super image. It can be sparsed or\n"
46*288bf522SAndroid Build Coastguard Worker               << "                                unsparsed. If sparsed, it will be unsparsed\n"
47*288bf522SAndroid Build Coastguard Worker               << "                                temporarily and re-sparsed over the original\n"
48*288bf522SAndroid Build Coastguard Worker               << "                                file. This will consume extra space during the\n"
49*288bf522SAndroid Build Coastguard Worker               << "                                execution of " << program << ".\n";
50*288bf522SAndroid Build Coastguard Worker     std::cerr << "  PARTNAME                      Name of the partition to add.\n";
51*288bf522SAndroid Build Coastguard Worker     std::cerr << "  PARTGROUP                     Name of the partition group to use. If the\n"
52*288bf522SAndroid Build Coastguard Worker               << "                                partition can be updated over OTA, the group\n"
53*288bf522SAndroid Build Coastguard Worker               << "                                should match its updatable group.\n";
54*288bf522SAndroid Build Coastguard Worker     std::cerr << "  IMAGE                         If specified, the contents of the given image\n"
55*288bf522SAndroid Build Coastguard Worker               << "                                will be added to the super image. If the image\n"
56*288bf522SAndroid Build Coastguard Worker               << "                                is sparsed, it will be temporarily unsparsed.\n"
57*288bf522SAndroid Build Coastguard Worker               << "                                If no image is specified, the partition will\n"
58*288bf522SAndroid Build Coastguard Worker               << "                                be zero-sized.\n";
59*288bf522SAndroid Build Coastguard Worker     std::cerr << "\n";
60*288bf522SAndroid Build Coastguard Worker     std::cerr << "Extra options:\n";
61*288bf522SAndroid Build Coastguard Worker     std::cerr << "  --readonly                    The partition should be mapped read-only.\n";
62*288bf522SAndroid Build Coastguard Worker     std::cerr << "  --replace                     The partition contents should be replaced with\n"
63*288bf522SAndroid Build Coastguard Worker               << "                                the input image.\n";
64*288bf522SAndroid Build Coastguard Worker     std::cerr << "\n";
65*288bf522SAndroid Build Coastguard Worker     return EX_USAGE;
66*288bf522SAndroid Build Coastguard Worker }
67*288bf522SAndroid Build Coastguard Worker 
68*288bf522SAndroid Build Coastguard Worker enum class OptionCode : int {
69*288bf522SAndroid Build Coastguard Worker     kReadonly = 1,
70*288bf522SAndroid Build Coastguard Worker     kReplace = 2,
71*288bf522SAndroid Build Coastguard Worker 
72*288bf522SAndroid Build Coastguard Worker     // Special options.
73*288bf522SAndroid Build Coastguard Worker     kHelp = (int)'h',
74*288bf522SAndroid Build Coastguard Worker };
75*288bf522SAndroid Build Coastguard Worker 
GetTemporaryDir()76*288bf522SAndroid Build Coastguard Worker static std::string GetTemporaryDir() {
77*288bf522SAndroid Build Coastguard Worker     if (!gTempDir) {
78*288bf522SAndroid Build Coastguard Worker         gTempDir.emplace();
79*288bf522SAndroid Build Coastguard Worker         int saved_errno = errno;
80*288bf522SAndroid Build Coastguard Worker         if (access(gTempDir->path, F_OK) != 0) {
81*288bf522SAndroid Build Coastguard Worker             std::cerr << "Could not create temporary dir: " << gTempDir->path << ": "
82*288bf522SAndroid Build Coastguard Worker                       << strerror(saved_errno) << std::endl;
83*288bf522SAndroid Build Coastguard Worker             abort();
84*288bf522SAndroid Build Coastguard Worker         }
85*288bf522SAndroid Build Coastguard Worker     }
86*288bf522SAndroid Build Coastguard Worker     return gTempDir->path;
87*288bf522SAndroid Build Coastguard Worker }
88*288bf522SAndroid Build Coastguard Worker 
89*288bf522SAndroid Build Coastguard Worker class LocalSuperOpener final : public android::fs_mgr::PartitionOpener {
90*288bf522SAndroid Build Coastguard Worker   public:
LocalSuperOpener(const std::string & path,borrowed_fd fd)91*288bf522SAndroid Build Coastguard Worker     LocalSuperOpener(const std::string& path, borrowed_fd fd)
92*288bf522SAndroid Build Coastguard Worker         : local_super_(path), local_super_fd_(fd) {}
93*288bf522SAndroid Build Coastguard Worker 
Open(const std::string & partition_name,int flags) const94*288bf522SAndroid Build Coastguard Worker     unique_fd Open(const std::string& partition_name, int flags) const override {
95*288bf522SAndroid Build Coastguard Worker         if (partition_name == local_super_) {
96*288bf522SAndroid Build Coastguard Worker             return unique_fd{dup(local_super_fd_.get())};
97*288bf522SAndroid Build Coastguard Worker         }
98*288bf522SAndroid Build Coastguard Worker         return PartitionOpener::Open(partition_name, flags);
99*288bf522SAndroid Build Coastguard Worker     }
100*288bf522SAndroid Build Coastguard Worker 
101*288bf522SAndroid Build Coastguard Worker   private:
102*288bf522SAndroid Build Coastguard Worker     std::string local_super_;
103*288bf522SAndroid Build Coastguard Worker     borrowed_fd local_super_fd_;
104*288bf522SAndroid Build Coastguard Worker };
105*288bf522SAndroid Build Coastguard Worker 
106*288bf522SAndroid Build Coastguard Worker class SuperHelper final {
107*288bf522SAndroid Build Coastguard Worker   public:
SuperHelper(const std::string & super_path)108*288bf522SAndroid Build Coastguard Worker     explicit SuperHelper(const std::string& super_path) : super_path_(super_path) {}
109*288bf522SAndroid Build Coastguard Worker 
110*288bf522SAndroid Build Coastguard Worker     bool Open();
111*288bf522SAndroid Build Coastguard Worker     bool AddPartition(const std::string& partition_name, const std::string& group_name,
112*288bf522SAndroid Build Coastguard Worker                       uint32_t attributes, const std::string& image_path, bool replace);
113*288bf522SAndroid Build Coastguard Worker     bool Finalize();
114*288bf522SAndroid Build Coastguard Worker 
115*288bf522SAndroid Build Coastguard Worker   private:
116*288bf522SAndroid Build Coastguard Worker     bool OpenSuperFile();
117*288bf522SAndroid Build Coastguard Worker     bool UpdateSuper();
118*288bf522SAndroid Build Coastguard Worker     bool WritePartition(borrowed_fd fd, uint64_t file_size, const std::string& partition_name);
119*288bf522SAndroid Build Coastguard Worker     bool WriteExtent(borrowed_fd fd, uint64_t file_size, const LpMetadataExtent& extent);
120*288bf522SAndroid Build Coastguard Worker 
121*288bf522SAndroid Build Coastguard Worker     // Returns true if |fd| does not contain a sparsed file. If |fd| does
122*288bf522SAndroid Build Coastguard Worker     // contain a sparsed file, |temp_file| will contain the unsparsed output.
123*288bf522SAndroid Build Coastguard Worker     // If |fd| cannot be read or failed to unsparse, false is returned.
124*288bf522SAndroid Build Coastguard Worker     bool MaybeUnsparse(const std::string& file, borrowed_fd fd,
125*288bf522SAndroid Build Coastguard Worker                        std::optional<TemporaryFile>* temp_file, uint32_t* block_size = nullptr);
126*288bf522SAndroid Build Coastguard Worker 
127*288bf522SAndroid Build Coastguard Worker     std::string super_path_;
128*288bf522SAndroid Build Coastguard Worker     std::string abs_super_path_;
129*288bf522SAndroid Build Coastguard Worker     bool was_empty_ = false;
130*288bf522SAndroid Build Coastguard Worker     // fd for the super file, sparsed or temporarily unsparsed.
131*288bf522SAndroid Build Coastguard Worker     int super_fd_;
132*288bf522SAndroid Build Coastguard Worker     // fd for the super file if unsparsed.
133*288bf522SAndroid Build Coastguard Worker     unique_fd output_fd_;
134*288bf522SAndroid Build Coastguard Worker     // If the super file is sparse, this holds the temp unsparsed file.
135*288bf522SAndroid Build Coastguard Worker     std::optional<TemporaryFile> temp_super_;
136*288bf522SAndroid Build Coastguard Worker     uint32_t sparse_block_size_ = 0;
137*288bf522SAndroid Build Coastguard Worker     std::unique_ptr<LpMetadata> metadata_;
138*288bf522SAndroid Build Coastguard Worker     std::unique_ptr<MetadataBuilder> builder_;
139*288bf522SAndroid Build Coastguard Worker };
140*288bf522SAndroid Build Coastguard Worker 
Open()141*288bf522SAndroid Build Coastguard Worker bool SuperHelper::Open() {
142*288bf522SAndroid Build Coastguard Worker     if (!OpenSuperFile()) {
143*288bf522SAndroid Build Coastguard Worker         return false;
144*288bf522SAndroid Build Coastguard Worker     }
145*288bf522SAndroid Build Coastguard Worker 
146*288bf522SAndroid Build Coastguard Worker     was_empty_ = android::fs_mgr::IsEmptySuperImage(abs_super_path_);
147*288bf522SAndroid Build Coastguard Worker     if (was_empty_) {
148*288bf522SAndroid Build Coastguard Worker         metadata_ = android::fs_mgr::ReadFromImageFile(abs_super_path_);
149*288bf522SAndroid Build Coastguard Worker     } else {
150*288bf522SAndroid Build Coastguard Worker         metadata_ = android::fs_mgr::ReadMetadata(abs_super_path_, 0);
151*288bf522SAndroid Build Coastguard Worker     }
152*288bf522SAndroid Build Coastguard Worker     if (!metadata_) {
153*288bf522SAndroid Build Coastguard Worker         std::cerr << "Could not read super partition metadata for " << super_path_ << "\n";
154*288bf522SAndroid Build Coastguard Worker         return false;
155*288bf522SAndroid Build Coastguard Worker     }
156*288bf522SAndroid Build Coastguard Worker     builder_ = MetadataBuilder::New(*metadata_.get());
157*288bf522SAndroid Build Coastguard Worker     if (!builder_) {
158*288bf522SAndroid Build Coastguard Worker         std::cerr << "Could not create MetadataBuilder for " << super_path_ << "\n";
159*288bf522SAndroid Build Coastguard Worker         return false;
160*288bf522SAndroid Build Coastguard Worker     }
161*288bf522SAndroid Build Coastguard Worker     return true;
162*288bf522SAndroid Build Coastguard Worker }
163*288bf522SAndroid Build Coastguard Worker 
AddPartition(const std::string & partition_name,const std::string & group_name,uint32_t attributes,const std::string & image_path,bool replace)164*288bf522SAndroid Build Coastguard Worker bool SuperHelper::AddPartition(const std::string& partition_name, const std::string& group_name,
165*288bf522SAndroid Build Coastguard Worker                                uint32_t attributes, const std::string& image_path, bool replace) {
166*288bf522SAndroid Build Coastguard Worker     if (!image_path.empty() && was_empty_) {
167*288bf522SAndroid Build Coastguard Worker         std::cerr << "Cannot add a partition image to an empty super file.\n";
168*288bf522SAndroid Build Coastguard Worker         return false;
169*288bf522SAndroid Build Coastguard Worker     }
170*288bf522SAndroid Build Coastguard Worker 
171*288bf522SAndroid Build Coastguard Worker     if (replace) {
172*288bf522SAndroid Build Coastguard Worker         auto partition = builder_->FindPartition(partition_name);
173*288bf522SAndroid Build Coastguard Worker         if (!partition) {
174*288bf522SAndroid Build Coastguard Worker             std::cerr << "Could not find partition to replace: " << partition_name << "\n";
175*288bf522SAndroid Build Coastguard Worker             return false;
176*288bf522SAndroid Build Coastguard Worker         }
177*288bf522SAndroid Build Coastguard Worker         builder_->RemovePartition(partition_name);
178*288bf522SAndroid Build Coastguard Worker     }
179*288bf522SAndroid Build Coastguard Worker 
180*288bf522SAndroid Build Coastguard Worker     auto partition = builder_->AddPartition(partition_name, group_name, attributes);
181*288bf522SAndroid Build Coastguard Worker     if (!partition) {
182*288bf522SAndroid Build Coastguard Worker         std::cerr << "Could not add partition: " << partition_name << "\n";
183*288bf522SAndroid Build Coastguard Worker         return false;
184*288bf522SAndroid Build Coastguard Worker     }
185*288bf522SAndroid Build Coastguard Worker 
186*288bf522SAndroid Build Coastguard Worker     // Open the source image and get its file size so we can resize the
187*288bf522SAndroid Build Coastguard Worker     // partition.
188*288bf522SAndroid Build Coastguard Worker     int source_fd = -1;
189*288bf522SAndroid Build Coastguard Worker     uint64_t file_size;
190*288bf522SAndroid Build Coastguard Worker     unique_fd raw_image_fd;
191*288bf522SAndroid Build Coastguard Worker     std::optional<TemporaryFile> temp_image;
192*288bf522SAndroid Build Coastguard Worker     if (!image_path.empty()) {
193*288bf522SAndroid Build Coastguard Worker         raw_image_fd.reset(open(image_path.c_str(), O_RDONLY | O_CLOEXEC));
194*288bf522SAndroid Build Coastguard Worker         if (raw_image_fd < 0) {
195*288bf522SAndroid Build Coastguard Worker             std::cerr << "open failed: " << image_path << ": " << strerror(errno) << "\n";
196*288bf522SAndroid Build Coastguard Worker             return false;
197*288bf522SAndroid Build Coastguard Worker         }
198*288bf522SAndroid Build Coastguard Worker         if (!MaybeUnsparse(image_path, raw_image_fd, &temp_image)) {
199*288bf522SAndroid Build Coastguard Worker             return false;
200*288bf522SAndroid Build Coastguard Worker         }
201*288bf522SAndroid Build Coastguard Worker         source_fd = temp_image ? temp_image->fd : raw_image_fd.get();
202*288bf522SAndroid Build Coastguard Worker 
203*288bf522SAndroid Build Coastguard Worker         auto size = lseek(source_fd, 0, SEEK_END);
204*288bf522SAndroid Build Coastguard Worker         if (size < 0 || lseek(source_fd, 0, SEEK_SET) < 0) {
205*288bf522SAndroid Build Coastguard Worker             std::cerr << "lseek failed: " << image_path << ": " << strerror(errno) << "\n";
206*288bf522SAndroid Build Coastguard Worker             return false;
207*288bf522SAndroid Build Coastguard Worker         }
208*288bf522SAndroid Build Coastguard Worker         if (!builder_->ResizePartition(partition, size)) {
209*288bf522SAndroid Build Coastguard Worker             std::cerr << "Failed to set partition " << partition_name << " size to " << size
210*288bf522SAndroid Build Coastguard Worker                       << "bytes.\n";
211*288bf522SAndroid Build Coastguard Worker             return false;
212*288bf522SAndroid Build Coastguard Worker         }
213*288bf522SAndroid Build Coastguard Worker         file_size = (uint64_t)size;
214*288bf522SAndroid Build Coastguard Worker     }
215*288bf522SAndroid Build Coastguard Worker 
216*288bf522SAndroid Build Coastguard Worker     // Write the new metadata out. We do this by re-using the on-device flashing
217*288bf522SAndroid Build Coastguard Worker     // logic, and using the local file instead of a block device.
218*288bf522SAndroid Build Coastguard Worker     if (!UpdateSuper()) {
219*288bf522SAndroid Build Coastguard Worker         return false;
220*288bf522SAndroid Build Coastguard Worker     }
221*288bf522SAndroid Build Coastguard Worker 
222*288bf522SAndroid Build Coastguard Worker     // If no partition contents were specified, early return. Otherwise, we
223*288bf522SAndroid Build Coastguard Worker     // require a full super image to continue writing.
224*288bf522SAndroid Build Coastguard Worker     if (source_fd >= 0 && !WritePartition(source_fd, file_size, partition_name)) {
225*288bf522SAndroid Build Coastguard Worker         return false;
226*288bf522SAndroid Build Coastguard Worker     }
227*288bf522SAndroid Build Coastguard Worker     return true;
228*288bf522SAndroid Build Coastguard Worker }
229*288bf522SAndroid Build Coastguard Worker 
OpenSuperFile()230*288bf522SAndroid Build Coastguard Worker bool SuperHelper::OpenSuperFile() {
231*288bf522SAndroid Build Coastguard Worker     auto actual_path = super_path_;
232*288bf522SAndroid Build Coastguard Worker 
233*288bf522SAndroid Build Coastguard Worker     output_fd_.reset(open(actual_path.c_str(), O_RDWR | O_CLOEXEC));
234*288bf522SAndroid Build Coastguard Worker     if (output_fd_ < 0) {
235*288bf522SAndroid Build Coastguard Worker         std::cerr << "open failed: " << actual_path << ": " << strerror(errno) << "\n";
236*288bf522SAndroid Build Coastguard Worker         return false;
237*288bf522SAndroid Build Coastguard Worker     }
238*288bf522SAndroid Build Coastguard Worker     super_fd_ = output_fd_.get();
239*288bf522SAndroid Build Coastguard Worker 
240*288bf522SAndroid Build Coastguard Worker     if (!MaybeUnsparse(super_path_, super_fd_, &temp_super_, &sparse_block_size_)) {
241*288bf522SAndroid Build Coastguard Worker         return false;
242*288bf522SAndroid Build Coastguard Worker     }
243*288bf522SAndroid Build Coastguard Worker     if (temp_super_) {
244*288bf522SAndroid Build Coastguard Worker         actual_path = temp_super_->path;
245*288bf522SAndroid Build Coastguard Worker         super_fd_ = temp_super_->fd;
246*288bf522SAndroid Build Coastguard Worker     }
247*288bf522SAndroid Build Coastguard Worker 
248*288bf522SAndroid Build Coastguard Worker     // PartitionOpener will decorate relative paths with /dev/block/by-name
249*288bf522SAndroid Build Coastguard Worker     // so get an absolute path here.
250*288bf522SAndroid Build Coastguard Worker     if (!android::base::Realpath(actual_path, &abs_super_path_)) {
251*288bf522SAndroid Build Coastguard Worker         std::cerr << "realpath failed: " << actual_path << ": " << strerror(errno) << "\n";
252*288bf522SAndroid Build Coastguard Worker         return false;
253*288bf522SAndroid Build Coastguard Worker     }
254*288bf522SAndroid Build Coastguard Worker     return true;
255*288bf522SAndroid Build Coastguard Worker }
256*288bf522SAndroid Build Coastguard Worker 
MaybeUnsparse(const std::string & file,borrowed_fd fd,std::optional<TemporaryFile> * temp_file,uint32_t * block_size)257*288bf522SAndroid Build Coastguard Worker bool SuperHelper::MaybeUnsparse(const std::string& file, borrowed_fd fd,
258*288bf522SAndroid Build Coastguard Worker                                 std::optional<TemporaryFile>* temp_file,
259*288bf522SAndroid Build Coastguard Worker                                 uint32_t* block_size) {
260*288bf522SAndroid Build Coastguard Worker     SparsePtr sf(sparse_file_import(fd.get(), false, false), sparse_file_destroy);
261*288bf522SAndroid Build Coastguard Worker     if (!sf) {
262*288bf522SAndroid Build Coastguard Worker         return true;
263*288bf522SAndroid Build Coastguard Worker     }
264*288bf522SAndroid Build Coastguard Worker 
265*288bf522SAndroid Build Coastguard Worker     temp_file->emplace(GetTemporaryDir());
266*288bf522SAndroid Build Coastguard Worker     if ((*temp_file)->fd < 0) {
267*288bf522SAndroid Build Coastguard Worker         std::cerr << "mkstemp failed: " << strerror(errno) << "\n";
268*288bf522SAndroid Build Coastguard Worker         return false;
269*288bf522SAndroid Build Coastguard Worker     }
270*288bf522SAndroid Build Coastguard Worker 
271*288bf522SAndroid Build Coastguard Worker     std::cout << "Unsparsing " << file << "... " << std::endl;
272*288bf522SAndroid Build Coastguard Worker 
273*288bf522SAndroid Build Coastguard Worker     if (sparse_file_write(sf.get(), (*temp_file)->fd, false, false, false) != 0) {
274*288bf522SAndroid Build Coastguard Worker         std::cerr << "Could not write unsparsed file.\n";
275*288bf522SAndroid Build Coastguard Worker         return false;
276*288bf522SAndroid Build Coastguard Worker     }
277*288bf522SAndroid Build Coastguard Worker     if (block_size) {
278*288bf522SAndroid Build Coastguard Worker         *block_size = sparse_file_block_size(sf.get());
279*288bf522SAndroid Build Coastguard Worker     }
280*288bf522SAndroid Build Coastguard Worker     return true;
281*288bf522SAndroid Build Coastguard Worker }
282*288bf522SAndroid Build Coastguard Worker 
UpdateSuper()283*288bf522SAndroid Build Coastguard Worker bool SuperHelper::UpdateSuper() {
284*288bf522SAndroid Build Coastguard Worker     metadata_ = builder_->Export();
285*288bf522SAndroid Build Coastguard Worker     if (!metadata_) {
286*288bf522SAndroid Build Coastguard Worker         std::cerr << "Failed to export new metadata.\n";
287*288bf522SAndroid Build Coastguard Worker         return false;
288*288bf522SAndroid Build Coastguard Worker     }
289*288bf522SAndroid Build Coastguard Worker 
290*288bf522SAndroid Build Coastguard Worker     // Empty images get written at the very end.
291*288bf522SAndroid Build Coastguard Worker     if (was_empty_) {
292*288bf522SAndroid Build Coastguard Worker         return true;
293*288bf522SAndroid Build Coastguard Worker     }
294*288bf522SAndroid Build Coastguard Worker 
295*288bf522SAndroid Build Coastguard Worker     // Note: A/B devices have an extra metadata slot that is unused, so we cap
296*288bf522SAndroid Build Coastguard Worker     // the writes to the first two slots.
297*288bf522SAndroid Build Coastguard Worker     LocalSuperOpener opener(abs_super_path_, super_fd_);
298*288bf522SAndroid Build Coastguard Worker     uint32_t slots = std::min(metadata_->geometry.metadata_slot_count, (uint32_t)2);
299*288bf522SAndroid Build Coastguard Worker     for (uint32_t i = 0; i < slots; i++) {
300*288bf522SAndroid Build Coastguard Worker         if (!UpdatePartitionTable(opener, abs_super_path_, *metadata_.get(), i)) {
301*288bf522SAndroid Build Coastguard Worker             std::cerr << "Could not write new super partition metadata.\n";
302*288bf522SAndroid Build Coastguard Worker             return false;
303*288bf522SAndroid Build Coastguard Worker         }
304*288bf522SAndroid Build Coastguard Worker     }
305*288bf522SAndroid Build Coastguard Worker     return true;
306*288bf522SAndroid Build Coastguard Worker }
307*288bf522SAndroid Build Coastguard Worker 
WritePartition(borrowed_fd fd,uint64_t file_size,const std::string & partition_name)308*288bf522SAndroid Build Coastguard Worker bool SuperHelper::WritePartition(borrowed_fd fd, uint64_t file_size,
309*288bf522SAndroid Build Coastguard Worker                                  const std::string& partition_name) {
310*288bf522SAndroid Build Coastguard Worker     auto partition = android::fs_mgr::FindPartition(*metadata_.get(), partition_name);
311*288bf522SAndroid Build Coastguard Worker     if (!partition) {
312*288bf522SAndroid Build Coastguard Worker         std::cerr << "Could not find partition in metadata: " << partition_name << "\n";
313*288bf522SAndroid Build Coastguard Worker         return false;
314*288bf522SAndroid Build Coastguard Worker     }
315*288bf522SAndroid Build Coastguard Worker 
316*288bf522SAndroid Build Coastguard Worker     std::cout << "Writing data for partition " << partition_name << "..." << std::endl;
317*288bf522SAndroid Build Coastguard Worker     for (uint32_t i = 0; i < partition->num_extents; i++) {
318*288bf522SAndroid Build Coastguard Worker         auto extent_index = partition->first_extent_index + i;
319*288bf522SAndroid Build Coastguard Worker         const auto& extent = metadata_->extents[extent_index];
320*288bf522SAndroid Build Coastguard Worker         if (!WriteExtent(fd, file_size, extent)) {
321*288bf522SAndroid Build Coastguard Worker             return false;
322*288bf522SAndroid Build Coastguard Worker         }
323*288bf522SAndroid Build Coastguard Worker     }
324*288bf522SAndroid Build Coastguard Worker 
325*288bf522SAndroid Build Coastguard Worker     // Assert that the full file was written.
326*288bf522SAndroid Build Coastguard Worker     [[maybe_unused]] auto pos = lseek(fd.get(), 0, SEEK_CUR);
327*288bf522SAndroid Build Coastguard Worker     CHECK(pos >= 0 && (uint64_t)pos == file_size);
328*288bf522SAndroid Build Coastguard Worker     return true;
329*288bf522SAndroid Build Coastguard Worker }
330*288bf522SAndroid Build Coastguard Worker 
WriteExtent(borrowed_fd fd,uint64_t file_size,const LpMetadataExtent & extent)331*288bf522SAndroid Build Coastguard Worker bool SuperHelper::WriteExtent(borrowed_fd fd, uint64_t file_size, const LpMetadataExtent& extent) {
332*288bf522SAndroid Build Coastguard Worker     // Must be a linear extent, and there must only be one block device.
333*288bf522SAndroid Build Coastguard Worker     CHECK(extent.target_type == LP_TARGET_TYPE_LINEAR);
334*288bf522SAndroid Build Coastguard Worker     CHECK(extent.target_source == 0);
335*288bf522SAndroid Build Coastguard Worker 
336*288bf522SAndroid Build Coastguard Worker     auto pos = lseek(fd.get(), 0, SEEK_CUR);
337*288bf522SAndroid Build Coastguard Worker     if (pos < 0) {
338*288bf522SAndroid Build Coastguard Worker         std::cerr << "lseek failed: " << strerror(errno) << "\n";
339*288bf522SAndroid Build Coastguard Worker         return false;
340*288bf522SAndroid Build Coastguard Worker     }
341*288bf522SAndroid Build Coastguard Worker 
342*288bf522SAndroid Build Coastguard Worker     // Clamp the number of bytes to either remaining data in the file, or the
343*288bf522SAndroid Build Coastguard Worker     // size of this extent.
344*288bf522SAndroid Build Coastguard Worker     CHECK((uint64_t)pos <= file_size);
345*288bf522SAndroid Build Coastguard Worker     uint64_t bytes_remaining =
346*288bf522SAndroid Build Coastguard Worker             std::min(file_size - (uint64_t)pos, extent.num_sectors * LP_SECTOR_SIZE);
347*288bf522SAndroid Build Coastguard Worker 
348*288bf522SAndroid Build Coastguard Worker     // Reposition to the appropriate offset in super.
349*288bf522SAndroid Build Coastguard Worker     if (lseek(super_fd_, extent.target_data * LP_SECTOR_SIZE, SEEK_SET) < 0) {
350*288bf522SAndroid Build Coastguard Worker         std::cerr << "lseek failed: " << strerror(errno) << "\n";
351*288bf522SAndroid Build Coastguard Worker         return false;
352*288bf522SAndroid Build Coastguard Worker     }
353*288bf522SAndroid Build Coastguard Worker 
354*288bf522SAndroid Build Coastguard Worker     uint8_t buffer[4096];
355*288bf522SAndroid Build Coastguard Worker     while (bytes_remaining > 0) {
356*288bf522SAndroid Build Coastguard Worker         uint64_t bytes = std::min((uint64_t)sizeof(buffer), bytes_remaining);
357*288bf522SAndroid Build Coastguard Worker         if (!android::base::ReadFully(fd.get(), buffer, bytes)) {
358*288bf522SAndroid Build Coastguard Worker             std::cerr << "read failed: " << strerror(errno) << "\n";
359*288bf522SAndroid Build Coastguard Worker             return false;
360*288bf522SAndroid Build Coastguard Worker         }
361*288bf522SAndroid Build Coastguard Worker         if (!android::base::WriteFully(super_fd_, buffer, bytes)) {
362*288bf522SAndroid Build Coastguard Worker             std::cerr << "write failed: " << strerror(errno) << "\n";
363*288bf522SAndroid Build Coastguard Worker             return false;
364*288bf522SAndroid Build Coastguard Worker         }
365*288bf522SAndroid Build Coastguard Worker         bytes_remaining -= bytes;
366*288bf522SAndroid Build Coastguard Worker     }
367*288bf522SAndroid Build Coastguard Worker     return true;
368*288bf522SAndroid Build Coastguard Worker }
369*288bf522SAndroid Build Coastguard Worker 
Truncate(borrowed_fd fd)370*288bf522SAndroid Build Coastguard Worker static bool Truncate(borrowed_fd fd) {
371*288bf522SAndroid Build Coastguard Worker     if (ftruncate(fd.get(), 0) < 0) {
372*288bf522SAndroid Build Coastguard Worker         std::cerr << "truncate failed: " << strerror(errno) << "\n";
373*288bf522SAndroid Build Coastguard Worker         return false;
374*288bf522SAndroid Build Coastguard Worker     }
375*288bf522SAndroid Build Coastguard Worker     if (lseek(fd.get(), 0, SEEK_SET) < 0) {
376*288bf522SAndroid Build Coastguard Worker         std::cerr << "lseek failed: " << strerror(errno) << "\n";
377*288bf522SAndroid Build Coastguard Worker         return false;
378*288bf522SAndroid Build Coastguard Worker     }
379*288bf522SAndroid Build Coastguard Worker     return true;
380*288bf522SAndroid Build Coastguard Worker }
381*288bf522SAndroid Build Coastguard Worker 
Finalize()382*288bf522SAndroid Build Coastguard Worker bool SuperHelper::Finalize() {
383*288bf522SAndroid Build Coastguard Worker     if (was_empty_) {
384*288bf522SAndroid Build Coastguard Worker         if (!Truncate(super_fd_)) {
385*288bf522SAndroid Build Coastguard Worker             return false;
386*288bf522SAndroid Build Coastguard Worker         }
387*288bf522SAndroid Build Coastguard Worker         if (!android::fs_mgr::WriteToImageFile(super_fd_, *metadata_.get())) {
388*288bf522SAndroid Build Coastguard Worker             std::cerr << "Could not write image file.\n";
389*288bf522SAndroid Build Coastguard Worker             return false;
390*288bf522SAndroid Build Coastguard Worker         }
391*288bf522SAndroid Build Coastguard Worker     }
392*288bf522SAndroid Build Coastguard Worker 
393*288bf522SAndroid Build Coastguard Worker     // If the super image wasn't original sparsed, we don't have to do anything
394*288bf522SAndroid Build Coastguard Worker     // else.
395*288bf522SAndroid Build Coastguard Worker     if (!temp_super_) {
396*288bf522SAndroid Build Coastguard Worker         return true;
397*288bf522SAndroid Build Coastguard Worker     }
398*288bf522SAndroid Build Coastguard Worker 
399*288bf522SAndroid Build Coastguard Worker     // Otherwise, we have to sparse the temporary file. Find its length.
400*288bf522SAndroid Build Coastguard Worker     auto len = lseek(super_fd_, 0, SEEK_END);
401*288bf522SAndroid Build Coastguard Worker     if (len < 0 || lseek(super_fd_, 0, SEEK_SET < 0)) {
402*288bf522SAndroid Build Coastguard Worker         std::cerr << "lseek failed: " << strerror(errno) << "\n";
403*288bf522SAndroid Build Coastguard Worker         return false;
404*288bf522SAndroid Build Coastguard Worker     }
405*288bf522SAndroid Build Coastguard Worker 
406*288bf522SAndroid Build Coastguard Worker     SparsePtr sf(sparse_file_new(sparse_block_size_, len), sparse_file_destroy);
407*288bf522SAndroid Build Coastguard Worker     if (!sf) {
408*288bf522SAndroid Build Coastguard Worker         std::cerr << "Could not allocate sparse file.\n";
409*288bf522SAndroid Build Coastguard Worker         return false;
410*288bf522SAndroid Build Coastguard Worker     }
411*288bf522SAndroid Build Coastguard Worker     sparse_file_verbose(sf.get());
412*288bf522SAndroid Build Coastguard Worker 
413*288bf522SAndroid Build Coastguard Worker     std::cout << "Writing sparse super image... " << std::endl;
414*288bf522SAndroid Build Coastguard Worker     if (sparse_file_read(sf.get(), super_fd_, SPARSE_READ_MODE_NORMAL, false) != 0) {
415*288bf522SAndroid Build Coastguard Worker         std::cerr << "Could not import super partition for sparsing.\n";
416*288bf522SAndroid Build Coastguard Worker         return false;
417*288bf522SAndroid Build Coastguard Worker     }
418*288bf522SAndroid Build Coastguard Worker     if (!Truncate(output_fd_)) {
419*288bf522SAndroid Build Coastguard Worker         return false;
420*288bf522SAndroid Build Coastguard Worker     }
421*288bf522SAndroid Build Coastguard Worker     if (sparse_file_write(sf.get(), output_fd_, false, true, false)) {
422*288bf522SAndroid Build Coastguard Worker         return false;
423*288bf522SAndroid Build Coastguard Worker     }
424*288bf522SAndroid Build Coastguard Worker     return true;
425*288bf522SAndroid Build Coastguard Worker }
426*288bf522SAndroid Build Coastguard Worker 
ErrorLogger(android::base::LogId,android::base::LogSeverity severity,const char *,const char *,unsigned int,const char * msg)427*288bf522SAndroid Build Coastguard Worker static void ErrorLogger(android::base::LogId, android::base::LogSeverity severity, const char*,
428*288bf522SAndroid Build Coastguard Worker                         const char*, unsigned int, const char* msg) {
429*288bf522SAndroid Build Coastguard Worker     if (severity < android::base::WARNING) {
430*288bf522SAndroid Build Coastguard Worker         return;
431*288bf522SAndroid Build Coastguard Worker     }
432*288bf522SAndroid Build Coastguard Worker     std::cerr << msg << std::endl;
433*288bf522SAndroid Build Coastguard Worker }
434*288bf522SAndroid Build Coastguard Worker 
main(int argc,char * argv[])435*288bf522SAndroid Build Coastguard Worker int main(int argc, char* argv[]) {
436*288bf522SAndroid Build Coastguard Worker     struct option options[] = {
437*288bf522SAndroid Build Coastguard Worker             {"readonly", no_argument, nullptr, (int)OptionCode::kReadonly},
438*288bf522SAndroid Build Coastguard Worker             {"replace", no_argument, nullptr, (int)OptionCode::kReplace},
439*288bf522SAndroid Build Coastguard Worker             {nullptr, 0, nullptr, 0},
440*288bf522SAndroid Build Coastguard Worker     };
441*288bf522SAndroid Build Coastguard Worker 
442*288bf522SAndroid Build Coastguard Worker     bool readonly = false;
443*288bf522SAndroid Build Coastguard Worker     bool replace = false;
444*288bf522SAndroid Build Coastguard Worker 
445*288bf522SAndroid Build Coastguard Worker     int rv, index;
446*288bf522SAndroid Build Coastguard Worker     while ((rv = getopt_long(argc, argv, "h", options, &index)) != -1) {
447*288bf522SAndroid Build Coastguard Worker         switch ((OptionCode)rv) {
448*288bf522SAndroid Build Coastguard Worker             case OptionCode::kHelp:
449*288bf522SAndroid Build Coastguard Worker                 usage(argv[0]);
450*288bf522SAndroid Build Coastguard Worker                 return EX_OK;
451*288bf522SAndroid Build Coastguard Worker             case OptionCode::kReadonly:
452*288bf522SAndroid Build Coastguard Worker                 readonly = true;
453*288bf522SAndroid Build Coastguard Worker                 break;
454*288bf522SAndroid Build Coastguard Worker             case OptionCode::kReplace:
455*288bf522SAndroid Build Coastguard Worker                 replace = true;
456*288bf522SAndroid Build Coastguard Worker                 break;
457*288bf522SAndroid Build Coastguard Worker             default:
458*288bf522SAndroid Build Coastguard Worker                 return usage(argv[0]);
459*288bf522SAndroid Build Coastguard Worker         }
460*288bf522SAndroid Build Coastguard Worker     }
461*288bf522SAndroid Build Coastguard Worker 
462*288bf522SAndroid Build Coastguard Worker     if (optind + 3 > argc) {
463*288bf522SAndroid Build Coastguard Worker         std::cerr << "Missing required arguments.\n\n";
464*288bf522SAndroid Build Coastguard Worker         return usage(argv[0]);
465*288bf522SAndroid Build Coastguard Worker     }
466*288bf522SAndroid Build Coastguard Worker 
467*288bf522SAndroid Build Coastguard Worker     std::string super_path = argv[optind++];
468*288bf522SAndroid Build Coastguard Worker     std::string partition_name = argv[optind++];
469*288bf522SAndroid Build Coastguard Worker     std::string group_name = argv[optind++];
470*288bf522SAndroid Build Coastguard Worker     std::string image_path;
471*288bf522SAndroid Build Coastguard Worker 
472*288bf522SAndroid Build Coastguard Worker     if (optind < argc) {
473*288bf522SAndroid Build Coastguard Worker         image_path = argv[optind++];
474*288bf522SAndroid Build Coastguard Worker     }
475*288bf522SAndroid Build Coastguard Worker     if (optind != argc) {
476*288bf522SAndroid Build Coastguard Worker         std::cerr << "Unexpected arguments.\n\n";
477*288bf522SAndroid Build Coastguard Worker         return usage(argv[0]);
478*288bf522SAndroid Build Coastguard Worker     }
479*288bf522SAndroid Build Coastguard Worker 
480*288bf522SAndroid Build Coastguard Worker     // Suppress log spam from liblp.
481*288bf522SAndroid Build Coastguard Worker     android::base::SetLogger(ErrorLogger);
482*288bf522SAndroid Build Coastguard Worker 
483*288bf522SAndroid Build Coastguard Worker     SuperHelper super(super_path);
484*288bf522SAndroid Build Coastguard Worker     if (!super.Open()) {
485*288bf522SAndroid Build Coastguard Worker         return EX_SOFTWARE;
486*288bf522SAndroid Build Coastguard Worker     }
487*288bf522SAndroid Build Coastguard Worker 
488*288bf522SAndroid Build Coastguard Worker     uint32_t attributes = LP_PARTITION_ATTR_NONE;
489*288bf522SAndroid Build Coastguard Worker     if (readonly) {
490*288bf522SAndroid Build Coastguard Worker         attributes |= LP_PARTITION_ATTR_READONLY;
491*288bf522SAndroid Build Coastguard Worker     }
492*288bf522SAndroid Build Coastguard Worker     if (!super.AddPartition(partition_name, group_name, attributes, image_path, replace)) {
493*288bf522SAndroid Build Coastguard Worker         return EX_SOFTWARE;
494*288bf522SAndroid Build Coastguard Worker     }
495*288bf522SAndroid Build Coastguard Worker     if (!super.Finalize()) {
496*288bf522SAndroid Build Coastguard Worker         return EX_SOFTWARE;
497*288bf522SAndroid Build Coastguard Worker     }
498*288bf522SAndroid Build Coastguard Worker 
499*288bf522SAndroid Build Coastguard Worker     std::cout << "Done.\n";
500*288bf522SAndroid Build Coastguard Worker     return EX_OK;
501*288bf522SAndroid Build Coastguard Worker }
502