From 4319a11c6e7d758929b41fa7371e4febb493f3fd Mon Sep 17 00:00:00 2001 From: Davin McCall Date: Fri, 24 Jun 2016 16:14:28 +0100 Subject: [PATCH] Add release/wake commands to dinitctl --- README | 3 +- TODO | 3 -- src/control.cc | 2 +- src/dinitctl.cc | 81 ++++++++++++++++++++++++++++++++++--------------- 4 files changed, 60 insertions(+), 29 deletions(-) diff --git a/README b/README index 934cb98..9c14a4a 100644 --- a/README +++ b/README @@ -123,7 +123,8 @@ lazily, as needed by Dinit. A service description file consists of a number of parameter settings. Settings in the SDF are denoted as a parameter name followed by either an equal sign or colon and then the parameter value (all on the same line). -Comments begin with a hash mark (#) and extend to the end of the line. +Comments begin with a hash mark (#) and extend to the end of the line (they +must be separated from setting values by at least one whitespace character). Parameter values are interpreted literally, except that: - whitespace is collapsed to a single space diff --git a/TODO b/TODO index 70528a4..41c027c 100644 --- a/TODO +++ b/TODO @@ -1,6 +1,3 @@ -* Implement a control utility to start/stop services after dinit has started - - basic version exists, needs a little more work to support all - start/stop command variants * Sort out single-user mode startup For version 1.0: diff --git a/src/control.cc b/src/control.cc index 54a6722..889870c 100644 --- a/src/control.cc +++ b/src/control.cc @@ -186,7 +186,7 @@ bool ControlConn::processStartStop(int pktType) case DINIT_CP_RELEASESERVICE: // remove required mark, stop if not required by dependents if (do_pin) service->pinStop(); - service->stop(); + service->stop(false); service_set->processQueues(false); already_there = service->getState() == ServiceState::STOPPED; break; diff --git a/src/dinitctl.cc b/src/dinitctl.cc index 95e0337..648cfc0 100644 --- a/src/dinitctl.cc +++ b/src/dinitctl.cc @@ -31,9 +31,11 @@ class ReadCPException ReadCPException(int err) : errcode(err) { } }; +enum class Command; + static int issueLoadService(int socknum, const char *service_name); static int checkLoadReply(int socknum, CPBuffer<1024> &rbuffer, handle_t *handle_p, ServiceState *state_p); -static int startStopService(int socknum, const char *service_name, int command, bool do_pin, bool wait_for_service, bool verbose); +static int startStopService(int socknum, const char *service_name, Command command, bool do_pin, bool wait_for_service, bool verbose); static int unpinService(int socknum, const char *service_name, bool verbose); static int listServices(int socknum); @@ -110,11 +112,15 @@ static int write_all(int fd, const void *buf, size_t count) } -static const int START_SERVICE = 1; -static const int STOP_SERVICE = 2; -static const int UNPIN_SERVICE = 3; -static const int LIST_SERVICES = 4; - +enum class Command { + NONE, + START_SERVICE, + WAKE_SERVICE, + STOP_SERVICE, + RELEASE_SERVICE, + UNPIN_SERVICE, + LIST_SERVICES +}; // Entry point. int main(int argc, char **argv) @@ -132,7 +138,7 @@ int main(int argc, char **argv) bool wait_for_service = true; bool do_pin = false; - int command = 0; + Command command = Command::NONE; for (int i = 1; i < argc; i++) { if (argv[i][0] == '-') { @@ -156,18 +162,24 @@ int main(int argc, char **argv) return 1; } } - else if (command == 0) { + else if (command == Command::NONE) { if (strcmp(argv[i], "start") == 0) { - command = START_SERVICE; + command = Command::START_SERVICE; + } + else if (strcmp(argv[i], "wake") == 0) { + command = Command::WAKE_SERVICE; } else if (strcmp(argv[i], "stop") == 0) { - command = STOP_SERVICE; + command = Command::STOP_SERVICE; + } + else if (strcmp(argv[i], "release") == 0) { + command = Command::RELEASE_SERVICE; } else if (strcmp(argv[i], "unpin") == 0) { - command = UNPIN_SERVICE; + command = Command::UNPIN_SERVICE; } else if (strcmp(argv[i], "list") == 0) { - command = LIST_SERVICES; + command = Command::LIST_SERVICES; } else { show_help = true; @@ -176,13 +188,20 @@ int main(int argc, char **argv) } else { // service name + if (service_name != nullptr) { + show_help = true; + break; + } service_name = argv[i]; - // TODO support multiple services (or at least give error if multiple - // services supplied) + // TODO support multiple services } } - if ((service_name == nullptr && command != LIST_SERVICES) || command == 0) { + if (service_name != nullptr && command == Command::LIST_SERVICES) { + show_help = true; + } + + if ((service_name == nullptr && command != Command::LIST_SERVICES) || command == Command::NONE) { show_help = true; } @@ -192,9 +211,9 @@ int main(int argc, char **argv) cout << "\nUsage:" << endl; cout << " dinitctl [options] start [options] : start and activate service" << endl; cout << " dinitctl [options] stop [options] : stop service and cancel explicit activation" << endl; + cout << " dinitctl [options] wake [options] : start but do not mark activated" << endl; + cout << " dinitctl [options] release [options] : release activation, stop if no dependents" << endl; cout << " dinitctl [options] unpin : un-pin the service (after a previous pin)" << endl; - // TODO: - // cout << " dinitctl [options] wake : start but don't activate service" << endl; cout << " dinitctl list : list loaded services" << endl; cout << "\nNote: An activated service continues running when its dependents stop." << endl; @@ -260,10 +279,10 @@ int main(int argc, char **argv) // TODO should start by querying protocol version - if (command == UNPIN_SERVICE) { + if (command == Command::UNPIN_SERVICE) { return unpinService(socknum, service_name, verbose); } - else if (command == LIST_SERVICES) { + else if (command == Command::LIST_SERVICES) { return listServices(socknum); } @@ -271,11 +290,11 @@ int main(int argc, char **argv) } // Start/stop a service -static int startStopService(int socknum, const char *service_name, int command, bool do_pin, bool wait_for_service, bool verbose) +static int startStopService(int socknum, const char *service_name, Command command, bool do_pin, bool wait_for_service, bool verbose) { using namespace std; - bool do_stop = (command == STOP_SERVICE); + bool do_stop = (command == Command::STOP_SERVICE || command == Command::RELEASE_SERVICE); if (issueLoadService(socknum, service_name)) { return 1; @@ -296,12 +315,26 @@ static int startStopService(int socknum, const char *service_name, int command, } ServiceState wanted_state = do_stop ? ServiceState::STOPPED : ServiceState::STARTED; - int command = do_stop ? DINIT_CP_STOPSERVICE : DINIT_CP_STARTSERVICE; + int pcommand = 0; + switch (command) { + case Command::STOP_SERVICE: + pcommand = DINIT_CP_STOPSERVICE; + break; + case Command::RELEASE_SERVICE: + pcommand = DINIT_CP_RELEASESERVICE; + break; + case Command::START_SERVICE: + pcommand = DINIT_CP_STARTSERVICE; + break; + case Command::WAKE_SERVICE: + pcommand = DINIT_CP_WAKESERVICE; + break; + default: ; + } // Need to issue STOPSERVICE/STARTSERVICE // We'll do this regardless of the current service state / target state, since issuing // start/stop also sets or clears the "explicitly started" flag on the service. - //if (target_state != wanted_state) { { int r; @@ -309,7 +342,7 @@ static int startStopService(int socknum, const char *service_name, int command, auto buf = new char[2 + sizeof(handle)]; unique_ptr ubuf(buf); - buf[0] = command; + buf[0] = pcommand; buf[1] = do_pin ? 1 : 0; memcpy(buf + 2, &handle, sizeof(handle)); r = write_all(socknum, buf, 2 + sizeof(handle)); -- 2.25.1