| /* |
| * Copyright (C) 2022 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #include "apex_init_util.h" |
| |
| #include <glob.h> |
| |
| #include <vector> |
| |
| #include <android-base/logging.h> |
| #include <android-base/result.h> |
| #include <android-base/properties.h> |
| #include <android-base/strings.h> |
| |
| #include "action_manager.h" |
| #include "init.h" |
| #include "parser.h" |
| #include "service_list.h" |
| #include "util.h" |
| |
| namespace android { |
| namespace init { |
| |
| static Result<std::vector<std::string>> CollectApexConfigs(const std::string& apex_name) { |
| glob_t glob_result; |
| std::string glob_pattern = apex_name.empty() ? |
| "/apex/*/etc/*rc" : "/apex/" + apex_name + "/etc/*rc"; |
| |
| const int ret = glob(glob_pattern.c_str(), GLOB_MARK, nullptr, &glob_result); |
| if (ret != 0 && ret != GLOB_NOMATCH) { |
| globfree(&glob_result); |
| return Error() << "Glob pattern '" << glob_pattern << "' failed"; |
| } |
| std::vector<std::string> configs; |
| for (size_t i = 0; i < glob_result.gl_pathc; i++) { |
| std::string path = glob_result.gl_pathv[i]; |
| // Filter-out /apex/<name>@<ver> paths. The paths are bind-mounted to |
| // /apex/<name> paths, so unless we filter them out, we will parse the |
| // same file twice. |
| std::vector<std::string> paths = android::base::Split(path, "/"); |
| if (paths.size() >= 3 && paths[2].find('@') != std::string::npos) { |
| continue; |
| } |
| // Filter directories |
| if (path.back() == '/') { |
| continue; |
| } |
| configs.push_back(path); |
| } |
| globfree(&glob_result); |
| return configs; |
| } |
| |
| static Result<void> ParseConfigs(const std::vector<std::string>& configs) { |
| Parser parser = |
| CreateApexConfigParser(ActionManager::GetInstance(), ServiceList::GetInstance()); |
| std::vector<std::string> errors; |
| for (const auto& c : configs) { |
| auto result = parser.ParseConfigFile(c); |
| // We should handle other config files even when there's an error. |
| if (!result.ok()) { |
| errors.push_back(result.error().message()); |
| } |
| } |
| if (!errors.empty()) { |
| return Error() << "Unable to parse apex configs: " << base::Join(errors, "|"); |
| } |
| return {}; |
| } |
| |
| Result<void> ParseApexConfigs(const std::string& apex_name) { |
| auto configs = OR_RETURN(CollectApexConfigs(apex_name)); |
| |
| if (configs.empty()) { |
| return {}; |
| } |
| |
| auto filtered_configs = FilterVersionedConfigs(configs, |
| android::base::GetIntProperty("ro.build.version.sdk", INT_MAX)); |
| return ParseConfigs(filtered_configs); |
| } |
| |
| } // namespace init |
| } // namespace android |