blob: dd3a39886b959754a82850c306e804545ca71ec2 [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 Kimd7fb1c12020-10-21 09:59:12 +090036#include "linkerconfig/configparser.h"
Kiyoung Kim284bc722020-01-20 13:33:00 +090037#include "linkerconfig/context.h"
Kiyoung Kime6558072019-09-30 16:58:39 +090038#include "linkerconfig/environment.h"
39#include "linkerconfig/legacy.h"
Kiyoung Kim853438d2019-07-16 09:51:14 +090040#include "linkerconfig/log.h"
Jooyung Han9960aca2020-02-06 20:17:53 +090041#include "linkerconfig/namespacebuilder.h"
Kiyoung Kim09cbb082019-12-05 16:44:34 +090042#include "linkerconfig/recovery.h"
Kiyoung Kime9a77fe2019-05-23 11:04:20 +090043#include "linkerconfig/variableloader.h"
Jooyung Hana3d5d092019-09-26 23:23:50 +090044#include "linkerconfig/variables.h"
Kiyoung Kime9a77fe2019-05-23 11:04:20 +090045
Kiyoung Kim5c8366d2019-12-30 18:43:00 +090046using android::base::ErrnoError;
47using android::base::Error;
Jooyung Han8e5cc8d2020-03-03 00:34:32 +090048using android::base::Join;
Kiyoung Kim5c8366d2019-12-30 18:43:00 +090049using android::base::Result;
Jooyung Han87e7df82020-02-03 14:23:06 +090050using android::linkerconfig::contents::Context;
Kiyoung Kim284bc722020-01-20 13:33:00 +090051using android::linkerconfig::modules::ApexInfo;
Kiyoung Kim5c8366d2019-12-30 18:43:00 +090052using android::linkerconfig::modules::Configuration;
53
Kiyoung Kime9a77fe2019-05-23 11:04:20 +090054namespace {
55const static struct option program_options[] = {
56 {"target", required_argument, 0, 't'},
Jooyung Hanb4af7472020-02-03 18:07:12 +090057 {"strict", no_argument, 0, 's'},
Josh Gao76614bb2019-12-11 15:28:30 -080058#ifndef __ANDROID__
Jooyung Hana3d5d092019-09-26 23:23:50 +090059 {"root", required_argument, 0, 'r'},
60 {"vndk", required_argument, 0, 'v'},
Jooyung Han0441fd32020-03-31 16:14:56 +090061 {"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 std::string product_vndk_version;
Kiyoung Kim722dad62019-12-19 15:59:55 +090073 bool is_recovery;
Kiyoung Kime9a77fe2019-05-23 11:04:20 +090074};
75
76[[noreturn]] void PrintUsage(int status = EXIT_SUCCESS) {
Kiyoung Kim5c8366d2019-12-30 18:43:00 +090077 std::cerr << "Usage : linkerconfig [--target <target_directory>]"
Jooyung Hanb4af7472020-02-03 18:07:12 +090078 " [--strict]"
Jooyung Hana3d5d092019-09-26 23:23:50 +090079#ifndef __ANDROID__
80 " --root <root dir>"
81 " --vndk <vndk version>"
Jooyung Han0441fd32020-03-31 16:14:56 +090082 " --product_vndk <product vndk version>"
Kiyoung Kim722dad62019-12-19 15:59:55 +090083 " --recovery"
Jooyung Hana3d5d092019-09-26 23:23:50 +090084#endif
85 " [--help]"
Kiyoung Kime9a77fe2019-05-23 11:04:20 +090086 << std::endl;
87 exit(status);
88}
89
Jooyung Han471aeb92020-02-20 18:21:03 +090090std::string RealPath(std::string_view path) {
91 char resolved_path[PATH_MAX];
92 if (realpath(path.data(), resolved_path) != nullptr) {
93 return resolved_path;
94 }
95 PrintUsage(-1);
96}
97
Kiyoung Kime9a77fe2019-05-23 11:04:20 +090098bool ParseArgs(int argc, char* argv[], ProgramArgs* args) {
99 int parse_result;
Jooyung Hana3d5d092019-09-26 23:23:50 +0900100 while ((parse_result = getopt_long(
Jooyung Han0441fd32020-03-31 16:14:56 +0900101 argc, argv, "t:sr:v:ep:hyl", program_options, NULL)) != -1) {
Kiyoung Kime9a77fe2019-05-23 11:04:20 +0900102 switch (parse_result) {
103 case 't':
Kiyoung Kim5c8366d2019-12-30 18:43:00 +0900104 args->target_directory = optarg;
Kiyoung Kime9a77fe2019-05-23 11:04:20 +0900105 break;
Jooyung Hanb4af7472020-02-03 18:07:12 +0900106 case 's':
107 args->strict = true;
108 break;
Jooyung Hana3d5d092019-09-26 23:23:50 +0900109 case 'r':
Jooyung Han471aeb92020-02-20 18:21:03 +0900110 args->root = RealPath(optarg);
Jooyung Hana3d5d092019-09-26 23:23:50 +0900111 break;
112 case 'v':
113 args->vndk_version = optarg;
114 break;
Jooyung Han0441fd32020-03-31 16:14:56 +0900115 case 'p':
116 args->product_vndk_version = optarg;
117 break;
Kiyoung Kim722dad62019-12-19 15:59:55 +0900118 case 'y':
119 args->is_recovery = true;
120 break;
Kiyoung Kime9a77fe2019-05-23 11:04:20 +0900121 case 'h':
122 PrintUsage();
123 default:
124 return false;
125 }
126 }
127
128 if (optind < argc) {
129 return false;
130 }
131
132 return true;
133}
134
Kiyoung Kim5c8366d2019-12-30 18:43:00 +0900135void LoadVariables(ProgramArgs args) {
Kiyoung Kim722dad62019-12-19 15:59:55 +0900136#ifndef __ANDROID__
Jooyung Han71b4bf32020-04-02 15:40:41 +0900137 if (!args.is_recovery && args.root == "") {
Kiyoung Kim722dad62019-12-19 15:59:55 +0900138 PrintUsage();
139 }
140 android::linkerconfig::modules::Variables::AddValue("ro.vndk.version",
141 args.vndk_version);
Jooyung Han0441fd32020-03-31 16:14:56 +0900142 android::linkerconfig::modules::Variables::AddValue(
143 "ro.product.vndk.version", args.product_vndk_version);
Kiyoung Kim722dad62019-12-19 15:59:55 +0900144#endif
Kiyoung Kim5c8366d2019-12-30 18:43:00 +0900145 if (!args.is_recovery) {
146 android::linkerconfig::generator::LoadVariables(args.root);
147 }
148}
Kiyoung Kim722dad62019-12-19 15:59:55 +0900149
Kiyoung Kim5c8366d2019-12-30 18:43:00 +0900150Result<void> WriteConfigurationToFile(Configuration& conf,
151 std::string file_path) {
152 std::ostream* out = &std::cout;
153 std::ofstream file_out;
154
155 if (file_path != "") {
156 file_out.open(file_path);
157 if (file_out.fail()) {
158 return ErrnoError() << "Failed to open file " << file_path;
159 }
160 out = &file_out;
161 }
162
163 android::linkerconfig::modules::ConfigWriter config_writer;
164
165 conf.WriteConfig(config_writer);
166 *out << config_writer.ToString();
167 if (!out->good()) {
168 return ErrnoError() << "Failed to write content to " << file_path;
169 }
170
171 return {};
172}
173
Jooyung Han5f246362020-01-28 15:44:14 +0900174Result<void> UpdatePermission([[maybe_unused]] const std::string& file_path) {
175#ifdef __ANDROID__
Kiyoung Kim5c8366d2019-12-30 18:43:00 +0900176 if (fchmodat(AT_FDCWD,
177 file_path.c_str(),
178 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH,
179 AT_SYMLINK_NOFOLLOW) < 0) {
180 return ErrnoError() << "Failed to update permission of " << file_path;
181 }
Jooyung Han5f246362020-01-28 15:44:14 +0900182#endif
Kiyoung Kim5c8366d2019-12-30 18:43:00 +0900183
184 return {};
185}
186
Jooyung Han87e7df82020-02-03 14:23:06 +0900187Context GetContext(ProgramArgs args) {
Jooyung Han87e7df82020-02-03 14:23:06 +0900188 Context ctx;
Jooyung Hanb4af7472020-02-03 18:07:12 +0900189 if (args.strict) {
190 ctx.SetStrictMode(true);
191 }
Jooyung Hanb6323922020-08-11 08:56:29 +0000192 if (!args.is_recovery) {
193 auto apex_list = android::linkerconfig::modules::ScanActiveApexes(args.root);
Kiyoung Kimb9727632020-12-08 16:14:57 +0900194 if (apex_list.ok()) {
195 for (auto const& apex_item : *apex_list) {
196 auto apex_info = apex_item.second;
197 if (apex_info.has_bin || apex_info.has_lib) {
198 ctx.AddApexModule(std::move(apex_info));
199 }
Jooyung Hanb6323922020-08-11 08:56:29 +0000200 }
Kiyoung Kimb9727632020-12-08 16:14:57 +0900201 } else {
202 LOG(ERROR) << "Failed to scan APEX modules : " << apex_list.error();
Jooyung Hanb6323922020-08-11 08:56:29 +0000203 }
Jooyung Hanb6323922020-08-11 08:56:29 +0000204 }
Kiyoung Kimd7fb1c12020-10-21 09:59:12 +0900205
206 std::string system_config_path = args.root + "/system/etc/linker.config.pb";
207 if (access(system_config_path.c_str(), F_OK) == 0) {
208 auto system_config =
209 android::linkerconfig::modules::ParseLinkerConfig(system_config_path);
210 if (system_config.ok()) {
211 ctx.SetSystemConfig(*system_config);
212 } else {
213 LOG(ERROR) << "Failed to read system config : " << system_config.error();
214 }
215 }
Kiyoung Kim6f084a62021-05-27 15:51:16 +0900216
217 std::string vendor_config_path = args.root + "/vendor/etc/linker.config.pb";
218 if (access(vendor_config_path.c_str(), F_OK) == 0) {
219 auto vendor_config =
220 android::linkerconfig::modules::ParseLinkerConfig(vendor_config_path);
221 if (vendor_config.ok()) {
222 ctx.SetVendorConfig(*vendor_config);
223 } else {
224 LOG(ERROR) << "Failed to read vendor config : " << vendor_config.error();
225 }
226 }
227
228 std::string product_config_path = args.root + "/product/etc/linker.config.pb";
229 if (access(product_config_path.c_str(), F_OK) == 0) {
230 auto product_config =
231 android::linkerconfig::modules::ParseLinkerConfig(product_config_path);
232 if (product_config.ok()) {
233 ctx.SetProductConfig(*product_config);
234 } else {
235 LOG(ERROR) << "Failed to read product config : " << product_config.error();
236 }
237 }
Jooyung Han87e7df82020-02-03 14:23:06 +0900238 return ctx;
239}
240
241Configuration GetConfiguration(Context& ctx) {
Kiyoung Kim5c8366d2019-12-30 18:43:00 +0900242 if (android::linkerconfig::modules::IsRecoveryMode()) {
Jooyung Han87e7df82020-02-03 14:23:06 +0900243 return android::linkerconfig::contents::CreateRecoveryConfiguration(ctx);
Kiyoung Kim5c8366d2019-12-30 18:43:00 +0900244 }
245
246 if (android::linkerconfig::modules::IsLegacyDevice()) {
Jooyung Han87e7df82020-02-03 14:23:06 +0900247 return android::linkerconfig::contents::CreateLegacyConfiguration(ctx);
Kiyoung Kime6558072019-09-30 16:58:39 +0900248 }
Kiyoung Kime9a77fe2019-05-23 11:04:20 +0900249
Kiyoung Kime9a77fe2019-05-23 11:04:20 +0900250 // Use base configuration in default
Jooyung Han87e7df82020-02-03 14:23:06 +0900251 return android::linkerconfig::contents::CreateBaseConfiguration(ctx);
Kiyoung Kime9a77fe2019-05-23 11:04:20 +0900252}
Kiyoung Kime3bad042019-07-23 13:38:34 +0900253
Kiyoung Kim32e93802020-08-03 23:15:52 +0900254Result<void> GenerateConfiguration(Configuration config,
255 const std::string& dir_path,
Kiyoung Kim5c8366d2019-12-30 18:43:00 +0900256 bool update_permission) {
257 std::string file_path = "";
258 if (dir_path != "") {
259 file_path = dir_path + "/ld.config.txt";
260 }
261
262 auto write_config = WriteConfigurationToFile(config, file_path);
Bernie Innocenti5c325562020-02-06 23:16:23 +0900263 if (!write_config.ok()) {
Kiyoung Kim5c8366d2019-12-30 18:43:00 +0900264 return write_config;
265 } else if (update_permission && file_path != "") {
266 return UpdatePermission(file_path);
267 }
268
269 return {};
270}
271
Jooyung Han87e7df82020-02-03 14:23:06 +0900272Result<void> GenerateBaseLinkerConfiguration(Context& ctx,
273 const std::string& dir_path) {
274 return GenerateConfiguration(GetConfiguration(ctx), dir_path, true);
Kiyoung Kim5c8366d2019-12-30 18:43:00 +0900275}
276
Jooyung Han87e7df82020-02-03 14:23:06 +0900277Result<void> GenerateRecoveryLinkerConfiguration(Context& ctx,
278 const std::string& dir_path) {
Kiyoung Kim5c8366d2019-12-30 18:43:00 +0900279 return GenerateConfiguration(
Jooyung Han87e7df82020-02-03 14:23:06 +0900280 android::linkerconfig::contents::CreateRecoveryConfiguration(ctx),
Kiyoung Kim5c8366d2019-12-30 18:43:00 +0900281 dir_path,
282 false);
283}
284
Kiyoung Kim284bc722020-01-20 13:33:00 +0900285Result<void> GenerateApexConfiguration(
286 const std::string& base_dir, android::linkerconfig::contents::Context& ctx,
287 const android::linkerconfig::modules::ApexInfo& target_apex) {
288 std::string dir_path = base_dir + "/" + target_apex.name;
Jooyung Hana59fbd52020-01-30 12:57:34 +0900289 if (auto ret = mkdir(dir_path.c_str(), 0755); ret != 0 && errno != EEXIST) {
Kiyoung Kim284bc722020-01-20 13:33:00 +0900290 return ErrnoError() << "Failed to create directory " << dir_path;
291 }
292
293 return GenerateConfiguration(
294 android::linkerconfig::contents::CreateApexConfiguration(ctx, target_apex),
295 dir_path,
296 true);
297}
298
Jooyung Han87e7df82020-02-03 14:23:06 +0900299void GenerateApexConfigurations(Context& ctx, const std::string& dir_path) {
300 for (auto const& apex_item : ctx.GetApexModules()) {
301 if (apex_item.has_bin) {
302 auto result = GenerateApexConfiguration(dir_path, ctx, apex_item);
Bernie Innocenti5c325562020-02-06 23:16:23 +0900303 if (!result.ok()) {
Kiyoung Kim284bc722020-01-20 13:33:00 +0900304 LOG(WARNING) << result.error();
305 }
306 }
307 }
308}
309
Jooyung Han52ccfa72020-09-01 13:49:27 +0900310void GenerateApexLibrariesConfig(Context& ctx, const std::string& dir_path) {
Jooyung Han8e5cc8d2020-03-03 00:34:32 +0900311 if (dir_path == "") {
312 return;
313 }
Jooyung Han52ccfa72020-09-01 13:49:27 +0900314 const std::string file_path = dir_path + "/apex.libraries.config.txt";
Jooyung Han8e5cc8d2020-03-03 00:34:32 +0900315 std::ofstream out(file_path);
316 for (auto const& apex_item : ctx.GetApexModules()) {
317 if (!apex_item.jni_libs.empty()) {
Jooyung Han52ccfa72020-09-01 13:49:27 +0900318 out << "jni " << apex_item.namespace_name << " "
319 << Join(apex_item.jni_libs, ":") << '\n';
320 }
321 if (!apex_item.public_libs.empty()) {
322 out << "public " << apex_item.namespace_name << " "
323 << Join(apex_item.public_libs, ":") << '\n';
Jooyung Han8e5cc8d2020-03-03 00:34:32 +0900324 }
325 }
326 out.close();
327 UpdatePermission(file_path);
328}
329
Kiyoung Kim5c8366d2019-12-30 18:43:00 +0900330void ExitOnFailure(Result<void> task) {
Bernie Innocenti5c325562020-02-06 23:16:23 +0900331 if (!task.ok()) {
Kiyoung Kim5c8366d2019-12-30 18:43:00 +0900332 LOG(FATAL) << task.error();
333 exit(EXIT_FAILURE);
334 }
335}
336
Jooyung Hana3d5d092019-09-26 23:23:50 +0900337#ifdef __ANDROID__
Kiyoung Kime3bad042019-07-23 13:38:34 +0900338struct CombinedLogger {
339 android::base::LogdLogger logd;
340
341 void operator()(android::base::LogId id, android::base::LogSeverity severity,
342 const char* tag, const char* file, unsigned int line,
343 const char* message) {
344 logd(id, severity, tag, file, line, message);
345 KernelLogger(id, severity, tag, file, line, message);
346 }
347};
Jooyung Hana3d5d092019-09-26 23:23:50 +0900348#endif
Kiyoung Kime9a77fe2019-05-23 11:04:20 +0900349} // namespace
350
351int main(int argc, char* argv[]) {
Jooyung Hana3d5d092019-09-26 23:23:50 +0900352 android::base::InitLogging(argv
353#ifdef __ANDROID__
354 ,
355 CombinedLogger()
356#endif
357 );
Kiyoung Kime3bad042019-07-23 13:38:34 +0900358
Jooyung Han5bbb1232019-12-23 13:35:00 +0900359 ProgramArgs args = {};
Kiyoung Kime9a77fe2019-05-23 11:04:20 +0900360
361 if (!ParseArgs(argc, argv, &args)) {
362 PrintUsage(EXIT_FAILURE);
363 }
364
Richard Fung28d91b52020-06-25 12:38:13 -0700365 if (!android::linkerconfig::modules::IsLegacyDevice() &&
366 android::linkerconfig::modules::IsVndkLiteDevice()) {
Kiyoung Kim2006ea72020-06-23 16:15:47 +0900367 LOG(ERROR) << "Linkerconfig no longer supports VNDK-Lite configuration";
368 exit(EXIT_FAILURE);
369 }
370
Kiyoung Kim5c8366d2019-12-30 18:43:00 +0900371 LoadVariables(args);
Jooyung Han87e7df82020-02-03 14:23:06 +0900372 Context ctx = GetContext(args);
Kiyoung Kime9a77fe2019-05-23 11:04:20 +0900373
Jooyung Han82bda262020-06-11 16:58:24 +0900374 // when exec'ed from init, this is 077, which makes the subdirectories
375 // inaccessible for others. set umask to 022 so that they can be
Jiyong Parkd6018202020-02-21 13:56:52 +0900376 // accessible.
Jooyung Han82bda262020-06-11 16:58:24 +0900377 umask(022);
Jiyong Parkd6018202020-02-21 13:56:52 +0900378
Kiyoung Kim5c8366d2019-12-30 18:43:00 +0900379 if (args.is_recovery) {
Jooyung Han87e7df82020-02-03 14:23:06 +0900380 ExitOnFailure(
381 GenerateRecoveryLinkerConfiguration(ctx, args.target_directory));
Kiyoung Kim5c8366d2019-12-30 18:43:00 +0900382 } else {
Jooyung Han87e7df82020-02-03 14:23:06 +0900383 ExitOnFailure(GenerateBaseLinkerConfiguration(ctx, args.target_directory));
384 GenerateApexConfigurations(ctx, args.target_directory);
Jooyung Han52ccfa72020-09-01 13:49:27 +0900385 GenerateApexLibrariesConfig(ctx, args.target_directory);
Kiyoung Kime9a77fe2019-05-23 11:04:20 +0900386 }
387
388 return EXIT_SUCCESS;
Kiyoung Kim32e93802020-08-03 23:15:52 +0900389}