//
// Syd: rock-solid application kernel
// src/kernel/ptrace/event/sig.rs: ptrace(2) signal event handler
//
// Copyright (c) 2025 Ali Polatel <alip@chesswob.org>
//
// SPDX-License-Identifier: GPL-3.0

use std::sync::Arc;

use nix::{
    errno::Errno,
    sys::signal::{kill, Signal},
    unistd::Pid,
};

use crate::{error, proc::proc_status, workers::WorkerCache};

pub(crate) fn sysevent_sig(pid: Pid, sig: i32, cache: &Arc<WorkerCache>) {
    // Pid received genuine signal:
    // 1. Check if this signal has a handler.
    // 2. If (1) is yes, increase signal count for SROP mitigation.
    //
    // SAFETY: Check for signal status in /proc/pid/status.
    let status = match proc_status(pid) {
        Ok(status) => status,
        Err(Errno::ESRCH) => {
            // SAFETY: Process already dead, continue.
            return;
        }
        Err(errno) => {
            // SAFETY: Failed to get process status, terminate the process.
            error!("ctx": "handle_signal", "op": "read_status", "err": errno as i32,
                "msg": format!("failed to read /proc/{}/status: {errno}", pid.as_raw()),
                "tip": "check with SYD_LOG=debug and/or submit a bug report");
            let _ = kill(pid, Some(Signal::SIGKILL));
            return;
        }
    };

    if status.sig_caught.contains(sig) {
        // SAFETY:
        // 1. Increase expected sigreturn(2) count, now that
        //    we're forwarding a signal to the sandbox
        //    process.
        // 2. Signal handlers are per-process not per-thread!
        cache.inc_sig_handle(status.pid);
    }

    // SAFETY: nix Signal type does not include realtime signals,
    // so we fallback to libc here.
    let _ = unsafe { libc::ptrace(libc::PTRACE_CONT, pid.as_raw(), 0, sig) };
}
