Factor out some Dinit client functions tp a new header (dinit-client.h).
authorDavin McCall <davmac@davmac.org>
Mon, 5 Feb 2018 10:58:44 +0000 (10:58 +0000)
committerDavin McCall <davmac@davmac.org>
Mon, 12 Feb 2018 17:21:21 +0000 (17:21 +0000)
src/dinitctl.cc
src/includes/dinit-client.h [new file with mode: 0644]
src/shutdown.cc

index 983f123fe297b3eae806eed16f51242e79314e56..e224932024bd502ee1afc7bae553f9528d22b59e 100644 (file)
 #include "control-cmds.h"
 #include "service-constants.h"
 #include "cpbuffer.h"
+#include "dinit-client.h"
 
 // dinitctl:  utility to control the Dinit daemon, including starting and stopping of services.
 
 // This utility communicates with the dinit daemon via a unix stream socket (/dev/initctl, or $HOME/.dinitctl).
 
-using handle_t = uint32_t;
-
-
-class read_cp_exception
-{
-    public:
-    int errcode;
-    read_cp_exception(int err) : errcode(err) { }
-};
 
 enum class command_t;
 
@@ -42,30 +34,6 @@ static int list_services(int socknum);
 static int shutdown_dinit(int soclknum);
 
 
-// Fill a circular buffer from a file descriptor, until it contains at least _rlength_ bytes.
-// Throws read_cp_exception if the requested number of bytes cannot be read, with:
-//     errcode = 0   if end of stream (remote end closed)
-//     errcode = errno   if another error occurred
-// Note that EINTR is ignored (i.e. the read will be re-tried).
-static void fillBufferTo(cpbuffer<1024> *buf, int fd, int rlength)
-{
-    do {
-        int r = buf->fill_to(fd, rlength);
-        if (r == -1) {
-            if (errno != EINTR) {
-                throw read_cp_exception(errno);
-            }
-        }
-        else if (r == 0) {
-            throw read_cp_exception(0);
-        }
-        else {
-            return;
-        }
-    }
-    while (true);
-}
-
 static const char * describeState(bool stopped)
 {
     return stopped ? "stopped" : "started";
@@ -76,55 +44,6 @@ static const char * describeVerb(bool stop)
     return stop ? "stop" : "start";
 }
 
