1/* 2 * Copyright (C) 2010 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 <dirent.h> 18#include <errno.h> 19#include <fcntl.h> 20 21#include "action.h" 22#include "init_parser.h" 23#include "log.h" 24#include "parser.h" 25#include "service.h" 26#include "util.h" 27 28#include <android-base/stringprintf.h> 29 30Parser::Parser() { 31} 32 33Parser& Parser::GetInstance() { 34 static Parser instance; 35 return instance; 36} 37 38void Parser::AddSectionParser(const std::string& name, 39 std::unique_ptr<SectionParser> parser) { 40 section_parsers_[name] = std::move(parser); 41} 42 43void Parser::ParseData(const std::string& filename, const std::string& data) { 44 //TODO: Use a parser with const input and remove this copy 45 std::vector<char> data_copy(data.begin(), data.end()); 46 data_copy.push_back('\0'); 47 48 parse_state state; 49 state.filename = filename.c_str(); 50 state.line = 0; 51 state.ptr = &data_copy[0]; 52 state.nexttoken = 0; 53 54 SectionParser* section_parser = nullptr; 55 std::vector<std::string> args; 56 57 for (;;) { 58 switch (next_token(&state)) { 59 case T_EOF: 60 if (section_parser) { 61 section_parser->EndSection(); 62 } 63 return; 64 case T_NEWLINE: 65 state.line++; 66 if (args.empty()) { 67 break; 68 } 69 if (section_parsers_.count(args[0])) { 70 if (section_parser) { 71 section_parser->EndSection(); 72 } 73 section_parser = section_parsers_[args[0]].get(); 74 std::string ret_err; 75 if (!section_parser->ParseSection(args, &ret_err)) { 76 parse_error(&state, "%s\n", ret_err.c_str()); 77 section_parser = nullptr; 78 } 79 } else if (section_parser) { 80 std::string ret_err; 81 if (!section_parser->ParseLineSection(args, state.filename, 82 state.line, &ret_err)) { 83 parse_error(&state, "%s\n", ret_err.c_str()); 84 } 85 } 86 args.clear(); 87 break; 88 case T_TEXT: 89 args.emplace_back(state.text); 90 break; 91 } 92 } 93} 94 95bool Parser::ParseConfigFile(const std::string& path) { 96 INFO("Parsing file %s...\n", path.c_str()); 97 Timer t; 98 std::string data; 99 if (!read_file(path.c_str(), &data)) { 100 return false; 101 } 102 103 data.push_back('\n'); // TODO: fix parse_config. 104 ParseData(path, data); 105 for (const auto& sp : section_parsers_) { 106 sp.second->EndFile(path); 107 } 108 109 // Turning this on and letting the INFO logging be discarded adds 0.2s to 110 // Nexus 9 boot time, so it's disabled by default. 111 if (false) DumpState(); 112 113 NOTICE("(Parsing %s took %.2fs.)\n", path.c_str(), t.duration()); 114 return true; 115} 116 117bool Parser::ParseConfigDir(const std::string& path) { 118 INFO("Parsing directory %s...\n", path.c_str()); 119 std::unique_ptr<DIR, int(*)(DIR*)> config_dir(opendir(path.c_str()), closedir); 120 if (!config_dir) { 121 ERROR("Could not import directory '%s'\n", path.c_str()); 122 return false; 123 } 124 dirent* current_file; 125 std::vector<std::string> files; 126 while ((current_file = readdir(config_dir.get()))) { 127 // Ignore directories and only process regular files. 128 if (current_file->d_type == DT_REG) { 129 std::string current_path = 130 android::base::StringPrintf("%s/%s", path.c_str(), current_file->d_name); 131 files.emplace_back(current_path); 132 } 133 } 134 // Sort first so we load files in a consistent order (bug 31996208) 135 std::sort(files.begin(), files.end()); 136 for (const auto& file : files) { 137 if (!ParseConfigFile(file)) { 138 ERROR("Could not import file '%s'\n", file.c_str()); 139 } 140 } 141 return true; 142} 143 144bool Parser::ParseConfig(const std::string& path) { 145 if (is_dir(path.c_str())) { 146 return ParseConfigDir(path); 147 } 148 return ParseConfigFile(path); 149} 150 151void Parser::DumpState() const { 152 ServiceManager::GetInstance().DumpState(); 153 ActionManager::GetInstance().DumpState(); 154} 155