use std::fmt;
use std::ops::{BitAnd, Shl};
use std::path::Path;
use std::sync::LazyLock;
use nix::libc;
use crate::portable;
use super::error::SyRes;
use super::throw_error;
bitflags! {
pub struct LogStat: libc::c_int
{
const LOG_PID = libc::LOG_PID;
const LOG_CONS = libc::LOG_CONS;
const LOG_ODELAY = libc::LOG_ODELAY;
const LOG_NDELAY = libc::LOG_NDELAY;
const LOG_NOWAIT = libc::LOG_NOWAIT;
const LOG_PERROR = 0x20;
}
}
bitflags! {
pub(crate) struct LogMask: libc::c_int
{
const LOG_FACMASK = libc::LOG_FACMASK;
const LOG_PRIMASK = libc::LOG_PRIMASK;
}
}
bitflags! {
pub struct Priority: libc::c_int
{
const LOG_EMERG = libc::LOG_EMERG;
const LOG_ALERT = libc::LOG_ALERT;
const LOG_CRIT = libc::LOG_CRIT;
const LOG_ERR = libc::LOG_ERR;
const LOG_WARNING = libc::LOG_WARNING;
const LOG_NOTICE = libc::LOG_NOTICE;
const LOG_INFO = libc::LOG_INFO;
const LOG_DEBUG = libc::LOG_DEBUG;
}
}
impl fmt::Display for Priority
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
{
if self.contains(Self::LOG_DEBUG) == true
{
write!(f, "[DEBUG]")
}
else if self.contains(Self::LOG_INFO) == true
{
write!(f, "[INFO]")
}
else if self.contains(Self::LOG_NOTICE) == true
{
write!(f, "[NOTICE]")
}
else if self.contains(Self::LOG_WARNING) == true
{
write!(f, "[WARNING]")
}
else if self.contains(Self::LOG_ERR) == true
{
write!(f, "[ERR]")
}
else if self.contains(Self::LOG_CRIT) == true
{
write!(f, "[CRIT]")
}
else if self.contains(Self::LOG_ALERT) == true
{
write!(f, "[ALERT]")
}
else if self.contains(Self::LOG_EMERG) == true
{
write!(f, "[EMERG]")
}
else
{
write!(f, "[UNKNOWN]")
}
}
}
impl Priority
{
pub(crate)
fn check_invalid_bits(&mut self) -> SyRes<()>
{
if (self.bits() & !(LogMask::LOG_PRIMASK | LogMask::LOG_FACMASK )) != 0
{
let pri_old = self.clone();
*self = unsafe { Self::from_bits_unchecked( self.bits() & (LogMask::LOG_PRIMASK | LogMask::LOG_FACMASK).bits() ) };
throw_error!("unknwon facility/priority: {:x}", pri_old);
}
return Ok(());
}
pub(crate)
fn set_facility(&mut self, f: LogFacility)
{
*self = unsafe { Self::from_bits_unchecked(self.bits | f.bits() )};
}
}
bitflags! {
pub struct LogFacility: libc::c_int
{
const LOG_KERN = libc::LOG_KERN;
const LOG_USER = libc::LOG_USER;
const LOG_MAIL = libc::LOG_MAIL;
const LOG_DAEMON = libc::LOG_DAEMON;
const LOG_AUTH = libc::LOG_AUTH;
const LOG_SYSLOG = libc::LOG_SYSLOG;
const LOG_LPR = libc::LOG_LPR;
const LOG_NEWS = libc::LOG_NEWS;
const LOG_UUCP = libc::LOG_UUCP;
const LOG_LOCAL0 = libc::LOG_LOCAL0;
const LOG_LOCAL1 = libc::LOG_LOCAL1;
const LOG_LOCAL2 = libc::LOG_LOCAL2;
const LOG_LOCAL3 = libc::LOG_LOCAL3;
const LOG_LOCAL4 = libc::LOG_LOCAL4;
const LOG_LOCAL5 = libc::LOG_LOCAL5;
const LOG_LOCAL6 = libc::LOG_LOCAL6;
const LOG_LOCAL7 = libc::LOG_LOCAL7;
}
}
pub const MAXHOSTNAMELEN: usize = 256;
pub const LOG_FACMASK: i32 = 0x03f8;
pub const MAXLINE: usize = 8192;
pub const RFC3164_MAX_PAYLOAD_LEN: usize = 1024;
#[cfg(all(feature = "udp_truncate_1024_bytes", feature = "udp_truncate_1440_bytes"))]
compile_error!("either 'udp_truncate_1024_bytes' or 'udp_truncate_1440_bytes' should be enabled");
#[cfg(feature = "udp_truncate_1024_bytes")]
pub const RFC5424_UDP_MAX_PKT_LEN: usize = 1024;
#[cfg(any(feature = "udp_truncate_1440_bytes", all(not(feature = "udp_truncate_1440_bytes"), not(feature = "udp_truncate_1024_bytes"))))]
pub const RFC5424_UDP_MAX_PKT_LEN: usize = 2048;
#[cfg(feature = "tcp_truncate_1024_bytes")]
pub const RFC5424_TCP_MAX_PKT_LEN: usize = 1024;
#[cfg(feature = "tcp_truncate_2048_bytes")]
pub const RFC5424_TCP_MAX_PKT_LEN: usize = 2048;
#[cfg(feature = "tcp_truncate_4096_bytes")]
pub const RFC5424_TCP_MAX_PKT_LEN: usize = 4096;
#[cfg(feature = "tcp_truncate_max_bytes")]
pub const RFC5424_TCP_MAX_PKT_LEN: usize = MAXLINE;
pub const RFC_MAX_APP_NAME: usize = 48;
pub const NILVALUE: &'static str = "-";
pub const NILVALUE_B: &'static [u8] = b"-";
pub const WSPACE: &'static str = " ";
pub const NEXTLINE: &'static str = "\n";
pub const PATH_LOG: &'static str = "/var/run/log";
pub const PATH_LOG_PRIV: &'static str = "/var/run/logpriv";
pub const PATH_OLDLOG: &'static str = "/dev/log";
pub const PATH_OSX: &'static str = "/var/run/syslog";
pub static PATH_CONSOLE: LazyLock<&Path> = LazyLock::new(||
{
Path::new("/dev/console")
}
);
pub static RFC5424_MAX_DGRAM: LazyLock<usize> = LazyLock::new(||
{
portable::get_local_dgram_maxdgram() as usize
}
);
#[macro_export]
macro_rules! LOG_MASK
{
($($arg:tt)*) => (
(1 << $($arg)*)
)
}
#[macro_export]
macro_rules! LOG_UPTO
{
($($arg:tt)*) => (
((1 << (($($arg)*) + 1)) - 1)
)
}
pub
fn get_internal_log() -> libc::c_int
{
return
Priority::LOG_ERR.bits() |
(LogStat::LOG_CONS| LogStat::LOG_PERROR| LogStat::LOG_PID).bits();
}
impl Shl<Priority> for i32
{
type Output = i32;
fn shl(self, rhs: Priority) -> i32
{
let lhs = self;
return lhs << rhs.bits();
}
}
impl BitAnd<Priority> for i32
{
type Output = i32;
#[inline]
fn bitand(self, rhs: Priority) -> i32
{
return self & rhs.bits();
}
}
impl BitAnd<LogMask> for Priority
{
type Output = Priority;
#[inline]
fn bitand(self, rhs: LogMask) -> Self::Output
{
return Self {bits: self.bits() & rhs.bits()};
}
}
impl BitAnd<LogMask> for LogFacility
{
type Output = LogFacility;
#[inline]
fn bitand(self, rhs: LogMask) -> Self::Output
{
return Self {bits: self.bits() & rhs.bits()};
}
}
impl BitAnd<LogMask> for i32
{
type Output = i32;
#[inline]
fn bitand(self, rhs: LogMask) -> i32
{
return self & rhs.bits();
}
}
#[cfg(feature = "build_sync")]
pub(crate) mod sync_portion
{
use std::borrow::Cow;
use std::io::Write;
use std::io::IoSlice;
use crate::error::SyRes;
use crate::map_error_os;
pub(crate)
fn send_to_fd<W>(mut file_fd: W, msg: &[Cow<'_, str>], newline: &str) -> SyRes<usize>
where W: Write
{
let mut iov_list: Vec<IoSlice<'_>> = Vec::with_capacity(msg.len() + 1);
msg.iter().for_each(|v| iov_list.push(IoSlice::new(v.as_bytes())));
iov_list.push(IoSlice::new(newline.as_bytes()));
return
file_fd
.write_vectored(&iov_list)
.map_err(|e|
map_error_os!(e, "send_to_fd() writev() failed")
);
}
}
#[cfg(feature = "build_sync")]
pub(crate) use self::sync_portion::*;
pub
fn truncate(lt: &str) -> &str
{
let ltt =
match lt.char_indices().nth(lt.len()-1)
{
None => lt,
Some((idx, _)) => <[..idx],
};
return ltt;
}
pub
fn truncate_n<'t>(lt: &'t str, n: usize) -> &'t str
{
if lt.as_bytes().len() <= n
{
return lt;
}
let mut nn: usize = 0;
let mut cc = lt.chars();
let mut ln: usize;
loop
{
match cc.next()
{
Some(r) =>
{
ln = r.len_utf8();
nn += ln;
if nn == n
{
return <[..nn];
}
else if nn > n
{
return <[..nn-ln];
}
},
None =>
return lt,
}
}
}
#[cfg(test)]
mod tests
{
use std::borrow::Cow;
use super::*;
#[cfg(feature = "build_sync")]
#[test]
fn test_error_message()
{
let testmsg = Cow::Borrowed("this is test message!");
let testmsg2 = Cow::Borrowed(" this is test message 2!");
let newline = "\n";
let stderr_lock = std::io::stderr().lock();
let res = send_to_fd(stderr_lock, &[testmsg, testmsg2], &newline);
println!("res: {:?}", res);
assert_eq!(res.is_ok(), true, "err: {}", res.err().unwrap());
return;
}
#[test]
fn test_truncate()
{
let test = "cat\n";
let trunc = truncate(test);
assert_eq!("cat", trunc);
}
#[test]
fn test_priority_shl()
{
assert_eq!((1 << 5), (1 << Priority::LOG_NOTICE));
}
#[test]
fn test_truncate_n()
{
assert_eq!(truncate_n("abcde", 3), "abc");
assert_eq!(truncate_n("ボルテ", 4), "ボ");
assert_eq!(truncate_n("ボルテ", 5), "ボ");
assert_eq!(truncate_n("ボルテ", 6), "ボル");
assert_eq!(truncate_n("abcde", 0), "");
assert_eq!(truncate_n("abcde", 5), "abcde");
assert_eq!(truncate_n("abcde", 6), "abcde");
assert_eq!(truncate_n("ДАТА", 3), "Д");
assert_eq!(truncate_n("ДАТА", 4), "ДА");
assert_eq!(truncate_n("ДАТА", 1), "");
}
}