Loading init/README.md +87 −20 Original line number Diff line number Diff line Loading @@ -16,9 +16,7 @@ Actions and Services implicitly declare a new section. All commands or options belong to the section most recently declared. Commands or options before the first section are ignored. Actions and Services have unique names. If a second Action is defined with the same name as an existing one, its commands are appended to the commands of the existing action. If a second Service is defined Services have unique names. If a second Service is defined with the same name as an existing one, it is ignored and an error message is logged. Loading @@ -31,10 +29,18 @@ locations on the system, described below. /init.rc is the primary .rc file and is loaded by the init executable at the beginning of its execution. It is responsible for the initial set up of the system. It imports /init.${ro.hardware}.rc which is the primary vendor supplied .rc file. During the mount\_all command, the init executable loads all of the set up of the system. Devices that mount /system, /vendor through the early mount mechanism load all of the files contained within the /{system,vendor,odm}/etc/init/ directories immediately after loading the primary /init.rc. This is explained in more details in the Imports section of this file. Legacy devices without the early mount mechanism do the following: 1. /init.rc imports /init.${ro.hardware}.rc which is the primary vendor supplied .rc file. 2. During the mount\_all command, the init executable loads all of the files contained within the /{system,vendor,odm}/etc/init/ directories. These directories are intended for all Actions and Services used after file system mounting. Loading Loading @@ -89,7 +95,7 @@ process all entries in the given fstab. Actions ------- Actions are named sequences of commands. Actions have a trigger which is used to determine when the action should occur. When an event is used to determine when the action is executed. When an event occurs which matches an action's trigger, that action is added to the tail of a to-be-executed queue (unless it is already on the queue). Loading @@ -106,6 +112,34 @@ Actions take the form of: <command> <command> Actions are added to the queue and executed based on the order that the file that contains them was parsed (see the Imports section), then sequentially within an individual file. For example if a file contains: on boot setprop a 1 setprop b 2 on boot && property:true=true setprop c 1 setprop d 2 on boot setprop e 1 setprop f 2 Then when the `boot` trigger occurs and assuming the property `true` equals `true`, then the order of the commands executed will be: setprop a 1 setprop b 2 setprop c 1 setprop d 2 setprop e 1 setprop f 2 Services -------- Loading Loading @@ -458,21 +492,54 @@ Commands Imports ------- The import keyword is not a command, but rather its own section and is handled immediately after the .rc file that contains it has finished being parsed. It takes the below form: `import <path>` > Parse an init config file, extending the current configuration. If _path_ is a directory, each file in the directory is parsed as a config file. It is not recursive, nested directories will not be parsed. There are only two times where the init executable imports .rc files: 1. When it imports /init.rc during initial boot 2. When it imports /{system,vendor,odm}/etc/init/ or .rc files at specified paths during mount_all The import keyword is not a command, but rather its own section, meaning that it does not happen as part of an Action, but rather, imports are handled as a file is being parsed and follow the below logic. There are only three times where the init executable imports .rc files: 1. When it imports /init.rc or the script indicated by the property `ro.boot.init_rc` during initial boot. 2. When it imports /{system,vendor,odm}/etc/init/ for early mount devices immediately after importing /init.rc. 3. When it imports /{system,vendor,odm}/etc/init/ or .rc files at specified paths during mount_all. The order that files are imported is a bit complex for legacy reasons and to keep backwards compatibility. It is not strictly guaranteed. The only correct way to guarantee that a command has been run before a different command is to either 1) place it in an Action with an earlier executed trigger, or 2) place it in an Action with the same trigger within the same file at an earlier line. Nonetheless, the defacto order for early mount devices is: 1. /init.rc is parsed then recursively each of its imports are parsed. 2. The contents of /system/etc/init/ are alphabetized and parsed sequentially, with imports happening recursively after each file is parsed. 3. Step 2 is repeated for /vendor/etc/init then /odm/etc/init The below pseudocode may explain this more clearly: fn Import(file) Parse(file) for (import : file.imports) Import(import) Import(/init.rc) Directories = [/system/etc/init, /vendor/etc/init, /odm/etc/init] for (directory : Directories) files = <Alphabetical order of directory's contents> for (file : files) Import(file) Properties Loading init/action.cpp +21 −56 Original line number Diff line number Diff line Loading @@ -26,10 +26,8 @@ using android::base::Join; using android::base::StringPrintf; Command::Command(BuiltinFunction f, const std::vector<std::string>& args, const std::string& filename, int line) : func_(f), args_(args), filename_(filename), line_(line) { } Command::Command(BuiltinFunction f, const std::vector<std::string>& args, int line) : func_(f), args_(args), line_(line) {} int Command::InvokeFunc() const { std::vector<std::string> expanded_args; Loading @@ -49,21 +47,12 @@ std::string Command::BuildCommandString() const { return Join(args_, ' '); } std::string Command::BuildSourceString() const { if (!filename_.empty()) { return StringPrintf(" (%s:%d)", filename_.c_str(), line_); } else { return std::string(); } } Action::Action(bool oneshot) : oneshot_(oneshot) { } Action::Action(bool oneshot, const std::string& filename, int line) : oneshot_(oneshot), filename_(filename), line_(line) {} const KeywordMap<BuiltinFunction>* Action::function_map_ = nullptr; bool Action::AddCommand(const std::vector<std::string>& args, const std::string& filename, int line, std::string* err) { bool Action::AddCommand(const std::vector<std::string>& args, int line, std::string* err) { if (!function_map_) { *err = "no function map available"; return false; Loading @@ -79,20 +68,12 @@ bool Action::AddCommand(const std::vector<std::string>& args, return false; } AddCommand(function, args, filename, line); AddCommand(function, args, line); return true; } void Action::AddCommand(BuiltinFunction f, const std::vector<std::string>& args, const std::string& filename, int line) { commands_.emplace_back(f, args, filename, line); } void Action::CombineAction(const Action& action) { for (const auto& c : action.commands_) { commands_.emplace_back(c); } void Action::AddCommand(BuiltinFunction f, const std::vector<std::string>& args, int line) { commands_.emplace_back(f, args, line); } std::size_t Action::NumCommands() const { Loading Loading @@ -122,7 +103,7 @@ void Action::ExecuteCommand(const Command& command) const { android::base::GetMinimumLogSeverity() <= android::base::DEBUG) { std::string trigger_name = BuildTriggersString(); std::string cmd_str = command.BuildCommandString(); std::string source = command.BuildSourceString(); std::string source = StringPrintf(" (%s:%d)", filename_.c_str(), command.line()); LOG(INFO) << "Command '" << cmd_str << "' action=" << trigger_name << source << " returned " << result << " took " << duration_ms << "ms."; Loading Loading @@ -234,11 +215,6 @@ bool Action::CheckPropertyTrigger(const std::string& name, return event_trigger_.empty() && CheckPropertyTriggers(name, value); } bool Action::TriggersEqual(const Action& other) const { return property_triggers_ == other.property_triggers_ && event_trigger_ == other.event_trigger_; } std::string Action::BuildTriggersString() const { std::vector<std::string> triggers; Loading Loading @@ -306,18 +282,8 @@ ActionManager& ActionManager::GetInstance() { } void ActionManager::AddAction(std::unique_ptr<Action> action) { auto old_action_it = std::find_if(actions_.begin(), actions_.end(), [&action] (std::unique_ptr<Action>& a) { return action->TriggersEqual(*a); }); if (old_action_it != actions_.end()) { (*old_action_it)->CombineAction(*action); } else { actions_.emplace_back(std::move(action)); } } void ActionManager::QueueEventTrigger(const std::string& trigger) { trigger_queue_.push(std::make_unique<EventTrigger>(trigger)); Loading @@ -332,16 +298,15 @@ void ActionManager::QueueAllPropertyTriggers() { QueuePropertyTrigger("", ""); } void ActionManager::QueueBuiltinAction(BuiltinFunction func, const std::string& name) { auto action = std::make_unique<Action>(true); void ActionManager::QueueBuiltinAction(BuiltinFunction func, const std::string& name) { auto action = std::make_unique<Action>(true, "<Builtin Action>", 0); std::vector<std::string> name_vector{name}; if (!action->InitSingleTrigger(name)) { return; } action->AddCommand(func, name_vector); action->AddCommand(func, name_vector, 0); trigger_queue_.push(std::make_unique<BuiltinTrigger>(action.get())); actions_.emplace_back(std::move(action)); Loading @@ -366,7 +331,8 @@ void ActionManager::ExecuteOneCommand() { if (current_command_ == 0) { std::string trigger_name = action->BuildTriggersString(); LOG(INFO) << "processing action (" << trigger_name << ")"; LOG(INFO) << "processing action (" << trigger_name << ") from (" << action->filename() << ":" << action->line() << ")"; } action->ExecuteOneCommand(current_command_); Loading Loading @@ -397,15 +363,15 @@ void ActionManager::DumpState() const { } } bool ActionParser::ParseSection(const std::vector<std::string>& args, std::string* err) { bool ActionParser::ParseSection(const std::vector<std::string>& args, const std::string& filename, int line, std::string* err) { std::vector<std::string> triggers(args.begin() + 1, args.end()); if (triggers.size() < 1) { *err = "actions must have a trigger"; return false; } auto action = std::make_unique<Action>(false); auto action = std::make_unique<Action>(false, filename, line); if (!action->InitTriggers(triggers, err)) { return false; } Loading @@ -414,10 +380,9 @@ bool ActionParser::ParseSection(const std::vector<std::string>& args, return true; } bool ActionParser::ParseLineSection(const std::vector<std::string>& args, const std::string& filename, int line, std::string* err) const { return action_ ? action_->AddCommand(args, filename, line, err) : false; bool ActionParser::ParseLineSection(const std::vector<std::string>& args, int line, std::string* err) { return action_ ? action_->AddCommand(args, line, err) : false; } void ActionParser::EndSection() { Loading init/action.h +19 −22 Original line number Diff line number Diff line Loading @@ -28,30 +28,25 @@ class Command { public: Command(BuiltinFunction f, const std::vector<std::string>& args, const std::string& filename, int line); Command(BuiltinFunction f, const std::vector<std::string>& args, int line); int InvokeFunc() const; std::string BuildCommandString() const; std::string BuildSourceString() const; int line() const { return line_; } private: BuiltinFunction func_; std::vector<std::string> args_; std::string filename_; int line_; }; class Action { public: explicit Action(bool oneshot = false); bool AddCommand(const std::vector<std::string>& args, const std::string& filename, int line, std::string* err); void AddCommand(BuiltinFunction f, const std::vector<std::string>& args, const std::string& filename = "", int line = 0); void CombineAction(const Action& action); explicit Action(bool oneshot, const std::string& filename, int line); bool AddCommand(const std::vector<std::string>& args, int line, std::string* err); void AddCommand(BuiltinFunction f, const std::vector<std::string>& args, int line); bool InitTriggers(const std::vector<std::string>& args, std::string* err); bool InitSingleTrigger(const std::string& trigger); std::size_t NumCommands() const; Loading @@ -60,11 +55,12 @@ public: bool CheckEventTrigger(const std::string& trigger) const; bool CheckPropertyTrigger(const std::string& name, const std::string& value) const; bool TriggersEqual(const Action& other) const; std::string BuildTriggersString() const; void DumpState() const; bool oneshot() const { return oneshot_; } const std::string& filename() const { return filename_; } int line() const { return line_; } static void set_function_map(const KeywordMap<BuiltinFunction>* function_map) { function_map_ = function_map; } Loading @@ -80,6 +76,8 @@ private: std::string event_trigger_; std::vector<Command> commands_; bool oneshot_; std::string filename_; int line_; static const KeywordMap<BuiltinFunction>* function_map_; }; Loading Loading @@ -118,14 +116,13 @@ class ActionParser : public SectionParser { public: ActionParser() : action_(nullptr) { } bool ParseSection(const std::vector<std::string>& args, bool ParseSection(const std::vector<std::string>& args, const std::string& filename, int line, std::string* err) override; bool ParseLineSection(const std::vector<std::string>& args, const std::string& filename, int line, std::string* err) const override; bool ParseLineSection(const std::vector<std::string>& args, int line, std::string* err) override; void EndSection() override; void EndFile(const std::string&) override { } private: std::unique_ptr<Action> action_; }; Loading init/import_parser.cpp +2 −2 Original line number Diff line number Diff line Loading @@ -20,8 +20,8 @@ #include "util.h" bool ImportParser::ParseSection(const std::vector<std::string>& args, std::string* err) { bool ImportParser::ParseSection(const std::vector<std::string>& args, const std::string& filename, int line, std::string* err) { if (args.size() != 2) { *err = "single argument needed for import\n"; return false; Loading init/import_parser.h +6 −6 Original line number Diff line number Diff line Loading @@ -26,16 +26,16 @@ class ImportParser : public SectionParser { public: ImportParser() { } bool ParseSection(const std::vector<std::string>& args, bool ParseSection(const std::vector<std::string>& args, const std::string& filename, int line, std::string* err) override; bool ParseLineSection(const std::vector<std::string>& args, const std::string& filename, int line, std::string* err) const override { bool ParseLineSection(const std::vector<std::string>& args, int line, std::string* err) override { return true; } void EndSection() override { } void EndFile(const std::string& filename) override; private: std::vector<std::string> imports_; }; Loading Loading
init/README.md +87 −20 Original line number Diff line number Diff line Loading @@ -16,9 +16,7 @@ Actions and Services implicitly declare a new section. All commands or options belong to the section most recently declared. Commands or options before the first section are ignored. Actions and Services have unique names. If a second Action is defined with the same name as an existing one, its commands are appended to the commands of the existing action. If a second Service is defined Services have unique names. If a second Service is defined with the same name as an existing one, it is ignored and an error message is logged. Loading @@ -31,10 +29,18 @@ locations on the system, described below. /init.rc is the primary .rc file and is loaded by the init executable at the beginning of its execution. It is responsible for the initial set up of the system. It imports /init.${ro.hardware}.rc which is the primary vendor supplied .rc file. During the mount\_all command, the init executable loads all of the set up of the system. Devices that mount /system, /vendor through the early mount mechanism load all of the files contained within the /{system,vendor,odm}/etc/init/ directories immediately after loading the primary /init.rc. This is explained in more details in the Imports section of this file. Legacy devices without the early mount mechanism do the following: 1. /init.rc imports /init.${ro.hardware}.rc which is the primary vendor supplied .rc file. 2. During the mount\_all command, the init executable loads all of the files contained within the /{system,vendor,odm}/etc/init/ directories. These directories are intended for all Actions and Services used after file system mounting. Loading Loading @@ -89,7 +95,7 @@ process all entries in the given fstab. Actions ------- Actions are named sequences of commands. Actions have a trigger which is used to determine when the action should occur. When an event is used to determine when the action is executed. When an event occurs which matches an action's trigger, that action is added to the tail of a to-be-executed queue (unless it is already on the queue). Loading @@ -106,6 +112,34 @@ Actions take the form of: <command> <command> Actions are added to the queue and executed based on the order that the file that contains them was parsed (see the Imports section), then sequentially within an individual file. For example if a file contains: on boot setprop a 1 setprop b 2 on boot && property:true=true setprop c 1 setprop d 2 on boot setprop e 1 setprop f 2 Then when the `boot` trigger occurs and assuming the property `true` equals `true`, then the order of the commands executed will be: setprop a 1 setprop b 2 setprop c 1 setprop d 2 setprop e 1 setprop f 2 Services -------- Loading Loading @@ -458,21 +492,54 @@ Commands Imports ------- The import keyword is not a command, but rather its own section and is handled immediately after the .rc file that contains it has finished being parsed. It takes the below form: `import <path>` > Parse an init config file, extending the current configuration. If _path_ is a directory, each file in the directory is parsed as a config file. It is not recursive, nested directories will not be parsed. There are only two times where the init executable imports .rc files: 1. When it imports /init.rc during initial boot 2. When it imports /{system,vendor,odm}/etc/init/ or .rc files at specified paths during mount_all The import keyword is not a command, but rather its own section, meaning that it does not happen as part of an Action, but rather, imports are handled as a file is being parsed and follow the below logic. There are only three times where the init executable imports .rc files: 1. When it imports /init.rc or the script indicated by the property `ro.boot.init_rc` during initial boot. 2. When it imports /{system,vendor,odm}/etc/init/ for early mount devices immediately after importing /init.rc. 3. When it imports /{system,vendor,odm}/etc/init/ or .rc files at specified paths during mount_all. The order that files are imported is a bit complex for legacy reasons and to keep backwards compatibility. It is not strictly guaranteed. The only correct way to guarantee that a command has been run before a different command is to either 1) place it in an Action with an earlier executed trigger, or 2) place it in an Action with the same trigger within the same file at an earlier line. Nonetheless, the defacto order for early mount devices is: 1. /init.rc is parsed then recursively each of its imports are parsed. 2. The contents of /system/etc/init/ are alphabetized and parsed sequentially, with imports happening recursively after each file is parsed. 3. Step 2 is repeated for /vendor/etc/init then /odm/etc/init The below pseudocode may explain this more clearly: fn Import(file) Parse(file) for (import : file.imports) Import(import) Import(/init.rc) Directories = [/system/etc/init, /vendor/etc/init, /odm/etc/init] for (directory : Directories) files = <Alphabetical order of directory's contents> for (file : files) Import(file) Properties Loading
init/action.cpp +21 −56 Original line number Diff line number Diff line Loading @@ -26,10 +26,8 @@ using android::base::Join; using android::base::StringPrintf; Command::Command(BuiltinFunction f, const std::vector<std::string>& args, const std::string& filename, int line) : func_(f), args_(args), filename_(filename), line_(line) { } Command::Command(BuiltinFunction f, const std::vector<std::string>& args, int line) : func_(f), args_(args), line_(line) {} int Command::InvokeFunc() const { std::vector<std::string> expanded_args; Loading @@ -49,21 +47,12 @@ std::string Command::BuildCommandString() const { return Join(args_, ' '); } std::string Command::BuildSourceString() const { if (!filename_.empty()) { return StringPrintf(" (%s:%d)", filename_.c_str(), line_); } else { return std::string(); } } Action::Action(bool oneshot) : oneshot_(oneshot) { } Action::Action(bool oneshot, const std::string& filename, int line) : oneshot_(oneshot), filename_(filename), line_(line) {} const KeywordMap<BuiltinFunction>* Action::function_map_ = nullptr; bool Action::AddCommand(const std::vector<std::string>& args, const std::string& filename, int line, std::string* err) { bool Action::AddCommand(const std::vector<std::string>& args, int line, std::string* err) { if (!function_map_) { *err = "no function map available"; return false; Loading @@ -79,20 +68,12 @@ bool Action::AddCommand(const std::vector<std::string>& args, return false; } AddCommand(function, args, filename, line); AddCommand(function, args, line); return true; } void Action::AddCommand(BuiltinFunction f, const std::vector<std::string>& args, const std::string& filename, int line) { commands_.emplace_back(f, args, filename, line); } void Action::CombineAction(const Action& action) { for (const auto& c : action.commands_) { commands_.emplace_back(c); } void Action::AddCommand(BuiltinFunction f, const std::vector<std::string>& args, int line) { commands_.emplace_back(f, args, line); } std::size_t Action::NumCommands() const { Loading Loading @@ -122,7 +103,7 @@ void Action::ExecuteCommand(const Command& command) const { android::base::GetMinimumLogSeverity() <= android::base::DEBUG) { std::string trigger_name = BuildTriggersString(); std::string cmd_str = command.BuildCommandString(); std::string source = command.BuildSourceString(); std::string source = StringPrintf(" (%s:%d)", filename_.c_str(), command.line()); LOG(INFO) << "Command '" << cmd_str << "' action=" << trigger_name << source << " returned " << result << " took " << duration_ms << "ms."; Loading Loading @@ -234,11 +215,6 @@ bool Action::CheckPropertyTrigger(const std::string& name, return event_trigger_.empty() && CheckPropertyTriggers(name, value); } bool Action::TriggersEqual(const Action& other) const { return property_triggers_ == other.property_triggers_ && event_trigger_ == other.event_trigger_; } std::string Action::BuildTriggersString() const { std::vector<std::string> triggers; Loading Loading @@ -306,18 +282,8 @@ ActionManager& ActionManager::GetInstance() { } void ActionManager::AddAction(std::unique_ptr<Action> action) { auto old_action_it = std::find_if(actions_.begin(), actions_.end(), [&action] (std::unique_ptr<Action>& a) { return action->TriggersEqual(*a); }); if (old_action_it != actions_.end()) { (*old_action_it)->CombineAction(*action); } else { actions_.emplace_back(std::move(action)); } } void ActionManager::QueueEventTrigger(const std::string& trigger) { trigger_queue_.push(std::make_unique<EventTrigger>(trigger)); Loading @@ -332,16 +298,15 @@ void ActionManager::QueueAllPropertyTriggers() { QueuePropertyTrigger("", ""); } void ActionManager::QueueBuiltinAction(BuiltinFunction func, const std::string& name) { auto action = std::make_unique<Action>(true); void ActionManager::QueueBuiltinAction(BuiltinFunction func, const std::string& name) { auto action = std::make_unique<Action>(true, "<Builtin Action>", 0); std::vector<std::string> name_vector{name}; if (!action->InitSingleTrigger(name)) { return; } action->AddCommand(func, name_vector); action->AddCommand(func, name_vector, 0); trigger_queue_.push(std::make_unique<BuiltinTrigger>(action.get())); actions_.emplace_back(std::move(action)); Loading @@ -366,7 +331,8 @@ void ActionManager::ExecuteOneCommand() { if (current_command_ == 0) { std::string trigger_name = action->BuildTriggersString(); LOG(INFO) << "processing action (" << trigger_name << ")"; LOG(INFO) << "processing action (" << trigger_name << ") from (" << action->filename() << ":" << action->line() << ")"; } action->ExecuteOneCommand(current_command_); Loading Loading @@ -397,15 +363,15 @@ void ActionManager::DumpState() const { } } bool ActionParser::ParseSection(const std::vector<std::string>& args, std::string* err) { bool ActionParser::ParseSection(const std::vector<std::string>& args, const std::string& filename, int line, std::string* err) { std::vector<std::string> triggers(args.begin() + 1, args.end()); if (triggers.size() < 1) { *err = "actions must have a trigger"; return false; } auto action = std::make_unique<Action>(false); auto action = std::make_unique<Action>(false, filename, line); if (!action->InitTriggers(triggers, err)) { return false; } Loading @@ -414,10 +380,9 @@ bool ActionParser::ParseSection(const std::vector<std::string>& args, return true; } bool ActionParser::ParseLineSection(const std::vector<std::string>& args, const std::string& filename, int line, std::string* err) const { return action_ ? action_->AddCommand(args, filename, line, err) : false; bool ActionParser::ParseLineSection(const std::vector<std::string>& args, int line, std::string* err) { return action_ ? action_->AddCommand(args, line, err) : false; } void ActionParser::EndSection() { Loading
init/action.h +19 −22 Original line number Diff line number Diff line Loading @@ -28,30 +28,25 @@ class Command { public: Command(BuiltinFunction f, const std::vector<std::string>& args, const std::string& filename, int line); Command(BuiltinFunction f, const std::vector<std::string>& args, int line); int InvokeFunc() const; std::string BuildCommandString() const; std::string BuildSourceString() const; int line() const { return line_; } private: BuiltinFunction func_; std::vector<std::string> args_; std::string filename_; int line_; }; class Action { public: explicit Action(bool oneshot = false); bool AddCommand(const std::vector<std::string>& args, const std::string& filename, int line, std::string* err); void AddCommand(BuiltinFunction f, const std::vector<std::string>& args, const std::string& filename = "", int line = 0); void CombineAction(const Action& action); explicit Action(bool oneshot, const std::string& filename, int line); bool AddCommand(const std::vector<std::string>& args, int line, std::string* err); void AddCommand(BuiltinFunction f, const std::vector<std::string>& args, int line); bool InitTriggers(const std::vector<std::string>& args, std::string* err); bool InitSingleTrigger(const std::string& trigger); std::size_t NumCommands() const; Loading @@ -60,11 +55,12 @@ public: bool CheckEventTrigger(const std::string& trigger) const; bool CheckPropertyTrigger(const std::string& name, const std::string& value) const; bool TriggersEqual(const Action& other) const; std::string BuildTriggersString() const; void DumpState() const; bool oneshot() const { return oneshot_; } const std::string& filename() const { return filename_; } int line() const { return line_; } static void set_function_map(const KeywordMap<BuiltinFunction>* function_map) { function_map_ = function_map; } Loading @@ -80,6 +76,8 @@ private: std::string event_trigger_; std::vector<Command> commands_; bool oneshot_; std::string filename_; int line_; static const KeywordMap<BuiltinFunction>* function_map_; }; Loading Loading @@ -118,14 +116,13 @@ class ActionParser : public SectionParser { public: ActionParser() : action_(nullptr) { } bool ParseSection(const std::vector<std::string>& args, bool ParseSection(const std::vector<std::string>& args, const std::string& filename, int line, std::string* err) override; bool ParseLineSection(const std::vector<std::string>& args, const std::string& filename, int line, std::string* err) const override; bool ParseLineSection(const std::vector<std::string>& args, int line, std::string* err) override; void EndSection() override; void EndFile(const std::string&) override { } private: std::unique_ptr<Action> action_; }; Loading
init/import_parser.cpp +2 −2 Original line number Diff line number Diff line Loading @@ -20,8 +20,8 @@ #include "util.h" bool ImportParser::ParseSection(const std::vector<std::string>& args, std::string* err) { bool ImportParser::ParseSection(const std::vector<std::string>& args, const std::string& filename, int line, std::string* err) { if (args.size() != 2) { *err = "single argument needed for import\n"; return false; Loading
init/import_parser.h +6 −6 Original line number Diff line number Diff line Loading @@ -26,16 +26,16 @@ class ImportParser : public SectionParser { public: ImportParser() { } bool ParseSection(const std::vector<std::string>& args, bool ParseSection(const std::vector<std::string>& args, const std::string& filename, int line, std::string* err) override; bool ParseLineSection(const std::vector<std::string>& args, const std::string& filename, int line, std::string* err) const override { bool ParseLineSection(const std::vector<std::string>& args, int line, std::string* err) override { return true; } void EndSection() override { } void EndFile(const std::string& filename) override; private: std::vector<std::string> imports_; }; Loading