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