-// Wait for a reply packet, skipping over any information packets that are received in the meantime.
-static void wait_for_reply(cpbuffer<1024> &rbuffer, int fd)
-{
-    fillBufferTo(&rbuffer, fd, 1);
-    
-    while (rbuffer[0] >= 100) {
-        // Information packet; discard.
-        fillBufferTo(&rbuffer, fd, 2);
-        int pktlen = (unsigned char) rbuffer[1];
-        
-        rbuffer.consume(1);  // Consume one byte so we'll read one byte of the next packet
-        fillBufferTo(&rbuffer, fd, pktlen);
-        rbuffer.consume(pktlen - 1);
-    }
-}
-
-// Wait for an info packet. If any other reply packet comes, throw a read_cp_exception.
-static void wait_for_info(cpbuffer<1024> &rbuffer, int fd)
-{
-    fillBufferTo(&rbuffer, fd, 2);
-
-    if (rbuffer[0] < 100) {
-        throw read_cp_exception(0);
-    }
-
-    int pktlen = (unsigned char) rbuffer[1];
-    fillBufferTo(&rbuffer, fd, pktlen);
-}
-
-// Write *all* the requested buffer and re-try if necessary until
-// the buffer is written or an unrecoverable error occurs.
-static int write_all(int fd, const void *buf, size_t count)
-{
-    const char *cbuf = static_cast<const char *>(buf);
-    int w = 0;
-    while (count > 0) {
-        int r = write(fd, cbuf, count);
-        if (r == -1) {
-            if (errno == EINTR) continue;
-            return r;
-        }
-        w += r;
-        cbuf += r;
-        count -= r;
-    }
-    return w;
-}
-
-
 enum class command_t {
     NONE,
     START_SERVICE,
@@ -424,7 +343,7 @@ static int start_stop_service(int socknum, const char *service_name, command_t c
         while (r > 0) {
             if (rbuffer[0] >= 100) {
                 int pktlen = (unsigned char) rbuffer[1];
-                fillBufferTo(&rbuffer, socknum, pktlen);
+                fill_buffer_to(&rbuffer, socknum, pktlen);
                 
                 if (rbuffer[0] == DINIT_IP_SERVICEEVENT) {
                     handle_t ev_handle;
@@ -520,7 +439,7 @@ static int check_load_reply(int socknum, cpbuffer<1024> &rbuffer, handle_t *hand
     using namespace std;
     
     if (rbuffer[0] == DINIT_RP_SERVICERECORD) {
-        fillBufferTo(&rbuffer, socknum, 2 + sizeof(*handle_p));
+        fill_buffer_to(&rbuffer, socknum, 2 + sizeof(*handle_p));
         rbuffer.extract((char *) handle_p, 2, sizeof(*handle_p));
         if (state_p) *state_p = static_cast<service_state_t>(rbuffer[1]);
         //target_state = static_cast<service_state_t>(rbuffer[2 + sizeof(handle)]);
@@ -678,12 +597,12 @@ static int list_services(int socknum)
         cpbuffer<1024> rbuffer;
         wait_for_reply(rbuffer, socknum);
         while (rbuffer[0] == DINIT_RP_SVCINFO) {
-            fillBufferTo(&rbuffer, socknum, 8);
+            fill_buffer_to(&rbuffer, socknum, 8);
             int nameLen = rbuffer[1];
             service_state_t current = static_cast<service_state_t>(rbuffer[2]);
             service_state_t target = static_cast<service_state_t>(rbuffer[3]);
             
-            fillBufferTo(&rbuffer, socknum, nameLen + 8);
+            fill_buffer_to(&rbuffer, socknum, nameLen + 8);
             
             char *name_ptr = rbuffer.get_ptr(8);
             int clength = std::min(rbuffer.get_contiguous_length(name_ptr), nameLen);
@@ -746,19 +665,12 @@ static int shutdown_dinit(int socknum)
     buf[0] = DINIT_CP_SHUTDOWN;
     buf[1] = static_cast<char>(shutdown_type_t::HALT);
 
-    // TODO make sure to write the whole buffer
-    int r = write(socknum, buf, bufsize);
+    int r = write_all(socknum, buf, bufsize);
     if (r == -1) {
         perror("write");
         return 1;
     }
 
-    // Wait for ACK/NACK
-    // r = read(socknum, buf, 1);
-    //if (r > 0) {
-    //    cout << "Received acknowledgement. System should now shut down." << endl;
-    //}
-
     cpbuffer<1024> rbuffer;
     try {
         wait_for_reply(rbuffer, socknum);
diff --git a/src/includes/dinit-client.h b/src/includes/dinit-client.h
new file mode 100644 (file)
index 0000000..34963cf
--- /dev/null
@@ -0,0 +1,85 @@
+#include <cstdint>
+
+// Client library for Dinit clients
+
+
+using handle_t = uint32_t;
+
+class read_cp_exception
+{
+    public:
+    int errcode;
+    read_cp_exception(int err) : errcode(err) { }
+};
+
+// Fill a circular buffer from a file descriptor, until it contains at least _rlength_ bytes.
+// Throws read_cp_exception if the requested number of bytes cannot be read, with:
+//     errcode = 0   if end of stream (remote end closed)
+//     errcode = errno   if another error occurred
+// Note that EINTR is ignored (i.e. the read will be re-tried).
+inline void fill_buffer_to(cpbuffer<1024> *buf, int fd, int rlength)
+{
+    do {
+        int r = buf->fill_to(fd, rlength);
+        if (r == -1) {
+            if (errno != EINTR) {
+                throw read_cp_exception(errno);
+            }
+        }
+        else if (r == 0) {
+            throw read_cp_exception(0);
+        }
+        else {
+            return;
+        }
+    }
+    while (true);
+}
+
+// Wait for a reply packet, skipping over any information packets that are received in the meantime.
+inline void wait_for_reply(cpbuffer<1024> &rbuffer, int fd)
+{
+    fill_buffer_to(&rbuffer, fd, 1);
+
+    while (rbuffer[0] >= 100) {
+        // Information packet; discard.
+        fill_buffer_to(&rbuffer, fd, 2);
+        int pktlen = (unsigned char) rbuffer[1];
+
+        rbuffer.consume(1);  // Consume one byte so we'll read one byte of the next packet
+        fill_buffer_to(&rbuffer, fd, pktlen);
+        rbuffer.consume(pktlen - 1);
+    }
+}
+
+// Wait for an info packet. If any other reply packet comes, throw a read_cp_exception.
+inline void wait_for_info(cpbuffer<1024> &rbuffer, int fd)
+{
+    fill_buffer_to(&rbuffer, fd, 2);
+
+    if (rbuffer[0] < 100) {
+        throw read_cp_exception(0);
+    }
+
+    int pktlen = (unsigned char) rbuffer[1];
+    fill_buffer_to(&rbuffer, fd, pktlen);
+}
+
+// Write *all* the requested buffer and re-try if necessary until
+// the buffer is written or an unrecoverable error occurs.
+inline int write_all(int fd, const void *buf, size_t count)
+{
+    const char *cbuf = static_cast<const char *>(buf);
+    int w = 0;
+    while (count > 0) {
+        int r = write(fd, cbuf, count);
+        if (r == -1) {
+            if (errno == EINTR) continue;
+            return r;
+        }
+        w += r;
+        cbuf += r;
+        count -= r;
+    }
+    return w;
+}
index c751fd086fe422a3e9beb877a7cc3abb37aa84c4..3f1a131e0e768bd5b91603ebdc6dffb900168790 100644 (file)
@@ -17,6 +17,7 @@
 #include "cpbuffer.h"
 #include "control-cmds.h"
 #include "service-constants.h"
+#include "dinit-client.h"
 
 // shutdown:  shut down the system
 // This utility communicates with the dinit daemon via a unix socket (/dev/initctl).
 void do_system_shutdown(shutdown_type_t shutdown_type);
 static void unmount_disks();
 static void swap_off();
-static void wait_for_reply(cpbuffer<1024> &rbuffer, int fd);
-
-
-class ReadCPException
-{
-    public:
-    int errcode;
-    ReadCPException(int err) : errcode(err) { }
-};
 
 
 int main(int argc, char **argv)
@@ -148,8 +140,7 @@ int main(int argc, char **argv)
     
     cout << "Issuing shutdown command..." << endl;
     
-    // TODO make sure to write the whole buffer
-    int r = write(socknum, buf, bufsize);
+    int r = write_all(socknum, buf, bufsize);
     if (r == -1) {
         perror("write");
         return 1;
@@ -170,7 +161,7 @@ int main(int argc, char **argv)
             return 1;
         }
     }
-    catch (ReadCPException &exc)
+    catch (read_cp_exception &exc)
     {
         cerr << "shutdown: control socket read failure or protocol error" << endl;    
         return 1;
@@ -183,47 +174,6 @@ int main(int argc, char **argv)
     return 0;
 }
 
-// Fill a circular buffer from a file descriptor, reading at least _rlength_ bytes.
-// Throws ReadException if the requested number of bytes cannot be read, with:
-//     errcode = 0   if end of stream (remote end closed)
-//     errcode = errno   if another error occurred
-// Note that EINTR is ignored (i.e. the read will be re-tried).
-static void fillBufferTo(cpbuffer<1024> *buf, int fd, int rlength)
-{
-    do {
-        int r = buf->fill_to(fd, rlength);
-        if (r == -1) {
-            if (errno != EINTR) {
-                throw ReadCPException(errno);
-            }
-        }
-        else if (r == 0) {
-            throw ReadCPException(0);
-        }
-        else {
-            return;
-        }
-    }
-    while (true);
-}
-
-// Wait for a reply packet, skipping over any information packets
-// that are received in the meantime.
-static void wait_for_reply(cpbuffer<1024> &rbuffer, int fd)
-{
-    fillBufferTo(&rbuffer, fd, 1);
-    
-    while (rbuffer[0] >= 100) {
-        // Information packet; discard.
-        fillBufferTo(&rbuffer, fd, 2);
-        int pktlen = (unsigned char) rbuffer[1];
-        
-        rbuffer.consume(1);  // Consume one byte so we'll read one byte of the next packet
-        fillBufferTo(&rbuffer, fd, pktlen);
-        rbuffer.consume(pktlen - 1);
-    }
-}
-
 // Actually shut down the system.
 void do_system_shutdown(shutdown_type_t shutdown_type)
 {