1 /*
2  * Copyright (C) 2020 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 
17 #define LOG_TAG "sysprop_type_checker_main"
18 
19 #include <android-base/file.h>
20 #include <android-base/logging.h>
21 #include <cstdio>
22 #include <cstdlib>
23 #include <string>
24 #include <vector>
25 
26 #include <getopt.h>
27 
28 #include "Common.h"
29 #include "TypeChecker.h"
30 
31 using android::base::Result;
32 using android::properties::ParsePropertyInfoFile;
33 using android::properties::PropertyInfoEntry;
34 
35 namespace {
36 
37 struct Arguments {
38   std::vector<std::string> api_paths;
39   std::vector<std::string> context_paths;
40 };
41 
PrintUsage(const char * exe_name)42 [[noreturn]] void PrintUsage(const char* exe_name) {
43   std::printf("Usage: %s [--api api_path]... [--context context_path]...\n",
44               exe_name);
45   std::exit(EXIT_FAILURE);
46 }
47 
ParseArgs(int argc,char * argv[])48 Result<Arguments> ParseArgs(int argc, char* argv[]) {
49   Arguments ret;
50   for (;;) {
51     static struct option long_options[] = {
52         {"api", required_argument, 0, 'a'},
53         {"context", required_argument, 0, 'c'},
54     };
55 
56     int opt = getopt_long_only(argc, argv, "", long_options, nullptr);
57     if (opt == -1) break;
58 
59     switch (opt) {
60       case 'a':
61         ret.api_paths.emplace_back(optarg);
62         break;
63       case 'c':
64         ret.context_paths.emplace_back(optarg);
65         break;
66       default:
67         PrintUsage(argv[0]);
68     }
69   }
70 
71   if (optind < argc) {
72     return Errorf("Unknown arguments");
73   }
74 
75   if (ret.api_paths.empty() || ret.context_paths.empty()) {
76     return Errorf("both api files and context files must be specified");
77   }
78 
79   return ret;
80 }
81 }  // namespace
82 
main(int argc,char * argv[])83 int main(int argc, char* argv[]) {
84   Arguments args;
85   if (auto res = ParseArgs(argc, argv); res.ok()) {
86     args = std::move(*res);
87   } else {
88     LOG(ERROR) << argv[0] << ": " << res.error();
89     PrintUsage(argv[0]);
90   }
91 
92   sysprop::SyspropLibraryApis api;
93 
94   // read all api files and merge them into one SyspropLibraryApis
95   for (auto& api_path : args.api_paths) {
96     if (auto res = ParseApiFile(api_path); res.ok()) {
97       api.MergeFrom(*res);
98     } else {
99       LOG(FATAL) << "parsing sysprop_library API file " << api_path
100                  << " failed: " << res.error();
101     }
102   }
103 
104   std::vector<PropertyInfoEntry> entries;
105 
106   // read all context files and parse entries
107   for (auto& context_path : args.context_paths) {
108     std::string contents;
109     if (!android::base::ReadFileToString(context_path, &contents)) {
110       LOG(FATAL) << "Could not read properties from '" << context_path << "'";
111     }
112 
113     std::vector<std::string> errors;
114     ParsePropertyInfoFile(contents, true, &entries, &errors);
115     if (!errors.empty()) {
116       for (const auto& error : errors) {
117         LOG(ERROR) << "Could not read line from '" << context_path
118                    << "': " << error;
119       }
120       LOG(FATAL) << "Could not parse properties from '" << context_path << "'";
121     }
122   }
123 
124   if (auto res = CheckPropertyTypes(api, entries); !res.ok()) {
125     LOG(ERROR) << "sysprop_library type check failed:\n\n" << res.error();
126     return EXIT_FAILURE;
127   }
128 }
129