diversion 0.2.0

Ergonomic function hooks for Windows and Linux
Documentation
#![allow(non_camel_case_types, non_snake_case)]

use std::{
    ffi::{c_int, c_long, c_short, c_uint, c_void},
    mem,
};

use libc::{
    SI_QUEUE, SYS_rt_tgsigqueueinfo, clock_t, getpid, getuid, pid_t, sigval, syscall, ucontext_t,
    uid_t,
};

pub type sa_handler = unsafe extern "C" fn(c_int);
pub type sa_sigaction = unsafe extern "C" fn(c_int, *mut siginfo_t, *mut ucontext_t);

const __SI_MAX_SIZE: usize = 128;
const __SI_PAD_SIZE: usize = if cfg!(target_pointer_width = "64") {
    __SI_MAX_SIZE / size_of::<c_int>() - 4
} else {
    __SI_MAX_SIZE / size_of::<c_int>() - 3
};

#[derive(Clone, Copy)]
#[repr(C)]
pub struct siginfo_t {
    pub si_signo: c_int,
    pub si_errno: c_int,
    pub si_code: c_int,
    #[cfg(target_pointer_width = "64")]
    __pad0: c_int,
    pub _sifields: __c_anonymous_siginfo_t__si_fields,
}

#[derive(Clone, Copy)]
#[repr(C)]
pub union __c_anonymous_siginfo_t__si_fields {
    _pad: [c_int; __SI_PAD_SIZE],
    pub _kill: __c_anonymous__si_fields__kill,
    pub _timer: __c_anonymous__si_fields__timer,
    pub _rt: __c_anonymous__si_fields__rt,
    pub _sigchld: __c_anonymous__si_fields__sigchld,
    pub _sigfault: __c_anonymous__si_fields__sigfault,
    pub _sigpoll: __c_anonymous__si_fields__sigpoll,
    pub _sigsys: __c_anonymous__si_fields__sigsys,
}

#[derive(Clone, Copy)]
#[repr(C)]
pub struct __c_anonymous__si_fields__kill {
    pub si_pid: pid_t,
    pub si_uid: uid_t,
}

#[derive(Clone, Copy)]
#[repr(C)]
pub struct __c_anonymous__si_fields__timer {
    pub si_tid: c_int,
    pub si_overrun: c_int,
    pub si_sigval: sigval,
}

#[derive(Clone, Copy)]
#[repr(C)]
pub struct __c_anonymous__si_fields__rt {
    pub si_pid: pid_t,
    pub si_uid: uid_t,
    pub si_sigval: sigval,
}

#[derive(Clone, Copy)]
#[repr(C)]
pub struct __c_anonymous__si_fields__sigchld {
    pub si_pid: pid_t,
    pub si_uid: uid_t,
    pub si_status: c_int,
    pub si_utime: clock_t,
    pub si_stime: clock_t,
}

#[derive(Clone, Copy)]
#[repr(C)]
pub struct __c_anonymous__si_fields__sigfault {
    pub si_addr: *mut c_void,
    pub si_addr_lsb: c_short,
    pub _bounds: __c_anonymous__sigfault__bounds,
}

#[derive(Clone, Copy)]
#[repr(C)]
pub struct __c_anonymous__si_fields__sigpoll {
    pub si_band: c_long,
    pub si_fd: c_int,
}

#[derive(Clone, Copy)]
#[repr(C)]
pub struct __c_anonymous__si_fields__sigsys {
    pub _call_addr: *mut c_void,
    pub _syscall: c_int,
    pub _arch: c_uint,
}

#[derive(Clone, Copy)]
#[repr(C)]
pub union __c_anonymous__sigfault__bounds {
    pub _addr_bnd: __c_anonymous__bounds__addr_bnd,
    pub _pkey: u32,
}

#[derive(Clone, Copy)]
#[repr(C)]
pub struct __c_anonymous__bounds__addr_bnd {
    pub _lower: *mut c_void,
    pub _upper: *mut c_void,
}

pub unsafe fn rt_tgsigqueueinfo(
    tgid: pid_t,
    tid: pid_t,
    sig: c_int,
    sival_ptr: *mut c_void,
) -> c_int {
    unsafe {
        let mut siginfo = mem::zeroed::<siginfo_t>();
        siginfo.si_signo = sig;
        siginfo.si_code = SI_QUEUE;
        siginfo._sifields._rt.si_pid = getpid();
        siginfo._sifields._rt.si_uid = getuid();
        siginfo._sifields._rt.si_sigval = sigval { sival_ptr };
        syscall(SYS_rt_tgsigqueueinfo, tgid, tid, sig, &raw mut siginfo) as c_int
    }
}