+
+// Issue a "load service" command (DINIT_CP_LOADSERVICE), without waiting for
+// a response. Returns 1 on failure (with error logged), 0 on success.
+static int issueLoadService(int socknum, const char *service_name)
+{
+ using namespace std;
+
+ // Build buffer;
+ uint16_t sname_len = strlen(service_name);
+ int bufsize = 3 + sname_len;
+ int r;
+
+ {
+ // TODO: new: catch exception
+ unique_ptr<char[]> ubuf(new char[bufsize]);
+ auto buf = ubuf.get();
+
+ buf[0] = DINIT_CP_LOADSERVICE;
+ memcpy(buf + 1, &sname_len, 2);
+ memcpy(buf + 3, service_name, sname_len);
+
+ r = write_all(socknum, buf, bufsize);
+ }
+
+ if (r == -1) {
+ perror("dinitctl: write");
+ return 1;
+ }
+
+ return 0;
+}
+
+// Check that a "load service" reply was received, and that the requested service was found.
+static int checkLoadReply(int socknum, CPBuffer<1024> &rbuffer, handle_t *handle_p, ServiceState *state_p)
+{
+ using namespace std;
+
+ if (rbuffer[0] == DINIT_RP_SERVICERECORD) {
+ fillBufferTo(&rbuffer, socknum, 2 + sizeof(*handle_p));
+ rbuffer.extract((char *) handle_p, 2, sizeof(*handle_p));
+ if (state_p) *state_p = static_cast<ServiceState>(rbuffer[1]);
+ //target_state = static_cast<ServiceState>(rbuffer[2 + sizeof(handle)]);
+ rbuffer.consume(3 + sizeof(*handle_p));
+ return 0;
+ }
+ else if (rbuffer[0] == DINIT_RP_NOSERVICE) {
+ cerr << "dinitctl: Failed to find/load service." << endl;
+ return 1;
+ }
+ else {
+ cerr << "dinitctl: Protocol error." << endl;
+ return 1;
+ }
+}
+
+static int unpinService(int socknum, const char *service_name, bool verbose)
+{
+ using namespace std;
+
+ // Build buffer;
+ if (issueLoadService(socknum, service_name) == 1) {
+ return 1;
+ }
+
+ // Now we expect a reply:
+
+ try {
+ CPBuffer<1024> rbuffer;
+ wait_for_reply(rbuffer, socknum);
+
+ handle_t handle;
+
+ if (checkLoadReply(socknum, rbuffer, &handle, nullptr) != 0) {
+ return 1;
+ }
+
+ // 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;
+ }
+
+ wait_for_reply(rbuffer, socknum);
+ if (rbuffer[0] != DINIT_RP_ACK) {
+ cerr << "dinitctl: Protocol error." << endl;
+ return 1;
+ }
+ rbuffer.consume(1);
+ }
+ }
+ catch (ReadCPException &exc) {
+ cerr << "dinitctl: Control socket read failure or protocol error" << endl;
+ return 1;
+ }
+ catch (std::bad_alloc &exc) {
+ cerr << "dinitctl: Out of memory" << endl;
+ return 1;
+ }
+
+ if (verbose) {
+ cout << "Service unpinned." << endl;
+ }
+ return 0;
+}