16310a8261c922533a692fb3e74ece2da98d4bafaColin Cross/*
26310a8261c922533a692fb3e74ece2da98d4bafaColin Cross * Copyright (C) 2010 The Android Open Source Project
36310a8261c922533a692fb3e74ece2da98d4bafaColin Cross *
46310a8261c922533a692fb3e74ece2da98d4bafaColin Cross * Licensed under the Apache License, Version 2.0 (the "License");
56310a8261c922533a692fb3e74ece2da98d4bafaColin Cross * you may not use this file except in compliance with the License.
66310a8261c922533a692fb3e74ece2da98d4bafaColin Cross * You may obtain a copy of the License at
76310a8261c922533a692fb3e74ece2da98d4bafaColin Cross *
86310a8261c922533a692fb3e74ece2da98d4bafaColin Cross *      http://www.apache.org/licenses/LICENSE-2.0
96310a8261c922533a692fb3e74ece2da98d4bafaColin Cross *
106310a8261c922533a692fb3e74ece2da98d4bafaColin Cross * Unless required by applicable law or agreed to in writing, software
116310a8261c922533a692fb3e74ece2da98d4bafaColin Cross * distributed under the License is distributed on an "AS IS" BASIS,
126310a8261c922533a692fb3e74ece2da98d4bafaColin Cross * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
136310a8261c922533a692fb3e74ece2da98d4bafaColin Cross * See the License for the specific language governing permissions and
146310a8261c922533a692fb3e74ece2da98d4bafaColin Cross * limitations under the License.
156310a8261c922533a692fb3e74ece2da98d4bafaColin Cross */
166310a8261c922533a692fb3e74ece2da98d4bafaColin Cross
17f13b1b31399aa501514eb9beeef303d1ae2e0e14Lee Campbell#include <dirent.h>
188d82ea05cb0945ba6cb8bf321b9ffbd0b6932745Elliott Hughes#include <errno.h>
196310a8261c922533a692fb3e74ece2da98d4bafaColin Cross#include <fcntl.h>
206310a8261c922533a692fb3e74ece2da98d4bafaColin Cross
21fa0c21c94ccb98bfa5cf3cc7a6b220be4a5fa378Tom Cherry#include "action.h"
226310a8261c922533a692fb3e74ece2da98d4bafaColin Cross#include "init_parser.h"
236310a8261c922533a692fb3e74ece2da98d4bafaColin Cross#include "log.h"
24bac3299720623f4226bca103b26260052732ad30Tom Cherry#include "parser.h"
25bac3299720623f4226bca103b26260052732ad30Tom Cherry#include "service.h"
266310a8261c922533a692fb3e74ece2da98d4bafaColin Cross#include "util.h"
276310a8261c922533a692fb3e74ece2da98d4bafaColin Cross
284f71319df011d796a60a43fc1bc68e16fbf7d321Elliott Hughes#include <android-base/stringprintf.h>
296310a8261c922533a692fb3e74ece2da98d4bafaColin Cross
30b7349902a945903f9e36a569051f5131beb0bc24Tom CherryParser::Parser() {
31c0e919c92062360a69b771722677d041c9998403Elliott Hughes}
32c0e919c92062360a69b771722677d041c9998403Elliott Hughes
33b7349902a945903f9e36a569051f5131beb0bc24Tom CherryParser& Parser::GetInstance() {
34b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry    static Parser instance;
35b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry    return instance;
36a6235eacf4b06b14b19125618d7aca570dbc02b0Dima Zavin}
37a6235eacf4b06b14b19125618d7aca570dbc02b0Dima Zavin
38b7349902a945903f9e36a569051f5131beb0bc24Tom Cherryvoid Parser::AddSectionParser(const std::string& name,
39b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry                              std::unique_ptr<SectionParser> parser) {
40b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry    section_parsers_[name] = std::move(parser);
4178a1b1fe1ab76964e35b4a4788238b197bfd613dDima Zavin}
4278a1b1fe1ab76964e35b4a4788238b197bfd613dDima Zavin
43b7349902a945903f9e36a569051f5131beb0bc24Tom Cherryvoid Parser::ParseData(const std::string& filename, const std::string& data) {
444ad60fbae51ef4a0b4a4beaa5128d823063c158cTom Cherry    //TODO: Use a parser with const input and remove this copy
454ad60fbae51ef4a0b4a4beaa5128d823063c158cTom Cherry    std::vector<char> data_copy(data.begin(), data.end());
464ad60fbae51ef4a0b4a4beaa5128d823063c158cTom Cherry    data_copy.push_back('\0');
474ad60fbae51ef4a0b4a4beaa5128d823063c158cTom Cherry
48eaa3b4ec6f79fe06163b8dd6fe8ba2581d3b9c0bTom Cherry    parse_state state;
49b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry    state.filename = filename.c_str();
501be6968d9d51f43fdb00535708a6fed0be6bfbcaBruce Beare    state.line = 0;
514ad60fbae51ef4a0b4a4beaa5128d823063c158cTom Cherry    state.ptr = &data_copy[0];
526310a8261c922533a692fb3e74ece2da98d4bafaColin Cross    state.nexttoken = 0;
5378a1b1fe1ab76964e35b4a4788238b197bfd613dDima Zavin
54b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry    SectionParser* section_parser = nullptr;
55b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry    std::vector<std::string> args;
5678a1b1fe1ab76964e35b4a4788238b197bfd613dDima Zavin
576310a8261c922533a692fb3e74ece2da98d4bafaColin Cross    for (;;) {
586310a8261c922533a692fb3e74ece2da98d4bafaColin Cross        switch (next_token(&state)) {
596310a8261c922533a692fb3e74ece2da98d4bafaColin Cross        case T_EOF:
60b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry            if (section_parser) {
61b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry                section_parser->EndSection();
62b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry            }
63b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry            return;
646310a8261c922533a692fb3e74ece2da98d4bafaColin Cross        case T_NEWLINE:
651be6968d9d51f43fdb00535708a6fed0be6bfbcaBruce Beare            state.line++;
66b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry            if (args.empty()) {
67b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry                break;
68b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry            }
69b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry            if (section_parsers_.count(args[0])) {
70b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry                if (section_parser) {
71b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry                    section_parser->EndSection();
72b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry                }
73b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry                section_parser = section_parsers_[args[0]].get();
74b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry                std::string ret_err;
75b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry                if (!section_parser->ParseSection(args, &ret_err)) {
76b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry                    parse_error(&state, "%s\n", ret_err.c_str());
77b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry                    section_parser = nullptr;
78b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry                }
79b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry            } else if (section_parser) {
80b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry                std::string ret_err;
81b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry                if (!section_parser->ParseLineSection(args, state.filename,
82b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry                                                      state.line, &ret_err)) {
83b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry                    parse_error(&state, "%s\n", ret_err.c_str());
846310a8261c922533a692fb3e74ece2da98d4bafaColin Cross                }
856310a8261c922533a692fb3e74ece2da98d4bafaColin Cross            }
86b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry            args.clear();
876310a8261c922533a692fb3e74ece2da98d4bafaColin Cross            break;
886310a8261c922533a692fb3e74ece2da98d4bafaColin Cross        case T_TEXT:
89b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry            args.emplace_back(state.text);
906310a8261c922533a692fb3e74ece2da98d4bafaColin Cross            break;
916310a8261c922533a692fb3e74ece2da98d4bafaColin Cross        }
926310a8261c922533a692fb3e74ece2da98d4bafaColin Cross    }
936310a8261c922533a692fb3e74ece2da98d4bafaColin Cross}
946310a8261c922533a692fb3e74ece2da98d4bafaColin Cross
95b7349902a945903f9e36a569051f5131beb0bc24Tom Cherrybool Parser::ParseConfigFile(const std::string& path) {
96b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry    INFO("Parsing file %s...\n", path.c_str());
97da40c00137f75543a69972f1be506e2d14a41845Elliott Hughes    Timer t;
98f682b4786a4093efb23bf80d69bf80eb274b145bElliott Hughes    std::string data;
99b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry    if (!read_file(path.c_str(), &data)) {
100e5ce30fed81d1918a259be092dcd8bfffc3c2649Elliott Hughes        return false;
101f682b4786a4093efb23bf80d69bf80eb274b145bElliott Hughes    }
1026310a8261c922533a692fb3e74ece2da98d4bafaColin Cross
103eaa3b4ec6f79fe06163b8dd6fe8ba2581d3b9c0bTom Cherry    data.push_back('\n'); // TODO: fix parse_config.
104b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry    ParseData(path, data);
105b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry    for (const auto& sp : section_parsers_) {
106b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry        sp.second->EndFile(path);
107b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry    }
1081946d3bca8a3b05d2a527606c06948882940287cElliott Hughes
1091946d3bca8a3b05d2a527606c06948882940287cElliott Hughes    // Turning this on and letting the INFO logging be discarded adds 0.2s to
1101946d3bca8a3b05d2a527606c06948882940287cElliott Hughes    // Nexus 9 boot time, so it's disabled by default.
1111946d3bca8a3b05d2a527606c06948882940287cElliott Hughes    if (false) DumpState();
112da40c00137f75543a69972f1be506e2d14a41845Elliott Hughes
113b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry    NOTICE("(Parsing %s took %.2fs.)\n", path.c_str(), t.duration());
114e5ce30fed81d1918a259be092dcd8bfffc3c2649Elliott Hughes    return true;
1156310a8261c922533a692fb3e74ece2da98d4bafaColin Cross}
1166310a8261c922533a692fb3e74ece2da98d4bafaColin Cross
117b7349902a945903f9e36a569051f5131beb0bc24Tom Cherrybool Parser::ParseConfigDir(const std::string& path) {
118b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry    INFO("Parsing directory %s...\n", path.c_str());
119b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry    std::unique_ptr<DIR, int(*)(DIR*)> config_dir(opendir(path.c_str()), closedir);
120f13b1b31399aa501514eb9beeef303d1ae2e0e14Lee Campbell    if (!config_dir) {
121b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry        ERROR("Could not import directory '%s'\n", path.c_str());
122f13b1b31399aa501514eb9beeef303d1ae2e0e14Lee Campbell        return false;
123f13b1b31399aa501514eb9beeef303d1ae2e0e14Lee Campbell    }
124f13b1b31399aa501514eb9beeef303d1ae2e0e14Lee Campbell    dirent* current_file;
125f13b1b31399aa501514eb9beeef303d1ae2e0e14Lee Campbell    while ((current_file = readdir(config_dir.get()))) {
126f13b1b31399aa501514eb9beeef303d1ae2e0e14Lee Campbell        std::string current_path =
127b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry            android::base::StringPrintf("%s/%s", path.c_str(), current_file->d_name);
128f13b1b31399aa501514eb9beeef303d1ae2e0e14Lee Campbell        // Ignore directories and only process regular files.
129f13b1b31399aa501514eb9beeef303d1ae2e0e14Lee Campbell        if (current_file->d_type == DT_REG) {
130b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry            if (!ParseConfigFile(current_path)) {
131f13b1b31399aa501514eb9beeef303d1ae2e0e14Lee Campbell                ERROR("could not import file '%s'\n", current_path.c_str());
132f13b1b31399aa501514eb9beeef303d1ae2e0e14Lee Campbell            }
133f13b1b31399aa501514eb9beeef303d1ae2e0e14Lee Campbell        }
134f13b1b31399aa501514eb9beeef303d1ae2e0e14Lee Campbell    }
135f13b1b31399aa501514eb9beeef303d1ae2e0e14Lee Campbell    return true;
136f13b1b31399aa501514eb9beeef303d1ae2e0e14Lee Campbell}
137f13b1b31399aa501514eb9beeef303d1ae2e0e14Lee Campbell
138b7349902a945903f9e36a569051f5131beb0bc24Tom Cherrybool Parser::ParseConfig(const std::string& path) {
139b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry    if (is_dir(path.c_str())) {
140b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry        return ParseConfigDir(path);
141f13b1b31399aa501514eb9beeef303d1ae2e0e14Lee Campbell    }
142b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry    return ParseConfigFile(path);
143f13b1b31399aa501514eb9beeef303d1ae2e0e14Lee Campbell}
144f13b1b31399aa501514eb9beeef303d1ae2e0e14Lee Campbell
145b7349902a945903f9e36a569051f5131beb0bc24Tom Cherryvoid Parser::DumpState() const {
146b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry    ServiceManager::GetInstance().DumpState();
147b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry    ActionManager::GetInstance().DumpState();
1486310a8261c922533a692fb3e74ece2da98d4bafaColin Cross}
149