2 * Copyright (C) 2019 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
16 #include <android-base/result.h>
27 #include <sys/types.h>
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"
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;
49 const static struct option program_options[] = {
50 {"target", required_argument, 0, 't'},
51 {"strict", no_argument, 0, 's'},
53 {"root", required_argument, 0, 'r'},
54 {"vndk", required_argument, 0, 'v'},
55 {"recovery", no_argument, 0, 'y'},
56 {"legacy", no_argument, 0, 'l'},
58 {"help", no_argument, 0, 'h'},
62 std::string target_directory;
65 std::string vndk_version;
70 [[noreturn]] void PrintUsage(int status = EXIT_SUCCESS) {
71 std::cerr << "Usage : linkerconfig [--target <target_directory>]"
75 " --vndk <vndk version>"
84 bool ParseArgs(int argc, char* argv[], ProgramArgs* args) {
86 while ((parse_result = getopt_long(
87 argc, argv, "t:sr:v:hyl", program_options, NULL)) != -1) {
88 switch (parse_result) {
90 args->target_directory = optarg;
99 args->vndk_version = optarg;
102 args->is_recovery = true;
105 args->is_legacy = true;
121 void LoadVariables(ProgramArgs args) {
123 if (!args.is_recovery && (args.root == "" || args.vndk_version == "")) {
126 android::linkerconfig::modules::Variables::AddValue("ro.vndk.version",
130 if (!args.is_recovery) {
131 android::linkerconfig::generator::LoadVariables(args.root);
135 Result<void> WriteConfigurationToFile(Configuration& conf,
136 std::string file_path) {
137 std::ostream* out = &std::cout;
138 std::ofstream file_out;
140 if (file_path != "") {
141 file_out.open(file_path);
142 if (file_out.fail()) {
143 return ErrnoError() << "Failed to open file " << file_path;
148 android::linkerconfig::modules::ConfigWriter config_writer;
150 conf.WriteConfig(config_writer);
151 *out << config_writer.ToString();
153 return ErrnoError() << "Failed to write content to " << file_path;
159 Result<void> UpdatePermission([[maybe_unused]] const std::string& file_path) {
161 if (fchmodat(AT_FDCWD,
163 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH,
164 AT_SYMLINK_NOFOLLOW) < 0) {
165 return ErrnoError() << "Failed to update permission of " << file_path;
172 Context GetContext(ProgramArgs args) {
173 const std::string apex_root = args.root + "/apex";
174 auto apex_list = android::linkerconfig::modules::ScanActiveApexes(apex_root);
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));
183 ctx.SetStrictMode(true);
185 android::linkerconfig::contents::RegisterApexNamespaceBuilders(ctx);
189 Configuration GetConfiguration(Context& ctx) {
190 if (android::linkerconfig::modules::IsRecoveryMode()) {
191 return android::linkerconfig::contents::CreateRecoveryConfiguration(ctx);
194 if (android::linkerconfig::modules::IsLegacyDevice()) {
195 return android::linkerconfig::contents::CreateLegacyConfiguration(ctx);
198 // Use base configuration in default
199 return android::linkerconfig::contents::CreateBaseConfiguration(ctx);
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";
209 auto write_config = WriteConfigurationToFile(config, file_path);
210 if (!write_config.ok()) {
212 } else if (update_permission && file_path != "") {
213 return UpdatePermission(file_path);
219 Result<void> GenerateBaseLinkerConfiguration(Context& ctx,
220 const std::string& dir_path) {
221 return GenerateConfiguration(GetConfiguration(ctx), dir_path, true);
224 Result<void> GenerateRecoveryLinkerConfiguration(Context& ctx,
225 const std::string& dir_path) {
226 return GenerateConfiguration(
227 android::linkerconfig::contents::CreateRecoveryConfiguration(ctx),
232 Result<void> GenerateLegacyLinkerConfiguration(Context& ctx,
233 const std::string& dir_path) {
234 return GenerateConfiguration(
235 android::linkerconfig::contents::CreateLegacyConfiguration(ctx),
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;
248 return GenerateConfiguration(
249 android::linkerconfig::contents::CreateApexConfiguration(ctx, target_apex),
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);
259 LOG(WARNING) << result.error();
265 void ExitOnFailure(Result<void> task) {
267 LOG(FATAL) << task.error();
273 struct CombinedLogger {
274 android::base::LogdLogger logd;
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);
286 int main(int argc, char* argv[]) {
287 android::base::InitLogging(argv
294 ProgramArgs args = {};
296 if (!ParseArgs(argc, argv, &args)) {
297 PrintUsage(EXIT_FAILURE);
301 Context ctx = GetContext(args);
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
308 if (args.is_recovery) {
310 GenerateRecoveryLinkerConfiguration(ctx, args.target_directory));
311 } else if (args.is_legacy) {
312 ExitOnFailure(GenerateLegacyLinkerConfiguration(ctx, args.target_directory));
314 ExitOnFailure(GenerateBaseLinkerConfiguration(ctx, args.target_directory));
315 GenerateApexConfigurations(ctx, args.target_directory);