Implement reload command for dinitctl
authorDavin McCall <davmac@davmac.org>
Sun, 1 Dec 2019 04:46:27 +0000 (14:46 +1000)
committerDavin McCall <davmac@davmac.org>
Sun, 1 Dec 2019 04:59:35 +0000 (14:59 +1000)
doc/manpages/dinitctl.8.m4
src/dinitctl.cc

index 14714ca4634a1479ce5635a61a3f55b3d972e211..f6271878820c953a79068bbd98590144eb59aa41 100644 (file)
@@ -27,6 +27,9 @@ dinitctl \- control services supervised by Dinit
 [\fIoptions\fR] \fBunload\fR \fIservice-name\fR
 .br
 .B dinitctl
+[\fIoptions\fR] \fBreload\fR \fIservice-name\fR
+.br
+.B dinitctl
 [\fIoptions\fR] \fBlist\fR
 .br
 .B dinitctl
@@ -128,6 +131,15 @@ any pending start/stop commands will be carried out.
 Completely unload a service. This can only be done if the service is stopped and has no loaded dependents
 (i.e. dependents must be unloaded before their dependencies).
 .TP
+\fBreload\fR
+Attempt to reload a service description. This is intended as a convenience for making simple changes to a
+service, without having to stop, remove dependencies to and unload the service. However it is not completely
+equivalent to doing a proper unload/reload; some altered settings may not take effect until the service is
+restarted, and some cannot be changed at all while the service is running.
+
+In particular, the type of a running service cannot be changed; nor can the \fBinittab-id\fR, \fBinittab-line\fR,
+or \fBpid-file\fR settings, or the \fBruns-on-console\fR or \fBshares-console\fR flags.
+.TP
 \fBlist\fR
 List loaded services and their state. Before each service, one of the following state indicators is
 displayed:
index 03b2cd1a60141160a53daf468b2c6e1c64b69571..b2af20b5e5c1a49209a95a06b28b6c3d13d88f3d 100644 (file)
@@ -41,6 +41,7 @@ static int start_stop_service(int socknum, cpbuffer_t &, const char *service_nam
         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 reload_service(int socknum, cpbuffer_t &, const char *service_name);
 static int list_services(int socknum, cpbuffer_t &);
 static int shutdown_dinit(int soclknum, cpbuffer_t &);
 static int add_remove_dependency(int socknum, cpbuffer_t &rbuffer, bool add, const char *service_from,
@@ -67,6 +68,7 @@ enum class command_t {
     RELEASE_SERVICE,
     UNPIN_SERVICE,
     UNLOAD_SERVICE,
+    RELOAD_SERVICE,
     LIST_SERVICES,
     SHUTDOWN,
     ADD_DEPENDENCY,
@@ -167,6 +169,9 @@ int main(int argc, char **argv)
             else if (strcmp(argv[i], "unload") == 0) {
                 command = command_t::UNLOAD_SERVICE;
             }
+            else if (strcmp(argv[i], "reload") == 0) {
+                command = command_t::RELOAD_SERVICE;
+            }
             else if (strcmp(argv[i], "list") == 0) {
                 command = command_t::LIST_SERVICES;
             }
@@ -267,6 +272,7 @@ int main(int argc, char **argv)
           "    dinitctl [options] release [options] <service-name>\n"
           "    dinitctl [options] unpin <service-name>\n"
           "    dinitctl [options] unload <service-name>\n"
+          "    dinitctl [options] reload <service-name>\n"
           "    dinitctl [options] list\n"
           "    dinitctl [options] shutdown\n"
           "    dinitctl [options] add-dep <type> <from-service> <to-service>\n"
@@ -354,6 +360,9 @@ int main(int argc, char **argv)
         else if (command == command_t::UNLOAD_SERVICE) {
             return unload_service(socknum, rbuffer, service_name);
         }
+        else if (command == command_t::RELOAD_SERVICE) {
+            return reload_service(socknum, rbuffer, service_name);
+        }
         else if (command == command_t::LIST_SERVICES) {
             return list_services(socknum, rbuffer);
         }
@@ -793,6 +802,51 @@ static int unload_service(int socknum, cpbuffer_t &rbuffer, const char *service_
     return 0;
 }
 
+static int reload_service(int socknum, cpbuffer_t &rbuffer, const char *service_name)
+{
+    using namespace std;
+
+    if (issue_load_service(socknum, service_name, true) == 1) {
+        return 1;
+    }
+
+    wait_for_reply(rbuffer, socknum);
+
+    handle_t handle;
+
+    if (rbuffer[0] == DINIT_RP_NOSERVICE) {
+        cerr << "dinitctl: service not loaded." << endl;
+        return 1;
+    }
+
+    if (check_load_reply(socknum, rbuffer, &handle, nullptr) != 0) {
+        return 1;
+    }
+
+    // Issue RELOAD command.
+    {
+        auto m = membuf()
+                .append<char>(DINIT_CP_RELOADSERVICE)
+                .append(handle);
+        write_all_x(socknum, m);
+
+        wait_for_reply(rbuffer, socknum);
+        if (rbuffer[0] == DINIT_RP_NAK) {
+            cerr << "dinitctl: Could not reload service; service in wrong state, incompatible change, "
+                    "or bad service description." << endl;
+            return 1;
+        }
+        if (rbuffer[0] != DINIT_RP_ACK) {
+            cerr << "dinitctl: Protocol error." << endl;
+            return 1;
+        }
+        rbuffer.consume(1);
+    }
+
+    cout << "Service reloaded." << endl;
+    return 0;
+}
+
 static int list_services(int socknum, cpbuffer_t &rbuffer)
 {
     using namespace std;