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

use libseccomp::ScmpNotifResp;
use nix::errno::Errno;

use crate::{
    kernel::syscall_path_handler,
    req::{SysArg, UNotifyEventRequest},
    warn,
};

pub(crate) fn sys_chroot(request: UNotifyEventRequest) -> ScmpNotifResp {
    let argv = &[SysArg {
        path: Some(0),
        ..Default::default()
    }];

    #[expect(clippy::cognitive_complexity)]
    syscall_path_handler(request, "chroot", argv, |path_args, request, sandbox| {
        let is_chroot = sandbox.is_chroot();
        drop(sandbox); // release the read lock.

        // SAFETY: SysArg has one element.
        #[expect(clippy::disallowed_methods)]
        let path = path_args.0.as_ref().unwrap();

        if let Some(typ) = path.typ.as_ref() {
            if !typ.is_dir() {
                return Err(Errno::ENOTDIR);
            }
        } else {
            return Err(Errno::ENOENT);
        }

        // SAFETY: Do not allow nested chroots.
        if is_chroot {
            return Err(Errno::EACCES);
        }

        // Acquire a write lock and chroot the sandbox.
        let mut sandbox = request.get_mut_sandbox();
        sandbox.chroot();
        let log_scmp = sandbox.log_scmp();
        drop(sandbox); // release the write-lock.

        if log_scmp {
            warn!("ctx": "chroot_sandbox",
                "sys": "chroot", "path": &path,
                "msg": "change root approved",
                "req": request);
        } else {
            warn!("ctx": "chroot_sandbox",
                "sys": "chroot", "path": &path,
                "msg": "change root approved",
                "pid": request.scmpreq.pid);
        }

        // Return success to the caller.
        Ok(request.return_syscall(0))
    })
}
