blob: db59dfff0dbebc57ed5d4ed6569a78d0c3e0a601 [file] [log] [blame]
Kiyoung Kime9a77fe2019-05-23 11:04:20 +09001/*
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 */
Kiyoung Kime6558072019-09-30 16:58:39 +090016
Jooyung Han471aeb92020-02-20 18:21:03 +090017#include <climits>
18#include <cstdlib>
Kiyoung Kime9a77fe2019-05-23 11:04:20 +090019#include <cstring>
20#include <fstream>
21#include <iostream>
22#include <string>
23
Jooyung Hana59fbd52020-01-30 12:57:34 +090024#include <errno.h>
Kiyoung Kim5c8366d2019-12-30 18:43:00 +090025#include <fcntl.h>
Jooyung Han471aeb92020-02-20 18:21:03 +090026#include <getopt.h>
Kiyoung Kim5c8366d2019-12-30 18:43:00 +090027#include <sys/stat.h>
Jooyung Hana59fbd52020-01-30 12:57:34 +090028#include <sys/types.h>
Kiyoung Kim5c8366d2019-12-30 18:43:00 +090029
Jooyung Han471aeb92020-02-20 18:21:03 +090030#include <android-base/result.h>
Jooyung Han8e5cc8d2020-03-03 00:34:32 +090031#include <android-base/strings.h>
Jooyung Han471aeb92020-02-20 18:21:03 +090032
Kiyoung Kim284bc722020-01-20 13:33:00 +090033#include "linkerconfig/apex.h"
34#include "linkerconfig/apexconfig.h"
Kiyoung Kime9a77fe2019-05-23 11:04:20 +090035#include "linkerconfig/baseconfig.h"
Kiyoung Kim284bc722020-01-20 13:33:00 +090036#include "linkerconfig/context.h"
Kiyoung Kime6558072019-09-30 16:58:39 +090037#include "linkerconfig/environment.h"
38#include "linkerconfig/legacy.h"
Kiyoung Kim853438d2019-07-16 09:51:14 +090039#include "linkerconfig/log.h"
Jooyung Han9960aca2020-02-06 20:17:53 +090040#include "linkerconfig/namespacebuilder.h"
Kiyoung Kim09cbb082019-12-05 16:44:34 +090041#include "linkerconfig/recovery.h"
Kiyoung Kime9a77fe2019-05-23 11:04:20 +090042#include "linkerconfig/variableloader.h"
Jooyung Hana3d5d092019-09-26 23:23:50 +090043#include "linkerconfig/variables.h"
Kiyoung Kime9a77fe2019-05-23 11:04:20 +090044
Kiyoung Kim5c8366d2019-12-30 18:43:00 +090045using android::base::ErrnoError;
46using android::base::Error;
Jooyung Han8e5cc8d2020-03-03 00:34:32 +090047using android::base::Join;
Kiyoung Kim5c8366d2019-12-30 18:43:00 +090048using android::base::Result;
Jooyung Han87e7df82020-02-03 14:23:06 +090049using android::linkerconfig::contents::Context;
Kiyoung Kim284bc722020-01-20 13:33:00 +090050using android::linkerconfig::modules::ApexInfo;
Kiyoung Kim5c8366d2019-12-30 18:43:00 +090051using android::linkerconfig::modules::Configuration;
52
Kiyoung Kime9a77fe2019-05-23 11:04:20 +090053namespace {
54const static struct option program_options[] = {
55 {"target", required_argument, 0, 't'},
Jooyung Hanb4af7472020-02-03 18:07:12 +090056 {"strict", no_argument, 0, 's'},
Josh Gao76614bb2019-12-11 15:28:30 -080057#ifndef __ANDROID__
Jooyung Hana3d5d092019-09-26 23:23:50 +090058 {"root", required_argument, 0, 'r'},
59 {"vndk", required_argument, 0, 'v'},
Jooyung Han0441fd32020-03-31 16:14:56 +090060 {"vndk_lite", no_argument, 0, 'e'},
61 {"product_vndk", required_argument, 0, 'p'},
Kiyoung Kim722dad62019-12-19 15:59:55 +090062 {"recovery", no_argument, 0, 'y'},
Jooyung Hana3d5d092019-09-26 23:23:50 +090063#endif
Kiyoung Kime9a77fe2019-05-23 11:04:20 +090064 {"help", no_argument, 0, 'h'},
65 {0, 0, 0, 0}};
66
67struct ProgramArgs {
Kiyoung Kim5c8366d2019-12-30 18:43:00 +090068 std::string target_directory;
Jooyung Hanb4af7472020-02-03 18:07:12 +090069 bool strict;
Jooyung Hana3d5d092019-09-26 23:23:50 +090070 std::string root;
71 std::string vndk_version;
Jooyung Han0441fd32020-03-31 16:14:56 +090072 bool vndk_lite;
73 std::string product_vndk_version;
Kiyoung Kim722dad62019-12-19 15:59:55 +090074 bool is_recovery;
Kiyoung Kime9a77fe2019-05-23 11:04:20 +090075};
76
77[[noreturn]] void PrintUsage(int status = EXIT_SUCCESS) {
Kiyoung Kim5c8366d2019-12-30 18:43:00 +090078 std::cerr << "Usage : linkerconfig [--target <target_directory>]"
Jooyung Hanb4af7472020-02-03 18:07:12 +090079 " [--strict]"
Jooyung Hana3d5d092019-09-26 23:23:50 +090080#ifndef __ANDROID__
81 " --root <root dir>"
82 " --vndk <vndk version>"
Jooyung Han0441fd32020-03-31 16:14:56 +090083 " --vndk_lite"
84 " --product_vndk <product vndk version>"
Kiyoung Kim722dad62019-12-19 15:59:55 +090085 " --recovery"
Jooyung Hana3d5d092019-09-26 23:23:50 +090086#endif
87 " [--help]"
Kiyoung Kime9a77fe2019-05-23 11:04:20 +090088 << std::endl;
89 exit(status);
90}
91
Jooyung Han471aeb92020-02-20 18:21:03 +090092std::string RealPath(std::string_view path) {
93 char resolved_path[PATH_MAX];
94 if (realpath(path.data(), resolved_path) != nullptr) {
95 return resolved_path;
96 }
97 PrintUsage(-1);
98}
99
Kiyoung Kime9a77fe2019-05-23 11:04:20 +0900100bool ParseArgs(int argc, char* argv[], ProgramArgs* args) {
101 int parse_result;
Jooyung Hana3d5d092019-09-26 23:23:50 +0900102 while ((parse_result = getopt_long(
Jooyung Han0441fd32020-03-31 16:14:56 +0900103 argc, argv, "t:sr:v:ep:hyl", program_options, NULL)) != -1) {
Kiyoung Kime9a77fe2019-05-23 11:04:20 +0900104 switch (parse_result) {
105 case 't':
Kiyoung Kim5c8366d2019-12-30 18:43:00 +0900106 args->target_directory = optarg;
Kiyoung Kime9a77fe2019-05-23 11:04:20 +0900107 break;
Jooyung Hanb4af7472020-02-03 18:07:12 +0900108 case 's':
109 args->strict = true;
110 break;
Jooyung Hana3d5d092019-09-26 23:23:50 +0900111 case 'r':
Jooyung Han471aeb92020-02-20 18:21:03 +0900112 args->root = RealPath(optarg);
Jooyung Hana3d5d092019-09-26 23:23:50 +0900113 break;
114 case 'v':
115 args->vndk_version = optarg;
116 break;
Jooyung Han0441fd32020-03-31 16:14:56 +0900117 case 'e':
118 args->vndk_lite = true;
119 break;
120 case 'p':
121 args->product_vndk_version = optarg;
122 break;
Kiyoung Kim722dad62019-12-19 15:59:55 +0900123 case 'y':
124 args->is_recovery = true;
125 break;
Kiyoung Kime9a77fe2019-05-23 11:04:20 +0900126 case 'h':
127 PrintUsage();
128 default:
129 return false;
130 }
131 }
132
133 if (optind < argc) {
134 return false;
135 }
136
137 return true;
138}
139
Kiyoung Kim5c8366d2019-12-30 18:43:00 +0900140void LoadVariables(ProgramArgs args) {
Kiyoung Kim722dad62019-12-19 15:59:55 +0900141#ifndef __ANDROID__
Jooyung Han71b4bf32020-04-02 15:40:41 +0900142 if (!args.is_recovery && args.root == "") {
Kiyoung Kim722dad62019-12-19 15:59:55 +0900143 PrintUsage();
144 }
145 android::linkerconfig::modules::Variables::AddValue("ro.vndk.version",
146 args.vndk_version);
Jooyung Han0441fd32020-03-31 16:14:56 +0900147 android::linkerconfig::modules::Variables::AddValue(
148 "ro.product.vndk.version", args.product_vndk_version);
149 if (args.vndk_lite) {
150 android::linkerconfig::modules::Variables::AddValue("ro.vndk.lite", "true");
151 }
Kiyoung Kim722dad62019-12-19 15:59:55 +0900152#endif
Kiyoung Kim5c8366d2019-12-30 18:43:00 +0900153 if (!args.is_recovery) {
154 android::linkerconfig::generator::LoadVariables(args.root);
155 }
156}
Kiyoung Kim722dad62019-12-19 15:59:55 +0900157
Kiyoung Kim5c8366d2019-12-30 18:43:00 +0900158Result<void> WriteConfigurationToFile(Configuration& conf,
159 std::string file_path) {
160 std::ostream* out = &std::cout;
161 std::ofstream file_out;
162
163 if (file_path != "") {
164 file_out.open(file_path);
165 if (file_out.fail()) {
166 return ErrnoError() << "Failed to open file " << file_path;
167 }
168 out = &file_out;
169 }
170
171 android::linkerconfig::modules::ConfigWriter config_writer;
172
173 conf.WriteConfig(config_writer);
174 *out << config_writer.ToString();
175 if (!out->good()) {
176 return ErrnoError() << "Failed to write content to " << file_path;
177 }
178
179 return {};
180}
181
Jooyung Han5f246362020-01-28 15:44:14 +0900182Result<void> UpdatePermission([[maybe_unused]] const std::string& file_path) {
183#ifdef __ANDROID__
Kiyoung Kim5c8366d2019-12-30 18:43:00 +0900184 if (fchmodat(AT_FDCWD,
185 file_path.c_str(),
186 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH,
187 AT_SYMLINK_NOFOLLOW) < 0) {
188 return ErrnoError() << "Failed to update permission of " << file_path;
189 }
Jooyung Han5f246362020-01-28 15:44:14 +0900190#endif
Kiyoung Kim5c8366d2019-12-30 18:43:00 +0900191
192 return {};
193}
194
Jooyung Han87e7df82020-02-03 14:23:06 +0900195Context GetContext(ProgramArgs args) {
Jooyung Han471aeb92020-02-20 18:21:03 +0900196 auto apex_list = android::linkerconfig::modules::ScanActiveApexes(args.root);
Jooyung Han87e7df82020-02-03 14:23:06 +0900197 Context ctx;
198 for (auto const& apex_item : apex_list) {
199 auto apex_info = apex_item.second;
200 if (apex_info.has_bin || apex_info.has_lib) {
201 ctx.AddApexModule(std::move(apex_info));
202 }
203 }
Jooyung Hanb4af7472020-02-03 18:07:12 +0900204 if (args.strict) {
205 ctx.SetStrictMode(true);
206 }
Jooyung Han9960aca2020-02-06 20:17:53 +0900207 android::linkerconfig::contents::RegisterApexNamespaceBuilders(ctx);
Jooyung Han87e7df82020-02-03 14:23:06 +0900208 return ctx;
209}
210
211Configuration GetConfiguration(Context& ctx) {
Kiyoung Kim5c8366d2019-12-30 18:43:00 +0900212 if (android::linkerconfig::modules::IsRecoveryMode()) {
Jooyung Han87e7df82020-02-03 14:23:06 +0900213 return android::linkerconfig::contents::CreateRecoveryConfiguration(ctx);
Kiyoung Kim5c8366d2019-12-30 18:43:00 +0900214 }
215
216 if (android::linkerconfig::modules::IsLegacyDevice()) {
Jooyung Han87e7df82020-02-03 14:23:06 +0900217 return android::linkerconfig::contents::CreateLegacyConfiguration(ctx);
Kiyoung Kime6558072019-09-30 16:58:39 +0900218 }
Kiyoung Kime9a77fe2019-05-23 11:04:20 +0900219
Kiyoung Kime9a77fe2019-05-23 11:04:20 +0900220 // Use base configuration in default
Jooyung Han87e7df82020-02-03 14:23:06 +0900221 return android::linkerconfig::contents::CreateBaseConfiguration(ctx);
Kiyoung Kime9a77fe2019-05-23 11:04:20 +0900222}
Kiyoung Kime3bad042019-07-23 13:38:34 +0900223
Kiyoung Kim5c8366d2019-12-30 18:43:00 +0900224Result<void> GenerateConfiguration(Configuration config, std::string dir_path,
225 bool update_permission) {
226 std::string file_path = "";
227 if (dir_path != "") {
228 file_path = dir_path + "/ld.config.txt";
229 }
230
231 auto write_config = WriteConfigurationToFile(config, file_path);
Bernie Innocenti5c325562020-02-06 23:16:23 +0900232 if (!write_config.ok()) {
Kiyoung Kim5c8366d2019-12-30 18:43:00 +0900233 return write_config;
234 } else if (update_permission && file_path != "") {
235 return UpdatePermission(file_path);
236 }
237
238 return {};
239}
240
Jooyung Han87e7df82020-02-03 14:23:06 +0900241Result<void> GenerateBaseLinkerConfiguration(Context& ctx,
242 const std::string& dir_path) {
243 return GenerateConfiguration(GetConfiguration(ctx), dir_path, true);
Kiyoung Kim5c8366d2019-12-30 18:43:00 +0900244}
245
Jooyung Han87e7df82020-02-03 14:23:06 +0900246Result<void> GenerateRecoveryLinkerConfiguration(Context& ctx,
247 const std::string& dir_path) {
Kiyoung Kim5c8366d2019-12-30 18:43:00 +0900248 return GenerateConfiguration(
Jooyung Han87e7df82020-02-03 14:23:06 +0900249 android::linkerconfig::contents::CreateRecoveryConfiguration(ctx),
Kiyoung Kim5c8366d2019-12-30 18:43:00 +0900250 dir_path,
251 false);
252}
253
Kiyoung Kim284bc722020-01-20 13:33:00 +0900254Result<void> GenerateApexConfiguration(
255 const std::string& base_dir, android::linkerconfig::contents::Context& ctx,
256 const android::linkerconfig::modules::ApexInfo& target_apex) {
257 std::string dir_path = base_dir + "/" + target_apex.name;
Jooyung Hana59fbd52020-01-30 12:57:34 +0900258 if (auto ret = mkdir(dir_path.c_str(), 0755); ret != 0 && errno != EEXIST) {
Kiyoung Kim284bc722020-01-20 13:33:00 +0900259 return ErrnoError() << "Failed to create directory " << dir_path;
260 }
261
262 return GenerateConfiguration(
263 android::linkerconfig::contents::CreateApexConfiguration(ctx, target_apex),
264 dir_path,
265 true);
266}
267
Jooyung Han87e7df82020-02-03 14:23:06 +0900268void GenerateApexConfigurations(Context& ctx, const std::string& dir_path) {
269 for (auto const& apex_item : ctx.GetApexModules()) {
270 if (apex_item.has_bin) {
271 auto result = GenerateApexConfiguration(dir_path, ctx, apex_item);
Bernie Innocenti5c325562020-02-06 23:16:23 +0900272 if (!result.ok()) {
Kiyoung Kim284bc722020-01-20 13:33:00 +0900273 LOG(WARNING) << result.error();
274 }
275 }
276 }
277}
278
Jooyung Han8e5cc8d2020-03-03 00:34:32 +0900279void GenerateJniConfig(Context& ctx, const std::string& dir_path) {
280 if (dir_path == "") {
281 return;
282 }
283 std::string file_path = dir_path + "/jni.config.txt";
284 std::ofstream out(file_path);
285 for (auto const& apex_item : ctx.GetApexModules()) {
286 if (!apex_item.jni_libs.empty()) {
287 out << apex_item.namespace_name << " " << Join(apex_item.jni_libs, ":")
288 << '\n';
289 }
290 }
291 out.close();
292 UpdatePermission(file_path);
293}
294
Kiyoung Kim5c8366d2019-12-30 18:43:00 +0900295void ExitOnFailure(Result<void> task) {
Bernie Innocenti5c325562020-02-06 23:16:23 +0900296 if (!task.ok()) {
Kiyoung Kim5c8366d2019-12-30 18:43:00 +0900297 LOG(FATAL) << task.error();
298 exit(EXIT_FAILURE);
299 }
300}
301
Jooyung Hana3d5d092019-09-26 23:23:50 +0900302#ifdef __ANDROID__
Kiyoung Kime3bad042019-07-23 13:38:34 +0900303struct CombinedLogger {
304 android::base::LogdLogger logd;
305
306 void operator()(android::base::LogId id, android::base::LogSeverity severity,
307 const char* tag, const char* file, unsigned int line,
308 const char* message) {
309 logd(id, severity, tag, file, line, message);
310 KernelLogger(id, severity, tag, file, line, message);
311 }
312};
Jooyung Hana3d5d092019-09-26 23:23:50 +0900313#endif
Kiyoung Kime9a77fe2019-05-23 11:04:20 +0900314} // namespace
315
316int main(int argc, char* argv[]) {
Jooyung Hana3d5d092019-09-26 23:23:50 +0900317 android::base::InitLogging(argv
318#ifdef __ANDROID__
319 ,
320 CombinedLogger()
321#endif
322 );
Kiyoung Kime3bad042019-07-23 13:38:34 +0900323
Jooyung Han5bbb1232019-12-23 13:35:00 +0900324 ProgramArgs args = {};
Kiyoung Kime9a77fe2019-05-23 11:04:20 +0900325
326 if (!ParseArgs(argc, argv, &args)) {
327 PrintUsage(EXIT_FAILURE);
328 }
329
Kiyoung Kim5c8366d2019-12-30 18:43:00 +0900330 LoadVariables(args);
Jooyung Han87e7df82020-02-03 14:23:06 +0900331 Context ctx = GetContext(args);
Kiyoung Kime9a77fe2019-05-23 11:04:20 +0900332
Jiyong Parkd6018202020-02-21 13:56:52 +0900333 // when exec'ed from init, this is 0x0077, which makes the subdirectories
334 // inaccessible for others. set umask to 0x0022 so that they can be
335 // accessible.
336 umask(0x0022);
337
Kiyoung Kim5c8366d2019-12-30 18:43:00 +0900338 if (args.is_recovery) {
Jooyung Han87e7df82020-02-03 14:23:06 +0900339 ExitOnFailure(
340 GenerateRecoveryLinkerConfiguration(ctx, args.target_directory));
Kiyoung Kim5c8366d2019-12-30 18:43:00 +0900341 } else {
Jooyung Han87e7df82020-02-03 14:23:06 +0900342 ExitOnFailure(GenerateBaseLinkerConfiguration(ctx, args.target_directory));
343 GenerateApexConfigurations(ctx, args.target_directory);
Jooyung Han8e5cc8d2020-03-03 00:34:32 +0900344 GenerateJniConfig(ctx, args.target_directory);
Kiyoung Kime9a77fe2019-05-23 11:04:20 +0900345 }
346
347 return EXIT_SUCCESS;
Josh Gao76614bb2019-12-11 15:28:30 -0800348}