//
// Syd: rock-solid application kernel
// src/kernel/syslog.rs: syslog(2) handler
//
// Copyright (c) 2023, 2024, 2025, 2026 Ali Polatel <alip@chesswob.org>
//
// SPDX-License-Identifier: GPL-3.0

// SAFETY: This module has been liberated from unsafe code!
#![forbid(unsafe_code)]

#[cfg(feature = "log")]
use libseccomp::ScmpNotifResp;
#[cfg(feature = "log")]
use nix::errno::Errno;

#[cfg(feature = "log")]
use crate::req::UNotifyEventRequest;

#[cfg(feature = "log")]
pub(crate) fn sys_syslog(request: UNotifyEventRequest) -> ScmpNotifResp {
    syscall_handler!(request, |request: UNotifyEventRequest| {
        // syslog(2) is only allowed if the sandbox lock is off,
        // unless trace/allow_safe_syslog:1 is set at startup.
        let req = request.scmpreq;
        let sandbox = request.get_sandbox();
        if !sandbox.options.allow_safe_syslog() && sandbox.locked_for(req.pid()) {
            return Err(Errno::EPERM);
        }
        drop(sandbox); // release the read-lock.

        // Return EPERM if the global Syslog has not be initialized.
        let syslog = if let Some(syslog) = crate::syslog::global_syslog() {
            syslog
        } else {
            return Err(Errno::EPERM);
        };

        #[expect(clippy::cast_possible_truncation)]
        let action = req.data.args[0] as libc::c_int;
        #[expect(clippy::cast_possible_truncation)]
        let len = req.data.args[2] as libc::c_int;
        if len < 0 {
            return Err(Errno::EINVAL);
        }
        #[expect(clippy::cast_sign_loss)]
        let len = len as usize;
        let (count, buf) = syslog.syslog(action, len)?;
        #[expect(clippy::cast_possible_wrap)]
        if let Some(buf) = buf {
            let n = request.write_mem(&buf, req.data.args[1])?;
            Ok(request.return_syscall(n as i64))
        } else {
            Ok(request.return_syscall(count as i64))
        }
    })
}
