Programming Language

Nocter

A self-contained systems language built around simplicity, encapsulation, and foolproof design.

/development/std/process/command_child_darwin.nct

command_child_darwin.nct

//! Darwin child-side standard-descriptor, directory, and executable setup.
//!
//! The child consumes only a prepared launch plan, one owning I/O session, and one close-on-exec
//! report. Every rejected transition is reported before raw child exit.

see ./command_io_session_darwin.nct
see ./launch_report_darwin.nct
see ./pipe_darwin.nct

use /internal/os/darwin

#target: "arm64-darwin"
noalloc func reject_command_setup(
    report: &+OwnedPipe,
    stage: i32,
    errno: i32,
): never {
    write_launch_failure_and_exit(report, stage, errno)
}

#target: "arm64-darwin"
noalloc func reject_malformed_command_setup(
    report: &+OwnedPipe,
): never {
    write_launch_failure_and_exit(report, 0, 1)
}

#target: "arm64-darwin"
noalloc func install_child_input(
    report: &+OwnedPipe,
    channel: &+CommandInputChannel,
): void {
    match channel {
        CommandInputChannel.inherited {}
        CommandInputChannel.configured(state) {
            close_pipe_write(&+state.pipe)
            match install_descriptor(pipe_read_fd(&state.pipe), darwin.STDIN_FD) {
                DescriptorInstallAttempt.ready {}
                DescriptorInstallAttempt.failed(errno) {
                    reject_command_setup(report, LAUNCH_STAGE_INPUT_SETUP, errno)
                }
                DescriptorInstallAttempt.invalid {
                    reject_malformed_command_setup(report)
                }
            }
            close_pipe_read(&+state.pipe)
        }
    }
    return
}

#target: "arm64-darwin"
noalloc func install_child_captures(
    report: &+OwnedPipe,
    channels: &+CommandCaptureChannels,
): void {
    match channels {
        CommandCaptureChannels.inherited {}
        CommandCaptureChannels.configured(state) {
            close_pipe_read(&+state.stdout_pipe)
            close_pipe_read(&+state.stderr_pipe)
            match install_descriptor(pipe_write_fd(&state.stdout_pipe), darwin.STDOUT_FD) {
                DescriptorInstallAttempt.ready {}
                DescriptorInstallAttempt.failed(errno) {
                    reject_command_setup(report, LAUNCH_STAGE_OUTPUT_SETUP, errno)
                }
                DescriptorInstallAttempt.invalid {
                    reject_malformed_command_setup(report)
                }
            }
            match install_descriptor(pipe_write_fd(&state.stderr_pipe), darwin.STDERR_FD) {
                DescriptorInstallAttempt.ready {}
                DescriptorInstallAttempt.failed(errno) {
                    reject_command_setup(report, LAUNCH_STAGE_OUTPUT_SETUP, errno)
                }
                DescriptorInstallAttempt.invalid {
                    reject_malformed_command_setup(report)
                }
            }
            close_pipe_write(&+state.stdout_pipe)
            close_pipe_write(&+state.stderr_pipe)
        }
    }
    return
}

#target: "arm64-darwin"
noalloc func enter_child_directory(
    path_address: usize,
    report: &+OwnedPipe,
): void {
    if path_address == 0 { return }
    var result = darwin.syscall1(darwin.SYS_CHDIR, path_address)
    while result.errno == darwin.ERRNO_INTERRUPTED {
        result = darwin.syscall1(darwin.SYS_CHDIR, path_address)
    }
    if result.errno != 0 {
        reject_command_setup(report, LAUNCH_STAGE_DIRECTORY, result.errno)
    }
    return
}

#target: "arm64-darwin"
noalloc func exec_command_child(
    path_address: usize,
    argv_address: usize,
    environment_address: usize,
    working_directory_address: usize,
    report: OwnedPipe,
    session: CommandIoSession,
): never {
    var launch_report = move report
    var command_io = move session
    close_pipe_read(&+launch_report)
    install_child_input(&+launch_report, &+command_io.input)
    install_child_captures(&+launch_report, &+command_io.captures)
    enter_child_directory(working_directory_address, &+launch_report)
    exec_child_after_setup(
        path_address,
        argv_address,
        environment_address,
        &+launch_report,
    )
}