service_state_t wanted_state = do_stop ? service_state_t::STOPPED : service_state_t::STARTED;
int pcommand = 0;
switch (command) {
- case command_t::STOP_SERVICE:
- pcommand = DINIT_CP_STOPSERVICE;
- break;
- case command_t::RELEASE_SERVICE:
- pcommand = DINIT_CP_RELEASESERVICE;
- break;
- case command_t::START_SERVICE:
- pcommand = DINIT_CP_STARTSERVICE;
- break;
- case command_t::WAKE_SERVICE:
- pcommand = DINIT_CP_WAKESERVICE;
- break;
- default: ;
+ case command_t::STOP_SERVICE:
+ pcommand = DINIT_CP_STOPSERVICE;
+ break;
+ case command_t::RELEASE_SERVICE:
+ pcommand = DINIT_CP_RELEASESERVICE;
+ break;
+ case command_t::START_SERVICE:
+ pcommand = DINIT_CP_STARTSERVICE;
+ break;
+ case command_t::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.
{
- int r;
-
- {
- auto buf = new char[2 + sizeof(handle)];
- unique_ptr<char[]> ubuf(buf);
-
- buf[0] = pcommand;
- buf[1] = do_pin ? 1 : 0;
- memcpy(buf + 2, &handle, sizeof(handle));
- r = write_all(socknum, buf, 2 + sizeof(handle));
- }
-
- if (r == -1) {
- perror("dinitctl: write");
- return 1;
- }
+ char buf[2 + sizeof(handle)];
+ buf[0] = pcommand;
+ buf[1] = do_pin ? 1 : 0;
+ memcpy(buf + 2, &handle, sizeof(handle));
+ write_all_x(socknum, buf, 2 + sizeof(handle));
wait_for_reply(rbuffer, socknum);
if (rbuffer[0] == DINIT_RP_ALREADYSS) {
// Build buffer;
uint16_t sname_len = strlen(service_name);
int bufsize = 3 + sname_len;
- int r;
- try {
- std::unique_ptr<char[]> ubuf(new char[bufsize]);
- auto buf = ubuf.get();
-
- buf[0] = find_only ? DINIT_CP_FINDSERVICE : DINIT_CP_LOADSERVICE;
- memcpy(buf + 1, &sname_len, 2);
- memcpy(buf + 3, service_name, sname_len);
-
- r = write_all(socknum, buf, bufsize);
- }
- catch (std::bad_alloc &badalloc) {
- std::cerr << "dinitctl: " << badalloc.what() << std::endl;
- return 1;
- }
-
- if (r == -1) {
- perror("dinitctl: write");
- return 1;
- }
+ std::unique_ptr<char[]> ubuf(new char[bufsize]);
+ auto buf = ubuf.get();
+
+ buf[0] = find_only ? DINIT_CP_FINDSERVICE : DINIT_CP_LOADSERVICE;
+ memcpy(buf + 1, &sname_len, 2);
+ memcpy(buf + 3, service_name, sname_len);
+
+ write_all_x(socknum, buf, bufsize);
return 0;
}
// Issue UNPIN command.
{
- int r;
-
- {
- char *buf = new char[1 + sizeof(handle)];
- unique_ptr<char[]> ubuf(buf);
- buf[0] = DINIT_CP_UNPINSERVICE;
- memcpy(buf + 1, &handle, sizeof(handle));
- r = write_all(socknum, buf, 2 + sizeof(handle));
- }
-
- if (r == -1) {
- perror("dinitctl: write");
- return 1;
- }
+ char buf[1 + sizeof(handle)];
+ buf[0] = DINIT_CP_UNPINSERVICE;
+ memcpy(buf + 1, &handle, sizeof(handle));
+ write_all_x(socknum, buf, 2 + sizeof(handle));
wait_for_reply(rbuffer, socknum);
if (rbuffer[0] != DINIT_RP_ACK) {
// Issue UNLOAD command.
{
- int r;
-
- {
- char *buf = new char[1 + sizeof(handle)];
- unique_ptr<char[]> ubuf(buf);
- buf[0] = DINIT_CP_UNLOADSERVICE;
- memcpy(buf + 1, &handle, sizeof(handle));
- r = write_all(socknum, buf, 2 + sizeof(handle));
- }
-
- if (r == -1) {
- perror("dinitctl: write");
- return 1;
- }
+ char buf[1 + sizeof(handle)];
+ buf[0] = DINIT_CP_UNLOADSERVICE;
+ memcpy(buf + 1, &handle, sizeof(handle));
+ write_all_x(socknum, buf, 2 + sizeof(handle));
wait_for_reply(rbuffer, socknum);
if (rbuffer[0] == DINIT_RP_NAK) {
using namespace std;
char cmdbuf[] = { (char)DINIT_CP_LISTSERVICES };
- int r = write_all(socknum, cmdbuf, 1);
-
- if (r == -1) {
- perror("dinitctl: write");
- return 1;
- }
+ write_all_x(socknum, cmdbuf, 1);
wait_for_reply(rbuffer, socknum);
while (rbuffer[0] == DINIT_RP_SVCINFO) {
buf[0] = DINIT_CP_SHUTDOWN;
buf[1] = static_cast<char>(shutdown_type_t::HALT);
- int r = write_all(socknum, buf, bufsize);
- if (r == -1) {
- perror("write");
- return 1;
- }
+ write_all_x(socknum, buf, bufsize);
wait_for_reply(rbuffer, socknum);
return w;
}
+// Write all the requested buffer, and throw an exception on failure.
+inline void write_all_x(int fd, const void *buf, size_t count)
+{
+ if (write_all(fd, buf, count) == -1) {
+ throw cp_write_exception(errno);
+ }
+}
+
// Check the protocol version is compatible with the client.
// minverison - minimum protocol version that client can speak
// version - maximum protocol version that client can speak
// rbuffer, fd - communication buffer and socket
// returns: the actual protocol version
// throws an exception on protocol mismatch or error.
-uint16_t check_protocol_version(int minversion, int version, cpbuffer_t &rbuffer, int fd)
+inline uint16_t check_protocol_version(int minversion, int version, cpbuffer_t &rbuffer, int fd)
{
constexpr int bufsize = 1;
char buf[bufsize] = { DINIT_CP_QUERYVERSION };
- int r = write_all(fd, buf, bufsize);
- if (r == -1) {
- throw cp_write_exception(errno);
- }
+ write_all_x(fd, buf, bufsize);
wait_for_reply(rbuffer, fd);
if (rbuffer[0] != DINIT_RP_CPVERSION) {
}
}
- // Build buffer;
- constexpr int bufsize = 2;
- char buf[bufsize];
-
- buf[0] = DINIT_CP_SHUTDOWN;
- buf[1] = static_cast<char>(shutdown_type);
-
- cout << "Issuing shutdown command..." << endl;
-
- int r = write_all(socknum, buf, bufsize);
- if (r == -1) {
- perror("write");
- return 1;
- }
+ try {
+ cpbuffer_t rbuffer;
- // Wait for ACK/NACK
- // r = read(socknum, buf, 1);
- //if (r > 0) {
- // cout << "Received acknowledgement. System should now shut down." << endl;
- //}
+ check_protocol_version(0, 0, rbuffer, socknum);
+
+ // Build buffer;
+ constexpr int bufsize = 2;
+ char buf[bufsize];
+
+ buf[0] = DINIT_CP_SHUTDOWN;
+ buf[1] = static_cast<char>(shutdown_type);
+
+ cout << "Issuing shutdown command..." << endl;
+
+ write_all_x(socknum, buf, bufsize);
+
+ // Wait for ACK/NACK
- cpbuffer<1024> rbuffer;
- try {
wait_for_reply(rbuffer, socknum);
if (rbuffer[0] != DINIT_RP_ACK) {
return 1;
}
}
- catch (cp_read_exception &exc)
- {
- cerr << "shutdown: control socket read failure or protocol error" << endl;
+ catch (cp_old_client_exception &e) {
+ std::cerr << "shutdown: too old (server reports newer protocol version)" << std::endl;
+ return 1;
+ }
+ catch (cp_old_server_exception &e) {
+ std::cerr << "shutdown: server too old or protocol error" << std::endl;
+ return 1;
+ }
+ catch (cp_read_exception &e) {
+ cerr << "shutdown: control socket read failure or protocol error" << endl;
+ return 1;
+ }
+ catch (cp_write_exception &e) {
+ cerr << "shutdown: control socket write error: " << std::strerror(e.errcode) << endl;
return 1;
}