// File: davmac314[P]dinit/src/dinitctl.cc
// Function: list_services(int, cpbuffer<1024u>&, unsigned short)
static int list_services(int socknum, cpbuffer_t &rbuffer, uint16_t proto_version)
{
    using namespace std;
    
    char cmdbuf[] = { (char)cp_cmd::LISTSERVICES };
    if (proto_version >= 5) {
        cmdbuf[0] = (char)cp_cmd::LISTSERVICES5;
    }
    write_all_x(socknum, cmdbuf, 1);

    unsigned status_buffer_size = proto_version < 5 ? STATUS_BUFFER_SIZE : STATUS_BUFFER5_SIZE;

    wait_for_reply(rbuffer, socknum);
    while (rbuffer[0] == (char)cp_rply::SVCINFO) {
        // Packet: SVCINFO (1), name length (1), status buffer (STATUS_BUFFER_SIZE), name (N)
        int hdrsize = 2 + status_buffer_size;
        fill_buffer_to(rbuffer, socknum, hdrsize);
        unsigned name_len = (unsigned char)rbuffer[1];
        service_state_t current = static_cast<service_state_t>(rbuffer[2]);
        service_state_t target = static_cast<service_state_t>(rbuffer[3]);

        int console_flags = rbuffer[4];
        bool has_console = (console_flags & 2) != 0;
        bool waiting_console = (console_flags & 1) != 0;
        bool was_skipped = (console_flags & 4) != 0;
        bool marked_active = (console_flags & 8) != 0;
        bool has_pid = (console_flags & 16) != 0;

        stopped_reason_t stop_reason = static_cast<stopped_reason_t>(rbuffer[5]);

        pid_t service_pid;
        int exit_status;
        int exit_si_code;
        int exit_si_status;
        if (has_pid) {
            // 8 = SVCINFO (1) + name length (1)
            //                 + current state (1) + target state (1) + flags (1)
            //                 + stop reason (1) + exec failure stage (2)
            rbuffer.extract((char *)&service_pid, 8, sizeof(service_pid));
        }
        else {
            if (proto_version < 5) {
                rbuffer.extract((char *)&exit_status, 8, sizeof(exit_status));
            }
            else {
                rbuffer.extract((char *)&exit_si_code, 8, sizeof(exit_si_code));
                rbuffer.extract((char *)&exit_si_status, 8 + sizeof(exit_si_code), sizeof(exit_si_status));
            }
        }

        fill_buffer_to(rbuffer, socknum, name_len + hdrsize);

        char *name_ptr = rbuffer.get_ptr(hdrsize);
        unsigned clength = std::min(rbuffer.get_contiguous_length(name_ptr), name_len);

        string name = string(name_ptr, clength);
        name.append(rbuffer.get_buf_base(), name_len - clength);

        cout << "[";

        // [ ] if marked active; otherwise, { } if target state is STARTED
        //  +  if started, 's' if skipped, space otherwise
        char lbracket = target == service_state_t::STARTED ? '{' : ' ';
        char rbracket = target == service_state_t::STARTED ? '}' : ' ';
        cout << (marked_active ? '[' : lbracket);
        if (current == service_state_t::STARTED) {
            cout << (was_skipped ? 's' : '+');
        }
        else {
            cout << ' ';
        }
        cout << (marked_active ? ']' : rbracket);
        
        if (current == service_state_t::STARTING) {
            cout << "<<";
        }
        else if (current == service_state_t::STOPPING) {
            cout << ">>";
        }
        else {
            cout << "  ";
        }
        
        cout << (target == service_state_t::STOPPED ? '{' : ' ');
        if (current == service_state_t::STOPPED) {
            bool did_fail = false;
            if (stop_reason == stopped_reason_t::TERMINATED) {
                if (proto_version < 5) {
                    if (!WIFEXITED(exit_status) || WEXITSTATUS(exit_status) != 0) {
                        did_fail = true;
                    }
                }
                else {
                    did_fail = (exit_si_code != CLD_EXITED) || (exit_si_status != 0);
                }
            }
            else {
                did_fail = (stop_reason != stopped_reason_t::NORMAL);
            }

            cout << (did_fail ? 'X' : '-');
        }
        else {
            cout << ' ';
        }
        cout << (target == service_state_t::STOPPED ? '}' : ' ');

        cout << "] " << name;

        if (current != service_state_t::STOPPED && has_pid) {
            cout << " (pid: " << service_pid << ")";
        }
        
        if (current == service_state_t::STOPPED && stop_reason == stopped_reason_t::TERMINATED) {
            if (proto_version < 5) {
                if (WIFEXITED(exit_status)) {
                    cout << " (exit status: " << WEXITSTATUS(exit_status) << ")";
                }
                else if (WIFSIGNALED(exit_status)) {
                    cout << " (signal: " << WTERMSIG(exit_status) << ")";
                }
            }
            else {
                if (exit_si_code == CLD_EXITED) {
                    cout << " (exit status: " << exit_si_status << ")";
                }
                else if (exit_si_code == CLD_KILLED) {
                    cout << " (signal: " << exit_si_status << ")";
                }
            }
        }

        if (has_console) {
            cout << " (has console)";
        }
        else if (waiting_console) {
            cout << " (waiting for console)";
        }

        cout << endl;

        rbuffer.consume(hdrsize + name_len);
        wait_for_reply(rbuffer, socknum);
    }

    if (rbuffer[0] != (char)cp_rply::LISTDONE) {
        cerr << "dinitctl: control socket protocol error" << endl;
        return 1;
    }

    return 0;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x110, %rsp            # imm = 0x110
movw %dx, %ax
movl %edi, -0x8(%rbp)
movq %rsi, -0x10(%rbp)
movw %ax, -0x12(%rbp)
movb 0x193cd(%rip), %al      # 0x2307c
movb %al, -0x13(%rbp)
movzwl -0x12(%rbp), %eax
cmpl $0x5, %eax
jl 0x9cbf
movb $0x19, -0x13(%rbp)
movl -0x8(%rbp), %edi
leaq -0x13(%rbp), %rsi
movl $0x1, %edx
callq 0x112c0
movzwl -0x12(%rbp), %edx
movl $0xe, %eax
movl $0xa, %ecx
cmpl $0x5, %edx
cmovll %ecx, %eax
movl %eax, -0x18(%rbp)
movq -0x10(%rbp), %rdi
movl -0x8(%rbp), %esi
callq 0x11350
movq -0x10(%rbp), %rdi
xorl %esi, %esi
callq 0x113e0
movsbl %al, %eax
cmpl $0x3e, %eax
jne 0xa436
movl -0x18(%rbp), %eax
addl $0x2, %eax
movl %eax, -0x1c(%rbp)
movq -0x10(%rbp), %rdi
movl -0x8(%rbp), %esi
movl -0x1c(%rbp), %edx
callq 0x11440
movq -0x10(%rbp), %rdi
movl $0x1, %esi
callq 0x113e0
movzbl %al, %eax
movl %eax, -0x20(%rbp)
movq -0x10(%rbp), %rdi
movl $0x2, %esi
callq 0x113e0
movb %al, -0x21(%rbp)
movq -0x10(%rbp), %rdi
movl $0x3, %esi
callq 0x113e0
movb %al, -0x22(%rbp)
movq -0x10(%rbp), %rdi
movl $0x4, %esi
callq 0x113e0
movsbl %al, %eax
movl %eax, -0x28(%rbp)
movl -0x28(%rbp), %eax
andl $0x2, %eax
cmpl $0x0, %eax
setne %al
andb $0x1, %al
movb %al, -0x29(%rbp)
movl -0x28(%rbp), %eax
andl $0x1, %eax
cmpl $0x0, %eax
setne %al
andb $0x1, %al
movb %al, -0x2a(%rbp)
movl -0x28(%rbp), %eax
andl $0x4, %eax
cmpl $0x0, %eax
setne %al
andb $0x1, %al
movb %al, -0x2b(%rbp)
movl -0x28(%rbp), %eax
andl $0x8, %eax
cmpl $0x0, %eax
setne %al
andb $0x1, %al
movb %al, -0x2c(%rbp)
movl -0x28(%rbp), %eax
andl $0x10, %eax
cmpl $0x0, %eax
setne %al
andb $0x1, %al
movb %al, -0x2d(%rbp)
movq -0x10(%rbp), %rdi
movl $0x5, %esi
callq 0x113e0
movsbl %al, %eax
movl %eax, -0x34(%rbp)
testb $0x1, -0x2d(%rbp)
je 0x9df4
movq -0x10(%rbp), %rdi
leaq -0x38(%rbp), %rsi
movl $0x8, %edx
movl $0x4, %ecx
callq 0x11540
jmp 0x9e46
movzwl -0x12(%rbp), %eax
cmpl $0x5, %eax
jge 0x9e16
movq -0x10(%rbp), %rdi
leaq -0x3c(%rbp), %rsi
movl $0x8, %edx
movl $0x4, %ecx
callq 0x11540
jmp 0x9e44
movq -0x10(%rbp), %rdi
leaq -0x40(%rbp), %rsi
movl $0x8, %edx
movl $0x4, %ecx
callq 0x11540
movq -0x10(%rbp), %rdi
leaq -0x44(%rbp), %rsi
movl $0xc, %edx
movl $0x4, %ecx
callq 0x11540
jmp 0x9e46
movq -0x10(%rbp), %rdi
movl -0x8(%rbp), %esi
movl -0x20(%rbp), %edx
movl -0x1c(%rbp), %eax
addl %eax, %edx
callq 0x11440
movq -0x10(%rbp), %rdi
movl -0x1c(%rbp), %esi
callq 0x130a0
movq %rax, -0x50(%rbp)
movq -0x10(%rbp), %rdi
movq -0x50(%rbp), %rsi
callq 0x13010
movl %eax, -0x58(%rbp)
leaq -0x58(%rbp), %rdi
leaq -0x20(%rbp), %rsi
callq 0x11840
movl (%rax), %eax
movl %eax, -0x54(%rbp)
movq -0x50(%rbp), %rax
movq %rax, -0xa8(%rbp)
movl -0x54(%rbp), %eax
movq %rax, -0xa0(%rbp)
leaq -0x79(%rbp), %rdi
movq %rdi, -0x98(%rbp)
callq 0x5700
movq -0xa8(%rbp), %rsi
movq -0xa0(%rbp), %rdx
movq -0x98(%rbp), %rcx
leaq -0x78(%rbp), %rdi
callq 0x5480
jmp 0x9ed1
leaq -0x79(%rbp), %rdi
callq 0x5440
movq -0x10(%rbp), %rdi
callq 0x132b0
movq %rax, -0xb0(%rbp)
jmp 0x9eec
movq -0xb0(%rbp), %rsi
movl -0x20(%rbp), %eax
movl -0x54(%rbp), %ecx
subl %ecx, %eax
movl %eax, %edx
leaq -0x78(%rbp), %rdi
callq 0x5080
jmp 0x9f08
movq 0x28089(%rip), %rdi     # 0x31f98
leaq 0x1a79c(%rip), %rsi     # 0x246b2
callq 0x53d0
jmp 0x9f1d
movb -0x22(%rbp), %cl
movb $0x7b, %al
movb $0x20, %dl
movb %dl, -0xb2(%rbp)
cmpb $0x2, %cl
movb %al, -0xb1(%rbp)
je 0x9f41
movb -0xb2(%rbp), %al
movb %al, -0xb1(%rbp)
movb -0xb1(%rbp), %al
movb %al, -0x8d(%rbp)
movb -0x22(%rbp), %cl
movb $0x7d, %al
movb $0x20, %dl
movb %dl, -0xb4(%rbp)
cmpb $0x2, %cl
movb %al, -0xb3(%rbp)
je 0x9f71
movb -0xb4(%rbp), %al
movb %al, -0xb3(%rbp)
movb -0xb3(%rbp), %al
movb %al, -0x8e(%rbp)
testb $0x1, -0x2c(%rbp)
je 0x9f8d
movb $0x5b, %al
movb %al, -0xb5(%rbp)
jmp 0x9f99
movb -0x8d(%rbp), %al
movb %al, -0xb5(%rbp)
movb -0xb5(%rbp), %al
movsbl %al, %esi
movq 0x27fef(%rip), %rdi     # 0x31f98
callq 0x54a0
jmp 0x9fb0
cmpb $0x2, -0x21(%rbp)
jne 0xa018
movb -0x2b(%rbp), %al
testb $0x1, %al
movl $0x73, %eax
movl $0x2b, %esi
cmovnel %eax, %esi
movq 0x27fc9(%rip), %rdi     # 0x31f98
callq 0x54a0
jmp 0x9fd6
jmp 0xa02d
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x88(%rbp)
movl %eax, -0x8c(%rbp)
leaq -0x79(%rbp), %rdi
callq 0x5440
jmp 0xa487
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x88(%rbp)
movl %eax, -0x8c(%rbp)
leaq -0x78(%rbp), %rdi
callq 0x5280
jmp 0xa487
movq 0x27f79(%rip), %rdi     # 0x31f98
movl $0x20, %esi
callq 0x54a0
jmp 0xa02b
jmp 0xa02d
testb $0x1, -0x2c(%rbp)
je 0xa03d
movb $0x5d, %al
movb %al, -0xb6(%rbp)
jmp 0xa049
movb -0x8e(%rbp), %al
movb %al, -0xb6(%rbp)
movb -0xb6(%rbp), %al
movsbl %al, %esi
movq 0x27f3f(%rip), %rdi     # 0x31f98
callq 0x54a0
jmp 0xa060
cmpb $0x1, -0x21(%rbp)
jne 0xa07d
movq 0x27f2b(%rip), %rdi     # 0x31f98
leaq 0x1a640(%rip), %rsi     # 0x246b4
callq 0x53d0
jmp 0xa07b
jmp 0xa0b3
cmpb $0x3, -0x21(%rbp)
jne 0xa09a
movq 0x27f0e(%rip), %rdi     # 0x31f98
leaq 0x1a626(%rip), %rsi     # 0x246b7
callq 0x53d0
jmp 0xa098
jmp 0xa0b1
movq 0x27ef7(%rip), %rdi     # 0x31f98
leaq 0x1a612(%rip), %rsi     # 0x246ba
callq 0x53d0
jmp 0xa0af
jmp 0xa0b1
jmp 0xa0b3
movb -0x22(%rbp), %al
testb %al, %al
movl $0x7b, %eax
movl $0x20, %esi
cmovel %eax, %esi
movq 0x27ecc(%rip), %rdi     # 0x31f98
callq 0x54a0
jmp 0xa0d3
cmpb $0x0, -0x21(%rbp)
jne 0xa176
movb $0x0, -0x8f(%rbp)
cmpl $0x6, -0x34(%rbp)
jne 0xa142
movzwl -0x12(%rbp), %eax
cmpl $0x5, %eax
jge 0xa117
movl -0x3c(%rbp), %eax
andl $0x7f, %eax
cmpl $0x0, %eax
jne 0xa10e
movl -0x3c(%rbp), %eax
andl $0xff00, %eax           # imm = 0xFF00
sarl $0x8, %eax
cmpl $0x0, %eax
je 0xa115
movb $0x1, -0x8f(%rbp)
jmp 0xa140
movb $0x1, %al
cmpl $0x1, -0x40(%rbp)
movb %al, -0xb7(%rbp)
jne 0xa132
cmpl $0x0, -0x44(%rbp)
setne %al
movb %al, -0xb7(%rbp)
movb -0xb7(%rbp), %al
andb $0x1, %al
movb %al, -0x8f(%rbp)
jmp 0xa151
cmpl $0x0, -0x34(%rbp)
setne %al
andb $0x1, %al
movb %al, -0x8f(%rbp)
movb -0x8f(%rbp), %al
testb $0x1, %al
movl $0x58, %eax
movl $0x2d, %esi
cmovnel %eax, %esi
movq 0x27e2b(%rip), %rdi     # 0x31f98
callq 0x54a0
jmp 0xa174
jmp 0xa18b
movq 0x27e1b(%rip), %rdi     # 0x31f98
movl $0x20, %esi
callq 0x54a0
jmp 0xa189
jmp 0xa18b
movb -0x22(%rbp), %al
testb %al, %al
movl $0x7d, %eax
movl $0x20, %esi
cmovel %eax, %esi
movq 0x27df4(%rip), %rdi     # 0x31f98
callq 0x54a0
jmp 0xa1ab
movq 0x27de6(%rip), %rdi     # 0x31f98
leaq 0x1a504(%rip), %rsi     # 0x246bd
callq 0x53d0
movq %rax, -0xc0(%rbp)
jmp 0xa1c7
movq -0xc0(%rbp), %rdi
leaq -0x78(%rbp), %rsi
callq 0x53a0
jmp 0xa1d9
cmpb $0x0, -0x21(%rbp)
je 0xa230
testb $0x1, -0x2d(%rbp)
je 0xa230
movq 0x27dac(%rip), %rdi     # 0x31f98
leaq 0x1a4cd(%rip), %rsi     # 0x246c0
callq 0x53d0
movq %rax, -0xc8(%rbp)
jmp 0xa201
movq -0xc8(%rbp), %rdi
movl -0x38(%rbp), %esi
callq 0x56d0
movq %rax, -0xd0(%rbp)
jmp 0xa219
movq -0xd0(%rbp), %rdi
leaq 0x1abf0(%rip), %rsi     # 0x24e17
callq 0x53d0
jmp 0xa22e
jmp 0xa230
cmpb $0x0, -0x21(%rbp)
jne 0xa3b8
cmpl $0x6, -0x34(%rbp)
jne 0xa3b8
movzwl -0x12(%rbp), %eax
cmpl $0x5, %eax
jge 0xa310
movl -0x3c(%rbp), %eax
andl $0x7f, %eax
cmpl $0x0, %eax
jne 0xa2a8
movq 0x27d35(%rip), %rdi     # 0x31f98
leaq 0x1a45e(%rip), %rsi     # 0x246c8
callq 0x53d0
movq %rax, -0xd8(%rbp)
jmp 0xa278
movq -0xd8(%rbp), %rdi
movzbl -0x3b(%rbp), %esi
callq 0x56d0
movq %rax, -0xe0(%rbp)
jmp 0xa291
movq -0xe0(%rbp), %rdi
leaq 0x1ab78(%rip), %rsi     # 0x24e17
callq 0x53d0
jmp 0xa2a6
jmp 0xa30b
movl -0x3c(%rbp), %eax
andl $0x7f, %eax
addl $0x1, %eax
movsbl %al, %eax
sarl %eax
cmpl $0x0, %eax
jle 0xa309
movq 0x27cd6(%rip), %rdi     # 0x31f98
leaq 0x1a40f(%rip), %rsi     # 0x246d8
callq 0x53d0
movq %rax, -0xe8(%rbp)
jmp 0xa2d7
movq -0xe8(%rbp), %rdi
movl -0x3c(%rbp), %esi
andl $0x7f, %esi
callq 0x56d0
movq %rax, -0xf0(%rbp)
jmp 0xa2f2
movq -0xf0(%rbp), %rdi
leaq 0x1ab17(%rip), %rsi     # 0x24e17
callq 0x53d0
jmp 0xa307
jmp 0xa309
jmp 0xa30b
jmp 0xa3b6
cmpl $0x1, -0x40(%rbp)
jne 0xa361
movq 0x27c7b(%rip), %rdi     # 0x31f98
leaq 0x1a3a4(%rip), %rsi     # 0x246c8
callq 0x53d0
movq %rax, -0xf8(%rbp)
jmp 0xa332
movq -0xf8(%rbp), %rdi
movl -0x44(%rbp), %esi
callq 0x56d0
movq %rax, -0x100(%rbp)
jmp 0xa34a
movq -0x100(%rbp), %rdi
leaq 0x1aabf(%rip), %rsi     # 0x24e17
callq 0x53d0
jmp 0xa35f
jmp 0xa3b4
cmpl $0x2, -0x40(%rbp)
jne 0xa3b2
movq 0x27c2a(%rip), %rdi     # 0x31f98
leaq 0x1a363(%rip), %rsi     # 0x246d8
callq 0x53d0
movq %rax, -0x108(%rbp)
jmp 0xa383
movq -0x108(%rbp), %rdi
movl -0x44(%rbp), %esi
callq 0x56d0
movq %rax, -0x110(%rbp)
jmp 0xa39b
movq -0x110(%rbp), %rdi
leaq 0x1aa6e(%rip), %rsi     # 0x24e17
callq 0x53d0
jmp 0xa3b0
jmp 0xa3b2
jmp 0xa3b4
jmp 0xa3b6
jmp 0xa3b8
testb $0x1, -0x29(%rbp)
je 0xa3d5
movq 0x27bd3(%rip), %rdi     # 0x31f98
leaq 0x1a317(%rip), %rsi     # 0x246e3
callq 0x53d0
jmp 0xa3d3
jmp 0xa3f4
testb $0x1, -0x2a(%rbp)
je 0xa3f2
movq 0x27bb6(%rip), %rdi     # 0x31f98
leaq 0x1a309(%rip), %rsi     # 0x246f2
callq 0x53d0
jmp 0xa3f0
jmp 0xa3f2
jmp 0xa3f4
movq 0x27b9d(%rip), %rdi     # 0x31f98
movq 0x27b66(%rip), %rsi     # 0x31f68
callq 0x5410
jmp 0xa409
movq -0x10(%rbp), %rdi
movl -0x1c(%rbp), %esi
movl -0x20(%rbp), %eax
addl %eax, %esi
callq 0x115f0
movq -0x10(%rbp), %rdi
movl -0x8(%rbp), %esi
callq 0x11350
jmp 0xa428
leaq -0x78(%rbp), %rdi
callq 0x5280
jmp 0x9cf3
movq -0x10(%rbp), %rdi
xorl %esi, %esi
callq 0x113e0
movsbl %al, %eax
cmpl $0x3f, %eax
je 0xa474
movq 0x27b98(%rip), %rdi     # 0x31fe8
leaq 0x1a2b2(%rip), %rsi     # 0x24709
callq 0x53d0
movq %rax, %rdi
movq 0x27b02(%rip), %rsi     # 0x31f68
callq 0x5410
movl $0x1, -0x4(%rbp)
jmp 0xa47b
movl $0x0, -0x4(%rbp)
movl -0x4(%rbp), %eax
addq $0x110, %rsp            # imm = 0x110
popq %rbp
retq
movq -0x88(%rbp), %rdi
callq 0x56f0
nopw %cs:(%rax,%rax)