// File: davmac314[P]dinit/src/shutdown.cc
// Function: main
int main(int argc, char **argv)
{
    using namespace std;
    
    bool show_help = false;
    bool sys_shutdown = false;
    bool use_passed_cfd = false;
    
    auto shutdown_type = shutdown_type_t::POWEROFF;

    const char *execname = base_name(argv[0]);
    if (strcmp(execname, reboot_execname) == 0) {
        shutdown_type = shutdown_type_t::REBOOT;
    }
    else if (strcmp(execname, soft_reboot_execname) == 0) {
        shutdown_type = shutdown_type_t::SOFTREBOOT;
    }
        
    for (int i = 1; i < argc; i++) {
        if (argv[i][0] == '-') {
            if (strcmp(argv[i], "--help") == 0) {
                show_help = true;
                break;
            }
            
            if (strcmp(argv[i], "--system") == 0) {
                sys_shutdown = true;
            }
            else if (strcmp(argv[i], "-r") == 0) {
                shutdown_type = shutdown_type_t::REBOOT;
            }
            else if (strcmp(argv[i], "-h") == 0) {
                shutdown_type = shutdown_type_t::HALT;
            }
            else if (strcmp(argv[i], "-p") == 0) {
                shutdown_type = shutdown_type_t::POWEROFF;
            }
            else if (strcmp(argv[i], "-s") == 0) {
                shutdown_type = shutdown_type_t::SOFTREBOOT;
            }
            else if (strcmp(argv[i], "-k") == 0) {
                shutdown_type = shutdown_type_t::KEXEC;
            }
            else if (strcmp(argv[i], "--use-passed-cfd") == 0) {
                use_passed_cfd = true;
            }
            else {
                cerr << "Unrecognized command-line parameter: " << argv[i] << endl;
                return 1;
            }
        }
        else {
            // time argument? TODO
            show_help = true;
        }
    }

    if (show_help) {
        cout << execname << " :   shutdown the system\n"
                "  --help           : show this help\n"
                "  -r               : reboot\n"
                "  -s               : soft-reboot (restart dinit with same boot-time arguments)\n"
#if defined(RB_HALT_SYSTEM) || defined(RB_HALT)
                "  -h               : halt system\n"
#endif
#ifdef RB_POWER_OFF
                "  -p               : power down (default)\n"
#endif
#ifdef RB_KEXEC
                "  -k               : stop dinit and reboot directly into kernel loaded with kexec\n"
#endif
                "  --use-passed-cfd : use the socket file descriptor identified by the DINIT_CS_FD\n"
                "                     environment variable to communicate with the init daemon.\n"
                "  --system         : perform shutdown immediately, instead of issuing shutdown\n"
                "                     command to the init program. Not recommended for use\n"
                "                     by users.\n";
        return 1;
    }
    
    if (sys_shutdown) {
        do_system_shutdown(shutdown_type);
        return 1; // likely to cause panic; the above shouldn't return
    }

    if (reboot_cmd_unsupported(shutdown_type)) {
        cerr << "Unsupported shutdown type\n";
        return 1;
    }

    signal(SIGPIPE, SIG_IGN);
    
    int socknum = -1;
    
    if (use_passed_cfd) {
        socknum = get_passed_cfd();
        if (socknum == -1) {
            use_passed_cfd = false;
        }
    }
    
    if (!use_passed_cfd) {
        socknum = socket(AF_UNIX, SOCK_STREAM, 0);
        if (socknum == -1) {
            perror("socket");
            return 1;
        }
        
        const char *naddr = SYSCONTROLSOCKET;
        
        struct sockaddr_un name;
        name.sun_family = AF_UNIX;
        strcpy(name.sun_path, naddr);
        int sunlen = offsetof(struct sockaddr_un, sun_path) + strlen(naddr) + 1; // family, (string), nul
        
        int connr = connect(socknum, (struct sockaddr *) &name, sunlen);
        if (connr == -1) {
            perror("connect");
            return 1;
        }
    }

    try {
        cpbuffer_t rbuffer;
    
        check_protocol_version(min_cp_version, max_cp_version, rbuffer, socknum);

        // Build buffer;
        constexpr int bufsize = 2;
        char buf[bufsize];

        buf[0] = (dinit_cptypes::cp_cmd_t)cp_cmd::SHUTDOWN;
        buf[1] = static_cast<char>(shutdown_type);

        cout << "Issuing shutdown command..." << endl;

        write_all_x(socknum, buf, bufsize);

        // Wait for ACK/NACK
    
        wait_for_reply(rbuffer, socknum);
        
        if (rbuffer[0] != (dinit_cptypes::cp_rply_t)cp_rply::ACK) {
            cerr << "shutdown: control socket protocol error" << endl;
            return 1;
        }
    }
    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;
    }

    while (true) {
        pause();
    }
    
    return 0;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x540, %rsp            # imm = 0x540
