dinitctl stop: gentle by default, implement --force.
authorDavin McCall <davmac@davmac.org>
Tue, 23 Jul 2019 11:09:15 +0000 (21:09 +1000)
committerDavin McCall <davmac@davmac.org>
Tue, 23 Jul 2019 11:14:13 +0000 (21:14 +1000)
A "gentle" stop won't stop if dependents will be affected, i.e. it warns
and aborts. The `--force' option (or `-f') can be used to force the
service to stop, which will also cause the dependents to stop.

Also sneak in a bug fix where certain options were not recognised.

doc/manpages/dinitctl.8.m4
src/dinitctl.cc

index cee4b0257092922648e08fc70561e5d9cf026785..d56e476cc0e8455d2092f60b4501695730e96e6e 100644 (file)
@@ -71,6 +71,9 @@ Do not wait for issued command to complete; exit immediately.
 Pin the service in the requested state. The service will not leave the state until it is unpinned, although
 start/stop commands will be "remembered" while the service is pinned.
 .TP
+\fB\-\-force\fR
+Stop the service even if it will require stopping other services which depend on the specified service.
+.TP
 \fIservice-name\fR
 Specifies the name of the service to which the command applies.
 .TP
index 8d8b8d5c55078c1068f1df1dc714f74dff6886cc..ad488bcd3a911c54b36daecda3a4caf7bb33cdb4 100644 (file)
@@ -38,7 +38,7 @@ enum class command_t;
 static int issue_load_service(int socknum, const char *service_name, bool find_only = false);
 static int check_load_reply(int socknum, cpbuffer_t &, handle_t *handle_p, service_state_t *state_p);
 static int start_stop_service(int socknum, cpbuffer_t &, const char *service_name, command_t command,
-        bool do_pin, bool wait_for_service, bool verbose);
+        bool do_pin, bool do_force, bool wait_for_service, bool verbose);
 static int unpin_service(int socknum, cpbuffer_t &, const char *service_name, bool verbose);
 static int unload_service(int socknum, cpbuffer_t &, const char *service_name);
 static int list_services(int socknum, cpbuffer_t &);
@@ -93,6 +93,7 @@ int main(int argc, char **argv)
     bool sys_dinit = false;  // communicate with system daemon
     bool wait_for_service = true;
     bool do_pin = false;
+    bool do_force = false;
     
     command_t command = command_t::NONE;
         
@@ -114,7 +115,7 @@ int main(int argc, char **argv)
             else if (strcmp(argv[i], "--pin") == 0) {
                 do_pin = true;
             }
-            else if (strcmp(argv[i], "--socket-path") || strcmp(argv[i], "-p")) {
+            else if (strcmp(argv[i], "--socket-path") == 0 || strcmp(argv[i], "-p") == 0) {
                 ++i;
                 if (i == argc) {
                     cerr << "dinitctl: --socket-path/-p should be followed by socket path" << std::endl;
@@ -131,8 +132,12 @@ int main(int argc, char **argv)
                 }
                 service_name = argv[i];
             }
+            else if ((command == command_t::STOP_SERVICE)
+                    && (strcmp(argv[i], "--force") == 0 || strcmp(argv[i], "-f") == 0)) {
+                do_force = true;
+            }
             else {
-                cerr << "dinitctl: unrecognized option: " << argv[i] << " (use --help for help)\n";
+                cerr << "dinitctl: unrecognized/invalid option: " << argv[i] << " (use --help for help)\n";
                 return 1;
             }
         }
@@ -264,15 +269,16 @@ int main(int argc, char **argv)
           "Note: An activated service continues running when its dependents stop.\n"
           "\n"
           "General options:\n"
+          "  --help           : show this help\n"
           "  -s, --system     : control system daemon instead of user daemon\n"
           "  --quiet          : suppress output (except errors)\n"
           "  --socket-path <path>, -p <path>\n"
           "                   : specify socket for communication with daemon\n"
           "\n"
           "Command options:\n"
-          "  --help           : show this help\n"
           "  --no-wait        : don't wait for service startup/shutdown to complete\n"
-          "  --pin            : pin the service in the requested state\n";
+          "  --pin            : pin the service in the requested state\n"
+          "  --force          : force stop even if dependents will be affected\n";
         return 1;
     }
     
@@ -358,7 +364,7 @@ int main(int argc, char **argv)
                     command == command_t::ENABLE_SERVICE);
         }
         else {
-            return start_stop_service(socknum, rbuffer, service_name, command, do_pin,
+            return start_stop_service(socknum, rbuffer, service_name, command, do_pin, do_force,
                     wait_for_service, verbose);
         }
     }
@@ -435,7 +441,7 @@ static bool load_service(int socknum, cpbuffer_t &rbuffer, const char *name, han
 
 // Start/stop a service
 static int start_stop_service(int socknum, cpbuffer_t &rbuffer, const char *service_name,
-        command_t command, bool do_pin, bool wait_for_service, bool verbose)
+        command_t command, bool do_pin, bool do_force, bool wait_for_service, bool verbose)
 {
     using namespace std;
 
@@ -472,7 +478,7 @@ static int start_stop_service(int socknum, cpbuffer_t &rbuffer, const char *serv
     {
         char buf[2 + sizeof(handle)];
         buf[0] = pcommand;
-        buf[1] = do_pin ? 1 : 0;
+        buf[1] = (do_pin ? 1 : 0) | ((pcommand == DINIT_CP_STOPSERVICE && !do_force) ? 2 : 0);
         memcpy(buf + 2, &handle, sizeof(handle));
         write_all_x(socknum, buf, 2 + sizeof(handle));
         
@@ -485,6 +491,10 @@ static int start_stop_service(int socknum, cpbuffer_t &rbuffer, const char *serv
             }
             return 0; // success!
         }
+        if (rbuffer[0] == DINIT_RP_DEPENDENTS && pcommand == DINIT_CP_STOPSERVICE) {
+            cerr << "dinitctl: Cannot stop service due to dependents (consider using --force)." << endl;
+            return 1;
+        }
         if (rbuffer[0] != DINIT_RP_ACK) {
             cerr << "dinitctl: Protocol error." << endl;
             return 1;