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 30 Parser::Parser() { 31 } 32 33 Parser& Parser::GetInstance() { 34 static Parser instance; 35 return instance; 36 } 37 38 void Parser::AddSectionParser(const std::string& name, 39 std::unique_ptr<SectionParser> parser) { 40 section_parsers_[name] = std::move(parser); 41 } 42 43 void 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 95 bool Parser::ParseConfigFile(const std::string& path) { 96 LOG(INFO) << "Parsing file " << path << "..."; 97 Timer t; 98 std::string data; 99 if (!read_file(path, &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 LOG(VERBOSE) << "(Parsing " << path << " took " << t << ".)"; 110 return true; 111 } 112 113 bool Parser::ParseConfigDir(const std::string& path) { 114 LOG(INFO) << "Parsing directory " << path << "..."; 115 std::unique_ptr<DIR, int(*)(DIR*)> config_dir(opendir(path.c_str()), closedir); 116 if (!config_dir) { 117 PLOG(ERROR) << "Could not import directory '" << path << "'"; 118 return false; 119 } 120 dirent* current_file; 121 std::vector<std::string> files; 122 while ((current_file = readdir(config_dir.get()))) { 123 // Ignore directories and only process regular files. 124 if (current_file->d_type == DT_REG) { 125 std::string current_path = 126 android::base::StringPrintf("%s/%s", path.c_str(), current_file->d_name); 127 files.emplace_back(current_path); 128 } 129 } 130 // Sort first so we load files in a consistent order (bug 31996208) 131 std::sort(files.begin(), files.end()); 132 for (const auto& file : files) { 133 if (!ParseConfigFile(file)) { 134 LOG(ERROR) << "could not import file '" << file << "'"; 135 } 136 } 137 return true; 138 } 139 140 bool Parser::ParseConfig(const std::string& path) { 141 if (is_dir(path.c_str())) { 142 return ParseConfigDir(path); 143 } 144 return ParseConfigFile(path); 145 } 146 147 void Parser::DumpState() const { 148 ServiceManager::GetInstance().DumpState(); 149 ActionManager::GetInstance().DumpState(); 150 } 151