Loading init/README.md +6 −0 Original line number Diff line number Diff line Loading @@ -311,6 +311,12 @@ Commands groups can be provided. No other commands will be run until this one finishes. _seclabel_ can be a - to denote default. Properties are expanded within _argument_. Init halts executing commands until the forked process exits. `exec_start <service>` > Start service a given service and halt processing of additional init commands until it returns. It functions similarly to the `exec` command, but uses an existing service definition instead of providing them as arguments. `export <name> <value>` > Set the environment variable _name_ equal to _value_ in the Loading init/builtins.cpp +8 −13 Original line number Diff line number Diff line Loading @@ -167,19 +167,11 @@ static int do_enable(const std::vector<std::string>& args) { } static int do_exec(const std::vector<std::string>& args) { Service* svc = ServiceManager::GetInstance().MakeExecOneshotService(args); if (!svc) { return -1; } if (!start_waiting_for_exec()) { return -1; return ServiceManager::GetInstance().Exec(args) ? 0 : -1; } if (!svc->Start()) { stop_waiting_for_exec(); ServiceManager::GetInstance().RemoveService(*svc); return -1; } return 0; static int do_exec_start(const std::vector<std::string>& args) { return ServiceManager::GetInstance().ExecStart(args[1]) ? 0 : -1; } static int do_export(const std::vector<std::string>& args) { Loading Loading @@ -897,6 +889,7 @@ static int do_init_user0(const std::vector<std::string>& args) { BuiltinFunctionMap::Map& BuiltinFunctionMap::map() const { constexpr std::size_t kMax = std::numeric_limits<std::size_t>::max(); // clang-format off static const Map builtin_functions = { {"bootchart", {1, 1, do_bootchart}}, {"chmod", {2, 2, do_chmod}}, Loading @@ -909,6 +902,7 @@ BuiltinFunctionMap::Map& BuiltinFunctionMap::map() const { {"domainname", {1, 1, do_domainname}}, {"enable", {1, 1, do_enable}}, {"exec", {1, kMax, do_exec}}, {"exec_start", {1, 1, do_exec_start}}, {"export", {2, 2, do_export}}, {"hostname", {1, 1, do_hostname}}, {"ifup", {1, 1, do_ifup}}, Loading Loading @@ -942,5 +936,6 @@ BuiltinFunctionMap::Map& BuiltinFunctionMap::map() const { {"wait_for_prop", {2, 2, do_wait_for_prop}}, {"write", {2, 2, do_write}}, }; // clang-format on return builtin_functions; } init/init.cpp +2 −21 Original line number Diff line number Diff line Loading @@ -84,8 +84,6 @@ static time_t process_needs_restart_at; const char *ENV[32]; static std::unique_ptr<Timer> waiting_for_exec(nullptr); static int epoll_fd = -1; static std::unique_ptr<Timer> waiting_for_prop(nullptr); Loading Loading @@ -133,23 +131,6 @@ int add_environment(const char *key, const char *val) return -1; } bool start_waiting_for_exec() { if (waiting_for_exec) { return false; } waiting_for_exec.reset(new Timer()); return true; } void stop_waiting_for_exec() { if (waiting_for_exec) { LOG(INFO) << "Wait for exec took " << *waiting_for_exec; waiting_for_exec.reset(); } } bool start_waiting_for_property(const char *name, const char *value) { if (waiting_for_prop) { Loading Loading @@ -1323,10 +1304,10 @@ int main(int argc, char** argv) { // By default, sleep until something happens. int epoll_timeout_ms = -1; if (!(waiting_for_exec || waiting_for_prop)) { if (!(waiting_for_prop || ServiceManager::GetInstance().IsWaitingForExec())) { am.ExecuteOneCommand(); } if (!(waiting_for_exec || waiting_for_prop)) { if (!(waiting_for_prop || ServiceManager::GetInstance().IsWaitingForExec())) { restart_processes(); // If there's a process that needs restarting, wake up in time for that. Loading init/init.h +0 −4 Original line number Diff line number Diff line Loading @@ -32,10 +32,6 @@ void register_epoll_handler(int fd, void (*fn)()); int add_environment(const char* key, const char* val); bool start_waiting_for_exec(); void stop_waiting_for_exec(); bool start_waiting_for_property(const char *name, const char *value); #endif /* _INIT_INIT_H */ init/service.cpp +58 −9 Original line number Diff line number Diff line Loading @@ -192,8 +192,8 @@ Service::Service(const std::string& name, unsigned flags, uid_t uid, gid_t gid, } void Service::NotifyStateChange(const std::string& new_state) const { if ((flags_ & SVC_EXEC) != 0) { // 'exec' commands don't have properties tracking their state. if ((flags_ & SVC_TEMPORARY) != 0) { // Services created by 'exec' are temporary and don't have properties tracking their state. return; } Loading Loading @@ -260,7 +260,7 @@ void Service::SetProcessAttributes() { } } bool Service::Reap() { void Service::Reap() { if (!(flags_ & SVC_ONESHOT) || (flags_ & SVC_RESTART)) { KillProcessGroup(SIGKILL); } Loading @@ -271,7 +271,10 @@ bool Service::Reap() { if (flags_ & SVC_EXEC) { LOG(INFO) << "SVC_EXEC pid " << pid_ << " finished..."; return true; } if (flags_ & SVC_TEMPORARY) { return; } pid_ = 0; Loading @@ -286,7 +289,7 @@ bool Service::Reap() { // Disabled and reset processes do not get restarted automatically. if (flags_ & (SVC_DISABLED | SVC_RESET)) { NotifyStateChange("stopped"); return false; return; } // If we crash > 4 times in 4 minutes, reboot into recovery. Loading @@ -310,7 +313,7 @@ bool Service::Reap() { onrestart_.ExecuteAllCommands(); NotifyStateChange("restarting"); return false; return; } void Service::DumpState() const { Loading Loading @@ -578,6 +581,18 @@ bool Service::ParseLine(const std::vector<std::string>& args, std::string* err) return (this->*parser)(args, err); } bool Service::ExecStart(std::unique_ptr<Timer>* exec_waiter) { flags_ |= SVC_EXEC | SVC_ONESHOT; exec_waiter->reset(new Timer); if (!Start()) { exec_waiter->reset(); return false; } return true; } bool Service::Start() { // Starting a service removes it from the disabled or reset state and // immediately takes it out of the restarting state if it was in there. Loading Loading @@ -864,6 +879,35 @@ void ServiceManager::AddService(std::unique_ptr<Service> service) { services_.emplace_back(std::move(service)); } bool ServiceManager::Exec(const std::vector<std::string>& args) { Service* svc = MakeExecOneshotService(args); if (!svc) { LOG(ERROR) << "Could not create exec service"; return false; } if (!svc->ExecStart(&exec_waiter_)) { LOG(ERROR) << "Could not start exec service"; ServiceManager::GetInstance().RemoveService(*svc); return false; } return true; } bool ServiceManager::ExecStart(const std::string& name) { Service* svc = FindServiceByName(name); if (!svc) { LOG(ERROR) << "ExecStart(" << name << "): Service not found"; return false; } if (!svc->ExecStart(&exec_waiter_)) { LOG(ERROR) << "ExecStart(" << name << "): Could not start Service"; return false; } return true; } bool ServiceManager::IsWaitingForExec() const { return exec_waiter_ != nullptr; } Service* ServiceManager::MakeExecOneshotService(const std::vector<std::string>& args) { // Parse the arguments: exec [SECLABEL [UID [GID]*] --] COMMAND ARGS... // SECLABEL can be a - to denote default Loading @@ -887,7 +931,7 @@ Service* ServiceManager::MakeExecOneshotService(const std::vector<std::string>& exec_count_++; std::string name = StringPrintf("exec %d (%s)", exec_count_, str_args[0].c_str()); unsigned flags = SVC_EXEC | SVC_ONESHOT; unsigned flags = SVC_EXEC | SVC_ONESHOT | SVC_TEMPORARY; CapSet no_capabilities; unsigned namespace_flags = 0; Loading Loading @@ -1027,8 +1071,13 @@ bool ServiceManager::ReapOneProcess() { return true; } if (svc->Reap()) { stop_waiting_for_exec(); svc->Reap(); if (svc->flags() & SVC_EXEC) { LOG(INFO) << "Wait for exec took " << *exec_waiter_; exec_waiter_.reset(); } if (svc->flags() & SVC_TEMPORARY) { RemoveService(*svc); } Loading Loading
init/README.md +6 −0 Original line number Diff line number Diff line Loading @@ -311,6 +311,12 @@ Commands groups can be provided. No other commands will be run until this one finishes. _seclabel_ can be a - to denote default. Properties are expanded within _argument_. Init halts executing commands until the forked process exits. `exec_start <service>` > Start service a given service and halt processing of additional init commands until it returns. It functions similarly to the `exec` command, but uses an existing service definition instead of providing them as arguments. `export <name> <value>` > Set the environment variable _name_ equal to _value_ in the Loading
init/builtins.cpp +8 −13 Original line number Diff line number Diff line Loading @@ -167,19 +167,11 @@ static int do_enable(const std::vector<std::string>& args) { } static int do_exec(const std::vector<std::string>& args) { Service* svc = ServiceManager::GetInstance().MakeExecOneshotService(args); if (!svc) { return -1; } if (!start_waiting_for_exec()) { return -1; return ServiceManager::GetInstance().Exec(args) ? 0 : -1; } if (!svc->Start()) { stop_waiting_for_exec(); ServiceManager::GetInstance().RemoveService(*svc); return -1; } return 0; static int do_exec_start(const std::vector<std::string>& args) { return ServiceManager::GetInstance().ExecStart(args[1]) ? 0 : -1; } static int do_export(const std::vector<std::string>& args) { Loading Loading @@ -897,6 +889,7 @@ static int do_init_user0(const std::vector<std::string>& args) { BuiltinFunctionMap::Map& BuiltinFunctionMap::map() const { constexpr std::size_t kMax = std::numeric_limits<std::size_t>::max(); // clang-format off static const Map builtin_functions = { {"bootchart", {1, 1, do_bootchart}}, {"chmod", {2, 2, do_chmod}}, Loading @@ -909,6 +902,7 @@ BuiltinFunctionMap::Map& BuiltinFunctionMap::map() const { {"domainname", {1, 1, do_domainname}}, {"enable", {1, 1, do_enable}}, {"exec", {1, kMax, do_exec}}, {"exec_start", {1, 1, do_exec_start}}, {"export", {2, 2, do_export}}, {"hostname", {1, 1, do_hostname}}, {"ifup", {1, 1, do_ifup}}, Loading Loading @@ -942,5 +936,6 @@ BuiltinFunctionMap::Map& BuiltinFunctionMap::map() const { {"wait_for_prop", {2, 2, do_wait_for_prop}}, {"write", {2, 2, do_write}}, }; // clang-format on return builtin_functions; }
init/init.cpp +2 −21 Original line number Diff line number Diff line Loading @@ -84,8 +84,6 @@ static time_t process_needs_restart_at; const char *ENV[32]; static std::unique_ptr<Timer> waiting_for_exec(nullptr); static int epoll_fd = -1; static std::unique_ptr<Timer> waiting_for_prop(nullptr); Loading Loading @@ -133,23 +131,6 @@ int add_environment(const char *key, const char *val) return -1; } bool start_waiting_for_exec() { if (waiting_for_exec) { return false; } waiting_for_exec.reset(new Timer()); return true; } void stop_waiting_for_exec() { if (waiting_for_exec) { LOG(INFO) << "Wait for exec took " << *waiting_for_exec; waiting_for_exec.reset(); } } bool start_waiting_for_property(const char *name, const char *value) { if (waiting_for_prop) { Loading Loading @@ -1323,10 +1304,10 @@ int main(int argc, char** argv) { // By default, sleep until something happens. int epoll_timeout_ms = -1; if (!(waiting_for_exec || waiting_for_prop)) { if (!(waiting_for_prop || ServiceManager::GetInstance().IsWaitingForExec())) { am.ExecuteOneCommand(); } if (!(waiting_for_exec || waiting_for_prop)) { if (!(waiting_for_prop || ServiceManager::GetInstance().IsWaitingForExec())) { restart_processes(); // If there's a process that needs restarting, wake up in time for that. Loading
init/init.h +0 −4 Original line number Diff line number Diff line Loading @@ -32,10 +32,6 @@ void register_epoll_handler(int fd, void (*fn)()); int add_environment(const char* key, const char* val); bool start_waiting_for_exec(); void stop_waiting_for_exec(); bool start_waiting_for_property(const char *name, const char *value); #endif /* _INIT_INIT_H */
init/service.cpp +58 −9 Original line number Diff line number Diff line Loading @@ -192,8 +192,8 @@ Service::Service(const std::string& name, unsigned flags, uid_t uid, gid_t gid, } void Service::NotifyStateChange(const std::string& new_state) const { if ((flags_ & SVC_EXEC) != 0) { // 'exec' commands don't have properties tracking their state. if ((flags_ & SVC_TEMPORARY) != 0) { // Services created by 'exec' are temporary and don't have properties tracking their state. return; } Loading Loading @@ -260,7 +260,7 @@ void Service::SetProcessAttributes() { } } bool Service::Reap() { void Service::Reap() { if (!(flags_ & SVC_ONESHOT) || (flags_ & SVC_RESTART)) { KillProcessGroup(SIGKILL); } Loading @@ -271,7 +271,10 @@ bool Service::Reap() { if (flags_ & SVC_EXEC) { LOG(INFO) << "SVC_EXEC pid " << pid_ << " finished..."; return true; } if (flags_ & SVC_TEMPORARY) { return; } pid_ = 0; Loading @@ -286,7 +289,7 @@ bool Service::Reap() { // Disabled and reset processes do not get restarted automatically. if (flags_ & (SVC_DISABLED | SVC_RESET)) { NotifyStateChange("stopped"); return false; return; } // If we crash > 4 times in 4 minutes, reboot into recovery. Loading @@ -310,7 +313,7 @@ bool Service::Reap() { onrestart_.ExecuteAllCommands(); NotifyStateChange("restarting"); return false; return; } void Service::DumpState() const { Loading Loading @@ -578,6 +581,18 @@ bool Service::ParseLine(const std::vector<std::string>& args, std::string* err) return (this->*parser)(args, err); } bool Service::ExecStart(std::unique_ptr<Timer>* exec_waiter) { flags_ |= SVC_EXEC | SVC_ONESHOT; exec_waiter->reset(new Timer); if (!Start()) { exec_waiter->reset(); return false; } return true; } bool Service::Start() { // Starting a service removes it from the disabled or reset state and // immediately takes it out of the restarting state if it was in there. Loading Loading @@ -864,6 +879,35 @@ void ServiceManager::AddService(std::unique_ptr<Service> service) { services_.emplace_back(std::move(service)); } bool ServiceManager::Exec(const std::vector<std::string>& args) { Service* svc = MakeExecOneshotService(args); if (!svc) { LOG(ERROR) << "Could not create exec service"; return false; } if (!svc->ExecStart(&exec_waiter_)) { LOG(ERROR) << "Could not start exec service"; ServiceManager::GetInstance().RemoveService(*svc); return false; } return true; } bool ServiceManager::ExecStart(const std::string& name) { Service* svc = FindServiceByName(name); if (!svc) { LOG(ERROR) << "ExecStart(" << name << "): Service not found"; return false; } if (!svc->ExecStart(&exec_waiter_)) { LOG(ERROR) << "ExecStart(" << name << "): Could not start Service"; return false; } return true; } bool ServiceManager::IsWaitingForExec() const { return exec_waiter_ != nullptr; } Service* ServiceManager::MakeExecOneshotService(const std::vector<std::string>& args) { // Parse the arguments: exec [SECLABEL [UID [GID]*] --] COMMAND ARGS... // SECLABEL can be a - to denote default Loading @@ -887,7 +931,7 @@ Service* ServiceManager::MakeExecOneshotService(const std::vector<std::string>& exec_count_++; std::string name = StringPrintf("exec %d (%s)", exec_count_, str_args[0].c_str()); unsigned flags = SVC_EXEC | SVC_ONESHOT; unsigned flags = SVC_EXEC | SVC_ONESHOT | SVC_TEMPORARY; CapSet no_capabilities; unsigned namespace_flags = 0; Loading Loading @@ -1027,8 +1071,13 @@ bool ServiceManager::ReapOneProcess() { return true; } if (svc->Reap()) { stop_waiting_for_exec(); svc->Reap(); if (svc->flags() & SVC_EXEC) { LOG(INFO) << "Wait for exec took " << *exec_waiter_; exec_waiter_.reset(); } if (svc->flags() & SVC_TEMPORARY) { RemoveService(*svc); } Loading