From 5360d84c8ce2fabd38644bc2a5a3423d133ac10d Mon Sep 17 00:00:00 2001 From: Davin McCall Date: Mon, 5 Feb 2018 10:58:44 +0000 Subject: [PATCH] Factor out some Dinit client functions tp a new header (dinit-client.h). --- src/dinitctl.cc | 100 +++--------------------------------- src/includes/dinit-client.h | 85 ++++++++++++++++++++++++++++++ src/shutdown.cc | 56 ++------------------ 3 files changed, 94 insertions(+), 147 deletions(-) create mode 100644 src/includes/dinit-client.h diff --git a/src/dinitctl.cc b/src/dinitctl.cc index 983f123..e224932 100644 --- a/src/dinitctl.cc +++ b/src/dinitctl.cc @@ -16,20 +16,12 @@ #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(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(rbuffer[1]); //target_state = static_cast(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(rbuffer[2]); service_state_t target = static_cast(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(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 index 0000000..34963cf --- /dev/null +++ b/src/includes/dinit-client.h @@ -0,0 +1,85 @@ +#include + +// 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(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; +} diff --git a/src/shutdown.cc b/src/shutdown.cc index c751fd0..3f1a131 100644 --- a/src/shutdown.cc +++ b/src/shutdown.cc @@ -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). @@ -24,15 +25,6 @@ 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) { -- 2.25.1