#[cfg(target_os = "linux")]
pub(crate) use self::portable_linux::*;
#[cfg(any(
target_os = "freebsd",
target_os = "dragonfly",
target_os = "openbsd",
target_os = "netbsd",
target_os = "macos"
))]
pub(crate) use self::portable_bsd::*;
#[cfg(target_family = "windows")]
pub(crate) use self::portable_windows::*;
#[cfg(target_family = "windows")]
pub mod portable_windows
{
use std::
{
env, ffi::{CStr, c_void}, io::{self, ErrorKind}, mem::transmute, time::Duration
};
use windows::
{
Win32::
{
Foundation::HANDLE,
Networking::WinSock::{self, SOCKET_ERROR},
System::
{
EventLog::{EVENTLOG_INFORMATION_TYPE, RegisterEventSourceA, ReportEventA},
SystemInformation
}
},
core::{Free, PCSTR}
};
use crate::{LogFacility, LogMask, NILVALUE, Priority, SyslogMsgPriFac, WindowsEvent, error::SyRes};
pub const DEFAULT_MAXGRAM_SIZE: u64 = 2048;
#[derive(Debug)]
pub struct EventLogLocal
{
evs: usize,
}
impl Drop for EventLogLocal
{
fn drop(&mut self)
{
unsafe { HANDLE(self.evs as *mut c_void).free() };
}
}
impl EventLogLocal
{
pub
fn new(winnie_ev: &WindowsEvent) -> io::Result<Self>
{
let evs =
unsafe
{
RegisterEventSourceA(
winnie_ev
.get_server_unc()
.map_or(
PCSTR::null(),
|f| PCSTR::from_raw( transmute(f.as_ptr()) )
),
PCSTR::from_raw(
transmute(winnie_ev.get_service_name().as_ptr())
)
)
}
.map_err(|e|
io::Error::new(ErrorKind::ConnectionRefused, e)
)?;
return Ok(Self{ evs: evs.0 as usize });
}
pub
fn send(&self, msg: &[u8]) -> io::Result<usize>
{
if msg.len() == 0
{
return Ok(0);
}
let mut event_log_type = EVENTLOG_INFORMATION_TYPE;
let mut facility = LogFacility::LOG_USER.into_win_facility();
if msg[0] == '|' as u8
{
for (idx, c) in msg.iter().enumerate().skip(1)
{
if *c == '|' as u8
{
let Ok(pri_fac) =
SyslogMsgPriFac::try_from(&msg[1..idx])
else { break };
event_log_type = pri_fac.get_priority().into();
facility = pri_fac.get_log_facility().into_win_facility();
break;
}
if idx == 8
{
break;
}
}
}
let cmsg =
CStr::from_bytes_with_nul(msg)
.map_err(|e|
io::Error::new(ErrorKind::InvalidData, e)
)?;
let msgs =
&[PCSTR::from_raw( unsafe { transmute( cmsg.as_ptr()) })];
unsafe
{
ReportEventA(
HANDLE(self.evs as *mut c_void),
event_log_type, 1,
0x20010000 | facility,
None,
0,
Some(msgs),
None
)
}
.map_err(|e|
io::Error::new(ErrorKind::ConnectionRefused, e)
)?;
return Ok(msg.len());
}
}
pub(crate)
fn p_getprogname() -> Option<String>
{
return
env::current_exe()
.ok()
.map_or(None,
|path|
path
.file_name()
.map(|name| name.to_string_lossy().to_string())
);
}
pub(crate)
fn get_local_dgram_maxdgram() -> u64
{
return DEFAULT_MAXGRAM_SIZE;
}
pub(crate)
fn get_uptime() -> SyRes<Duration>
{
let ret: u64 = unsafe {SystemInformation::GetTickCount64() };
return Ok(Duration::from_millis(ret));
}
pub(crate)
fn portable_gethostname() -> SyRes<String>
{
let mut hostname = vec![0_u8; 512];
let res =
unsafe
{
WinSock::gethostname(&mut hostname)
};
if res == SOCKET_ERROR
{
let err = unsafe { WinSock::WSAGetLastError() };
throw_error!("can bot obtain kern.boottime, err: '{}'", err.0);
}
return Ok(String::from_utf8(hostname).map_or(NILVALUE.into(), |f| f));
}
}
#[cfg(target_os = "linux")]
pub mod portable_linux
{
use std::ffi::CStr;
use std::path::Path;
use std::time::Duration;
use nix::libc;
use crate::error::SyRes;
use crate::{map_error};
pub const DEFAULT_MAXGRAM_SIZE: u64 = 2048;
#[link(name = "c")]
unsafe extern "C" {
pub static mut program_invocation_name : *mut libc::c_char ;
}
pub(crate)
fn p_getprogname() -> Option<String>
{
let pn = unsafe{ program_invocation_name };
let temp = unsafe {CStr::from_ptr(pn)};
return
temp
.to_str()
.ok()
.map_or(None, |r| Path::new(r).file_name().map(|r| r.to_string_lossy().into()));
}
pub(crate)
fn get_local_dgram_maxdgram() -> u64
{
return DEFAULT_MAXGRAM_SIZE;
}
pub(crate)
fn get_uptime() -> SyRes<Duration>
{
let sysinfo =
nix::sys::sysinfo::sysinfo()
.map_err(|e|
map_error!("get_uptime() sysinfo error: {}", e)
)?;
return Ok(sysinfo.uptime());
}
pub(crate)
fn portable_gethostname() -> SyRes<String>
{
return
nix::unistd::gethostname()
.map_or_else(
|e|
Err(map_error!("gethostname() error: {}", e)),
|hn|
hn.into_string()
.map_or(
Err(map_error!("gethostname() into_string() error")),
|hostname| Ok(hostname)
)
);
}
}
#[cfg(any(
target_os = "freebsd",
target_os = "dragonfly",
target_os = "openbsd",
target_os = "netbsd",
target_os = "macos"
))]
pub mod portable_bsd
{
use std::{ffi::{CStr, CString}, time::Duration};
use chrono::Local;
use nix::{errno::Errno, libc::{self, timeval}};
use crate::error::SyRes;
pub const DEFAULT_MAXGRAM_SIZE: u64 = 2048;
#[link(name = "c")]
unsafe extern "C" {
fn getprogname() -> *const libc::c_char;
}
pub(crate)
fn p_getprogname() -> Option<String>
{
let pn = unsafe { getprogname() };
let temp = unsafe {CStr::from_ptr(pn)};
match temp.to_str()
{
Ok(r) =>
return Some(r.to_string()),
Err(_) =>
return None,
}
}
pub(crate)
fn get_local_dgram_maxdgram() -> u64
{
let name = CString::new("net.local.dgram.maxdgram").unwrap();
let mut maxdgram: u64 = 0;
let mut maxdgram_size: libc::size_t = std::mem::size_of_val(&maxdgram) as libc::size_t;
let res =
unsafe
{
libc::sysctlbyname(
name.as_ptr(),
&mut maxdgram as *mut _ as *mut libc::c_void,
&mut maxdgram_size as *mut _ as *mut libc::size_t,
std::ptr::null(),
0)
};
if res == -1
{
if cfg!(feature = "dgram_sysctl_failure_panic")
{
let err = Errno::last_raw();
panic!("can not obtain MAXDGRAM from sysctl '{}', err: '{}'", name.to_string_lossy(), err);
}
else
{
return DEFAULT_MAXGRAM_SIZE;
}
}
else if res == 0
{
return maxdgram;
}
else
{
panic!("can not obtain MAXDGRAM from sysctl '{}', unknwon res: '{}'", name.to_string_lossy(), res);
}
}
pub(crate)
fn get_uptime() -> SyRes<Duration>
{
let name = CString::new("kern.boottime").unwrap();
let mut boottime: timeval = unsafe { std::mem::zeroed() };
let mut size: libc::size_t = std::mem::size_of_val(&boottime) as libc::size_t;
let res =
unsafe
{
libc::sysctlbyname(
name.as_ptr(),
&mut boottime as *mut _ as *mut libc::c_void,
&mut size as *mut _ as *mut libc::size_t,
std::ptr::null(),
0)
};
if res == -1
{
throw_error!("can bot obtain kern.boottime, err: '{}'", Errno::last_raw());
}
else if res == 0
{
let c =
chrono::Duration::new(boottime.tv_sec, boottime.tv_usec as u32)
.ok_or_else(||
map_error!("timeval to chrono::Duration converion error")
)?;
let now = Local::now();
let r =
now
.checked_sub_signed(c)
.ok_or_else(||
map_error!("error checked_sub_signed()")
)?;
return Ok(Duration::from_millis(r.timestamp_millis() as u64));
}
else
{
throw_error!("can not obtain kern.boottime from sysctl '{}', unknwon res: '{}'", name.to_string_lossy(), res);
}
}
pub(crate)
fn portable_gethostname() -> SyRes<String>
{
return
nix::unistd::gethostname()
.map_or_else(
|e|
Err(map_error!("gethostname() error: {}", e)),
|hn|
hn.into_string()
.map_or(
Err(map_error!("gethostname() into_string() error")),
|hostname| Ok(hostname)
)
);
}
#[cfg(test)]
mod tests
{
use crate::portable::get_uptime;
#[test]
fn test_get_uptime()
{
let res = get_uptime();
assert_eq!(res.is_ok(), true);
println!("{:?}", res.unwrap());
}
}
}
#[inline]
pub
fn get_pid() -> u32
{
return std::process::id();
}
#[cfg(test)]
mod test_portables
{
use super::*;
#[test]
fn test_get_procname()
{
let procname = p_getprogname();
println!("Processname is: {:?}", procname);
assert_eq!(procname.is_some(), true);
assert_eq!(procname.as_ref().unwrap().starts_with("syslog_rs"), true);
}
#[test]
fn test_maxgram()
{
let max = get_local_dgram_maxdgram();
println!("maxdgram: '{}'", max);
assert_eq!(max > 0, true);
}
}