OSDN Git Service

Merge "Define vndk_product namespace for product apps" am: 6eb18354c1
[android-x86/system-linkerconfig.git] / main.cc
1 /*
2  * Copyright (C) 2019 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 #include <android-base/result.h>
17 #include <getopt.h>
18
19 #include <cstring>
20 #include <fstream>
21 #include <iostream>
22 #include <string>
23
24 #include <errno.h>
25 #include <fcntl.h>
26 #include <sys/stat.h>
27 #include <sys/types.h>
28
29 #include "linkerconfig/apex.h"
30 #include "linkerconfig/apexconfig.h"
31 #include "linkerconfig/baseconfig.h"
32 #include "linkerconfig/context.h"
33 #include "linkerconfig/environment.h"
34 #include "linkerconfig/legacy.h"
35 #include "linkerconfig/log.h"
36 #include "linkerconfig/namespacebuilder.h"
37 #include "linkerconfig/recovery.h"
38 #include "linkerconfig/variableloader.h"
39 #include "linkerconfig/variables.h"
40
41 using android::base::ErrnoError;
42 using android::base::Error;
43 using android::base::Result;
44 using android::linkerconfig::contents::Context;
45 using android::linkerconfig::modules::ApexInfo;
46 using android::linkerconfig::modules::Configuration;
47
48 namespace {
49 const static struct option program_options[] = {
50     {"target", required_argument, 0, 't'},
51     {"strict", no_argument, 0, 's'},
52 #ifndef __ANDROID__
53     {"root", required_argument, 0, 'r'},
54     {"vndk", required_argument, 0, 'v'},
55     {"recovery", no_argument, 0, 'y'},
56     {"legacy", no_argument, 0, 'l'},
57 #endif
58     {"help", no_argument, 0, 'h'},
59     {0, 0, 0, 0}};
60
61 struct ProgramArgs {
62   std::string target_directory;
63   bool strict;
64   std::string root;
65   std::string vndk_version;
66   bool is_recovery;
67   bool is_legacy;
68 };
69
70 [[noreturn]] void PrintUsage(int status = EXIT_SUCCESS) {
71   std::cerr << "Usage : linkerconfig [--target <target_directory>]"
72                " [--strict]"
73 #ifndef __ANDROID__
74                " --root <root dir>"
75                " --vndk <vndk version>"
76                " --recovery"
77                " --legacy"
78 #endif
79                " [--help]"
80             << std::endl;
81   exit(status);
82 }
83
84 bool ParseArgs(int argc, char* argv[], ProgramArgs* args) {
85   int parse_result;
86   while ((parse_result = getopt_long(
87               argc, argv, "t:sr:v:hyl", program_options, NULL)) != -1) {
88     switch (parse_result) {
89       case 't':
90         args->target_directory = optarg;
91         break;
92       case 's':
93         args->strict = true;
94         break;
95       case 'r':
96         args->root = optarg;
97         break;
98       case 'v':
99         args->vndk_version = optarg;
100         break;
101       case 'y':
102         args->is_recovery = true;
103         break;
104       case 'l':
105         args->is_legacy = true;
106         break;
107       case 'h':
108         PrintUsage();
109       default:
110         return false;
111     }
112   }
113
114   if (optind < argc) {
115     return false;
116   }
117
118   return true;
119 }
120
121 void LoadVariables(ProgramArgs args) {
122 #ifndef __ANDROID__
123   if (!args.is_recovery && (args.root == "" || args.vndk_version == "")) {
124     PrintUsage();
125   }
126   android::linkerconfig::modules::Variables::AddValue("ro.vndk.version",
127                                                       args.vndk_version);
128 #endif
129
130   if (!args.is_recovery) {
131     android::linkerconfig::generator::LoadVariables(args.root);
132   }
133 }
134
135 Result<void> WriteConfigurationToFile(Configuration& conf,
136                                       std::string file_path) {
137   std::ostream* out = &std::cout;
138   std::ofstream file_out;
139
140   if (file_path != "") {
141     file_out.open(file_path);
142     if (file_out.fail()) {
143       return ErrnoError() << "Failed to open file " << file_path;
144     }
145     out = &file_out;
146   }
147
148   android::linkerconfig::modules::ConfigWriter config_writer;
149
150   conf.WriteConfig(config_writer);
151   *out << config_writer.ToString();
152   if (!out->good()) {
153     return ErrnoError() << "Failed to write content to " << file_path;
154   }
155
156   return {};
157 }
158
159 Result<void> UpdatePermission([[maybe_unused]] const std::string& file_path) {
160 #ifdef __ANDROID__
161   if (fchmodat(AT_FDCWD,
162                file_path.c_str(),
163                S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH,
164                AT_SYMLINK_NOFOLLOW) < 0) {
165     return ErrnoError() << "Failed to update permission of " << file_path;
166   }
167 #endif
168
169   return {};
170 }
171
172 Context GetContext(ProgramArgs args) {
173   const std::string apex_root = args.root + "/apex";
174   auto apex_list = android::linkerconfig::modules::ScanActiveApexes(apex_root);
175   Context ctx;
176   for (auto const& apex_item : apex_list) {
177     auto apex_info = apex_item.second;
178     if (apex_info.has_bin || apex_info.has_lib) {
179       ctx.AddApexModule(std::move(apex_info));
180     }
181   }
182   if (args.strict) {
183     ctx.SetStrictMode(true);
184   }
185   android::linkerconfig::contents::RegisterApexNamespaceBuilders(ctx);
186   return ctx;
187 }
188
189 Configuration GetConfiguration(Context& ctx) {
190   if (android::linkerconfig::modules::IsRecoveryMode()) {
191     return android::linkerconfig::contents::CreateRecoveryConfiguration(ctx);
192   }
193
194   if (android::linkerconfig::modules::IsLegacyDevice()) {
195     return android::linkerconfig::contents::CreateLegacyConfiguration(ctx);
196   }
197
198   // Use base configuration in default
199   return android::linkerconfig::contents::CreateBaseConfiguration(ctx);
200 }
201
202 Result<void> GenerateConfiguration(Configuration config, std::string dir_path,
203                                    bool update_permission) {
204   std::string file_path = "";
205   if (dir_path != "") {
206     file_path = dir_path + "/ld.config.txt";
207   }
208
209   auto write_config = WriteConfigurationToFile(config, file_path);
210   if (!write_config.ok()) {
211     return write_config;
212   } else if (update_permission && file_path != "") {
213     return UpdatePermission(file_path);
214   }
215
216   return {};
217 }
218
219 Result<void> GenerateBaseLinkerConfiguration(Context& ctx,
220                                              const std::string& dir_path) {
221   return GenerateConfiguration(GetConfiguration(ctx), dir_path, true);
222 }
223
224 Result<void> GenerateRecoveryLinkerConfiguration(Context& ctx,
225                                                  const std::string& dir_path) {
226   return GenerateConfiguration(
227       android::linkerconfig::contents::CreateRecoveryConfiguration(ctx),
228       dir_path,
229       false);
230 }
231
232 Result<void> GenerateLegacyLinkerConfiguration(Context& ctx,
233                                                const std::string& dir_path) {
234   return GenerateConfiguration(
235       android::linkerconfig::contents::CreateLegacyConfiguration(ctx),
236       dir_path,
237       false);
238 }
239
240 Result<void> GenerateApexConfiguration(
241     const std::string& base_dir, android::linkerconfig::contents::Context& ctx,
242     const android::linkerconfig::modules::ApexInfo& target_apex) {
243   std::string dir_path = base_dir + "/" + target_apex.name;
244   if (auto ret = mkdir(dir_path.c_str(), 0755); ret != 0 && errno != EEXIST) {
245     return ErrnoError() << "Failed to create directory " << dir_path;
246   }
247
248   return GenerateConfiguration(
249       android::linkerconfig::contents::CreateApexConfiguration(ctx, target_apex),
250       dir_path,
251       true);
252 }
253
254 void GenerateApexConfigurations(Context& ctx, const std::string& dir_path) {
255   for (auto const& apex_item : ctx.GetApexModules()) {
256     if (apex_item.has_bin) {
257       auto result = GenerateApexConfiguration(dir_path, ctx, apex_item);
258       if (!result.ok()) {
259         LOG(WARNING) << result.error();
260       }
261     }
262   }
263 }
264
265 void ExitOnFailure(Result<void> task) {
266   if (!task.ok()) {
267     LOG(FATAL) << task.error();
268     exit(EXIT_FAILURE);
269   }
270 }
271
272 #ifdef __ANDROID__
273 struct CombinedLogger {
274   android::base::LogdLogger logd;
275
276   void operator()(android::base::LogId id, android::base::LogSeverity severity,
277                   const char* tag, const char* file, unsigned int line,
278                   const char* message) {
279     logd(id, severity, tag, file, line, message);
280     KernelLogger(id, severity, tag, file, line, message);
281   }
282 };
283 #endif
284 }  // namespace
285
286 int main(int argc, char* argv[]) {
287   android::base::InitLogging(argv
288 #ifdef __ANDROID__
289                              ,
290                              CombinedLogger()
291 #endif
292   );
293
294   ProgramArgs args = {};
295
296   if (!ParseArgs(argc, argv, &args)) {
297     PrintUsage(EXIT_FAILURE);
298   }
299
300   LoadVariables(args);
301   Context ctx = GetContext(args);
302
303   // when exec'ed from init, this is 0x0077, which makes the subdirectories
304   // inaccessible for others. set umask to 0x0022 so that they can be
305   // accessible.
306   umask(0x0022);
307
308   if (args.is_recovery) {
309     ExitOnFailure(
310         GenerateRecoveryLinkerConfiguration(ctx, args.target_directory));
311   } else if (args.is_legacy) {
312     ExitOnFailure(GenerateLegacyLinkerConfiguration(ctx, args.target_directory));
313   } else {
314     ExitOnFailure(GenerateBaseLinkerConfiguration(ctx, args.target_directory));
315     GenerateApexConfigurations(ctx, args.target_directory);
316   }
317
318   return EXIT_SUCCESS;
319 }