blob: b5a4553bf54d0337ec2b4b1dde56781ca78aa93e [file] [log] [blame]
Yifan Honga72bde72017-09-28 13:36:48 -07001/*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Yifan Hong69c1b112018-02-27 17:06:00 -080017#include <getopt.h>
Yifan Hong62503e12019-08-26 12:47:41 -070018#include <sysexits.h>
Yifan Hong69c1b112018-02-27 17:06:00 -080019#include <unistd.h>
Yifan Honga72bde72017-09-28 13:36:48 -070020
Yifan Hong69c1b112018-02-27 17:06:00 -080021#include <iostream>
22#include <map>
23
Yifan Hong07292852019-08-21 15:40:30 -070024#include <android-base/file.h>
Yifan Hong6aef2fc2020-01-09 14:41:11 -080025#include <android-base/logging.h>
Yifan Hong69c1b112018-02-27 17:06:00 -080026#include <android-base/parseint.h>
Yifan Hong07292852019-08-21 15:40:30 -070027#include <android-base/strings.h>
Yifan Hong69c1b112018-02-27 17:06:00 -080028#include <utils/Errors.h>
Yifan Hong07292852019-08-21 15:40:30 -070029#include <vintf/KernelConfigParser.h>
Yifan Hong69c1b112018-02-27 17:06:00 -080030#include <vintf/VintfObject.h>
Yifan Hong07292852019-08-21 15:40:30 -070031#include <vintf/parse_string.h>
Yifan Honga72bde72017-09-28 13:36:48 -070032#include <vintf/parse_xml.h>
33#include "utils.h"
34
35namespace android {
36namespace vintf {
Yifan Hong69c1b112018-02-27 17:06:00 -080037namespace details {
Yifan Honga72bde72017-09-28 13:36:48 -070038
Yifan Hong69c1b112018-02-27 17:06:00 -080039// fake sysprops
40using Properties = std::map<std::string, std::string>;
41
Yifan Hong07292852019-08-21 15:40:30 -070042using Dirmap = std::map<std::string, std::string>;
43
Yifan Hong69c1b112018-02-27 17:06:00 -080044enum Option : int {
Yifan Hong0dfc3d52020-01-09 14:30:02 -080045 // Modes
Yifan Hong69c1b112018-02-27 17:06:00 -080046 HELP,
Yifan Hong0dfc3d52020-01-09 14:30:02 -080047 DUMP_FILE_LIST = 1,
Yifan Hong69c1b112018-02-27 17:06:00 -080048 CHECK_COMPAT,
Yifan Hong0dfc3d52020-01-09 14:30:02 -080049 CHECK_ONE,
50
51 // Options
52 ROOTDIR,
53 PROPERTY,
Yifan Hong07292852019-08-21 15:40:30 -070054 DIR_MAP,
55 KERNEL,
Yifan Hong69c1b112018-02-27 17:06:00 -080056};
57// command line arguments
58using Args = std::multimap<Option, std::string>;
59
Yifan Hong07292852019-08-21 15:40:30 -070060class HostFileSystem : public details::FileSystemImpl {
Yifan Hong69c1b112018-02-27 17:06:00 -080061 public:
Yifan Hong0dfc3d52020-01-09 14:30:02 -080062 HostFileSystem(const Dirmap& dirmap, status_t missingError)
63 : mDirMap(dirmap), mMissingError(missingError) {}
Yifan Hong10d86222018-04-06 15:41:05 -070064 status_t fetch(const std::string& path, std::string* fetched,
65 std::string* error) const override {
Yifan Hong6aef2fc2020-01-09 14:41:11 -080066 auto resolved = resolve(path, error);
Yifan Hong07292852019-08-21 15:40:30 -070067 if (resolved.empty()) {
Yifan Hong0dfc3d52020-01-09 14:30:02 -080068 return mMissingError;
Yifan Hong07292852019-08-21 15:40:30 -070069 }
70 status_t status = details::FileSystemImpl::fetch(resolved, fetched, error);
Yifan Hong6aef2fc2020-01-09 14:41:11 -080071 LOG(INFO) << "Fetch '" << resolved << "': " << toString(status);
Yifan Hong10d86222018-04-06 15:41:05 -070072 return status;
Yifan Hong69c1b112018-02-27 17:06:00 -080073 }
Yifan Hong10d86222018-04-06 15:41:05 -070074 status_t listFiles(const std::string& path, std::vector<std::string>* out,
75 std::string* error) const override {
Yifan Hong6aef2fc2020-01-09 14:41:11 -080076 auto resolved = resolve(path, error);
Yifan Hong07292852019-08-21 15:40:30 -070077 if (resolved.empty()) {
Yifan Hong0dfc3d52020-01-09 14:30:02 -080078 return mMissingError;
Yifan Hong07292852019-08-21 15:40:30 -070079 }
80 status_t status = details::FileSystemImpl::listFiles(resolved, out, error);
Yifan Hong6aef2fc2020-01-09 14:41:11 -080081 LOG(INFO) << "List '" << resolved << "': " << toString(status);
Yifan Hong69c1b112018-02-27 17:06:00 -080082 return status;
83 }
84
85 private:
Yifan Hong69c1b112018-02-27 17:06:00 -080086 static std::string toString(status_t status) {
87 return status == OK ? "SUCCESS" : strerror(-status);
88 }
Yifan Hong6aef2fc2020-01-09 14:41:11 -080089 std::string resolve(const std::string& path, std::string* error) const {
Yifan Hong07292852019-08-21 15:40:30 -070090 for (auto [prefix, mappedPath] : mDirMap) {
91 if (path == prefix) {
92 return mappedPath;
93 }
94 if (android::base::StartsWith(path, prefix + "/")) {
95 return mappedPath + "/" + path.substr(prefix.size() + 1);
96 }
97 }
Yifan Hong6aef2fc2020-01-09 14:41:11 -080098 if (error) {
99 *error = "Cannot resolve path " + path;
100 } else {
Yifan Hong0dfc3d52020-01-09 14:30:02 -0800101 LOG(mMissingError == NAME_NOT_FOUND ? INFO : ERROR) << "Cannot resolve path " << path;
Yifan Hong6aef2fc2020-01-09 14:41:11 -0800102 }
Yifan Hong07292852019-08-21 15:40:30 -0700103 return "";
104 }
105
106 Dirmap mDirMap;
Yifan Hong0dfc3d52020-01-09 14:30:02 -0800107 status_t mMissingError;
Yifan Hong69c1b112018-02-27 17:06:00 -0800108};
109
110class PresetPropertyFetcher : public PropertyFetcher {
111 public:
112 std::string getProperty(const std::string& key,
113 const std::string& defaultValue) const override {
114 auto it = mProps.find(key);
115 if (it == mProps.end()) {
Yifan Hong6aef2fc2020-01-09 14:41:11 -0800116 LOG(INFO) << "Sysprop " << key << " is missing, default to '" << defaultValue << "'";
Yifan Hong69c1b112018-02-27 17:06:00 -0800117 return defaultValue;
118 }
Yifan Hong6aef2fc2020-01-09 14:41:11 -0800119 LOG(INFO) << "Sysprop " << key << "=" << it->second;
Yifan Hong69c1b112018-02-27 17:06:00 -0800120 return it->second;
121 }
122 uint64_t getUintProperty(const std::string& key, uint64_t defaultValue,
123 uint64_t max) const override {
124 uint64_t result;
125 std::string value = getProperty(key, "");
126 if (!value.empty() && android::base::ParseUint(value, &result, max)) return result;
127 return defaultValue;
128 }
129 bool getBoolProperty(const std::string& key, bool defaultValue) const override {
130 std::string value = getProperty(key, "");
131 if (value == "1" || value == "true") {
132 return true;
133 } else if (value == "0" || value == "false") {
134 return false;
135 }
136 return defaultValue;
137 }
138 void setProperties(const Properties& props) { mProps.insert(props.begin(), props.end()); }
139
140 private:
141 std::map<std::string, std::string> mProps;
142};
143
Yifan Hong07292852019-08-21 15:40:30 -0700144struct StaticRuntimeInfo : public RuntimeInfo {
145 KernelVersion kernelVersion;
146 std::string kernelConfigFile;
147
148 status_t fetchAllInformation(FetchFlags flags) override {
149 if (flags & RuntimeInfo::FetchFlag::CPU_VERSION) {
150 mKernel.mVersion = kernelVersion;
Yifan Hong6aef2fc2020-01-09 14:41:11 -0800151 LOG(INFO) << "fetched kernel version " << kernelVersion;
Yifan Hong07292852019-08-21 15:40:30 -0700152 }
153 if (flags & RuntimeInfo::FetchFlag::CONFIG_GZ) {
154 std::string content;
155 if (!android::base::ReadFileToString(kernelConfigFile, &content)) {
Yifan Hong6aef2fc2020-01-09 14:41:11 -0800156 LOG(ERROR) << "Cannot read " << kernelConfigFile;
Yifan Hong07292852019-08-21 15:40:30 -0700157 return UNKNOWN_ERROR;
158 }
159 KernelConfigParser parser;
160 auto status = parser.processAndFinish(content);
161 if (status != OK) {
162 return status;
163 }
164 mKernel.mConfigs = std::move(parser.configs());
Yifan Hong6aef2fc2020-01-09 14:41:11 -0800165 LOG(INFO) << "read kernel configs from " << kernelConfigFile;
Yifan Hong07292852019-08-21 15:40:30 -0700166 }
167 if (flags & RuntimeInfo::FetchFlag::POLICYVERS) {
168 mKernelSepolicyVersion = SIZE_MAX;
169 }
170 return OK;
171 }
172};
173
174struct StubRuntimeInfo : public RuntimeInfo {
175 status_t fetchAllInformation(FetchFlags) override { return UNKNOWN_ERROR; }
176};
177
178struct StaticRuntimeInfoFactory : public ObjectFactory<RuntimeInfo> {
179 std::shared_ptr<RuntimeInfo> info;
180 StaticRuntimeInfoFactory(std::shared_ptr<RuntimeInfo> i) : info(i) {}
181 std::shared_ptr<RuntimeInfo> make_shared() const override {
182 if (info) return info;
183 return std::make_shared<StubRuntimeInfo>();
184 }
185};
186
Yifan Hong69c1b112018-02-27 17:06:00 -0800187// helper functions
Yifan Honga72bde72017-09-28 13:36:48 -0700188template <typename T>
Yifan Hong9f78c182018-07-12 14:45:52 -0700189std::unique_ptr<T> readObject(FileSystem* fileSystem, const std::string& path,
190 const XmlConverter<T>& converter) {
Yifan Honga72bde72017-09-28 13:36:48 -0700191 std::string xml;
Yifan Hong60217032018-01-08 16:19:42 -0800192 std::string error;
Yifan Hong9f78c182018-07-12 14:45:52 -0700193 status_t err = fileSystem->fetch(path, &xml, &error);
Yifan Honga72bde72017-09-28 13:36:48 -0700194 if (err != OK) {
Yifan Hong6aef2fc2020-01-09 14:41:11 -0800195 LOG(ERROR) << "Cannot read '" << path << "' (" << strerror(-err) << "): " << error;
Yifan Honga72bde72017-09-28 13:36:48 -0700196 return nullptr;
197 }
198 auto ret = std::make_unique<T>();
Yifan Hong94757062018-02-09 16:36:31 -0800199 if (!converter(ret.get(), xml, &error)) {
Yifan Hong6aef2fc2020-01-09 14:41:11 -0800200 LOG(ERROR) << "Cannot parse '" << path << "': " << error;
Yifan Honga72bde72017-09-28 13:36:48 -0700201 return nullptr;
202 }
203 return ret;
204}
205
Yifan Hong69c1b112018-02-27 17:06:00 -0800206int checkCompatibilityForFiles(const std::string& manifestPath, const std::string& matrixPath) {
Yifan Hong9f78c182018-07-12 14:45:52 -0700207 auto fileSystem = std::make_unique<FileSystemImpl>();
208 auto manifest = readObject(fileSystem.get(), manifestPath, gHalManifestConverter);
209 auto matrix = readObject(fileSystem.get(), matrixPath, gCompatibilityMatrixConverter);
Yifan Honga72bde72017-09-28 13:36:48 -0700210 if (manifest == nullptr || matrix == nullptr) {
211 return -1;
212 }
213
214 std::string error;
215 if (!manifest->checkCompatibility(*matrix, &error)) {
Yifan Hong6aef2fc2020-01-09 14:41:11 -0800216 LOG(ERROR) << "Incompatible: " << error;
Yifan Honga72bde72017-09-28 13:36:48 -0700217 std::cout << "false" << std::endl;
218 return 1;
219 }
220
221 std::cout << "true" << std::endl;
222 return 0;
223}
Yifan Hong69c1b112018-02-27 17:06:00 -0800224
225Args parseArgs(int argc, char** argv) {
226 int longOptFlag;
227 int optionIndex;
228 Args ret;
229 std::vector<struct option> longopts{
Yifan Hong0dfc3d52020-01-09 14:30:02 -0800230 // Modes
Yifan Hong69c1b112018-02-27 17:06:00 -0800231 {"help", no_argument, &longOptFlag, HELP},
Yifan Hong0dfc3d52020-01-09 14:30:02 -0800232 {"dump-file-list", no_argument, &longOptFlag, DUMP_FILE_LIST},
Yifan Hong69c1b112018-02-27 17:06:00 -0800233 {"check-compat", no_argument, &longOptFlag, CHECK_COMPAT},
Yifan Hong0dfc3d52020-01-09 14:30:02 -0800234 {"check-one", no_argument, &longOptFlag, CHECK_ONE},
235 // Options
236 {"rootdir", required_argument, &longOptFlag, ROOTDIR},
237 {"property", required_argument, &longOptFlag, PROPERTY},
Yifan Hong07292852019-08-21 15:40:30 -0700238 {"dirmap", required_argument, &longOptFlag, DIR_MAP},
239 {"kernel", required_argument, &longOptFlag, KERNEL},
Yifan Hong69c1b112018-02-27 17:06:00 -0800240 {0, 0, 0, 0}};
241 std::map<int, Option> shortopts{
242 {'h', HELP}, {'D', PROPERTY}, {'c', CHECK_COMPAT},
243 };
244 for (;;) {
245 int c = getopt_long(argc, argv, "hcD:", longopts.data(), &optionIndex);
246 if (c == -1) {
247 break;
248 }
249 std::string argValue = optarg ? optarg : std::string{};
250 if (c == 0) {
251 ret.emplace(static_cast<Option>(longOptFlag), std::move(argValue));
252 } else {
253 ret.emplace(shortopts[c], std::move(argValue));
254 }
255 }
256 if (optind < argc) {
257 // see non option
Yifan Hong6aef2fc2020-01-09 14:41:11 -0800258 LOG(ERROR) << "unrecognized option `" << argv[optind] << "'";
Yifan Hong69c1b112018-02-27 17:06:00 -0800259 return {{HELP, ""}};
260 }
261 return ret;
262}
263
264template <typename T>
Yifan Hong07292852019-08-21 15:40:30 -0700265std::map<std::string, std::string> splitArgs(const T& args, char split) {
266 std::map<std::string, std::string> ret;
Yifan Hong69c1b112018-02-27 17:06:00 -0800267 for (const auto& arg : args) {
Yifan Hong07292852019-08-21 15:40:30 -0700268 auto pos = arg.find(split);
Yifan Hong69c1b112018-02-27 17:06:00 -0800269 auto key = arg.substr(0, pos);
270 auto value = pos == std::string::npos ? std::string{} : arg.substr(pos + 1);
271 ret[key] = value;
272 }
273 return ret;
274}
Yifan Hong07292852019-08-21 15:40:30 -0700275template <typename T>
276Properties getProperties(const T& args) {
277 return splitArgs(args, '=');
278}
279
280template <typename T>
281Dirmap getDirmap(const T& args) {
282 return splitArgs(args, ':');
283}
284
285template <typename T>
286std::shared_ptr<StaticRuntimeInfo> getRuntimeInfo(const T& args) {
287 auto ret = std::make_shared<StaticRuntimeInfo>();
288 if (std::distance(args.begin(), args.end()) > 1) {
Yifan Hong6aef2fc2020-01-09 14:41:11 -0800289 LOG(ERROR) << "Can't have multiple --kernel options";
Yifan Hong07292852019-08-21 15:40:30 -0700290 return nullptr;
291 }
292 auto pair = android::base::Split(*args.begin(), ":");
293 if (pair.size() != 2) {
Yifan Hong6aef2fc2020-01-09 14:41:11 -0800294 LOG(ERROR) << "Invalid --kernel";
Yifan Hong07292852019-08-21 15:40:30 -0700295 return nullptr;
296 }
297 if (!parse(pair[0], &ret->kernelVersion)) {
Yifan Hong6aef2fc2020-01-09 14:41:11 -0800298 LOG(ERROR) << "Cannot parse " << pair[0] << " as kernel version";
Yifan Hong07292852019-08-21 15:40:30 -0700299 return nullptr;
300 }
301 ret->kernelConfigFile = std::move(pair[1]);
302 return ret;
303}
Yifan Hong69c1b112018-02-27 17:06:00 -0800304
305int usage(const char* me) {
Yifan Hong6aef2fc2020-01-09 14:41:11 -0800306 LOG(ERROR)
Yifan Hong69c1b112018-02-27 17:06:00 -0800307 << me << ": check VINTF metadata." << std::endl
Yifan Hong0dfc3d52020-01-09 14:30:02 -0800308 << " Modes:" << std::endl
Yifan Hong69c1b112018-02-27 17:06:00 -0800309 << " --dump-file-list: Dump a list of directories / files on device" << std::endl
310 << " that is required to be used by --check-compat." << std::endl
311 << " -c, --check-compat: check compatibility for files under the root" << std::endl
312 << " directory specified by --root-dir." << std::endl
Yifan Hong0dfc3d52020-01-09 14:30:02 -0800313 << " --check-one: check consistency of VINTF metadata for a single partition."
314 << std::endl
315 << std::endl
316 << " Options:" << std::endl
Yifan Hong07292852019-08-21 15:40:30 -0700317 << " --rootdir=<dir>: specify root directory for all metadata. Same as " << std::endl
318 << " --dirmap /:<dir>" << std::endl
Yifan Hong69c1b112018-02-27 17:06:00 -0800319 << " -D, --property <key>=<value>: specify sysprops." << std::endl
Yifan Hong07292852019-08-21 15:40:30 -0700320 << " --dirmap </system:/dir/to/system> [--dirmap </vendor:/dir/to/vendor>[...]]"
321 << std::endl
322 << " Map partitions to directories. Cannot be specified with --rootdir."
323 << " --kernel <x.y.z:path/to/config>" << std::endl
324 << " Use the given kernel version and config to check. If" << std::endl
325 << " unspecified, kernel requirements are skipped." << std::endl
326 << std::endl
Yifan Hong69c1b112018-02-27 17:06:00 -0800327 << " --help: show this message." << std::endl
328 << std::endl
329 << " Example:" << std::endl
330 << " # Get the list of required files." << std::endl
331 << " " << me << " --dump-file-list > /tmp/files.txt" << std::endl
332 << " # Pull from ADB, or use your own command to extract files from images"
333 << std::endl
334 << " ROOTDIR=/tmp/device/" << std::endl
335 << " cat /tmp/files.txt | xargs -I{} bash -c \"mkdir -p $ROOTDIR`dirname {}` && adb "
336 "pull {} $ROOTDIR{}\""
337 << std::endl
338 << " # Check compatibility." << std::endl
339 << " " << me << " --check-compat --rootdir=$ROOTDIR \\" << std::endl
340 << " --property ro.product.first_api_level=`adb shell getprop "
341 "ro.product.first_api_level` \\"
342 << std::endl
343 << " --property ro.boot.product.hardware.sku=`adb shell getprop "
Yifan Hong6aef2fc2020-01-09 14:41:11 -0800344 "ro.boot.product.hardware.sku`";
Yifan Hong62503e12019-08-26 12:47:41 -0700345 return EX_USAGE;
Yifan Hong69c1b112018-02-27 17:06:00 -0800346}
347
Yifan Hong07292852019-08-21 15:40:30 -0700348int checkAllFiles(const Dirmap& dirmap, const Properties& props,
349 std::shared_ptr<StaticRuntimeInfo> runtimeInfo, std::string* error) {
Yifan Hong9f78c182018-07-12 14:45:52 -0700350 auto hostPropertyFetcher = std::make_unique<PresetPropertyFetcher>();
351 hostPropertyFetcher->setProperties(props);
Yifan Hong07292852019-08-21 15:40:30 -0700352
353 CheckFlags::Type flags = CheckFlags::DEFAULT;
354 if (!runtimeInfo) flags = flags.disableRuntimeInfo();
355
356 auto vintfObject =
357 VintfObject::Builder()
Yifan Hong0dfc3d52020-01-09 14:30:02 -0800358 .setFileSystem(std::make_unique<HostFileSystem>(dirmap, UNKNOWN_ERROR))
Yifan Hong07292852019-08-21 15:40:30 -0700359 .setPropertyFetcher(std::move(hostPropertyFetcher))
360 .setRuntimeInfoFactory(std::make_unique<StaticRuntimeInfoFactory>(runtimeInfo))
361 .build();
362 return vintfObject->checkCompatibility(error, flags);
Yifan Hong69c1b112018-02-27 17:06:00 -0800363}
364
Yifan Hong3b4a3ea2020-03-13 18:44:22 -0700365int checkDirmaps(const Dirmap& dirmap, const Properties& props) {
366 auto hostPropertyFetcher = std::make_unique<PresetPropertyFetcher>();
367 hostPropertyFetcher->setProperties(props);
Yifan Hong0dfc3d52020-01-09 14:30:02 -0800368 auto exitCode = EX_OK;
369 for (auto&& [prefix, mappedPath] : dirmap) {
370 auto vintfObject =
371 VintfObject::Builder()
372 .setFileSystem(std::make_unique<HostFileSystem>(dirmap, NAME_NOT_FOUND))
Yifan Hong3b4a3ea2020-03-13 18:44:22 -0700373 .setPropertyFetcher(std::move(hostPropertyFetcher))
Yifan Hong0dfc3d52020-01-09 14:30:02 -0800374 .setRuntimeInfoFactory(std::make_unique<StaticRuntimeInfoFactory>(nullptr))
375 .build();
376
377 if (android::base::StartsWith(prefix, "/system")) {
378 LOG(INFO) << "Checking system manifest.";
379 auto manifest = vintfObject->getFrameworkHalManifest();
380 if (!manifest) {
381 LOG(ERROR) << "Cannot fetch system manifest.";
382 exitCode = EX_SOFTWARE;
383 }
384 LOG(INFO) << "Checking system matrix.";
385 auto matrix = vintfObject->getFrameworkCompatibilityMatrix();
386 if (!matrix) {
387 LOG(ERROR) << "Cannot fetch system matrix.";
388 exitCode = EX_SOFTWARE;
389 }
390 continue;
391 }
392
393 if (android::base::StartsWith(prefix, "/vendor")) {
394 LOG(INFO) << "Checking vendor manifest.";
395 auto manifest = vintfObject->getDeviceHalManifest();
396 if (!manifest) {
397 LOG(ERROR) << "Cannot fetch vendor manifest.";
398 exitCode = EX_SOFTWARE;
399 }
400 LOG(INFO) << "Checking vendor matrix.";
401 auto matrix = vintfObject->getDeviceCompatibilityMatrix();
402 if (!matrix) {
403 LOG(ERROR) << "Cannot fetch vendor matrix.";
404 exitCode = EX_SOFTWARE;
405 }
406 continue;
407 }
408
409 LOG(ERROR) << "--check-one does not work with --dirmap " << prefix;
410 exitCode = EX_SOFTWARE;
411 }
412 return exitCode;
413}
414
Yifan Hong69c1b112018-02-27 17:06:00 -0800415} // namespace details
416} // namespace vintf
417} // namespace android
418
419int main(int argc, char** argv) {
Yifan Hong6aef2fc2020-01-09 14:41:11 -0800420 android::base::SetLogger(android::base::StderrLogger);
421
Yifan Hong69c1b112018-02-27 17:06:00 -0800422 using namespace android::vintf;
423 using namespace android::vintf::details;
424 // legacy usage: check_vintf <manifest.xml> <matrix.xml>
Yifan Hong0dfc3d52020-01-09 14:30:02 -0800425 if (argc == 3 && *argv[1] != '-' && *argv[2] != '-') {
Yifan Hong69c1b112018-02-27 17:06:00 -0800426 int ret = checkCompatibilityForFiles(argv[1], argv[2]);
427 if (ret >= 0) return ret;
428 }
429
430 Args args = parseArgs(argc, argv);
431
432 if (!iterateValues(args, HELP).empty()) {
433 return usage(argv[0]);
434 }
435
436 if (!iterateValues(args, DUMP_FILE_LIST).empty()) {
437 for (const auto& file : dumpFileList()) {
438 std::cout << file << std::endl;
439 }
440 return 0;
441 }
442
Yifan Hong0dfc3d52020-01-09 14:30:02 -0800443 auto dirmap = getDirmap(iterateValues(args, DIR_MAP));
Yifan Hong3b4a3ea2020-03-13 18:44:22 -0700444 auto properties = getProperties(iterateValues(args, PROPERTY));
Yifan Hong0dfc3d52020-01-09 14:30:02 -0800445
446 if (!iterateValues(args, CHECK_ONE).empty()) {
Yifan Hong3b4a3ea2020-03-13 18:44:22 -0700447 return checkDirmaps(dirmap, properties);
Yifan Hong0dfc3d52020-01-09 14:30:02 -0800448 }
449
Yifan Hong69c1b112018-02-27 17:06:00 -0800450 auto checkCompat = iterateValues(args, CHECK_COMPAT);
Yifan Hong07292852019-08-21 15:40:30 -0700451 if (checkCompat.empty()) {
452 return usage(argv[0]);
Yifan Hong69c1b112018-02-27 17:06:00 -0800453 }
454
Yifan Hong07292852019-08-21 15:40:30 -0700455 auto rootdirs = iterateValues(args, ROOTDIR);
456 if (!rootdirs.empty()) {
457 if (std::distance(rootdirs.begin(), rootdirs.end()) > 1) {
Yifan Hong6aef2fc2020-01-09 14:41:11 -0800458 LOG(ERROR) << "Can't have multiple --rootdir options";
Yifan Hong07292852019-08-21 15:40:30 -0700459 return usage(argv[0]);
460 }
461 args.emplace(DIR_MAP, "/:" + *rootdirs.begin());
462 }
463
Yifan Hong07292852019-08-21 15:40:30 -0700464 std::shared_ptr<StaticRuntimeInfo> runtimeInfo;
465 auto kernelArgs = iterateValues(args, KERNEL);
466 if (!kernelArgs.empty()) {
467 runtimeInfo = getRuntimeInfo(kernelArgs);
468 if (runtimeInfo == nullptr) {
469 return usage(argv[0]);
470 }
471 }
472
473 std::string error;
474 if (dirmap.empty()) {
Yifan Hong6aef2fc2020-01-09 14:41:11 -0800475 LOG(ERROR) << "Missing --rootdir or --dirmap option.";
Yifan Hong07292852019-08-21 15:40:30 -0700476 return usage(argv[0]);
477 }
478
479 int compat = checkAllFiles(dirmap, properties, runtimeInfo, &error);
Yifan Hong62503e12019-08-26 12:47:41 -0700480
481 if (compat == COMPATIBLE) {
482 std::cout << "COMPATIBLE" << std::endl;
483 return EX_OK;
484 }
485 if (compat == INCOMPATIBLE) {
Yifan Hong6aef2fc2020-01-09 14:41:11 -0800486 LOG(ERROR) << "files are incompatible: " << error;
Yifan Hong62503e12019-08-26 12:47:41 -0700487 std::cout << "INCOMPATIBLE" << std::endl;
488 return EX_DATAERR;
489 }
Yifan Hong6aef2fc2020-01-09 14:41:11 -0800490 LOG(ERROR) << strerror(-compat) << ": " << error;
Yifan Hong62503e12019-08-26 12:47:41 -0700491 return EX_SOFTWARE;
Yifan Hong69c1b112018-02-27 17:06:00 -0800492}