// File: davmac314[P]dinit/src/dinit.cc
// Function: dinit_main(int, char**)
int dinit_main(int argc, char **argv)
{
    using namespace std;
    
    am_system_mgr = (getpid() == 1);
    am_system_init = (getuid() == 0);
    
    struct options opts;

    // if we are PID 1 and user id 0, we are *most probably* the system init. (Or on linux at least, we
    // could instead be in a container; then we expect -o argument and unset this then).
    opts.process_sys_args = am_system_mgr && am_system_init;

    const char * &env_file = opts.env_file;
    bool &control_socket_path_set = opts.control_socket_path_set;
    bool &env_file_set = opts.env_file_set;
    bool &log_specified = opts.log_specified;
    service_dir_opt &service_dir_opts = opts.service_dir_opts;
    list<const char *> &services_to_start = opts.services_to_start;

    for (int i = 1; i < argc; i++) {
        int p = process_commandline_arg(argv, argc, i, opts);
        if (p == -1) {
            // clean exit
            return 0;
        }
        if (p == 1) {
            // error exit
            return 1;
        }
    }

    if (am_system_mgr) {
        // setup STDIN, STDOUT, STDERR so that we can use them
        int onefd = open("/dev/console", O_RDONLY, 0);
        if (onefd != -1) {
            dup2(onefd, 0);
        }
        int twofd = open("/dev/console", O_RDWR, 0);
        if (twofd != -1) {
            dup2(twofd, 1);
            dup2(twofd, 2);
        }
        
        if (onefd > 2) close(onefd);
        if (twofd > 2) close(twofd);

        if (! env_file_set) {
            env_file = env_file_path;
        }

        // we will assume an empty cgroups root path
        #if SUPPORT_CGROUPS
        have_cgroups_path = true;
        #endif
    }

    /* Set up signal handlers etc */
    sigset_t sigwait_set;
    if (am_system_mgr) {
        // Block all signals in system manager mode - don't want to chance provoking a signal that
        // will suspend or terminate the process
        sigfillset(&sigwait_set);
    }
    else {
        sigemptyset(&sigwait_set);
        sigaddset(&sigwait_set, SIGCHLD);
        sigaddset(&sigwait_set, SIGINT);
        sigaddset(&sigwait_set, SIGTERM);
    }
    sigprocmask(SIG_BLOCK, &sigwait_set, &orig_signal_mask);

    // Terminal access control signals - we ignore these so that dinit can't be
    // suspended if it writes to the terminal after some other process has claimed
    // ownership of it.
    signal(SIGTSTP, SIG_IGN);
    signal(SIGTTIN, SIG_IGN);
    signal(SIGTTOU, SIG_IGN);
    
    signal(SIGPIPE, SIG_IGN);
    
    event_loop.init();

    if (!am_system_init && !control_socket_path_set) {
        const char * rundir = getenv("XDG_RUNTIME_DIR");
        const char * sockname = "dinitctl";
        if (rundir == nullptr) {
            rundir = service_dir_opt::get_user_home();
            sockname = ".dinitctl";
        }
        if (rundir != nullptr) {
            control_socket_str = rundir;
            control_socket_str.push_back('/');
            control_socket_str += sockname;
            control_socket_path = control_socket_str.c_str();
        }
    }
    
    if (services_to_start.empty()) {
        services_to_start.push_back("boot");
    }

    // Set up signal handlers
    callback_signal_handler sigterm_watcher {sigterm_cb};
    callback_signal_handler sigint_watcher;
    callback_signal_handler sigquit_watcher;

    if (am_system_mgr) {
        sigint_watcher.set_cb_func(sigint_reboot_cb);
        sigquit_watcher.set_cb_func(sigquit_cb);
    }
    else {
        sigint_watcher.set_cb_func(sigterm_cb);
    }

    sigint_watcher.add_watch(event_loop, SIGINT);
    sigterm_watcher.add_watch(event_loop, SIGTERM);
    
    if (am_system_mgr) {
        // PID 1: we may ask for console input; SIGQUIT exec's shutdown
        console_input_io.add_watch(event_loop, STDIN_FILENO, dasynq::IN_EVENTS, false);
        sigquit_watcher.add_watch(event_loop, SIGQUIT);
        // (If not PID 1, we instead just let SIGQUIT perform the default action.)
    }

    init_log(log_is_syslog);
    log_flush_timer.add_timer(event_loop, dasynq::clock_type::MONOTONIC);

    #if SUPPORT_CGROUPS
    if (!have_cgroups_path) {
        find_cgroup_path();
        // We will press on if the cgroup root path could not be identified, since services might
        // not require cgroups anyway and/or might only specify absolute cgroups paths.
    }
    #endif

    // Try to open control socket (may fail due to readonly filesystem, we ignore that if we are
    // system init)
    if (!open_control_socket(!am_system_init)) {
        flush_log();
        return EXIT_FAILURE;
    }
    
#ifdef __linux__
    if (am_system_mgr) {
        // Disable non-critical kernel output to console
        klogctl(6 /* SYSLOG_ACTION_CONSOLE_OFF */, nullptr, 0);
        // Make ctrl+alt+del combination send SIGINT to PID 1 (this process)
        reboot(RB_DISABLE_CAD);
    }

    // Mark ourselves as a subreaper. This means that if a process we start double-forks, the
    // orphaned child will re-parent to us rather than to PID 1 (although that could be us too).
    prctl(PR_SET_CHILD_SUBREAPER, 1);
#elif defined(__FreeBSD__) || defined(__DragonFly__)
    // Documentation (man page) for this kind-of sucks. PROC_REAP_ACQUIRE "acquires the reaper status for
    // the current process" but does that mean the first two arguments still need valid values to be
    // supplied? We'll play it safe and explicitly target our own process:
    procctl(P_PID, getpid(), PROC_REAP_ACQUIRE, NULL);
#endif
    
    service_dir_opts.build_paths(am_system_init);

    // Start requested services

    services = new dirload_service_set(std::move(service_dir_opts.get_paths()));

    setup_log_console_handoff(services);

    if (am_system_init) {
        log(loglevel_t::NOTICE, false, "Starting system");
    }
    
    // If a log file was specified, open it now.
    if (log_specified) {
        setup_external_log();
        if (!am_system_init && !external_log_open) {
            flush_log(); // flush console messages
            return EXIT_FAILURE;
        }
    }

    if (env_file != nullptr) {
        read_env_file(env_file, true, main_env, false);
    }

    for (auto svc : services_to_start) {
        try {
            services->start_service(svc);
            // Note in general if we fail to start a service we don't need any special error handling,
            // since we either leave other services running or, if it was the only service, then no
            // services will be running and we will process normally (reboot if system process,
            // exit if user process).
        }
        catch (service_not_found &snf) {
            log(loglevel_t::ERROR, snf.service_name, ": could not find service description.");
        }
        catch (service_description_exc &sde) {
            log_service_load_failure(sde);
        }
        catch (service_load_exc &sle) {
            log(loglevel_t::ERROR, sle.service_name, ": error loading: ", sle.exc_description);
        }
        catch (std::bad_alloc &badalloce) {
            log(loglevel_t::ERROR, "Out of memory when trying to start service: ", svc, ".");
            break;
        }
    }

    // Notify readiness just before the event loop starts (and after services
    // are scheduled to start). If the socket is not ready yet (may be in case
    // of read-only file system), we will report it when it is.
    control_socket_ready();
    
    run_event_loop:
    
    // Process events until all services have terminated.
    while (services->count_active_services() != 0) {
        event_loop.run();
    }

    shutdown_type_t shutdown_type = services->get_shutdown_type();
    if (shutdown_type == shutdown_type_t::REMAIN) {
        goto run_event_loop;
    }
    
    if (am_system_mgr) {
        log_msg_begin(loglevel_t::NOTICE, "No more active services.");
        
        if (shutdown_type == shutdown_type_t::REBOOT) {
            log_msg_end(" Will reboot.");
        }
        if (shutdown_type == shutdown_type_t::SOFTREBOOT) {
            log_msg_end(" Will soft-reboot.");
        }
        else if (shutdown_type == shutdown_type_t::HALT) {
            log_msg_end(" Will halt.");
        }
        else if (shutdown_type == shutdown_type_t::POWEROFF) {
            log_msg_end(" Will power down.");
        }
        else if (shutdown_type == shutdown_type_t::KEXEC) {
            log_msg_end(" Will kexec.");
        }
        else if (shutdown_type == shutdown_type_t::NONE) {
            log_msg_end(" Will handle boot failure.");
        }
    }

    flush_log();
    bool need_log_flush = false;
    close_control_socket();
    
    if (am_system_mgr) {
        if (shutdown_type == shutdown_type_t::SOFTREBOOT) {
            sync(); // Sync to minimise data loss in case soft-boot fails

            execv(dinit_exec, argv);
            log(loglevel_t::ERROR, error_exec_dinit, strerror(errno));

            // if we get here, soft reboot failed; reboot normally
            log(loglevel_t::ERROR, "Could not soft-reboot. Will attempt reboot.");
            shutdown_type = shutdown_type_t::REBOOT;
            need_log_flush = true;
        }

        if (shutdown_type == shutdown_type_t::NONE) {
            // Services all stopped but there was no shutdown issued. Inform user, wait for ack, and
            // re-start boot sequence.
            sync(); // Sync to minimise data loss if user elects to power off / hard reset
            if (auto_recovery) {
                try {
                    services->start_service("recovery");
                }
                catch (std::exception &exc) {
                    log(loglevel_t::ERROR, "Unable to start recovery service: ", exc.what());
                    // As the following prompt UI could be inaccessible flush the log again already
                    flush_log();
                }
            }
            confirm_restart_boot();
            if (services->count_active_services() != 0) {
                // Recovery service started
                goto run_event_loop;
            }
            shutdown_type = services->get_shutdown_type();
            if (shutdown_type == shutdown_type_t::NONE) {
                try {
                    services->start_service("boot");
                    goto run_event_loop; // yes, the "evil" goto
                }
                catch (...) {
                    // Couldn't start boot service, let's reboot the system
                    log(loglevel_t::ERROR, "Could not start 'boot' service. Will attempt reboot.");
                    need_log_flush = true;
                    shutdown_type = shutdown_type_t::REBOOT;
                }
            }
        }
        
        if (need_log_flush) {
            // In case of error since the log was previously flushed, flush again now
            flush_log();
        }

        const char * cmd_arg;
        if (shutdown_type == shutdown_type_t::HALT) {
            cmd_arg = "-h";
        }
        else if (shutdown_type == shutdown_type_t::REBOOT) {
            cmd_arg = "-r";
        }
        else if (shutdown_type == shutdown_type_t::KEXEC) {
            cmd_arg = "-k";
        }
        else {
            // power off.
            cmd_arg = "-p";
        }
        
        // Fork and execute dinit-reboot.
        execl(shutdown_exec.c_str(), shutdown_exec.c_str(), "--system", cmd_arg, nullptr);
        log(loglevel_t::ERROR, error_exec_sd, strerror(errno));
        
        // PID 1 must not actually exit, although we should never reach this point:
        while (true) {
            event_loop.run();
        }
    }
    else if (shutdown_type == shutdown_type_t::REBOOT) {
        // Non-system-process. If we got SIGINT, let's die due to it:
        sigset_t sigwait_set_int;
        sigemptyset(&sigwait_set_int);
        sigaddset(&sigwait_set_int, SIGINT);
        raise(SIGINT);
        sigprocmask(SIG_UNBLOCK, &sigwait_set_int, NULL);
    }
    
    return EXIT_SUCCESS;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x490, %rsp            # imm = 0x490
movl %edi, -0x8(%rbp)
movq %rsi, -0x10(%rbp)
callq 0xab00
cmpl $0x1, %eax
sete %al
andb $0x1, %al
movb %al, 0x9d8eb(%rip)      # 0xa8e40
callq 0xa330
cmpl $0x0, %eax
sete %al
andb $0x1, %al
movb %al, 0x9d8d9(%rip)      # 0xa8e41
leaq -0x68(%rbp), %rdi
callq 0xf570
xorl %eax, %eax
testb $0x1, 0x9d8c6(%rip)     # 0xa8e40
movb %al, -0x439(%rbp)
je 0xb58e
movb 0x9d8b9(%rip), %al      # 0xa8e41
movb %al, -0x439(%rbp)
movb -0x439(%rbp), %al
andb $0x1, %al
movb %al, -0x5d(%rbp)
leaq -0x68(%rbp), %rax
movq %rax, -0x70(%rbp)
leaq -0x68(%rbp), %rax
addq $0x8, %rax
movq %rax, -0x78(%rbp)
leaq -0x68(%rbp), %rax
addq $0x9, %rax
movq %rax, -0x80(%rbp)
leaq -0x68(%rbp), %rax
addq $0xa, %rax
movq %rax, -0x88(%rbp)
leaq -0x68(%rbp), %rax
addq $0x10, %rax
movq %rax, -0x90(%rbp)
leaq -0x68(%rbp), %rax
addq $0x40, %rax
movq %rax, -0x98(%rbp)
movl $0x1, -0x9c(%rbp)
movl -0x9c(%rbp), %eax
cmpl -0x8(%rbp), %eax
jge 0xb695
movq -0x10(%rbp), %rdi
movl -0x8(%rbp), %esi
leaq -0x9c(%rbp), %rdx
leaq -0x68(%rbp), %rcx
callq 0xc2f0
movl %eax, -0x440(%rbp)
jmp 0xb61e
movl -0x440(%rbp), %eax
movl %eax, -0xa0(%rbp)
cmpl $-0x1, -0xa0(%rbp)
jne 0xb660
movl $0x0, -0x4(%rbp)
movl $0x1, -0xb0(%rbp)
jmp 0xc2b0
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0xa8(%rbp)
movl %eax, -0xac(%rbp)
jmp 0xc2c5
cmpl $0x1, -0xa0(%rbp)
jne 0xb67f
movl $0x1, -0x4(%rbp)
movl $0x1, -0xb0(%rbp)
jmp 0xc2b0
jmp 0xb681
movl -0x9c(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x9c(%rbp)
jmp 0xb5f0
testb $0x1, 0x9d7a4(%rip)     # 0xa8e40
je 0xb77e
leaq 0x6a95f(%rip), %rdi     # 0x76008
xorl %edx, %edx
movb %dl, %al
movl %edx, %esi
callq 0xa520
movl %eax, -0x444(%rbp)
jmp 0xb6bc
movl -0x444(%rbp), %eax
movl %eax, -0xb4(%rbp)
cmpl $-0x1, -0xb4(%rbp)
je 0xb6de
movl -0xb4(%rbp), %edi
xorl %esi, %esi
callq 0xa690
leaq 0x6a923(%rip), %rdi     # 0x76008
xorl %edx, %edx
movb %dl, %al
movl $0x2, %esi
callq 0xa520
movl %eax, -0x448(%rbp)
jmp 0xb6fb
movl -0x448(%rbp), %eax
movl %eax, -0xb8(%rbp)
cmpl $-0x1, -0xb8(%rbp)
je 0xb730
movl -0xb8(%rbp), %edi
movl $0x1, %esi
callq 0xa690
movl -0xb8(%rbp), %edi
movl $0x2, %esi
callq 0xa690
cmpl $0x2, -0xb4(%rbp)
jle 0xb748
movl -0xb4(%rbp), %edi
callq 0xad80
jmp 0xb746
jmp 0xb748
cmpl $0x2, -0xb8(%rbp)
jle 0xb760
movl -0xb8(%rbp), %edi
callq 0xad80
jmp 0xb75e
jmp 0xb760
movq -0x80(%rbp), %rax
testb $0x1, (%rax)
jne 0xb777
movq 0x9cf98(%rip), %rcx     # 0xa8708
movq -0x70(%rbp), %rax
movq %rcx, (%rax)
movb $0x1, 0x9d612(%rip)     # 0xa8d90
testb $0x1, 0x9d6bb(%rip)     # 0xa8e40
je 0xb795
leaq -0x138(%rbp), %rdi
callq 0xa1c0
jmp 0xb7d4
leaq -0x138(%rbp), %rdi
callq 0xa8f0
leaq -0x138(%rbp), %rdi
movl $0x11, %esi
callq 0xab50
leaq -0x138(%rbp), %rdi
movl $0x2, %esi
callq 0xab50
leaq -0x138(%rbp), %rdi
movl $0xf, %esi
callq 0xab50
leaq 0x9d4f5(%rip), %rdx     # 0xa8cd0
xorl %edi, %edi
leaq -0x138(%rbp), %rsi
callq 0xa2f0
movl $0x14, %edi
movl $0x1, %esi
movq %rsi, -0x450(%rbp)
callq 0xa870
movq -0x450(%rbp), %rsi
movl $0x15, %edi
callq 0xa870
movq -0x450(%rbp), %rsi
movl $0x16, %edi
callq 0xa870
movq -0x450(%rbp), %rsi
movl $0xd, %edi
callq 0xa870
leaq 0x9d327(%rip), %rdi     # 0xa8b60
callq 0xf5c0
jmp 0xb840
testb $0x1, 0x9d5fa(%rip)     # 0xa8e41
jne 0xb90b
movq -0x78(%rbp), %rax
testb $0x1, (%rax)
jne 0xb90b
leaq 0x6a7b4(%rip), %rdi     # 0x76015
callq 0xa8a0
movq %rax, -0x140(%rbp)
leaq 0x6a7b2(%rip), %rax     # 0x76026
movq %rax, -0x148(%rbp)
cmpq $0x0, -0x140(%rbp)
jne 0xb8af
callq 0x6e280
movq %rax, -0x458(%rbp)
jmp 0xb893
movq -0x458(%rbp), %rax
movq %rax, -0x140(%rbp)
leaq 0x6a77d(%rip), %rax     # 0x76025
movq %rax, -0x148(%rbp)
cmpq $0x0, -0x140(%rbp)
je 0xb909
movq -0x140(%rbp), %rsi
leaq 0x9d489(%rip), %rdi     # 0xa8d50
callq 0xaa00
jmp 0xb8ce
leaq 0x9d47b(%rip), %rdi     # 0xa8d50
movl $0x2f, %esi
callq 0xa600
jmp 0xb8e1
movq -0x148(%rbp), %rsi
leaq 0x9d461(%rip), %rdi     # 0xa8d50
callq 0xa6d0
jmp 0xb8f6
leaq 0x9d453(%rip), %rdi     # 0xa8d50
callq 0xa250
movq %rax, 0x9ce07(%rip)     # 0xa8710
jmp 0xb90b
movq -0x98(%rbp), %rdi
callq 0xf5e0
testb $0x1, %al
jne 0xb91d
jmp 0xb942
movq -0x98(%rbp), %rdi
leaq 0x6a704(%rip), %rax     # 0x7602f
movq %rax, -0x150(%rbp)
leaq -0x150(%rbp), %rsi
callq 0xf600
jmp 0xb940
jmp 0xb942
leaq 0x13a7(%rip), %rsi      # 0xccf0
leaq -0x1f8(%rbp), %rdi
callq 0xcd20
jmp 0xb957
leaq -0x2a0(%rbp), %rdi
callq 0xcd60
jmp 0xb965
leaq -0x348(%rbp), %rdi
callq 0xcd60
jmp 0xb973
testb $0x1, 0x9d4c6(%rip)     # 0xa8e40
je 0xb9ed
leaq 0x143d(%rip), %rsi      # 0xcdc0
leaq -0x2a0(%rbp), %rdi
callq 0xcda0
jmp 0xb991
leaq 0x1458(%rip), %rsi      # 0xcdf0
leaq -0x348(%rbp), %rdi
callq 0xcda0
jmp 0xb9a6
jmp 0xba04
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0xa8(%rbp)
movl %eax, -0xac(%rbp)
jmp 0xc2a2
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0xa8(%rbp)
movl %eax, -0xac(%rbp)
jmp 0xc296
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0xa8(%rbp)
movl %eax, -0xac(%rbp)
jmp 0xc28a
leaq 0x12fc(%rip), %rsi      # 0xccf0
leaq -0x2a0(%rbp), %rdi
callq 0xcda0
jmp 0xba02
jmp 0xba04
leaq 0x9d155(%rip), %rsi     # 0xa8b60
leaq -0x2a0(%rbp), %rdi
movl $0x2, %edx
movl $0x32, %ecx
callq 0xf640
jmp 0xba23
leaq 0x9d136(%rip), %rsi     # 0xa8b60
leaq -0x1f8(%rbp), %rdi
movl $0xf, %edx
movl $0x32, %ecx
callq 0xf640
jmp 0xba42
testb $0x1, 0x9d3f7(%rip)     # 0xa8e40
je 0xba92
leaq 0x9d36e(%rip), %rdi     # 0xa8dc0
leaq 0x9d107(%rip), %rsi     # 0xa8b60
movl $0x1, %ecx
xorl %r8d, %r8d
movl $0x32, %r9d
movl %r8d, %edx
callq 0xf690
jmp 0xba71
leaq 0x9d0e8(%rip), %rsi     # 0xa8b60
leaq -0x348(%rbp), %rdi
movl $0x3, %edx
movl $0x32, %ecx
callq 0xf640
jmp 0xba90
jmp 0xba92
movzbl 0x9cc7f(%rip), %edi     # 0xa8718
andl $0x1, %edi
callq 0x6b180
jmp 0xbaa3
leaq 0x9d33e(%rip), %rdi     # 0xa8de8
leaq 0x9d0af(%rip), %rsi     # 0xa8b60
movl $0x1, %edx
movl $0x32, %ecx
callq 0xf700
jmp 0xbac2
testb $0x1, 0x9d2c7(%rip)     # 0xa8d90
jne 0xbad0
callq 0xce80
movb 0x9d36b(%rip), %al      # 0xa8e41
xorb $-0x1, %al
movzbl %al, %edi
andl $0x1, %edi
callq 0xd230
testb $0x1, %al
jne 0xbb02
callq 0xd6a0
movl $0x1, -0x4(%rbp)
movl $0x1, -0xb0(%rbp)
jmp 0xc264
testb $0x1, 0x9d337(%rip)     # 0xa8e40
je 0xbb22
movl $0x6, %edi
xorl %eax, %eax
movl %eax, %esi
xorl %edx, %edx
callq 0xadb0
xorl %edi, %edi
callq 0xa5e0
xorl %eax, %eax
movl $0x24, %edi
movl $0x1, %esi
callq 0xa980
movq -0x90(%rbp), %rdi
movzbl 0x9d300(%rip), %esi     # 0xa8e41
andl $0x1, %esi
callq 0x6e2f0
jmp 0xbb4b
movl $0x60, %edi
callq 0xa700
movq %rax, -0x460(%rbp)
jmp 0xbb5e
movq -0x90(%rbp), %rdi
callq 0xf750
movq %rax, -0x468(%rbp)
jmp 0xbb73
movq -0x460(%rbp), %rdi
movq -0x468(%rbp), %rsi
callq 0xf770
movq -0x460(%rbp), %rax
movq %rax, 0x9d2b4(%rip)     # 0xa8e48
movq 0x9d2ad(%rip), %rdi     # 0xa8e48
callq 0x6b2c0
jmp 0xbba2
testb $0x1, 0x9d298(%rip)     # 0xa8e41
je 0xbbe8
movl $0x1, %edi
xorl %esi, %esi
leaq 0x6a47b(%rip), %rdx     # 0x76034
callq 0x6b660
jmp 0xbbe8
movq -0x460(%rbp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0xa8(%rbp)
movl %eax, -0xac(%rbp)
movl $0x60, %esi
callq 0xa720
jmp 0xc28a
movq -0x88(%rbp), %rax
testb $0x1, (%rax)
je 0xbc28
callq 0xd740
testb $0x1, 0x9d241(%rip)     # 0xa8e41
jne 0xbc26
testb $0x1, 0x9d0bf(%rip)     # 0xa8cc8
jne 0xbc26
callq 0xd6a0
movl $0x1, -0x4(%rbp)
movl $0x1, -0xb0(%rbp)
jmp 0xc264
jmp 0xbc28
movq -0x70(%rbp), %rax
cmpq $0x0, (%rax)
je 0xbc50
movq -0x70(%rbp), %rax
movq (%rax), %rdi
leaq 0x9f300(%rip), %rdx     # 0xaaf40
movl $0x1, %esi
xorl %ecx, %ecx
callq 0x70810
jmp 0xbc4e
jmp 0xbc50
movq -0x98(%rbp), %rax
movq %rax, -0x350(%rbp)
movq -0x350(%rbp), %rdi
callq 0xf7c0
movq %rax, -0x358(%rbp)
movq -0x350(%rbp), %rdi
callq 0xf7f0
movq %rax, -0x360(%rbp)
leaq -0x358(%rbp), %rdi
leaq -0x360(%rbp), %rsi
callq 0xf820
testb $0x1, %al
jne 0xbca0
jmp 0xbe37
leaq -0x358(%rbp), %rdi
callq 0xf850
movq (%rax), %rax
movq %rax, -0x368(%rbp)
movq 0x9d18b(%rip), %rdi     # 0xa8e48
movq -0x368(%rbp), %rsi
callq 0xf870
jmp 0xbccb
jmp 0xbd28
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0xa8(%rbp)
movl %eax, -0xac(%rbp)
movl -0xac(%rbp), %eax
movl %eax, -0x46c(%rbp)
movl $0x4, %ecx
cmpl %ecx, %eax
jne 0xbd3b
movq -0xa8(%rbp), %rdi
callq 0xa240
movq %rax, -0x388(%rbp)
movq -0x388(%rbp), %rsi
leaq 0x6a36e(%rip), %rdx     # 0x76083
movl $0x3, %edi
callq 0xda50
callq 0xac30
jmp 0xbd26
jmp 0xbd28
jmp 0xbd2a
leaq -0x358(%rbp), %rdi
callq 0xfa40
jmp 0xbc84
movl -0x46c(%rbp), %eax
movl $0x3, %ecx
cmpl %ecx, %eax
jne 0xbd74
movq -0xa8(%rbp), %rdi
callq 0xa240
movq %rax, -0x380(%rbp)
movq -0x380(%rbp), %rdi
callq 0xf8b0
jmp 0xbd6b
callq 0xac30
jmp 0xbd72
jmp 0xbd28
movl -0x46c(%rbp), %eax
movl $0x2, %ecx
cmpl %ecx, %eax
jne 0xbdc1
movq -0xa8(%rbp), %rdi
callq 0xa240
movq %rax, -0x378(%rbp)
movq -0x378(%rbp), %rsi
movq %rsi, %rcx
addq $0x20, %rcx
leaq 0x6a2c6(%rip), %rdx     # 0x76071
movl $0x3, %edi
callq 0xda10
callq 0xac30
jmp 0xbdbc
jmp 0xbd28
movl -0x46c(%rbp), %eax
movl $0x1, %ecx
cmpl %ecx, %eax
jne 0xc28a
movq -0xa8(%rbp), %rdi
callq 0xa240
movq %rax, -0x370(%rbp)
leaq 0x6a256(%rip), %rsi     # 0x76044
leaq 0x6bcb5(%rip), %rcx     # 0x77aaa
movl $0x3, %edi
leaq -0x368(%rbp), %rdx
callq 0xd9d0
movl $0x5, -0xb0(%rbp)
callq 0xac30
jmp 0xbe17
jmp 0xbe37
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0xa8(%rbp)
movl %eax, -0xac(%rbp)
callq 0xac30
jmp 0xbe32
jmp 0xc28a
callq 0xda80
jmp 0xbe3e
movq 0x9d003(%rip), %rdi     # 0xa8e48
callq 0xfa60
cmpl $0x0, %eax
je 0xbe62
leaq 0x9cd0a(%rip), %rdi     # 0xa8b60
movl $0xffffffff, %esi       # imm = 0xFFFFFFFF
callq 0xfa80
jmp 0xbe3e
movq 0x9cfdf(%rip), %rdi     # 0xa8e48
callq 0xfb10
movb %al, -0x389(%rbp)
cmpb $0x1, -0x389(%rbp)
jne 0xbe7f
jmp 0xbe3c
testb $0x1, 0x9cfba(%rip)     # 0xa8e40
je 0xbf2d
movl $0x1, %edi
leaq 0x6a211(%rip), %rsi     # 0x760a9
callq 0x6b6a0
cmpb $0x4, -0x389(%rbp)
jne 0xbeb2
leaq 0x6a215(%rip), %rdi     # 0x760c2
callq 0x6b8e0
cmpb $0x5, -0x389(%rbp)
jne 0xbec9
leaq 0x6a20e(%rip), %rdi     # 0x760d0
callq 0x6b8e0
jmp 0xbf2b
cmpb $0x2, -0x389(%rbp)
jne 0xbee0
leaq 0x6a20a(%rip), %rdi     # 0x760e3
callq 0x6b8e0
jmp 0xbf29
cmpb $0x3, -0x389(%rbp)
jne 0xbef7
leaq 0x6a1ff(%rip), %rdi     # 0x760ef
callq 0x6b8e0
jmp 0xbf27
cmpb $0x6, -0x389(%rbp)
jne 0xbf0e
leaq 0x6a1fa(%rip), %rdi     # 0x76101
callq 0x6b8e0
jmp 0xbf25
cmpb $0x0, -0x389(%rbp)
jne 0xbf23
leaq 0x6a1f0(%rip), %rdi     # 0x7610e
callq 0x6b8e0
jmp 0xbf25
jmp 0xbf27
jmp 0xbf29
jmp 0xbf2b
jmp 0xbf2d
callq 0xd6a0
movb $0x0, -0x38a(%rbp)
callq 0xdb00
testb $0x1, 0x9cefb(%rip)     # 0xa8e40
je 0xc20c
cmpb $0x5, -0x389(%rbp)
jne 0xbfc8
callq 0xa6b0
leaq 0x6afc3(%rip), %rdi     # 0x76f23
callq 0xfb30
movq %rax, -0x478(%rbp)
jmp 0xbf6e
movq -0x478(%rbp), %rdi
movq -0x10(%rbp), %rsi
callq 0xa670
callq 0xa060
movl (%rax), %edi
callq 0xa1f0
movq %rax, -0x398(%rbp)
movl $0x3, %edi
leaq 0x6af92(%rip), %rsi     # 0x76f2f
leaq -0x398(%rbp), %rdx
callq 0xdb60
movl $0x3, %edi
leaq 0x6a174(%rip), %rsi     # 0x76129
callq 0x6b540
movb $0x4, -0x389(%rbp)
movb $0x1, -0x38a(%rbp)
cmpb $0x0, -0x389(%rbp)
jne 0xc10f
callq 0xa6b0
testb $0x1, 0x9ce6f(%rip)     # 0xa8e50
je 0xc075
movq 0x9ce5a(%rip), %rdi     # 0xa8e48
leaq 0x6bfda(%rip), %rsi     # 0x77fcf
callq 0xf870
jmp 0xbffc
jmp 0xc073
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0xa8(%rbp)
movl %eax, -0xac(%rbp)
movl -0xac(%rbp), %eax
movl $0x5, %ecx
cmpl %ecx, %eax
jne 0xc28a
movq -0xa8(%rbp), %rdi
callq 0xa240
movq %rax, -0x3a0(%rbp)
movq -0x3a0(%rbp), %rdi
movq (%rdi), %rax
movq 0x10(%rax), %rax
callq *%rax
movq %rax, -0x3a8(%rbp)
leaq 0x6a101(%rip), %rsi     # 0x76155
movl $0x3, %edi
leaq -0x3a8(%rbp), %rdx
callq 0xdbb0
callq 0xd6a0
callq 0xac30
jmp 0xc071
jmp 0xc073
jmp 0xc075
callq 0xdbe0
movq 0x9cdc7(%rip), %rdi     # 0xa8e48
callq 0xfa60
cmpl $0x0, %eax
je 0xc090
jmp 0xbe3c
movq 0x9cdb1(%rip), %rdi     # 0xa8e48
callq 0xfb10
movb %al, -0x389(%rbp)
cmpb $0x0, -0x389(%rbp)
jne 0xc10d
movq 0x9cd96(%rip), %rdi     # 0xa8e48
leaq 0x69f76(%rip), %rsi     # 0x7602f
callq 0xf870
jmp 0xc0c0
jmp 0xbe3c
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0xa8(%rbp)
movl %eax, -0xac(%rbp)
movq -0xa8(%rbp), %rdi
callq 0xa240
leaq 0x6a08e(%rip), %rsi     # 0x76178
movl $0x3, %edi
callq 0x6b540
movb $0x1, -0x38a(%rbp)
movb $0x4, -0x389(%rbp)
callq 0xac30
jmp 0xc109
jmp 0xc10b
jmp 0xc10d
jmp 0xc10f
testb $0x1, -0x38a(%rbp)
je 0xc11d
callq 0xd6a0
cmpb $0x2, -0x389(%rbp)
jne 0xc136
leaq 0x6a080(%rip), %rax     # 0x761ad
movq %rax, -0x3b0(%rbp)
jmp 0xc17a
cmpb $0x4, -0x389(%rbp)
jne 0xc14f
leaq 0x6a06a(%rip), %rax     # 0x761b0
movq %rax, -0x3b0(%rbp)
jmp 0xc178
cmpb $0x6, -0x389(%rbp)
jne 0xc168
leaq 0x6a054(%rip), %rax     # 0x761b3
movq %rax, -0x3b0(%rbp)
jmp 0xc176
leaq 0x6a047(%rip), %rax     # 0x761b6
movq %rax, -0x3b0(%rbp)
jmp 0xc178
jmp 0xc17a
leaq 0x6adcc(%rip), %rdi     # 0x76f4d
callq 0xfb50
movq %rax, -0x480(%rbp)
jmp 0xc18f
leaq 0x6adb7(%rip), %rdi     # 0x76f4d
callq 0xfb50
movq %rax, -0x488(%rbp)
jmp 0xc1a4
movq -0x488(%rbp), %rsi
movq -0x480(%rbp), %rdi
movq -0x3b0(%rbp), %rcx
leaq 0x69ff9(%rip), %rdx     # 0x761b9
xorl %eax, %eax
movl %eax, %r8d
movb $0x0, %al
callq 0xa8d0
callq 0xa060
movl (%rax), %edi
callq 0xa1f0
movq %rax, -0x3b8(%rbp)
movl $0x3, %edi
leaq 0x6ad71(%rip), %rsi     # 0x76f5c
leaq -0x3b8(%rbp), %rdx
callq 0xdeb0
jmp 0xc1f9
leaq 0x9c960(%rip), %rdi     # 0xa8b60
movl $0xffffffff, %esi       # imm = 0xFFFFFFFF
callq 0xfa80
jmp 0xc1f7
cmpb $0x4, -0x389(%rbp)
jne 0xc251
leaq -0x438(%rbp), %rdi
callq 0xa8f0
leaq -0x438(%rbp), %rdi
movl $0x2, %esi
callq 0xab50
movl $0x2, %edi
callq 0xa710
movl $0x1, %edi
leaq -0x438(%rbp), %rsi
xorl %eax, %eax
movl %eax, %edx
callq 0xa2f0
jmp 0xc253
movl $0x0, -0x4(%rbp)
movl $0x1, -0xb0(%rbp)
leaq -0x348(%rbp), %rdi
callq 0xdf00
leaq -0x2a0(%rbp), %rdi
callq 0xdf00
leaq -0x1f8(%rbp), %rdi
callq 0xdf00
jmp 0xc2b0
leaq -0x348(%rbp), %rdi
callq 0xdf00
leaq -0x2a0(%rbp), %rdi
callq 0xdf00
leaq -0x1f8(%rbp), %rdi
callq 0xdf00
jmp 0xc2c5
leaq -0x68(%rbp), %rdi
callq 0xfb60
movl -0x4(%rbp), %eax
addq $0x490, %rsp            # imm = 0x490
popq %rbp
retq
leaq -0x68(%rbp), %rdi
callq 0xfb60
movq -0xa8(%rbp), %rdi
callq 0xacc0
movq %rax, %rdi
callq 0xfa30
nopw %cs:(%rax,%rax)