movl $0x0, -0x4(%rbp)
movl %edi, -0x8(%rbp)
movq %rsi, -0x10(%rbp)
movb $0x0, -0x11(%rbp)
movb $0x0, -0x12(%rbp)
movb $0x0, -0x13(%rbp)
movb $0x3, -0x14(%rbp)
movq -0x10(%rbp), %rax
movq (%rax), %rdi
callq 0x4e80
movq %rax, -0x20(%rbp)
movq -0x20(%rbp), %rax
movq %rax, -0x4f0(%rbp)
leaq 0xda35(%rip), %rdi      # 0x11010
callq 0x4ed0
movq -0x4f0(%rbp), %rdi
movq %rax, %rsi
callq 0x3350
cmpl $0x0, %eax
jne 0x35fa
movb $0x4, -0x14(%rbp)
jmp 0x362b
movq -0x20(%rbp), %rax
movq %rax, -0x4f8(%rbp)
leaq 0xda0b(%rip), %rdi      # 0x11017
callq 0x4ef0
movq -0x4f8(%rbp), %rdi
movq %rax, %rsi
callq 0x3350
cmpl $0x0, %eax
jne 0x3629
movb $0x5, -0x14(%rbp)
jmp 0x362b
movl $0x1, -0x24(%rbp)
movl -0x24(%rbp), %eax
cmpl -0x8(%rbp), %eax
jge 0x37e4
movq -0x10(%rbp), %rax
movslq -0x24(%rbp), %rcx
movq (%rax,%rcx,8), %rax
movsbl (%rax), %eax
cmpl $0x2d, %eax
jne 0x37d0
movq -0x10(%rbp), %rax
movslq -0x24(%rbp), %rcx
movq (%rax,%rcx,8), %rdi
leaq 0xdcdb(%rip), %rsi      # 0x11344
callq 0x3350
cmpl $0x0, %eax
jne 0x367c
movb $0x1, -0x11(%rbp)
jmp 0x37e4
movq -0x10(%rbp), %rax
movslq -0x24(%rbp), %rcx
movq (%rax,%rcx,8), %rdi
leaq 0xdcbc(%rip), %rsi      # 0x1134b
callq 0x3350
cmpl $0x0, %eax
jne 0x36a2
movb $0x1, -0x12(%rbp)
jmp 0x37ce
movq -0x10(%rbp), %rax
movslq -0x24(%rbp), %rcx
movq (%rax,%rcx,8), %rdi
leaq 0xdc9f(%rip), %rsi      # 0x11354
callq 0x3350
cmpl $0x0, %eax
jne 0x36c8
movb $0x4, -0x14(%rbp)
jmp 0x37cc
movq -0x10(%rbp), %rax
movslq -0x24(%rbp), %rcx
movq (%rax,%rcx,8), %rdi
leaq 0xdc7c(%rip), %rsi      # 0x11357
callq 0x3350
cmpl $0x0, %eax
jne 0x36ee
movb $0x2, -0x14(%rbp)
jmp 0x37ca
movq -0x10(%rbp), %rax
movslq -0x24(%rbp), %rcx
movq (%rax,%rcx,8), %rdi
leaq 0xdc59(%rip), %rsi      # 0x1135a
callq 0x3350
cmpl $0x0, %eax
jne 0x3714
movb $0x3, -0x14(%rbp)
jmp 0x37c8
movq -0x10(%rbp), %rax
movslq -0x24(%rbp), %rcx
movq (%rax,%rcx,8), %rdi
leaq 0xdc36(%rip), %rsi      # 0x1135d
callq 0x3350
cmpl $0x0, %eax
jne 0x373a
movb $0x5, -0x14(%rbp)
jmp 0x37c6
movq -0x10(%rbp), %rax
movslq -0x24(%rbp), %rcx
movq (%rax,%rcx,8), %rdi
leaq 0xdc13(%rip), %rsi      # 0x11360
callq 0x3350
cmpl $0x0, %eax
jne 0x375d
movb $0x6, -0x14(%rbp)
jmp 0x37c4
movq -0x10(%rbp), %rax
movslq -0x24(%rbp), %rcx
movq (%rax,%rcx,8), %rdi
leaq 0xdbf3(%rip), %rsi      # 0x11363
callq 0x3350
cmpl $0x0, %eax
jne 0x3780
movb $0x1, -0x13(%rbp)
jmp 0x37c2
movq 0x16861(%rip), %rdi     # 0x19fe8
leaq 0xdbe6(%rip), %rsi      # 0x11374
callq 0x3270
movq %rax, %rdi
movq -0x10(%rbp), %rax
movslq -0x24(%rbp), %rcx
movq (%rax,%rcx,8), %rsi
callq 0x3270
movq %rax, %rdi
movq 0x167d7(%rip), %rsi     # 0x19f88
callq 0x32a0
movl $0x1, -0x4(%rbp)
jmp 0x3c81
jmp 0x37c4
jmp 0x37c6
jmp 0x37c8
jmp 0x37ca
jmp 0x37cc
jmp 0x37ce
jmp 0x37d4
movb $0x1, -0x11(%rbp)
jmp 0x37d6
movl -0x24(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x24(%rbp)
jmp 0x3632
testb $0x1, -0x11(%rbp)
je 0x3815
movq -0x20(%rbp), %rsi
movq 0x167c3(%rip), %rdi     # 0x19fb8
callq 0x3270
movq %rax, %rdi
leaq 0xdb96(%rip), %rsi      # 0x1139a
callq 0x3270
movl $0x1, -0x4(%rbp)
jmp 0x3c81
testb $0x1, -0x12(%rbp)
je 0x3830
movsbl -0x14(%rbp), %edi
callq 0x3cb0
movl $0x1, -0x4(%rbp)
jmp 0x3c81
movsbl -0x14(%rbp), %edi
callq 0x4210
testb $0x1, %al
jne 0x383f
jmp 0x385e
movq 0x167a2(%rip), %rdi     # 0x19fe8
leaq 0xddec(%rip), %rsi      # 0x11639
callq 0x3270
movl $0x1, -0x4(%rbp)
jmp 0x3c81
movl $0xd, %edi
movl $0x1, %esi
callq 0x32b0
movl $0xffffffff, -0x28(%rbp) # imm = 0xFFFFFFFF
testb $0x1, -0x13(%rbp)
je 0x388e
callq 0x4f10
movl %eax, -0x28(%rbp)
cmpl $-0x1, -0x28(%rbp)
jne 0x388c
movb $0x0, -0x13(%rbp)
jmp 0x388e
testb $0x1, -0x13(%rbp)
jne 0x3944
movl $0x1, %esi
xorl %edx, %edx
movl %esi, %edi
callq 0x3050
movl %eax, -0x28(%rbp)
cmpl $-0x1, -0x28(%rbp)
jne 0x38c7
leaq 0xdd9e(%rip), %rdi      # 0x11654
callq 0x31f0
movl $0x1, -0x4(%rbp)
jmp 0x3c81
leaq 0xd755(%rip), %rax      # 0x11023
movq %rax, -0x30(%rbp)
movw $0x1, -0x9e(%rbp)
leaq -0x9e(%rbp), %rdi
addq $0x2, %rdi
movq -0x30(%rbp), %rsi
callq 0x3250
movq -0x30(%rbp), %rdi
callq 0x30e0
addq $0x2, %rax
addq $0x1, %rax
movl %eax, -0xa4(%rbp)
movl -0x28(%rbp), %edi
movl -0xa4(%rbp), %edx
leaq -0x9e(%rbp), %rsi
callq 0x31e0
movl %eax, -0xa8(%rbp)
cmpl $-0x1, -0xa8(%rbp)
jne 0x3942
leaq 0xdd2a(%rip), %rdi      # 0x1165b
callq 0x31f0
movl $0x1, -0x4(%rbp)
jmp 0x3c81
jmp 0x3944
leaq -0x4b0(%rbp), %rdi
movq %rdi, -0x500(%rbp)
callq 0x4fc0
movq -0x500(%rbp), %rdx
movl -0x28(%rbp), %ecx
movl $0x1, %edi
movl $0x5, %esi
callq 0x4ff0
jmp 0x3972
movl $0x2, -0x4c0(%rbp)
movb $0xa, -0x4c2(%rbp)
movb -0x14(%rbp), %al
movb %al, -0x4c1(%rbp)
movq 0x16625(%rip), %rdi     # 0x19fb8
leaq 0xdcc9(%rip), %rsi      # 0x11663
callq 0x3270
movq %rax, -0x508(%rbp)
jmp 0x39a8
movq -0x508(%rbp), %rdi
movq 0x165d2(%rip), %rsi     # 0x19f88
callq 0x32a0
jmp 0x39bd
movl -0x28(%rbp), %edi
leaq -0x4c2(%rbp), %rsi
movl $0x2, %edx
callq 0x5150
jmp 0x39d3
movl -0x28(%rbp), %esi
leaq -0x4b0(%rbp), %rdi
callq 0x51e0
jmp 0x39e4
leaq -0x4b0(%rbp), %rdi
xorl %esi, %esi
callq 0x5270
movsbl %al, %eax
cmpl $0x32, %eax
je 0x3c0a
movq 0x165e3(%rip), %rdi     # 0x19fe8
leaq 0xdc73(%rip), %rsi      # 0x1167f
callq 0x3270
movq %rax, -0x510(%rbp)
jmp 0x3a1a
movq -0x510(%rbp), %rdi
movq 0x16560(%rip), %rsi     # 0x19f88
callq 0x32a0
jmp 0x3a2f
movl $0x1, -0x4(%rbp)
jmp 0x3c81
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x4b8(%rbp)
movl %eax, -0x4bc(%rbp)
movl -0x4bc(%rbp), %eax
movl %eax, -0x514(%rbp)
movl $0x4, %ecx
cmpl %ecx, %eax
jne 0x3ab7
movq -0x4b8(%rbp), %rdi
callq 0x30d0
movq %rax, -0x4e8(%rbp)
movq 0x1656c(%rip), %rdi     # 0x19fe8
leaq 0xdcae(%rip), %rsi      # 0x11731
callq 0x3270
movq %rax, -0x520(%rbp)
jmp 0x3a91
movq -0x520(%rbp), %rdi
movq 0x164e9(%rip), %rsi     # 0x19f88
callq 0x32a0
jmp 0x3aa6
movl $0x1, -0x4(%rbp)
callq 0x33e0
jmp 0x3c81
movl -0x514(%rbp), %eax
movl $0x3, %ecx
cmpl %ecx, %eax
jne 0x3b1b
movq -0x4b8(%rbp), %rdi
callq 0x30d0
movq %rax, -0x4e0(%rbp)
movq 0x16508(%rip), %rdi     # 0x19fe8
leaq 0xdc1f(%rip), %rsi      # 0x11706
callq 0x3270
movq %rax, -0x528(%rbp)
jmp 0x3af5
movq -0x528(%rbp), %rdi
movq 0x16485(%rip), %rsi     # 0x19f88
callq 0x32a0
jmp 0x3b0a
movl $0x1, -0x4(%rbp)
callq 0x33e0
jmp 0x3c81
movl -0x514(%rbp), %eax
movl $0x2, %ecx
cmpl %ecx, %eax
jne 0x3b7f
movq -0x4b8(%rbp), %rdi
callq 0x30d0
movq %rax, -0x4d8(%rbp)
movq 0x164a4(%rip), %rdi     # 0x19fe8
leaq 0xdb83(%rip), %rsi      # 0x116ce
callq 0x3270
movq %rax, -0x530(%rbp)
jmp 0x3b59
movq -0x530(%rbp), %rdi
movq 0x16421(%rip), %rsi     # 0x19f88
callq 0x32a0
jmp 0x3b6e
movl $0x1, -0x4(%rbp)
callq 0x33e0
jmp 0x3c81
movl -0x514(%rbp), %eax
movl $0x1, %ecx
cmpl %ecx, %eax
jne 0x3c8d
movq -0x4b8(%rbp), %rdi
callq 0x30d0
movq %rax, -0x4d0(%rbp)
movq 0x1643c(%rip), %rdi     # 0x19fe8
leaq 0xdaf4(%rip), %rsi      # 0x116a7
callq 0x3270
movq %rax, -0x538(%rbp)
jmp 0x3bc1
movq -0x4d0(%rbp), %rax
movl (%rax), %edi
callq 0x30a0
movq -0x538(%rbp), %rdi
movq %rax, %rsi
callq 0x3270
movq %rax, -0x540(%rbp)
jmp 0x3be7
movq -0x540(%rbp), %rdi
movq 0x16393(%rip), %rsi     # 0x19f88
callq 0x32a0
jmp 0x3bfc
movl $0x1, -0x4(%rbp)
callq 0x33e0
jmp 0x3c81
jmp 0x3c78
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x4b8(%rbp)
movl %eax, -0x4bc(%rbp)
callq 0x33e0
jmp 0x3c25
jmp 0x3c8d
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x4b8(%rbp)
movl %eax, -0x4bc(%rbp)
callq 0x33e0
jmp 0x3c40
jmp 0x3c8d
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x4b8(%rbp)
movl %eax, -0x4bc(%rbp)
callq 0x33e0
jmp 0x3c5b
jmp 0x3c8d
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x4b8(%rbp)
movl %eax, -0x4bc(%rbp)
callq 0x33e0
jmp 0x3c76
jmp 0x3c8d
jmp 0x3c7a
callq 0x3040
jmp 0x3c7a
movl -0x4(%rbp), %eax
addq $0x540, %rsp            # imm = 0x540
popq %rbp
retq
movq -0x4b8(%rbp), %rdi
callq 0x3410
movq %rax, %rdi
callq 0x52b0
nopw %cs:(%rax,%rax)