xref: /aosp_15_r20/system/extras/partition_tools/lpmake.cc (revision 288bf5226967eb3dac5cce6c939ccc2a7f2b4fe5)
1*288bf522SAndroid Build Coastguard Worker /*
2*288bf522SAndroid Build Coastguard Worker  * Copyright (C) 2018 The Android Open Source Project
3*288bf522SAndroid Build Coastguard Worker  *
4*288bf522SAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*288bf522SAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*288bf522SAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*288bf522SAndroid Build Coastguard Worker  *
8*288bf522SAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*288bf522SAndroid Build Coastguard Worker  *
10*288bf522SAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*288bf522SAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*288bf522SAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*288bf522SAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*288bf522SAndroid Build Coastguard Worker  * limitations under the License.
15*288bf522SAndroid Build Coastguard Worker  */
16*288bf522SAndroid Build Coastguard Worker 
17*288bf522SAndroid Build Coastguard Worker #include <getopt.h>
18*288bf522SAndroid Build Coastguard Worker #include <inttypes.h>
19*288bf522SAndroid Build Coastguard Worker #include <stdio.h>
20*288bf522SAndroid Build Coastguard Worker #include <stdlib.h>
21*288bf522SAndroid Build Coastguard Worker #ifndef WIN32
22*288bf522SAndroid Build Coastguard Worker #include <sysexits.h>
23*288bf522SAndroid Build Coastguard Worker #endif
24*288bf522SAndroid Build Coastguard Worker #include <unistd.h>
25*288bf522SAndroid Build Coastguard Worker 
26*288bf522SAndroid Build Coastguard Worker #include <algorithm>
27*288bf522SAndroid Build Coastguard Worker #include <memory>
28*288bf522SAndroid Build Coastguard Worker 
29*288bf522SAndroid Build Coastguard Worker #include <android-base/parseint.h>
30*288bf522SAndroid Build Coastguard Worker #include <android-base/result.h>
31*288bf522SAndroid Build Coastguard Worker #include <android-base/strings.h>
32*288bf522SAndroid Build Coastguard Worker #include <android-base/unique_fd.h>
33*288bf522SAndroid Build Coastguard Worker #include <liblp/builder.h>
34*288bf522SAndroid Build Coastguard Worker #include <liblp/liblp.h>
35*288bf522SAndroid Build Coastguard Worker 
36*288bf522SAndroid Build Coastguard Worker using namespace android;
37*288bf522SAndroid Build Coastguard Worker using namespace android::fs_mgr;
38*288bf522SAndroid Build Coastguard Worker 
39*288bf522SAndroid Build Coastguard Worker using android::base::Error;
40*288bf522SAndroid Build Coastguard Worker using android::base::Result;
41*288bf522SAndroid Build Coastguard Worker using android::base::unique_fd;
42*288bf522SAndroid Build Coastguard Worker 
43*288bf522SAndroid Build Coastguard Worker #ifdef WIN32
44*288bf522SAndroid Build Coastguard Worker static constexpr int EX_OK = 0;
45*288bf522SAndroid Build Coastguard Worker static constexpr int EX_USAGE = 1;
46*288bf522SAndroid Build Coastguard Worker static constexpr int EX_SOFTWARE = 2;
47*288bf522SAndroid Build Coastguard Worker static constexpr int EX_CANTCREAT = 3;
48*288bf522SAndroid Build Coastguard Worker #else
49*288bf522SAndroid Build Coastguard Worker static constexpr int O_BINARY = 0;
50*288bf522SAndroid Build Coastguard Worker #endif
51*288bf522SAndroid Build Coastguard Worker 
52*288bf522SAndroid Build Coastguard Worker /* Prints program usage to |where|. */
usage(int,char * argv[])53*288bf522SAndroid Build Coastguard Worker static int usage(int /* argc */, char* argv[]) {
54*288bf522SAndroid Build Coastguard Worker     fprintf(stderr,
55*288bf522SAndroid Build Coastguard Worker             "%s - command-line tool for creating Android Logical Partition images.\n"
56*288bf522SAndroid Build Coastguard Worker             "\n"
57*288bf522SAndroid Build Coastguard Worker             "Usage:\n"
58*288bf522SAndroid Build Coastguard Worker             "  %s [options]\n"
59*288bf522SAndroid Build Coastguard Worker             "\n"
60*288bf522SAndroid Build Coastguard Worker             "Required options:\n"
61*288bf522SAndroid Build Coastguard Worker             "  -d,--device-size=[SIZE|auto]  Size of the block device for logical partitions.\n"
62*288bf522SAndroid Build Coastguard Worker             "                                Can be set to auto to automatically calculate the\n"
63*288bf522SAndroid Build Coastguard Worker             "                                minimum size, the sum of partition sizes plus\n"
64*288bf522SAndroid Build Coastguard Worker             "                                metadata-size times the number of partitions.\n"
65*288bf522SAndroid Build Coastguard Worker             "  -m,--metadata-size=SIZE       Maximum size to reserve for partition metadata.\n"
66*288bf522SAndroid Build Coastguard Worker             "  -s,--metadata-slots=COUNT     Number of slots to store metadata copies.\n"
67*288bf522SAndroid Build Coastguard Worker             "  -p,--partition=DATA           Add a partition given the data, see below.\n"
68*288bf522SAndroid Build Coastguard Worker             "  -o,--output=FILE              Output file.\n"
69*288bf522SAndroid Build Coastguard Worker             "\n"
70*288bf522SAndroid Build Coastguard Worker             "Optional:\n"
71*288bf522SAndroid Build Coastguard Worker             "  -b,--block-size=SIZE          Physical block size, defaults to 4096.\n"
72*288bf522SAndroid Build Coastguard Worker             "  -a,--alignment=N              Optimal partition alignment in bytes.\n"
73*288bf522SAndroid Build Coastguard Worker             "  -O,--alignment-offset=N       Alignment offset in bytes to device parent.\n"
74*288bf522SAndroid Build Coastguard Worker             "  -S,--sparse                   Output a sparse image for fastboot.\n"
75*288bf522SAndroid Build Coastguard Worker             "  -i,--image=PARTITION=FILE     If building a sparse image for fastboot, include\n"
76*288bf522SAndroid Build Coastguard Worker             "                                the given file (or sparse file) as initial data for\n"
77*288bf522SAndroid Build Coastguard Worker             "                                the named partition.\n"
78*288bf522SAndroid Build Coastguard Worker             "  -g,--group=GROUP:SIZE         Define a named partition group with the given\n"
79*288bf522SAndroid Build Coastguard Worker             "                                maximum size.\n"
80*288bf522SAndroid Build Coastguard Worker             "  -D,--device=DATA              Add a block device that the super partition\n"
81*288bf522SAndroid Build Coastguard Worker             "                                spans over. If specified, then -d/--device-size\n"
82*288bf522SAndroid Build Coastguard Worker             "                                and alignments must not be specified. The format\n"
83*288bf522SAndroid Build Coastguard Worker             "                                for DATA is listed below.\n"
84*288bf522SAndroid Build Coastguard Worker             "  -n,--super-name=NAME          Specify the name of the block device that will\n"
85*288bf522SAndroid Build Coastguard Worker             "                                house the super partition.\n"
86*288bf522SAndroid Build Coastguard Worker             "  -x,--auto-slot-suffixing      Mark the block device and partition names needing\n"
87*288bf522SAndroid Build Coastguard Worker             "                                slot suffixes before being used.\n"
88*288bf522SAndroid Build Coastguard Worker             "  -F,--force-full-image         Force a full image to be written even if no\n"
89*288bf522SAndroid Build Coastguard Worker             "                                partition images were specified. Normally, this\n"
90*288bf522SAndroid Build Coastguard Worker             "                                would produce a minimal super_empty.img which\n"
91*288bf522SAndroid Build Coastguard Worker             "                                cannot be flashed; force-full-image will produce\n"
92*288bf522SAndroid Build Coastguard Worker             "                                a flashable image.\n"
93*288bf522SAndroid Build Coastguard Worker             "  --virtual-ab                  Add the VIRTUAL_AB_DEVICE flag to the metadata\n"
94*288bf522SAndroid Build Coastguard Worker             "                                header. Note that the resulting super.img will\n"
95*288bf522SAndroid Build Coastguard Worker             "                                require a liblp capable of parsing a v1.2 header.\n"
96*288bf522SAndroid Build Coastguard Worker             "\n"
97*288bf522SAndroid Build Coastguard Worker             "Partition data format:\n"
98*288bf522SAndroid Build Coastguard Worker             "  <name>:<attributes>:<size>[:group]\n"
99*288bf522SAndroid Build Coastguard Worker             "  Attrs must be 'none' or 'readonly'.\n"
100*288bf522SAndroid Build Coastguard Worker             "\n"
101*288bf522SAndroid Build Coastguard Worker             "Device data format:\n"
102*288bf522SAndroid Build Coastguard Worker             "  <partition_name>:<size>[:<alignment>:<alignment_offset>]\n"
103*288bf522SAndroid Build Coastguard Worker             "  The partition name is the basename of the /dev/block/by-name/ path of the\n"
104*288bf522SAndroid Build Coastguard Worker             "  block device. The size is the device size in bytes. The alignment and\n"
105*288bf522SAndroid Build Coastguard Worker             "  alignment offset parameters are the same as -a/--alignment and \n"
106*288bf522SAndroid Build Coastguard Worker             "  -O/--alignment-offset.\n",
107*288bf522SAndroid Build Coastguard Worker             argv[0], argv[0]);
108*288bf522SAndroid Build Coastguard Worker     return EX_USAGE;
109*288bf522SAndroid Build Coastguard Worker }
110*288bf522SAndroid Build Coastguard Worker 
111*288bf522SAndroid Build Coastguard Worker enum class Option : int {
112*288bf522SAndroid Build Coastguard Worker     // Long-only options.
113*288bf522SAndroid Build Coastguard Worker     kVirtualAB = 1,
114*288bf522SAndroid Build Coastguard Worker 
115*288bf522SAndroid Build Coastguard Worker     // Short character codes.
116*288bf522SAndroid Build Coastguard Worker     kDeviceSize = 'd',
117*288bf522SAndroid Build Coastguard Worker     kMetadataSize = 'm',
118*288bf522SAndroid Build Coastguard Worker     kMetadataSlots = 's',
119*288bf522SAndroid Build Coastguard Worker     kPartition = 'p',
120*288bf522SAndroid Build Coastguard Worker     kOutput = 'o',
121*288bf522SAndroid Build Coastguard Worker     kHelp = 'h',
122*288bf522SAndroid Build Coastguard Worker     kAlignmentOffset = 'O',
123*288bf522SAndroid Build Coastguard Worker     kAlignment = 'a',
124*288bf522SAndroid Build Coastguard Worker     kSparse = 'S',
125*288bf522SAndroid Build Coastguard Worker     kBlockSize = 'b',
126*288bf522SAndroid Build Coastguard Worker     kImage = 'i',
127*288bf522SAndroid Build Coastguard Worker     kGroup = 'g',
128*288bf522SAndroid Build Coastguard Worker     kDevice = 'D',
129*288bf522SAndroid Build Coastguard Worker     kSuperName = 'n',
130*288bf522SAndroid Build Coastguard Worker     kAutoSlotSuffixing = 'x',
131*288bf522SAndroid Build Coastguard Worker     kForceFullImage = 'F',
132*288bf522SAndroid Build Coastguard Worker };
133*288bf522SAndroid Build Coastguard Worker 
134*288bf522SAndroid Build Coastguard Worker struct PartitionInfo {
135*288bf522SAndroid Build Coastguard Worker     std::string name;
136*288bf522SAndroid Build Coastguard Worker     uint64_t size;
137*288bf522SAndroid Build Coastguard Worker     uint32_t attribute_flags;
138*288bf522SAndroid Build Coastguard Worker     std::string group_name;
139*288bf522SAndroid Build Coastguard Worker 
ParsePartitionInfo140*288bf522SAndroid Build Coastguard Worker     static Result<PartitionInfo> Parse(const char* arg) {
141*288bf522SAndroid Build Coastguard Worker         std::vector<std::string> parts = android::base::Split(arg, ":");
142*288bf522SAndroid Build Coastguard Worker         if (parts.size() > 4) {
143*288bf522SAndroid Build Coastguard Worker             return Error() << "Partition info has invalid formatting.";
144*288bf522SAndroid Build Coastguard Worker         }
145*288bf522SAndroid Build Coastguard Worker 
146*288bf522SAndroid Build Coastguard Worker         std::string name = parts[0];
147*288bf522SAndroid Build Coastguard Worker         if (name.empty()) {
148*288bf522SAndroid Build Coastguard Worker             return Error() << "Partition must have a valid name.";
149*288bf522SAndroid Build Coastguard Worker         }
150*288bf522SAndroid Build Coastguard Worker 
151*288bf522SAndroid Build Coastguard Worker         uint64_t size;
152*288bf522SAndroid Build Coastguard Worker         if (!android::base::ParseUint(parts[2].c_str(), &size)) {
153*288bf522SAndroid Build Coastguard Worker             return Error() << "Partition must have a valid size.";
154*288bf522SAndroid Build Coastguard Worker         }
155*288bf522SAndroid Build Coastguard Worker 
156*288bf522SAndroid Build Coastguard Worker         uint32_t attribute_flags = 0;
157*288bf522SAndroid Build Coastguard Worker         std::string attributes = parts[1];
158*288bf522SAndroid Build Coastguard Worker         if (attributes == "readonly") {
159*288bf522SAndroid Build Coastguard Worker             attribute_flags |= LP_PARTITION_ATTR_READONLY;
160*288bf522SAndroid Build Coastguard Worker         } else if (attributes != "none") {
161*288bf522SAndroid Build Coastguard Worker             return Error() << "Attribute not recognized: " << attributes;
162*288bf522SAndroid Build Coastguard Worker         }
163*288bf522SAndroid Build Coastguard Worker 
164*288bf522SAndroid Build Coastguard Worker         std::string group_name = "default";
165*288bf522SAndroid Build Coastguard Worker         if (parts.size() >= 4) {
166*288bf522SAndroid Build Coastguard Worker             group_name = parts[3];
167*288bf522SAndroid Build Coastguard Worker         }
168*288bf522SAndroid Build Coastguard Worker 
169*288bf522SAndroid Build Coastguard Worker         return PartitionInfo{name, size, attribute_flags, group_name};
170*288bf522SAndroid Build Coastguard Worker     }
171*288bf522SAndroid Build Coastguard Worker };
172*288bf522SAndroid Build Coastguard Worker 
CalculateBlockDeviceSize(uint32_t alignment,uint32_t metadata_size,uint32_t metadata_slots,const std::vector<PartitionInfo> & partitions)173*288bf522SAndroid Build Coastguard Worker static uint64_t CalculateBlockDeviceSize(uint32_t alignment, uint32_t metadata_size,
174*288bf522SAndroid Build Coastguard Worker                                          uint32_t metadata_slots,
175*288bf522SAndroid Build Coastguard Worker                                          const std::vector<PartitionInfo>& partitions) {
176*288bf522SAndroid Build Coastguard Worker     uint64_t ret = LP_PARTITION_RESERVED_BYTES;
177*288bf522SAndroid Build Coastguard Worker     ret += LP_METADATA_GEOMETRY_SIZE * 2;
178*288bf522SAndroid Build Coastguard Worker 
179*288bf522SAndroid Build Coastguard Worker     // Each metadata slot has a primary and backup copy.
180*288bf522SAndroid Build Coastguard Worker     ret += metadata_slots * metadata_size * 2;
181*288bf522SAndroid Build Coastguard Worker 
182*288bf522SAndroid Build Coastguard Worker     if (alignment) {
183*288bf522SAndroid Build Coastguard Worker         uint64_t remainder = ret % alignment;
184*288bf522SAndroid Build Coastguard Worker         uint64_t to_add = alignment - remainder;
185*288bf522SAndroid Build Coastguard Worker         if (to_add > std::numeric_limits<uint64_t>::max() - ret) {
186*288bf522SAndroid Build Coastguard Worker             return 0;
187*288bf522SAndroid Build Coastguard Worker         }
188*288bf522SAndroid Build Coastguard Worker         ret += to_add;
189*288bf522SAndroid Build Coastguard Worker     }
190*288bf522SAndroid Build Coastguard Worker 
191*288bf522SAndroid Build Coastguard Worker     ret += partitions.size() * alignment;
192*288bf522SAndroid Build Coastguard Worker     for (const auto& partition_info : partitions) {
193*288bf522SAndroid Build Coastguard Worker         ret += partition_info.size;
194*288bf522SAndroid Build Coastguard Worker     }
195*288bf522SAndroid Build Coastguard Worker     return ret;
196*288bf522SAndroid Build Coastguard Worker }
197*288bf522SAndroid Build Coastguard Worker 
GetFileSize(const std::string & path,uint64_t * size)198*288bf522SAndroid Build Coastguard Worker static bool GetFileSize(const std::string& path, uint64_t* size) {
199*288bf522SAndroid Build Coastguard Worker     unique_fd fd(open(path.c_str(), O_RDONLY | O_BINARY));
200*288bf522SAndroid Build Coastguard Worker     if (fd < 0) {
201*288bf522SAndroid Build Coastguard Worker         fprintf(stderr, "Could not open file: %s: %s\n", path.c_str(), strerror(errno));
202*288bf522SAndroid Build Coastguard Worker         return false;
203*288bf522SAndroid Build Coastguard Worker     }
204*288bf522SAndroid Build Coastguard Worker 
205*288bf522SAndroid Build Coastguard Worker     auto offs = lseek(fd.get(), 0, SEEK_END);
206*288bf522SAndroid Build Coastguard Worker     if (offs < 0) {
207*288bf522SAndroid Build Coastguard Worker         fprintf(stderr, "Failed to seek file: %s: %s\n", path.c_str(), strerror(errno));
208*288bf522SAndroid Build Coastguard Worker         return false;
209*288bf522SAndroid Build Coastguard Worker     }
210*288bf522SAndroid Build Coastguard Worker 
211*288bf522SAndroid Build Coastguard Worker     *size = offs;
212*288bf522SAndroid Build Coastguard Worker     return true;
213*288bf522SAndroid Build Coastguard Worker }
214*288bf522SAndroid Build Coastguard Worker 
main(int argc,char * argv[])215*288bf522SAndroid Build Coastguard Worker int main(int argc, char* argv[]) {
216*288bf522SAndroid Build Coastguard Worker     struct option options[] = {
217*288bf522SAndroid Build Coastguard Worker         { "device-size", required_argument, nullptr, (int)Option::kDeviceSize },
218*288bf522SAndroid Build Coastguard Worker         { "metadata-size", required_argument, nullptr, (int)Option::kMetadataSize },
219*288bf522SAndroid Build Coastguard Worker         { "metadata-slots", required_argument, nullptr, (int)Option::kMetadataSlots },
220*288bf522SAndroid Build Coastguard Worker         { "partition", required_argument, nullptr, (int)Option::kPartition },
221*288bf522SAndroid Build Coastguard Worker         { "output", required_argument, nullptr, (int)Option::kOutput },
222*288bf522SAndroid Build Coastguard Worker         { "help", no_argument, nullptr, (int)Option::kHelp },
223*288bf522SAndroid Build Coastguard Worker         { "alignment-offset", required_argument, nullptr, (int)Option::kAlignmentOffset },
224*288bf522SAndroid Build Coastguard Worker         { "alignment", required_argument, nullptr, (int)Option::kAlignment },
225*288bf522SAndroid Build Coastguard Worker         { "sparse", no_argument, nullptr, (int)Option::kSparse },
226*288bf522SAndroid Build Coastguard Worker         { "block-size", required_argument, nullptr, (int)Option::kBlockSize },
227*288bf522SAndroid Build Coastguard Worker         { "image", required_argument, nullptr, (int)Option::kImage },
228*288bf522SAndroid Build Coastguard Worker         { "group", required_argument, nullptr, (int)Option::kGroup },
229*288bf522SAndroid Build Coastguard Worker         { "device", required_argument, nullptr, (int)Option::kDevice },
230*288bf522SAndroid Build Coastguard Worker         { "super-name", required_argument, nullptr, (int)Option::kSuperName },
231*288bf522SAndroid Build Coastguard Worker         { "auto-slot-suffixing", no_argument, nullptr, (int)Option::kAutoSlotSuffixing },
232*288bf522SAndroid Build Coastguard Worker         { "force-full-image", no_argument, nullptr, (int)Option::kForceFullImage },
233*288bf522SAndroid Build Coastguard Worker         { "virtual-ab", no_argument, nullptr, (int)Option::kVirtualAB },
234*288bf522SAndroid Build Coastguard Worker         { nullptr, 0, nullptr, 0 },
235*288bf522SAndroid Build Coastguard Worker     };
236*288bf522SAndroid Build Coastguard Worker 
237*288bf522SAndroid Build Coastguard Worker     uint64_t blockdevice_size = 0;
238*288bf522SAndroid Build Coastguard Worker     uint32_t metadata_size = 0;
239*288bf522SAndroid Build Coastguard Worker     uint32_t metadata_slots = 0;
240*288bf522SAndroid Build Coastguard Worker     uint32_t alignment_offset = 0;
241*288bf522SAndroid Build Coastguard Worker     uint32_t alignment = kDefaultPartitionAlignment;
242*288bf522SAndroid Build Coastguard Worker     uint32_t block_size = 4096;
243*288bf522SAndroid Build Coastguard Worker     std::string super_name = "super";
244*288bf522SAndroid Build Coastguard Worker     std::string output_path;
245*288bf522SAndroid Build Coastguard Worker     std::vector<PartitionInfo> partitions;
246*288bf522SAndroid Build Coastguard Worker     std::vector<std::string> groups;
247*288bf522SAndroid Build Coastguard Worker     std::vector<BlockDeviceInfo> block_devices;
248*288bf522SAndroid Build Coastguard Worker     std::map<std::string, std::string> images;
249*288bf522SAndroid Build Coastguard Worker     bool output_sparse = false;
250*288bf522SAndroid Build Coastguard Worker     bool has_implied_super = false;
251*288bf522SAndroid Build Coastguard Worker     bool auto_slot_suffixing = false;
252*288bf522SAndroid Build Coastguard Worker     bool force_full_image = false;
253*288bf522SAndroid Build Coastguard Worker     bool virtual_ab = false;
254*288bf522SAndroid Build Coastguard Worker     bool auto_blockdevice_size = false;
255*288bf522SAndroid Build Coastguard Worker 
256*288bf522SAndroid Build Coastguard Worker     int rv;
257*288bf522SAndroid Build Coastguard Worker     int index;
258*288bf522SAndroid Build Coastguard Worker     while ((rv = getopt_long_only(argc, argv, "d:m:s:p:o:h:FSx", options, &index)) != -1) {
259*288bf522SAndroid Build Coastguard Worker         switch ((Option)rv) {
260*288bf522SAndroid Build Coastguard Worker             case Option::kHelp:
261*288bf522SAndroid Build Coastguard Worker                 return usage(argc, argv);
262*288bf522SAndroid Build Coastguard Worker             case Option::kDeviceSize:
263*288bf522SAndroid Build Coastguard Worker                 if (strcmp(optarg, "auto") == 0) {
264*288bf522SAndroid Build Coastguard Worker                     auto_blockdevice_size = true;
265*288bf522SAndroid Build Coastguard Worker                 } else if (!android::base::ParseUint(optarg, &blockdevice_size) ||
266*288bf522SAndroid Build Coastguard Worker                            !blockdevice_size) {
267*288bf522SAndroid Build Coastguard Worker                     fprintf(stderr, "Invalid argument to --device-size.\n");
268*288bf522SAndroid Build Coastguard Worker                     return EX_USAGE;
269*288bf522SAndroid Build Coastguard Worker                 }
270*288bf522SAndroid Build Coastguard Worker                 has_implied_super = true;
271*288bf522SAndroid Build Coastguard Worker                 break;
272*288bf522SAndroid Build Coastguard Worker             case Option::kMetadataSize:
273*288bf522SAndroid Build Coastguard Worker                 if (!android::base::ParseUint(optarg, &metadata_size)) {
274*288bf522SAndroid Build Coastguard Worker                     fprintf(stderr, "Invalid argument to --metadata-size.\n");
275*288bf522SAndroid Build Coastguard Worker                     return EX_USAGE;
276*288bf522SAndroid Build Coastguard Worker                 }
277*288bf522SAndroid Build Coastguard Worker                 break;
278*288bf522SAndroid Build Coastguard Worker             case Option::kMetadataSlots:
279*288bf522SAndroid Build Coastguard Worker                 if (!android::base::ParseUint(optarg, &metadata_slots)) {
280*288bf522SAndroid Build Coastguard Worker                     fprintf(stderr, "Invalid argument to --metadata-slots.\n");
281*288bf522SAndroid Build Coastguard Worker                     return EX_USAGE;
282*288bf522SAndroid Build Coastguard Worker                 }
283*288bf522SAndroid Build Coastguard Worker                 break;
284*288bf522SAndroid Build Coastguard Worker             case Option::kPartition:
285*288bf522SAndroid Build Coastguard Worker                 if (auto res = PartitionInfo::Parse(optarg); !res.ok()) {
286*288bf522SAndroid Build Coastguard Worker                     fprintf(stderr, "%s\n", res.error().message().c_str());
287*288bf522SAndroid Build Coastguard Worker                     return EX_USAGE;
288*288bf522SAndroid Build Coastguard Worker                 } else {
289*288bf522SAndroid Build Coastguard Worker                     partitions.push_back(std::move(*res));
290*288bf522SAndroid Build Coastguard Worker                 }
291*288bf522SAndroid Build Coastguard Worker                 break;
292*288bf522SAndroid Build Coastguard Worker             case Option::kGroup:
293*288bf522SAndroid Build Coastguard Worker                 groups.push_back(optarg);
294*288bf522SAndroid Build Coastguard Worker                 break;
295*288bf522SAndroid Build Coastguard Worker             case Option::kOutput:
296*288bf522SAndroid Build Coastguard Worker                 output_path = optarg;
297*288bf522SAndroid Build Coastguard Worker                 break;
298*288bf522SAndroid Build Coastguard Worker             case Option::kAlignmentOffset:
299*288bf522SAndroid Build Coastguard Worker                 if (!android::base::ParseUint(optarg, &alignment_offset)) {
300*288bf522SAndroid Build Coastguard Worker                     fprintf(stderr, "Invalid argument to --alignment-offset.\n");
301*288bf522SAndroid Build Coastguard Worker                     return EX_USAGE;
302*288bf522SAndroid Build Coastguard Worker                 }
303*288bf522SAndroid Build Coastguard Worker                 has_implied_super = true;
304*288bf522SAndroid Build Coastguard Worker                 break;
305*288bf522SAndroid Build Coastguard Worker             case Option::kAlignment:
306*288bf522SAndroid Build Coastguard Worker                 if (!android::base::ParseUint(optarg, &alignment)) {
307*288bf522SAndroid Build Coastguard Worker                     fprintf(stderr, "Invalid argument to --alignment.\n");
308*288bf522SAndroid Build Coastguard Worker                     return EX_USAGE;
309*288bf522SAndroid Build Coastguard Worker                 }
310*288bf522SAndroid Build Coastguard Worker                 has_implied_super = true;
311*288bf522SAndroid Build Coastguard Worker                 break;
312*288bf522SAndroid Build Coastguard Worker             case Option::kSparse:
313*288bf522SAndroid Build Coastguard Worker                 output_sparse = true;
314*288bf522SAndroid Build Coastguard Worker                 break;
315*288bf522SAndroid Build Coastguard Worker             case Option::kBlockSize:
316*288bf522SAndroid Build Coastguard Worker                 if (!android::base::ParseUint(optarg, &block_size) || !block_size) {
317*288bf522SAndroid Build Coastguard Worker                     fprintf(stderr, "Invalid argument to --block-size.\n");
318*288bf522SAndroid Build Coastguard Worker                     return EX_USAGE;
319*288bf522SAndroid Build Coastguard Worker                 }
320*288bf522SAndroid Build Coastguard Worker                 break;
321*288bf522SAndroid Build Coastguard Worker             case Option::kImage:
322*288bf522SAndroid Build Coastguard Worker             {
323*288bf522SAndroid Build Coastguard Worker                 char* separator = strchr(optarg, '=');
324*288bf522SAndroid Build Coastguard Worker                 if (!separator || separator == optarg || !strlen(separator + 1)) {
325*288bf522SAndroid Build Coastguard Worker                     fprintf(stderr, "Expected PARTITION=FILE.\n");
326*288bf522SAndroid Build Coastguard Worker                     return EX_USAGE;
327*288bf522SAndroid Build Coastguard Worker                 }
328*288bf522SAndroid Build Coastguard Worker                 *separator = '\0';
329*288bf522SAndroid Build Coastguard Worker 
330*288bf522SAndroid Build Coastguard Worker                 std::string partition_name(optarg);
331*288bf522SAndroid Build Coastguard Worker                 std::string file(separator + 1);
332*288bf522SAndroid Build Coastguard Worker                 images[partition_name] = file;
333*288bf522SAndroid Build Coastguard Worker                 break;
334*288bf522SAndroid Build Coastguard Worker             }
335*288bf522SAndroid Build Coastguard Worker             case Option::kSuperName:
336*288bf522SAndroid Build Coastguard Worker                 super_name = optarg;
337*288bf522SAndroid Build Coastguard Worker                 break;
338*288bf522SAndroid Build Coastguard Worker             case Option::kDevice:
339*288bf522SAndroid Build Coastguard Worker             {
340*288bf522SAndroid Build Coastguard Worker                 std::vector<std::string> parts = android::base::Split(optarg, ":");
341*288bf522SAndroid Build Coastguard Worker                 if (parts.size() < 2) {
342*288bf522SAndroid Build Coastguard Worker                     fprintf(stderr, "Block device info has invalid formatting.\n");
343*288bf522SAndroid Build Coastguard Worker                     return EX_USAGE;
344*288bf522SAndroid Build Coastguard Worker                 }
345*288bf522SAndroid Build Coastguard Worker 
346*288bf522SAndroid Build Coastguard Worker                 BlockDeviceInfo info;
347*288bf522SAndroid Build Coastguard Worker                 info.partition_name = parts[0];
348*288bf522SAndroid Build Coastguard Worker                 if (!android::base::ParseUint(parts[1].c_str(), &info.size) || !info.size) {
349*288bf522SAndroid Build Coastguard Worker                     fprintf(stderr, "Block device must have a valid size.\n");
350*288bf522SAndroid Build Coastguard Worker                     return EX_USAGE;
351*288bf522SAndroid Build Coastguard Worker                 }
352*288bf522SAndroid Build Coastguard Worker                 info.alignment = kDefaultPartitionAlignment;
353*288bf522SAndroid Build Coastguard Worker                 if (parts.size() >= 3 &&
354*288bf522SAndroid Build Coastguard Worker                     !android::base::ParseUint(parts[2].c_str(), &info.alignment)) {
355*288bf522SAndroid Build Coastguard Worker                     fprintf(stderr, "Block device must have a valid alignment.\n");
356*288bf522SAndroid Build Coastguard Worker                     return EX_USAGE;
357*288bf522SAndroid Build Coastguard Worker                 }
358*288bf522SAndroid Build Coastguard Worker                 if (parts.size() >= 4 &&
359*288bf522SAndroid Build Coastguard Worker                     !android::base::ParseUint(parts[3].c_str(), &info.alignment_offset)) {
360*288bf522SAndroid Build Coastguard Worker                     fprintf(stderr, "Block device must have a valid alignment offset.\n");
361*288bf522SAndroid Build Coastguard Worker                     return EX_USAGE;
362*288bf522SAndroid Build Coastguard Worker                 }
363*288bf522SAndroid Build Coastguard Worker                 block_devices.emplace_back(info);
364*288bf522SAndroid Build Coastguard Worker                 break;
365*288bf522SAndroid Build Coastguard Worker             }
366*288bf522SAndroid Build Coastguard Worker             case Option::kAutoSlotSuffixing:
367*288bf522SAndroid Build Coastguard Worker                 auto_slot_suffixing = true;
368*288bf522SAndroid Build Coastguard Worker                 break;
369*288bf522SAndroid Build Coastguard Worker             case Option::kForceFullImage:
370*288bf522SAndroid Build Coastguard Worker                 force_full_image = true;
371*288bf522SAndroid Build Coastguard Worker                 break;
372*288bf522SAndroid Build Coastguard Worker             case Option::kVirtualAB:
373*288bf522SAndroid Build Coastguard Worker                 virtual_ab = true;
374*288bf522SAndroid Build Coastguard Worker                 break;
375*288bf522SAndroid Build Coastguard Worker             default:
376*288bf522SAndroid Build Coastguard Worker                 break;
377*288bf522SAndroid Build Coastguard Worker         }
378*288bf522SAndroid Build Coastguard Worker     }
379*288bf522SAndroid Build Coastguard Worker 
380*288bf522SAndroid Build Coastguard Worker     // Check for empty arguments so we can print a more helpful message rather
381*288bf522SAndroid Build Coastguard Worker     // than error on each individual missing argument.
382*288bf522SAndroid Build Coastguard Worker     if (optind == 1) {
383*288bf522SAndroid Build Coastguard Worker         return usage(argc, argv);
384*288bf522SAndroid Build Coastguard Worker     }
385*288bf522SAndroid Build Coastguard Worker 
386*288bf522SAndroid Build Coastguard Worker     if (auto_blockdevice_size) {
387*288bf522SAndroid Build Coastguard Worker         blockdevice_size =
388*288bf522SAndroid Build Coastguard Worker                 CalculateBlockDeviceSize(alignment, metadata_size, metadata_slots, partitions);
389*288bf522SAndroid Build Coastguard Worker         if (!blockdevice_size) {
390*288bf522SAndroid Build Coastguard Worker             fprintf(stderr, "Invalid block device parameters.\n");
391*288bf522SAndroid Build Coastguard Worker             return EX_USAGE;
392*288bf522SAndroid Build Coastguard Worker         }
393*288bf522SAndroid Build Coastguard Worker     }
394*288bf522SAndroid Build Coastguard Worker 
395*288bf522SAndroid Build Coastguard Worker     // Must specify a block device via the old method (--device-size etc) or
396*288bf522SAndroid Build Coastguard Worker     // via --device, but not both.
397*288bf522SAndroid Build Coastguard Worker     if ((has_implied_super && (!block_devices.empty() || !blockdevice_size)) ||
398*288bf522SAndroid Build Coastguard Worker         (!has_implied_super && block_devices.empty()) ||
399*288bf522SAndroid Build Coastguard Worker         (block_devices.empty() && !blockdevice_size)) {
400*288bf522SAndroid Build Coastguard Worker         fprintf(stderr, "Must specify --device OR --device-size.\n");
401*288bf522SAndroid Build Coastguard Worker         return EX_USAGE;
402*288bf522SAndroid Build Coastguard Worker     }
403*288bf522SAndroid Build Coastguard Worker     if (!metadata_size) {
404*288bf522SAndroid Build Coastguard Worker         fprintf(stderr, "--metadata-size must be more than 0 bytes.\n");
405*288bf522SAndroid Build Coastguard Worker         return EX_USAGE;
406*288bf522SAndroid Build Coastguard Worker     }
407*288bf522SAndroid Build Coastguard Worker     if (!metadata_slots) {
408*288bf522SAndroid Build Coastguard Worker         fprintf(stderr, "--metadata-slots must be more than 0.\n");
409*288bf522SAndroid Build Coastguard Worker         return EX_USAGE;
410*288bf522SAndroid Build Coastguard Worker     }
411*288bf522SAndroid Build Coastguard Worker     if (output_path.empty()) {
412*288bf522SAndroid Build Coastguard Worker         fprintf(stderr, "--output must specify a valid path.\n");
413*288bf522SAndroid Build Coastguard Worker         return EX_USAGE;
414*288bf522SAndroid Build Coastguard Worker     }
415*288bf522SAndroid Build Coastguard Worker     if (partitions.empty()) {
416*288bf522SAndroid Build Coastguard Worker         fprintf(stderr, "Partition table must have at least one entry.\n");
417*288bf522SAndroid Build Coastguard Worker         return EX_USAGE;
418*288bf522SAndroid Build Coastguard Worker     }
419*288bf522SAndroid Build Coastguard Worker 
420*288bf522SAndroid Build Coastguard Worker     // Note that we take the block_size to mean both the logical block size and
421*288bf522SAndroid Build Coastguard Worker     // the block size for libsparse.
422*288bf522SAndroid Build Coastguard Worker     if (has_implied_super) {
423*288bf522SAndroid Build Coastguard Worker         block_devices.emplace_back(super_name, blockdevice_size, alignment, alignment_offset, block_size);
424*288bf522SAndroid Build Coastguard Worker     } else {
425*288bf522SAndroid Build Coastguard Worker         // Apply the block size to each device.
426*288bf522SAndroid Build Coastguard Worker         for (auto& block_device : block_devices) {
427*288bf522SAndroid Build Coastguard Worker             block_device.logical_block_size = block_size;
428*288bf522SAndroid Build Coastguard Worker         }
429*288bf522SAndroid Build Coastguard Worker     }
430*288bf522SAndroid Build Coastguard Worker 
431*288bf522SAndroid Build Coastguard Worker     std::unique_ptr<MetadataBuilder> builder =
432*288bf522SAndroid Build Coastguard Worker             MetadataBuilder::New(block_devices, super_name, metadata_size, metadata_slots);
433*288bf522SAndroid Build Coastguard Worker     if (!builder) {
434*288bf522SAndroid Build Coastguard Worker         fprintf(stderr, "Invalid metadata parameters.\n");
435*288bf522SAndroid Build Coastguard Worker         return EX_USAGE;
436*288bf522SAndroid Build Coastguard Worker     }
437*288bf522SAndroid Build Coastguard Worker 
438*288bf522SAndroid Build Coastguard Worker     if (auto_slot_suffixing) {
439*288bf522SAndroid Build Coastguard Worker         builder->SetAutoSlotSuffixing();
440*288bf522SAndroid Build Coastguard Worker     }
441*288bf522SAndroid Build Coastguard Worker     if (virtual_ab) {
442*288bf522SAndroid Build Coastguard Worker         builder->SetVirtualABDeviceFlag();
443*288bf522SAndroid Build Coastguard Worker     }
444*288bf522SAndroid Build Coastguard Worker 
445*288bf522SAndroid Build Coastguard Worker     for (const auto& group_info : groups) {
446*288bf522SAndroid Build Coastguard Worker         std::vector<std::string> parts = android::base::Split(group_info, ":");
447*288bf522SAndroid Build Coastguard Worker         if (parts.size() != 2) {
448*288bf522SAndroid Build Coastguard Worker             fprintf(stderr, "Partition info has invalid formatting.\n");
449*288bf522SAndroid Build Coastguard Worker             return EX_USAGE;
450*288bf522SAndroid Build Coastguard Worker         }
451*288bf522SAndroid Build Coastguard Worker 
452*288bf522SAndroid Build Coastguard Worker         std::string name = parts[0];
453*288bf522SAndroid Build Coastguard Worker         if (name.empty()) {
454*288bf522SAndroid Build Coastguard Worker             fprintf(stderr, "Partition group must have a valid name.\n");
455*288bf522SAndroid Build Coastguard Worker             return EX_USAGE;
456*288bf522SAndroid Build Coastguard Worker         }
457*288bf522SAndroid Build Coastguard Worker 
458*288bf522SAndroid Build Coastguard Worker         uint64_t size;
459*288bf522SAndroid Build Coastguard Worker         if (!android::base::ParseUint(parts[1].c_str(), &size)) {
460*288bf522SAndroid Build Coastguard Worker             fprintf(stderr, "Partition group must have a valid maximum size.\n");
461*288bf522SAndroid Build Coastguard Worker             return EX_USAGE;
462*288bf522SAndroid Build Coastguard Worker         }
463*288bf522SAndroid Build Coastguard Worker 
464*288bf522SAndroid Build Coastguard Worker         if (!builder->AddGroup(name, size)) {
465*288bf522SAndroid Build Coastguard Worker             fprintf(stderr, "Group name %s already exists.\n", name.c_str());
466*288bf522SAndroid Build Coastguard Worker             return EX_SOFTWARE;
467*288bf522SAndroid Build Coastguard Worker         }
468*288bf522SAndroid Build Coastguard Worker     }
469*288bf522SAndroid Build Coastguard Worker 
470*288bf522SAndroid Build Coastguard Worker     for (auto& partition_info : partitions) {
471*288bf522SAndroid Build Coastguard Worker         Partition* partition = builder->AddPartition(partition_info.name, partition_info.group_name,
472*288bf522SAndroid Build Coastguard Worker                                                      partition_info.attribute_flags);
473*288bf522SAndroid Build Coastguard Worker         if (!partition) {
474*288bf522SAndroid Build Coastguard Worker             fprintf(stderr, "Could not add partition: %s\n", partition_info.name.c_str());
475*288bf522SAndroid Build Coastguard Worker             return EX_SOFTWARE;
476*288bf522SAndroid Build Coastguard Worker         }
477*288bf522SAndroid Build Coastguard Worker         if (!partition_info.size) {
478*288bf522SAndroid Build Coastguard Worker             // Deduce the size automatically.
479*288bf522SAndroid Build Coastguard Worker             if (auto iter = images.find(partition_info.name); iter != images.end()) {
480*288bf522SAndroid Build Coastguard Worker                 if (!GetFileSize(iter->second, &partition_info.size)) {
481*288bf522SAndroid Build Coastguard Worker                     return EX_SOFTWARE;
482*288bf522SAndroid Build Coastguard Worker                 }
483*288bf522SAndroid Build Coastguard Worker             }
484*288bf522SAndroid Build Coastguard Worker         }
485*288bf522SAndroid Build Coastguard Worker         if (!builder->ResizePartition(partition, partition_info.size)) {
486*288bf522SAndroid Build Coastguard Worker             fprintf(stderr, "Not enough space on device for partition %s with size %" PRIu64 "\n",
487*288bf522SAndroid Build Coastguard Worker                     partition_info.name.c_str(), partition_info.size);
488*288bf522SAndroid Build Coastguard Worker             return EX_SOFTWARE;
489*288bf522SAndroid Build Coastguard Worker         }
490*288bf522SAndroid Build Coastguard Worker     }
491*288bf522SAndroid Build Coastguard Worker 
492*288bf522SAndroid Build Coastguard Worker     // unlink before writing, in case it is being used by an emulator or other program,
493*288bf522SAndroid Build Coastguard Worker     // we don't want to break that program by changing the data it is accessing.
494*288bf522SAndroid Build Coastguard Worker     unlink(output_path.c_str());
495*288bf522SAndroid Build Coastguard Worker 
496*288bf522SAndroid Build Coastguard Worker     std::unique_ptr<LpMetadata> metadata = builder->Export();
497*288bf522SAndroid Build Coastguard Worker     if (!images.empty() || force_full_image) {
498*288bf522SAndroid Build Coastguard Worker         if (block_devices.size() == 1) {
499*288bf522SAndroid Build Coastguard Worker             if (!WriteToImageFile(output_path.c_str(), *metadata.get(), block_size, images,
500*288bf522SAndroid Build Coastguard Worker                                   output_sparse)) {
501*288bf522SAndroid Build Coastguard Worker                 return EX_CANTCREAT;
502*288bf522SAndroid Build Coastguard Worker             }
503*288bf522SAndroid Build Coastguard Worker         } else {
504*288bf522SAndroid Build Coastguard Worker             if (!WriteSplitImageFiles(output_path, *metadata.get(), block_size, images,
505*288bf522SAndroid Build Coastguard Worker                                       output_sparse)) {
506*288bf522SAndroid Build Coastguard Worker                 return EX_CANTCREAT;
507*288bf522SAndroid Build Coastguard Worker             }
508*288bf522SAndroid Build Coastguard Worker         }
509*288bf522SAndroid Build Coastguard Worker     } else if (!WriteToImageFile(output_path.c_str(), *metadata.get())) {
510*288bf522SAndroid Build Coastguard Worker         return EX_CANTCREAT;
511*288bf522SAndroid Build Coastguard Worker     }
512*288bf522SAndroid Build Coastguard Worker     return EX_OK;
513*288bf522SAndroid Build Coastguard Worker }
514