xref: /aosp_15_r20/system/apex/tools/host_apex_verifier.cc (revision 33f3758387333dbd2962d7edbd98681940d895da)
1*33f37583SAndroid Build Coastguard Worker //
2*33f37583SAndroid Build Coastguard Worker // Copyright (C) 2022 The Android Open Source Project
3*33f37583SAndroid Build Coastguard Worker //
4*33f37583SAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License");
5*33f37583SAndroid Build Coastguard Worker // you may not use this file except in compliance with the License.
6*33f37583SAndroid Build Coastguard Worker // You may obtain a copy of the License at
7*33f37583SAndroid Build Coastguard Worker //
8*33f37583SAndroid Build Coastguard Worker //      http://www.apache.org/licenses/LICENSE-2.0
9*33f37583SAndroid Build Coastguard Worker //
10*33f37583SAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
11*33f37583SAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS,
12*33f37583SAndroid Build Coastguard Worker // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*33f37583SAndroid Build Coastguard Worker // See the License for the specific language governing permissions and
14*33f37583SAndroid Build Coastguard Worker // limitations under the License.
15*33f37583SAndroid Build Coastguard Worker //
16*33f37583SAndroid Build Coastguard Worker 
17*33f37583SAndroid Build Coastguard Worker #include <action.h>
18*33f37583SAndroid Build Coastguard Worker #include <action_manager.h>
19*33f37583SAndroid Build Coastguard Worker #include <action_parser.h>
20*33f37583SAndroid Build Coastguard Worker #include <android-base/file.h>
21*33f37583SAndroid Build Coastguard Worker #include <android-base/logging.h>
22*33f37583SAndroid Build Coastguard Worker #include <android-base/parseint.h>
23*33f37583SAndroid Build Coastguard Worker #include <android-base/result.h>
24*33f37583SAndroid Build Coastguard Worker #include <android-base/strings.h>
25*33f37583SAndroid Build Coastguard Worker #include <apex_file.h>
26*33f37583SAndroid Build Coastguard Worker #include <getopt.h>
27*33f37583SAndroid Build Coastguard Worker #include <parser.h>
28*33f37583SAndroid Build Coastguard Worker #include <pwd.h>
29*33f37583SAndroid Build Coastguard Worker #include <service_list.h>
30*33f37583SAndroid Build Coastguard Worker #include <service_parser.h>
31*33f37583SAndroid Build Coastguard Worker #include <stdio.h>
32*33f37583SAndroid Build Coastguard Worker #include <stdlib.h>
33*33f37583SAndroid Build Coastguard Worker 
34*33f37583SAndroid Build Coastguard Worker #include <iostream>
35*33f37583SAndroid Build Coastguard Worker #include <string_view>
36*33f37583SAndroid Build Coastguard Worker 
37*33f37583SAndroid Build Coastguard Worker using ::apex::proto::ApexManifest;
38*33f37583SAndroid Build Coastguard Worker 
39*33f37583SAndroid Build Coastguard Worker // Fake getpwnam for host execution, used by the init::ServiceParser.
getpwnam(const char *)40*33f37583SAndroid Build Coastguard Worker passwd* getpwnam(const char*) {
41*33f37583SAndroid Build Coastguard Worker   static char fake_buf[] = "fake";
42*33f37583SAndroid Build Coastguard Worker   static passwd fake_passwd = {
43*33f37583SAndroid Build Coastguard Worker       .pw_name = fake_buf,
44*33f37583SAndroid Build Coastguard Worker       .pw_dir = fake_buf,
45*33f37583SAndroid Build Coastguard Worker       .pw_shell = fake_buf,
46*33f37583SAndroid Build Coastguard Worker       .pw_uid = 123,
47*33f37583SAndroid Build Coastguard Worker       .pw_gid = 123,
48*33f37583SAndroid Build Coastguard Worker   };
49*33f37583SAndroid Build Coastguard Worker   return &fake_passwd;
50*33f37583SAndroid Build Coastguard Worker }
51*33f37583SAndroid Build Coastguard Worker 
52*33f37583SAndroid Build Coastguard Worker namespace android {
53*33f37583SAndroid Build Coastguard Worker namespace apex {
54*33f37583SAndroid Build Coastguard Worker namespace {
55*33f37583SAndroid Build Coastguard Worker 
56*33f37583SAndroid Build Coastguard Worker static const std::vector<std::string> partitions = {"system", "system_ext",
57*33f37583SAndroid Build Coastguard Worker                                                     "product", "vendor", "odm"};
58*33f37583SAndroid Build Coastguard Worker 
PrintUsage(const std::string & msg="")59*33f37583SAndroid Build Coastguard Worker void PrintUsage(const std::string& msg = "") {
60*33f37583SAndroid Build Coastguard Worker   if (msg != "") {
61*33f37583SAndroid Build Coastguard Worker     std::cerr << "Error: " << msg << "\n";
62*33f37583SAndroid Build Coastguard Worker   }
63*33f37583SAndroid Build Coastguard Worker   printf(R"(usage: host_apex_verifier [options]
64*33f37583SAndroid Build Coastguard Worker 
65*33f37583SAndroid Build Coastguard Worker Tests APEX file(s) for correctness.
66*33f37583SAndroid Build Coastguard Worker 
67*33f37583SAndroid Build Coastguard Worker Options:
68*33f37583SAndroid Build Coastguard Worker   --deapexer=PATH             Use the deapexer binary at this path when extracting APEXes.
69*33f37583SAndroid Build Coastguard Worker   --debugfs=PATH              Use the debugfs binary at this path when extracting APEXes.
70*33f37583SAndroid Build Coastguard Worker   --fsckerofs=PATH            Use the fsck.erofs binary at this path when extracting APEXes.
71*33f37583SAndroid Build Coastguard Worker   --sdk_version=INT           The active system SDK version used when filtering versioned
72*33f37583SAndroid Build Coastguard Worker                               init.rc files.
73*33f37583SAndroid Build Coastguard Worker for checking all APEXes:
74*33f37583SAndroid Build Coastguard Worker   --out_system=DIR            Path to the factory APEX directory for the system partition.
75*33f37583SAndroid Build Coastguard Worker   --out_system_ext=DIR        Path to the factory APEX directory for the system_ext partition.
76*33f37583SAndroid Build Coastguard Worker   --out_product=DIR           Path to the factory APEX directory for the product partition.
77*33f37583SAndroid Build Coastguard Worker   --out_vendor=DIR            Path to the factory APEX directory for the vendor partition.
78*33f37583SAndroid Build Coastguard Worker   --out_odm=DIR               Path to the factory APEX directory for the odm partition.
79*33f37583SAndroid Build Coastguard Worker 
80*33f37583SAndroid Build Coastguard Worker for checking a single APEX:
81*33f37583SAndroid Build Coastguard Worker   --apex=PATH                 Path to the target APEX.
82*33f37583SAndroid Build Coastguard Worker   --partition_tag=[system|vendor|...] Partition for the target APEX.
83*33f37583SAndroid Build Coastguard Worker )");
84*33f37583SAndroid Build Coastguard Worker }
85*33f37583SAndroid Build Coastguard Worker 
86*33f37583SAndroid Build Coastguard Worker // Use this for better error message when unavailable keyword is used.
87*33f37583SAndroid Build Coastguard Worker class NotAvailableParser : public init::SectionParser {
88*33f37583SAndroid Build Coastguard Worker  public:
NotAvailableParser(const std::string & keyword)89*33f37583SAndroid Build Coastguard Worker   NotAvailableParser(const std::string& keyword) : keyword_(keyword) {}
ParseSection(std::vector<std::string> &&,const std::string &,int)90*33f37583SAndroid Build Coastguard Worker   base::Result<void> ParseSection(std::vector<std::string>&&,
91*33f37583SAndroid Build Coastguard Worker                                   const std::string&, int) override {
92*33f37583SAndroid Build Coastguard Worker     return base::Error() << "'" << keyword_ << "' is not available.";
93*33f37583SAndroid Build Coastguard Worker   }
94*33f37583SAndroid Build Coastguard Worker 
95*33f37583SAndroid Build Coastguard Worker  private:
96*33f37583SAndroid Build Coastguard Worker   std::string keyword_;
97*33f37583SAndroid Build Coastguard Worker };
98*33f37583SAndroid Build Coastguard Worker 
99*33f37583SAndroid Build Coastguard Worker // Validate any init rc files inside the APEX.
CheckInitRc(const std::string & apex_dir,const ApexManifest & manifest,int sdk_version,bool is_vendor)100*33f37583SAndroid Build Coastguard Worker void CheckInitRc(const std::string& apex_dir, const ApexManifest& manifest,
101*33f37583SAndroid Build Coastguard Worker                  int sdk_version, bool is_vendor) {
102*33f37583SAndroid Build Coastguard Worker   init::Parser parser;
103*33f37583SAndroid Build Coastguard Worker   if (is_vendor) {
104*33f37583SAndroid Build Coastguard Worker     init::InitializeHostSubcontext({apex_dir});
105*33f37583SAndroid Build Coastguard Worker   }
106*33f37583SAndroid Build Coastguard Worker   init::ServiceList service_list = init::ServiceList();
107*33f37583SAndroid Build Coastguard Worker   parser.AddSectionParser("service", std::make_unique<init::ServiceParser>(
108*33f37583SAndroid Build Coastguard Worker                                          &service_list, init::GetSubcontext()));
109*33f37583SAndroid Build Coastguard Worker   const init::BuiltinFunctionMap& function_map = init::GetBuiltinFunctionMap();
110*33f37583SAndroid Build Coastguard Worker   init::Action::set_function_map(&function_map);
111*33f37583SAndroid Build Coastguard Worker   init::ActionManager action_manager = init::ActionManager();
112*33f37583SAndroid Build Coastguard Worker   if (is_vendor) {
113*33f37583SAndroid Build Coastguard Worker     parser.AddSectionParser("on", std::make_unique<init::ActionParser>(
114*33f37583SAndroid Build Coastguard Worker                                       &action_manager, init::GetSubcontext()));
115*33f37583SAndroid Build Coastguard Worker   } else {
116*33f37583SAndroid Build Coastguard Worker     // "on" keyword is not available in non-vendor APEXes.
117*33f37583SAndroid Build Coastguard Worker     parser.AddSectionParser("on", std::make_unique<NotAvailableParser>("on"));
118*33f37583SAndroid Build Coastguard Worker   }
119*33f37583SAndroid Build Coastguard Worker 
120*33f37583SAndroid Build Coastguard Worker   std::string init_dir_path = apex_dir + "/etc";
121*33f37583SAndroid Build Coastguard Worker   std::vector<std::string> init_configs;
122*33f37583SAndroid Build Coastguard Worker   std::unique_ptr<DIR, decltype(&closedir)> init_dir(
123*33f37583SAndroid Build Coastguard Worker       opendir(init_dir_path.c_str()), closedir);
124*33f37583SAndroid Build Coastguard Worker   if (init_dir) {
125*33f37583SAndroid Build Coastguard Worker     dirent* entry;
126*33f37583SAndroid Build Coastguard Worker     while ((entry = readdir(init_dir.get()))) {
127*33f37583SAndroid Build Coastguard Worker       if (base::EndsWith(entry->d_name, "rc")) {
128*33f37583SAndroid Build Coastguard Worker         init_configs.push_back(init_dir_path + "/" + entry->d_name);
129*33f37583SAndroid Build Coastguard Worker       }
130*33f37583SAndroid Build Coastguard Worker     }
131*33f37583SAndroid Build Coastguard Worker   }
132*33f37583SAndroid Build Coastguard Worker   // TODO(b/225380016): Extend this tool to check all init.rc files
133*33f37583SAndroid Build Coastguard Worker   // in the APEX, possibly including different requirements depending
134*33f37583SAndroid Build Coastguard Worker   // on the SDK version.
135*33f37583SAndroid Build Coastguard Worker   for (const auto& c :
136*33f37583SAndroid Build Coastguard Worker        init::FilterVersionedConfigs(init_configs, sdk_version)) {
137*33f37583SAndroid Build Coastguard Worker     auto result = parser.ParseConfigFile(c);
138*33f37583SAndroid Build Coastguard Worker     if (!result.ok()) {
139*33f37583SAndroid Build Coastguard Worker       LOG(FATAL) << result.error();
140*33f37583SAndroid Build Coastguard Worker     }
141*33f37583SAndroid Build Coastguard Worker   }
142*33f37583SAndroid Build Coastguard Worker 
143*33f37583SAndroid Build Coastguard Worker   for (const auto& service : service_list) {
144*33f37583SAndroid Build Coastguard Worker     // Ensure the service path points inside this APEX.
145*33f37583SAndroid Build Coastguard Worker     auto service_path = service->args()[0];
146*33f37583SAndroid Build Coastguard Worker     if (!base::StartsWith(service_path, "/apex/" + manifest.name())) {
147*33f37583SAndroid Build Coastguard Worker       LOG(FATAL) << "Service " << service->name()
148*33f37583SAndroid Build Coastguard Worker                  << " has path outside of the APEX: " << service_path;
149*33f37583SAndroid Build Coastguard Worker     }
150*33f37583SAndroid Build Coastguard Worker     LOG(INFO) << service->name() << ": " << service_path;
151*33f37583SAndroid Build Coastguard Worker   }
152*33f37583SAndroid Build Coastguard Worker 
153*33f37583SAndroid Build Coastguard Worker   // The parser will fail if there are any unsupported actions.
154*33f37583SAndroid Build Coastguard Worker   if (parser.parse_error_count() > 0) {
155*33f37583SAndroid Build Coastguard Worker     exit(EXIT_FAILURE);
156*33f37583SAndroid Build Coastguard Worker   }
157*33f37583SAndroid Build Coastguard Worker }
158*33f37583SAndroid Build Coastguard Worker 
159*33f37583SAndroid Build Coastguard Worker // Extract and validate a single APEX.
ScanApex(const std::string & deapexer,int sdk_version,const std::string & apex_path,const std::string & partition_tag)160*33f37583SAndroid Build Coastguard Worker void ScanApex(const std::string& deapexer, int sdk_version,
161*33f37583SAndroid Build Coastguard Worker               const std::string& apex_path, const std::string& partition_tag) {
162*33f37583SAndroid Build Coastguard Worker   LOG(INFO) << "Checking APEX " << apex_path;
163*33f37583SAndroid Build Coastguard Worker 
164*33f37583SAndroid Build Coastguard Worker   auto apex = OR_FATAL(ApexFile::Open(apex_path));
165*33f37583SAndroid Build Coastguard Worker   ApexManifest manifest = apex.GetManifest();
166*33f37583SAndroid Build Coastguard Worker 
167*33f37583SAndroid Build Coastguard Worker   auto extracted_apex = TemporaryDir();
168*33f37583SAndroid Build Coastguard Worker   std::string extracted_apex_dir = extracted_apex.path;
169*33f37583SAndroid Build Coastguard Worker   std::string deapexer_command =
170*33f37583SAndroid Build Coastguard Worker       deapexer + " extract " + apex_path + " " + extracted_apex_dir;
171*33f37583SAndroid Build Coastguard Worker   auto code = system(deapexer_command.c_str());
172*33f37583SAndroid Build Coastguard Worker   if (code != 0) {
173*33f37583SAndroid Build Coastguard Worker     LOG(FATAL) << "Error running deapexer command \"" << deapexer_command
174*33f37583SAndroid Build Coastguard Worker                << "\": " << code;
175*33f37583SAndroid Build Coastguard Worker   }
176*33f37583SAndroid Build Coastguard Worker   bool is_vendor = partition_tag == "vendor" || partition_tag == "odm";
177*33f37583SAndroid Build Coastguard Worker   CheckInitRc(extracted_apex_dir, manifest, sdk_version, is_vendor);
178*33f37583SAndroid Build Coastguard Worker }
179*33f37583SAndroid Build Coastguard Worker 
180*33f37583SAndroid Build Coastguard Worker // Scan the factory APEX files in the partition apex dir.
181*33f37583SAndroid Build Coastguard Worker // Scans APEX files directly, rather than flattened ${PRODUCT_OUT}/apex/
182*33f37583SAndroid Build Coastguard Worker // directories. This allows us to check:
183*33f37583SAndroid Build Coastguard Worker //   - Prebuilt APEXes which do not flatten to that path.
184*33f37583SAndroid Build Coastguard Worker //   - Multi-installed APEXes, where only the default
185*33f37583SAndroid Build Coastguard Worker //     APEX may flatten to that path.
186*33f37583SAndroid Build Coastguard Worker //   - Extracted target_files archives which may not contain
187*33f37583SAndroid Build Coastguard Worker //     flattened <PARTITON>/apex/ directories.
ScanPartitionApexes(const std::string & deapexer,int sdk_version,const std::string & partition_dir,const std::string & partition_tag)188*33f37583SAndroid Build Coastguard Worker void ScanPartitionApexes(const std::string& deapexer, int sdk_version,
189*33f37583SAndroid Build Coastguard Worker                          const std::string& partition_dir,
190*33f37583SAndroid Build Coastguard Worker                          const std::string& partition_tag) {
191*33f37583SAndroid Build Coastguard Worker   LOG(INFO) << "Scanning " << partition_dir << " for factory APEXes in "
192*33f37583SAndroid Build Coastguard Worker             << partition_tag;
193*33f37583SAndroid Build Coastguard Worker 
194*33f37583SAndroid Build Coastguard Worker   std::unique_ptr<DIR, decltype(&closedir)> apex_dir(
195*33f37583SAndroid Build Coastguard Worker       opendir(partition_dir.c_str()), closedir);
196*33f37583SAndroid Build Coastguard Worker   if (!apex_dir) {
197*33f37583SAndroid Build Coastguard Worker     LOG(WARNING) << "Unable to open dir " << partition_dir;
198*33f37583SAndroid Build Coastguard Worker     return;
199*33f37583SAndroid Build Coastguard Worker   }
200*33f37583SAndroid Build Coastguard Worker 
201*33f37583SAndroid Build Coastguard Worker   dirent* entry;
202*33f37583SAndroid Build Coastguard Worker   while ((entry = readdir(apex_dir.get()))) {
203*33f37583SAndroid Build Coastguard Worker     if (base::EndsWith(entry->d_name, ".apex") ||
204*33f37583SAndroid Build Coastguard Worker         base::EndsWith(entry->d_name, ".capex")) {
205*33f37583SAndroid Build Coastguard Worker       ScanApex(deapexer, sdk_version, partition_dir + "/" + entry->d_name,
206*33f37583SAndroid Build Coastguard Worker                partition_tag);
207*33f37583SAndroid Build Coastguard Worker     }
208*33f37583SAndroid Build Coastguard Worker   }
209*33f37583SAndroid Build Coastguard Worker }
210*33f37583SAndroid Build Coastguard Worker 
211*33f37583SAndroid Build Coastguard Worker }  // namespace
212*33f37583SAndroid Build Coastguard Worker 
main(int argc,char ** argv)213*33f37583SAndroid Build Coastguard Worker int main(int argc, char** argv) {
214*33f37583SAndroid Build Coastguard Worker   android::base::SetMinimumLogSeverity(android::base::ERROR);
215*33f37583SAndroid Build Coastguard Worker   android::base::InitLogging(argv, &android::base::StdioLogger);
216*33f37583SAndroid Build Coastguard Worker 
217*33f37583SAndroid Build Coastguard Worker   std::string deapexer, debugfs, fsckerofs;
218*33f37583SAndroid Build Coastguard Worker   // Use ANDROID_HOST_OUT for convenience
219*33f37583SAndroid Build Coastguard Worker   const char* host_out = getenv("ANDROID_HOST_OUT");
220*33f37583SAndroid Build Coastguard Worker   if (host_out) {
221*33f37583SAndroid Build Coastguard Worker     deapexer = std::string(host_out) + "/bin/deapexer";
222*33f37583SAndroid Build Coastguard Worker     debugfs = std::string(host_out) + "/bin/debugfs_static";
223*33f37583SAndroid Build Coastguard Worker     fsckerofs = std::string(host_out) + "/bin/fsck.erofs";
224*33f37583SAndroid Build Coastguard Worker   }
225*33f37583SAndroid Build Coastguard Worker   int sdk_version = INT_MAX;
226*33f37583SAndroid Build Coastguard Worker   std::map<std::string, std::string> partition_map;
227*33f37583SAndroid Build Coastguard Worker   std::string apex;
228*33f37583SAndroid Build Coastguard Worker   std::string partition_tag;
229*33f37583SAndroid Build Coastguard Worker 
230*33f37583SAndroid Build Coastguard Worker   while (true) {
231*33f37583SAndroid Build Coastguard Worker     static const struct option long_options[] = {
232*33f37583SAndroid Build Coastguard Worker         {"help", no_argument, nullptr, 'h'},
233*33f37583SAndroid Build Coastguard Worker         {"deapexer", required_argument, nullptr, 0},
234*33f37583SAndroid Build Coastguard Worker         {"debugfs", required_argument, nullptr, 0},
235*33f37583SAndroid Build Coastguard Worker         {"fsckerofs", required_argument, nullptr, 0},
236*33f37583SAndroid Build Coastguard Worker         {"sdk_version", required_argument, nullptr, 0},
237*33f37583SAndroid Build Coastguard Worker         {"out_system", required_argument, nullptr, 0},
238*33f37583SAndroid Build Coastguard Worker         {"out_system_ext", required_argument, nullptr, 0},
239*33f37583SAndroid Build Coastguard Worker         {"out_product", required_argument, nullptr, 0},
240*33f37583SAndroid Build Coastguard Worker         {"out_vendor", required_argument, nullptr, 0},
241*33f37583SAndroid Build Coastguard Worker         {"out_odm", required_argument, nullptr, 0},
242*33f37583SAndroid Build Coastguard Worker         {"apex", required_argument, nullptr, 0},
243*33f37583SAndroid Build Coastguard Worker         {"partition_tag", required_argument, nullptr, 0},
244*33f37583SAndroid Build Coastguard Worker         {nullptr, 0, nullptr, 0},
245*33f37583SAndroid Build Coastguard Worker     };
246*33f37583SAndroid Build Coastguard Worker 
247*33f37583SAndroid Build Coastguard Worker     int option_index;
248*33f37583SAndroid Build Coastguard Worker     int arg = getopt_long(argc, argv, "h", long_options, &option_index);
249*33f37583SAndroid Build Coastguard Worker 
250*33f37583SAndroid Build Coastguard Worker     if (arg == -1) {
251*33f37583SAndroid Build Coastguard Worker       break;
252*33f37583SAndroid Build Coastguard Worker     }
253*33f37583SAndroid Build Coastguard Worker 
254*33f37583SAndroid Build Coastguard Worker     switch (arg) {
255*33f37583SAndroid Build Coastguard Worker       case 0: {
256*33f37583SAndroid Build Coastguard Worker         std::string_view name(long_options[option_index].name);
257*33f37583SAndroid Build Coastguard Worker         if (name == "deapexer") {
258*33f37583SAndroid Build Coastguard Worker           deapexer = optarg;
259*33f37583SAndroid Build Coastguard Worker         }
260*33f37583SAndroid Build Coastguard Worker         if (name == "debugfs") {
261*33f37583SAndroid Build Coastguard Worker           debugfs = optarg;
262*33f37583SAndroid Build Coastguard Worker         }
263*33f37583SAndroid Build Coastguard Worker         if (name == "fsckerofs") {
264*33f37583SAndroid Build Coastguard Worker           fsckerofs = optarg;
265*33f37583SAndroid Build Coastguard Worker         }
266*33f37583SAndroid Build Coastguard Worker         if (name == "sdk_version") {
267*33f37583SAndroid Build Coastguard Worker           if (!base::ParseInt(optarg, &sdk_version)) {
268*33f37583SAndroid Build Coastguard Worker             PrintUsage();
269*33f37583SAndroid Build Coastguard Worker             return EXIT_FAILURE;
270*33f37583SAndroid Build Coastguard Worker           }
271*33f37583SAndroid Build Coastguard Worker         }
272*33f37583SAndroid Build Coastguard Worker         if (name == "apex") {
273*33f37583SAndroid Build Coastguard Worker           apex = optarg;
274*33f37583SAndroid Build Coastguard Worker         }
275*33f37583SAndroid Build Coastguard Worker         if (name == "partition_tag") {
276*33f37583SAndroid Build Coastguard Worker           partition_tag = optarg;
277*33f37583SAndroid Build Coastguard Worker         }
278*33f37583SAndroid Build Coastguard Worker         for (const auto& p : partitions) {
279*33f37583SAndroid Build Coastguard Worker           if (name == "out_" + p) {
280*33f37583SAndroid Build Coastguard Worker             partition_map[p] = optarg;
281*33f37583SAndroid Build Coastguard Worker           }
282*33f37583SAndroid Build Coastguard Worker         }
283*33f37583SAndroid Build Coastguard Worker         break;
284*33f37583SAndroid Build Coastguard Worker       }
285*33f37583SAndroid Build Coastguard Worker       case 'h':
286*33f37583SAndroid Build Coastguard Worker         PrintUsage();
287*33f37583SAndroid Build Coastguard Worker         return EXIT_SUCCESS;
288*33f37583SAndroid Build Coastguard Worker       default:
289*33f37583SAndroid Build Coastguard Worker         LOG(ERROR) << "getopt returned invalid result: " << arg;
290*33f37583SAndroid Build Coastguard Worker         return EXIT_FAILURE;
291*33f37583SAndroid Build Coastguard Worker     }
292*33f37583SAndroid Build Coastguard Worker   }
293*33f37583SAndroid Build Coastguard Worker 
294*33f37583SAndroid Build Coastguard Worker   argc -= optind;
295*33f37583SAndroid Build Coastguard Worker   argv += optind;
296*33f37583SAndroid Build Coastguard Worker 
297*33f37583SAndroid Build Coastguard Worker   if (argc != 0) {
298*33f37583SAndroid Build Coastguard Worker     PrintUsage();
299*33f37583SAndroid Build Coastguard Worker     return EXIT_FAILURE;
300*33f37583SAndroid Build Coastguard Worker   }
301*33f37583SAndroid Build Coastguard Worker   if (deapexer.empty() || debugfs.empty() || fsckerofs.empty()) {
302*33f37583SAndroid Build Coastguard Worker     PrintUsage();
303*33f37583SAndroid Build Coastguard Worker     return EXIT_FAILURE;
304*33f37583SAndroid Build Coastguard Worker   }
305*33f37583SAndroid Build Coastguard Worker   deapexer += " --debugfs_path " + debugfs;
306*33f37583SAndroid Build Coastguard Worker   deapexer += " --fsckerofs_path " + fsckerofs;
307*33f37583SAndroid Build Coastguard Worker 
308*33f37583SAndroid Build Coastguard Worker   if (!!apex.empty() + !!partition_map.empty() != 1) {
309*33f37583SAndroid Build Coastguard Worker     PrintUsage("use either --apex or --out_<partition>.\n");
310*33f37583SAndroid Build Coastguard Worker     return EXIT_FAILURE;
311*33f37583SAndroid Build Coastguard Worker   }
312*33f37583SAndroid Build Coastguard Worker   if (!apex.empty()) {
313*33f37583SAndroid Build Coastguard Worker     if (std::find(partitions.begin(), partitions.end(), partition_tag) ==
314*33f37583SAndroid Build Coastguard Worker         partitions.end()) {
315*33f37583SAndroid Build Coastguard Worker       PrintUsage(
316*33f37583SAndroid Build Coastguard Worker           "--apex should come with "
317*33f37583SAndroid Build Coastguard Worker           "--partition_tag=[system|system_ext|product|vendor|odm].\n");
318*33f37583SAndroid Build Coastguard Worker       return EXIT_FAILURE;
319*33f37583SAndroid Build Coastguard Worker     }
320*33f37583SAndroid Build Coastguard Worker   }
321*33f37583SAndroid Build Coastguard Worker 
322*33f37583SAndroid Build Coastguard Worker   if (!partition_map.empty()) {
323*33f37583SAndroid Build Coastguard Worker     for (const auto& [partition, dir] : partition_map) {
324*33f37583SAndroid Build Coastguard Worker       ScanPartitionApexes(deapexer, sdk_version, dir, partition);
325*33f37583SAndroid Build Coastguard Worker     }
326*33f37583SAndroid Build Coastguard Worker   } else {
327*33f37583SAndroid Build Coastguard Worker     ScanApex(deapexer, sdk_version, apex, partition_tag);
328*33f37583SAndroid Build Coastguard Worker   }
329*33f37583SAndroid Build Coastguard Worker   return EXIT_SUCCESS;
330*33f37583SAndroid Build Coastguard Worker }
331*33f37583SAndroid Build Coastguard Worker 
332*33f37583SAndroid Build Coastguard Worker }  // namespace apex
333*33f37583SAndroid Build Coastguard Worker }  // namespace android
334*33f37583SAndroid Build Coastguard Worker 
main(int argc,char ** argv)335*33f37583SAndroid Build Coastguard Worker int main(int argc, char** argv) { return android::apex::main(argc, argv); }
336