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) {
96f86b5a6b90619e02d1d034ef7b0adc3b439f4abbElliott Hughes    LOG(INFO) << "Parsing file " << path << "...";
97da40c00137f75543a69972f1be506e2d14a41845Elliott Hughes    Timer t;
98f682b4786a4093efb23bf80d69bf80eb274b145bElliott Hughes    std::string data;
99ef52ae14abaf091b1bece89656d80850b497e084Tom Cherry    if (!read_file(path, &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
109331cf2fb7c16b5b25064f8d2f00284105a9b413fElliott Hughes    LOG(VERBOSE) << "(Parsing " << path << " took " << t << ".)";
110e5ce30fed81d1918a259be092dcd8bfffc3c2649Elliott Hughes    return true;
1116310a8261c922533a692fb3e74ece2da98d4bafaColin Cross}
1126310a8261c922533a692fb3e74ece2da98d4bafaColin Cross
113b7349902a945903f9e36a569051f5131beb0bc24Tom Cherrybool Parser::ParseConfigDir(const std::string& path) {
114f86b5a6b90619e02d1d034ef7b0adc3b439f4abbElliott Hughes    LOG(INFO) << "Parsing directory " << path << "...";
115b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry    std::unique_ptr<DIR, int(*)(DIR*)> config_dir(opendir(path.c_str()), closedir);
116f13b1b31399aa501514eb9beeef303d1ae2e0e14Lee Campbell    if (!config_dir) {
117f86b5a6b90619e02d1d034ef7b0adc3b439f4abbElliott Hughes        PLOG(ERROR) << "Could not import directory '" << path << "'";
118f13b1b31399aa501514eb9beeef303d1ae2e0e14Lee Campbell        return false;
119f13b1b31399aa501514eb9beeef303d1ae2e0e14Lee Campbell    }
120f13b1b31399aa501514eb9beeef303d1ae2e0e14Lee Campbell    dirent* current_file;
1212de796491aed1c5c40af94d9c9b08a385a309e1fGlenn Kasten    std::vector<std::string> files;
122f13b1b31399aa501514eb9beeef303d1ae2e0e14Lee Campbell    while ((current_file = readdir(config_dir.get()))) {
123f13b1b31399aa501514eb9beeef303d1ae2e0e14Lee Campbell        // Ignore directories and only process regular files.
124f13b1b31399aa501514eb9beeef303d1ae2e0e14Lee Campbell        if (current_file->d_type == DT_REG) {
1252de796491aed1c5c40af94d9c9b08a385a309e1fGlenn Kasten            std::string current_path =
1262de796491aed1c5c40af94d9c9b08a385a309e1fGlenn Kasten                android::base::StringPrintf("%s/%s", path.c_str(), current_file->d_name);
1272de796491aed1c5c40af94d9c9b08a385a309e1fGlenn Kasten            files.emplace_back(current_path);
1282de796491aed1c5c40af94d9c9b08a385a309e1fGlenn Kasten        }
1292de796491aed1c5c40af94d9c9b08a385a309e1fGlenn Kasten    }
1302de796491aed1c5c40af94d9c9b08a385a309e1fGlenn Kasten    // Sort first so we load files in a consistent order (bug 31996208)
1312de796491aed1c5c40af94d9c9b08a385a309e1fGlenn Kasten    std::sort(files.begin(), files.end());
1322de796491aed1c5c40af94d9c9b08a385a309e1fGlenn Kasten    for (const auto& file : files) {
1332de796491aed1c5c40af94d9c9b08a385a309e1fGlenn Kasten        if (!ParseConfigFile(file)) {
1342de796491aed1c5c40af94d9c9b08a385a309e1fGlenn Kasten            LOG(ERROR) << "could not import file '" << file << "'";
135f13b1b31399aa501514eb9beeef303d1ae2e0e14Lee Campbell        }
136f13b1b31399aa501514eb9beeef303d1ae2e0e14Lee Campbell    }
137f13b1b31399aa501514eb9beeef303d1ae2e0e14Lee Campbell    return true;
138f13b1b31399aa501514eb9beeef303d1ae2e0e14Lee Campbell}
139f13b1b31399aa501514eb9beeef303d1ae2e0e14Lee Campbell
140b7349902a945903f9e36a569051f5131beb0bc24Tom Cherrybool Parser::ParseConfig(const std::string& path) {
141b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry    if (is_dir(path.c_str())) {
142b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry        return ParseConfigDir(path);
143f13b1b31399aa501514eb9beeef303d1ae2e0e14Lee Campbell    }
144b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry    return ParseConfigFile(path);
145f13b1b31399aa501514eb9beeef303d1ae2e0e14Lee Campbell}
146f13b1b31399aa501514eb9beeef303d1ae2e0e14Lee Campbell
147b7349902a945903f9e36a569051f5131beb0bc24Tom Cherryvoid Parser::DumpState() const {
148b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry    ServiceManager::GetInstance().DumpState();
149b7349902a945903f9e36a569051f5131beb0bc24Tom Cherry    ActionManager::GetInstance().DumpState();
1506310a8261c922533a692fb3e74ece2da98d4bafaColin Cross}
151