From 8e371537a29838112801f891db10211ef1014acc Mon Sep 17 00:00:00 2001 From: Davin McCall Date: Sat, 27 Jul 2019 10:16:53 +1000 Subject: [PATCH] dinitctl: print names of dependents which are inhibiting stop --- src/dinitctl.cc | 73 ++++++++++++++++++++++++++++++++++++++++- src/includes/cpbuffer.h | 5 +++ 2 files changed, 77 insertions(+), 1 deletion(-) diff --git a/src/dinitctl.cc b/src/dinitctl.cc index ad488bc..af128ba 100644 --- a/src/dinitctl.cc +++ b/src/dinitctl.cc @@ -439,6 +439,55 @@ static bool load_service(int socknum, cpbuffer_t &rbuffer, const char *name, han return true; } +// Get the service name for a given handle, by querying the daemon. +static std::string get_service_name(int socknum, cpbuffer_t &rbuffer, handle_t handle) +{ + char buf[2 + sizeof(handle)]; + buf[0] = DINIT_CP_QUERYSERVICENAME; + buf[1] = 0; + memcpy(buf + 2, &handle, sizeof(handle)); + + write_all_x(socknum, buf, sizeof(buf)); + + wait_for_reply(rbuffer, socknum); + + if (rbuffer[0] != DINIT_RP_SERVICENAME) { + throw cp_read_exception{0}; + } + + // 1 byte reserved + // uint16_t size + fill_buffer_to(rbuffer, socknum, 2 + sizeof(uint16_t)); + uint16_t namesize; + rbuffer.extract(&namesize, 2, sizeof(uint16_t)); + rbuffer.consume(2 + sizeof(uint16_t)); + + std::string name; + + do { + if (rbuffer.get_length() == 0) { + rbuffer.fill(socknum); + } + + size_t to_extract = std::min(size_t(rbuffer.get_length()), namesize - name.length()); + size_t contiguous_len = rbuffer.get_contiguous_length(rbuffer.get_ptr(0)); + if (contiguous_len <= to_extract) { + name.append(rbuffer.get_ptr(0), contiguous_len); + rbuffer.consume(contiguous_len); + name.append(rbuffer.get_ptr(0), to_extract - contiguous_len); + rbuffer.consume(to_extract - contiguous_len); + } + else { + name.append(rbuffer.get_ptr(0), to_extract); + rbuffer.consume(to_extract); + break; + } + + } while (name.length() < namesize); + + return name; +} + // 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 do_force, bool wait_for_service, bool verbose) @@ -492,7 +541,29 @@ 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; + cerr << "dinitctl: Cannot stop service due to the following dependents:\n" + "(Only direct dependents are listed. Exercise caution before using '--force' !!)\n"; + // size_t number, N * handle_t handles + rbuffer.consume(1); // packet header + size_t number; + rbuffer.fill_to(socknum, sizeof(number)); + rbuffer.extract(&number, 0, sizeof(number)); + rbuffer.consume(sizeof(number)); + std::vector handles; + handles.reserve(number); + for (size_t i = 0; i < number; i++) { + handle_t handle; + rbuffer.fill_to(socknum, sizeof(handle_t)); + rbuffer.extract(&handle, 0, sizeof(handle)); + handles.push_back(handle); + rbuffer.consume(sizeof(handle)); + } + // Print the directly affected dependents: + cerr << " "; + for (handle_t handle : handles) { + cerr << " " << get_service_name(socknum, rbuffer, handle); + } + cerr << "\n"; return 1; } if (rbuffer[0] != DINIT_RP_ACK) { diff --git a/src/includes/cpbuffer.h b/src/includes/cpbuffer.h index 5273211..a9f14a0 100644 --- a/src/includes/cpbuffer.h +++ b/src/includes/cpbuffer.h @@ -15,6 +15,11 @@ template class cpbuffer int length = 0; // number of elements in the buffer public: + static constexpr int get_size() + { + return SIZE; + } + int get_length() noexcept { return length; -- 2.25.1