#![warn(missing_docs)]
pub mod checks;
pub mod convert;
pub mod ffi;
pub mod log;
pub use cradle_shared::{CheckResult, CradleError, CradleMutex, CradleResult, Severity};
pub const CRADLE_PLUGIN_API_MAJOR: u16 = 1;
pub const CRADLE_PLUGIN_API_MINOR: u16 = 1;
pub const CRADLE_PLUGIN_API_VERSION: u32 =
((CRADLE_PLUGIN_API_MAJOR as u32) << 16) | CRADLE_PLUGIN_API_MINOR as u32;
pub use checks::*;
pub use convert::{
check_results_to_ffi, ffi_event_to_agent_event, ffi_string_array_to_vec, free_ffi_results,
free_ffi_string, free_ffi_string_array, string_to_ffi_ptr, strings_to_ffi_array,
};
pub use cradle_hooks;
use cradle_hooks::engine::HookEngine;
pub use ffi::*;
pub use log::*;
pub use paste::paste;
#[macro_export]
macro_rules! register_plugin {
($plugin_ty:ty) => {
static __CRADLE_PLUGIN: std::sync::OnceLock<std::sync::Mutex<$plugin_ty>> =
std::sync::OnceLock::new();
#[unsafe(no_mangle)]
pub extern "C" fn cradle_check_api_version() -> u32 {
$crate::CRADLE_PLUGIN_API_VERSION
}
#[unsafe(no_mangle)]
pub extern "C" fn cradle_plugin_kind() -> u32 {
1
}
#[unsafe(no_mangle)]
pub extern "C" fn cradle_plugin_name() -> *mut std::os::raw::c_char {
let p = __CRADLE_PLUGIN
.get_or_init(|| std::sync::Mutex::new(<$plugin_ty as Default>::default()));
let name = match p.lock() {
Ok(plugin) => plugin.name().to_string(),
Err(_) => return std::ptr::null_mut(),
};
$crate::string_to_ffi_ptr(name)
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn cradle_plugin_free_string(ptr: *mut std::os::raw::c_char) {
unsafe {
$crate::free_ffi_string(ptr);
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn cradle_plugin_init(engine_ptr: *mut std::ffi::c_void) -> i32 {
if engine_ptr.is_null() {
$crate::cradle_log(
"[cradle-plugin-api] plugin init received a null engine pointer",
);
return -1;
}
let p = __CRADLE_PLUGIN
.get_or_init(|| std::sync::Mutex::new(<$plugin_ty as Default>::default()));
unsafe {
let arc = std::sync::Arc::from_raw(
engine_ptr as *const std::sync::Mutex<$crate::cradle_hooks::engine::HookEngine>,
);
let arc_clone = std::sync::Arc::clone(&arc);
std::mem::forget(arc);
let cmutex = $crate::CradleMutex(arc_clone);
match p.lock() {
Ok(mut plugin) => match plugin.init(cmutex) {
Ok(()) => 0,
Err(e) => {
$crate::cradle_log(&format!(
"[cradle-plugin-api] failed to load plugin: {e}"
));
-1
}
},
Err(_) => {
$crate::cradle_log("[cradle-plugin-api] failed to lock plugin during init");
-1
}
}
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn cradle_plugin_on_event(event: *const $crate::FfiEvent) -> i32 {
if event.is_null() {
$crate::cradle_log("[cradle-plugin-api] plugin received a null event pointer");
return -1;
}
let p = __CRADLE_PLUGIN
.get_or_init(|| std::sync::Mutex::new(<$plugin_ty as Default>::default()));
unsafe {
let event = $crate::ffi_event_to_agent_event(&*event);
match p.lock() {
Ok(mut plugin) => match plugin.on_event(&event) {
Ok(()) => 0,
Err(e) => {
$crate::cradle_log(&format!(
"[cradle-plugin-api] failed to run plugin: {e}"
));
-1
}
},
Err(_) => {
$crate::cradle_log(
"[cradle-plugin-api] failed to lock plugin during event handling",
);
-1
}
}
}
}
#[unsafe(no_mangle)]
pub extern "C" fn cradle_plugin_collect() -> $crate::FfiResultArray {
let p = __CRADLE_PLUGIN
.get_or_init(|| std::sync::Mutex::new(<$plugin_ty as Default>::default()));
match p.lock() {
Ok(mut plugin) => $crate::check_results_to_ffi(plugin.results()),
Err(_) => $crate::FfiResultArray {
ptr: std::ptr::null_mut(),
len: 0,
},
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn cradle_plugin_free_results(arr: $crate::FfiResultArray) {
unsafe { $crate::free_ffi_results(arr) }
}
#[unsafe(no_mangle)]
pub extern "C" fn cradle_plugin_drain_logs() -> $crate::FfiStringArray {
$crate::strings_to_ffi_array($crate::drain_log())
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn cradle_plugin_free_log_array(arr: $crate::FfiStringArray) {
unsafe { $crate::free_ffi_string_array(arr) }
}
#[unsafe(no_mangle)]
pub extern "C" fn cradle_plugin_cleanup() {
let p = __CRADLE_PLUGIN
.get_or_init(|| std::sync::Mutex::new(<$plugin_ty as Default>::default()));
if let Ok(mut plugin) = p.lock() {
plugin.cleanup();
}
}
};
}
pub trait CradlePlugin: Default + Send {
fn name(&self) -> &str;
fn init(&mut self, engine: CradleMutex<HookEngine>) -> CradleResult {
let _ = engine;
Ok(())
}
fn on_event(&mut self, event: &AgentEvent) -> CradleResult {
let _ = event;
Ok(())
}
fn results(&mut self) -> Vec<CheckResult>;
fn cleanup(&mut self) {}
}