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