1use std::fmt;
24use std::ops::{BitAnd, Shl};
25use std::path::Path;
26use std::sync::LazyLock;
27
28use nix::libc;
29
30
31use crate::portable;
32
33use super::error::SyRes;
34use super::throw_error;
35
36bitflags! {
37 pub struct LogStat: libc::c_int
40 {
41 const LOG_PID = libc::LOG_PID;
43
44 const LOG_CONS = libc::LOG_CONS;
47
48 const LOG_ODELAY = libc::LOG_ODELAY;
52
53 const LOG_NDELAY = libc::LOG_NDELAY;
55
56 const LOG_NOWAIT = libc::LOG_NOWAIT;
59
60 const LOG_PERROR = 0x20;
62 }
63}
64
65bitflags! {
66 pub(crate) struct LogMask: libc::c_int
67 {
68 const LOG_FACMASK = libc::LOG_FACMASK;
69 const LOG_PRIMASK = libc::LOG_PRIMASK;
70 }
71}
72
73bitflags! {
74 pub struct Priority: libc::c_int
76 {
77 const LOG_EMERG = libc::LOG_EMERG;
79
80 const LOG_ALERT = libc::LOG_ALERT;
82
83 const LOG_CRIT = libc::LOG_CRIT;
85
86 const LOG_ERR = libc::LOG_ERR;
88
89 const LOG_WARNING = libc::LOG_WARNING;
91
92 const LOG_NOTICE = libc::LOG_NOTICE;
94
95 const LOG_INFO = libc::LOG_INFO;
97
98 const LOG_DEBUG = libc::LOG_DEBUG;
100 }
101}
102
103impl fmt::Display for Priority
104{
105 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
106 {
107 if self.contains(Self::LOG_DEBUG) == true
110 {
111 write!(f, "[DEBUG]")
112 }
113 else if self.contains(Self::LOG_INFO) == true
114 {
115 write!(f, "[INFO]")
116 }
117 else if self.contains(Self::LOG_NOTICE) == true
118 {
119 write!(f, "[NOTICE]")
120 }
121 else if self.contains(Self::LOG_WARNING) == true
122 {
123 write!(f, "[WARNING]")
124 }
125 else if self.contains(Self::LOG_ERR) == true
126 {
127 write!(f, "[ERR]")
128 }
129 else if self.contains(Self::LOG_CRIT) == true
130 {
131 write!(f, "[CRIT]")
132 }
133 else if self.contains(Self::LOG_ALERT) == true
134 {
135 write!(f, "[ALERT]")
136 }
137 else if self.contains(Self::LOG_EMERG) == true
138 {
139 write!(f, "[EMERG]")
140 }
141 else
142 {
143 write!(f, "[UNKNOWN]")
144 }
145 }
146}
147
148impl Priority
149{
150 pub(crate)
162 fn check_invalid_bits(&mut self) -> SyRes<()>
163 {
164
165 if (self.bits() & !(LogMask::LOG_PRIMASK | LogMask::LOG_FACMASK )) != 0
166 {
167 let pri_old = self.clone();
168
169 *self = unsafe { Self::from_bits_unchecked( self.bits() & (LogMask::LOG_PRIMASK | LogMask::LOG_FACMASK).bits() ) };
170
171 throw_error!("unknwon facility/priority: {:x}", pri_old);
172 }
173
174 return Ok(());
175 }
176
177 pub(crate)
178 fn set_facility(&mut self, f: LogFacility)
179 {
180 *self = unsafe { Self::from_bits_unchecked(self.bits | f.bits() )};
181 }
182}
183
184bitflags! {
185 pub struct LogFacility: libc::c_int
188 {
189 const LOG_KERN = libc::LOG_KERN;
191
192 const LOG_USER = libc::LOG_USER;
194
195 const LOG_MAIL = libc::LOG_MAIL;
197
198 const LOG_DAEMON = libc::LOG_DAEMON;
200
201 const LOG_AUTH = libc::LOG_AUTH;
203
204 const LOG_SYSLOG = libc::LOG_SYSLOG;
206
207 const LOG_LPR = libc::LOG_LPR;
209
210 const LOG_NEWS = libc::LOG_NEWS;
212
213 const LOG_UUCP = libc::LOG_UUCP;
215
216 const LOG_LOCAL0 = libc::LOG_LOCAL0;
218
219 const LOG_LOCAL1 = libc::LOG_LOCAL1;
221
222 const LOG_LOCAL2 = libc::LOG_LOCAL2;
224
225 const LOG_LOCAL3 = libc::LOG_LOCAL3;
227
228 const LOG_LOCAL4 = libc::LOG_LOCAL4;
230
231 const LOG_LOCAL5 = libc::LOG_LOCAL5;
233
234 const LOG_LOCAL6 = libc::LOG_LOCAL6;
236
237 const LOG_LOCAL7 = libc::LOG_LOCAL7;
239 }
240}
241
242pub const MAXHOSTNAMELEN: usize = 256;
244
245pub const LOG_FACMASK: i32 = 0x03f8;
247
248pub const MAXLINE: usize = 8192;
252
253pub const RFC3164_MAX_PAYLOAD_LEN: usize = 1024;
255
256#[cfg(all(feature = "udp_truncate_1024_bytes", feature = "udp_truncate_1440_bytes"))]
257compile_error!("either 'udp_truncate_1024_bytes' or 'udp_truncate_1440_bytes' should be enabled");
258
259#[cfg(feature = "udp_truncate_1024_bytes")]
261pub const RFC5424_UDP_MAX_PKT_LEN: usize = 1024;
262
263#[cfg(any(feature = "udp_truncate_1440_bytes", all(not(feature = "udp_truncate_1440_bytes"), not(feature = "udp_truncate_1024_bytes"))))]
264pub const RFC5424_UDP_MAX_PKT_LEN: usize = 2048;
265
266#[cfg(feature = "tcp_truncate_1024_bytes")]
267pub const RFC5424_TCP_MAX_PKT_LEN: usize = 1024;
268
269#[cfg(feature = "tcp_truncate_2048_bytes")]
270pub const RFC5424_TCP_MAX_PKT_LEN: usize = 2048;
271
272#[cfg(feature = "tcp_truncate_4096_bytes")]
273pub const RFC5424_TCP_MAX_PKT_LEN: usize = 4096;
274
275#[cfg(feature = "tcp_truncate_max_bytes")]
276pub const RFC5424_TCP_MAX_PKT_LEN: usize = MAXLINE;
277
278pub const RFC_MAX_APP_NAME: usize = 48;
280
281pub const NILVALUE: &'static str = "-";
283
284pub const NILVALUE_B: &'static [u8] = b"-";
286
287pub const WSPACE: &'static str = " ";
288
289pub const NEXTLINE: &'static str = "\n";
290
291pub const PATH_LOG: &'static str = "/var/run/log";
293
294pub const PATH_LOG_PRIV: &'static str = "/var/run/logpriv";
296
297pub const PATH_OLDLOG: &'static str = "/dev/log";
299
300pub const PATH_OSX: &'static str = "/var/run/syslog";
302
303pub static PATH_CONSOLE: LazyLock<&Path> = LazyLock::new(||
311 {
312 Path::new("/dev/console")
313 }
314);
315
316pub static RFC5424_MAX_DGRAM: LazyLock<usize> = LazyLock::new(||
317 {
318 portable::get_local_dgram_maxdgram() as usize
319 }
320);
321
322
323
324#[macro_export]
335macro_rules! LOG_MASK
336{
337 ($($arg:tt)*) => (
338 (1 << $($arg)*)
339 )
340}
341
342#[macro_export]
352macro_rules! LOG_UPTO
353{
354 ($($arg:tt)*) => (
355 ((1 << (($($arg)*) + 1)) - 1)
356 )
357}
358
359pub
361fn get_internal_log() -> libc::c_int
362{
363 return
364 Priority::LOG_ERR.bits() |
365 (LogStat::LOG_CONS| LogStat::LOG_PERROR| LogStat::LOG_PID).bits();
366}
367
368impl Shl<Priority> for i32
369{
370 type Output = i32;
371
372 fn shl(self, rhs: Priority) -> i32
373 {
374 let lhs = self;
375 return lhs << rhs.bits();
376 }
377}
378
379impl BitAnd<Priority> for i32
380{
381 type Output = i32;
382
383 #[inline]
384 fn bitand(self, rhs: Priority) -> i32
385 {
386 return self & rhs.bits();
387 }
388}
389
390impl BitAnd<LogMask> for Priority
391{
392 type Output = Priority;
393
394 #[inline]
395 fn bitand(self, rhs: LogMask) -> Self::Output
396 {
397 return Self {bits: self.bits() & rhs.bits()};
398 }
399}
400
401impl BitAnd<LogMask> for LogFacility
402{
403 type Output = LogFacility;
404
405 #[inline]
406 fn bitand(self, rhs: LogMask) -> Self::Output
407 {
408 return Self {bits: self.bits() & rhs.bits()};
409 }
410}
411
412impl BitAnd<LogMask> for i32
413{
414 type Output = i32;
415
416 #[inline]
417 fn bitand(self, rhs: LogMask) -> i32
418 {
419 return self & rhs.bits();
420 }
421}
422
423#[cfg(any(feature = "use_sync", feature = "use_sync_queue"))]
424pub(crate) mod sync_portion
425{
426 use std::borrow::Cow;
427 use std::io::Write;
428 use std::io::IoSlice;
429 use crate::error::SyRes;
430 use crate::map_error_os;
431
432 pub(crate)
443 fn send_to_fd<W>(mut file_fd: W, msg: &[Cow<'_, str>], newline: &str) -> SyRes<usize>
444 where W: Write
445 {
446 let mut iov_list: Vec<IoSlice<'_>> = Vec::with_capacity(msg.len() + 1);
447
448 msg.iter().for_each(|v| iov_list.push(IoSlice::new(v.as_bytes())));
449 iov_list.push(IoSlice::new(newline.as_bytes()));
450
451 return
452 file_fd
453 .write_vectored(&iov_list)
454 .map_err(|e|
455 map_error_os!(e, "send_to_fd() writev() failed")
456 );
457 }
458}
459
460#[cfg(any(feature = "use_sync", feature = "use_sync_queue"))]
461pub(crate) use self::sync_portion::*;
462
463#[cfg(feature = "use_async")]
464pub(crate) mod async_portion
465{
466 use std::borrow::Cow;
467
468 use tokio::io::AsyncWrite;
469 use tokio::io::AsyncWriteExt;
470 use std::io::IoSlice;
471
472 use crate::error::SyRes;
473 use crate::map_error_os;
474
475 pub(crate) async
486 fn async_send_to_fd<W>(mut file_fd: W, msg: &[Cow<'_, str>], newline: &str) -> SyRes<usize>
487 where W: AsyncWrite + Unpin
488 {
489 let mut iov_list: Vec<IoSlice<'_>> = Vec::with_capacity(msg.len() + 1);
490
491 msg.iter().for_each(|v| iov_list.push(IoSlice::new(v.as_bytes())));
492 iov_list.push(IoSlice::new(newline.as_bytes()));
493
494
495 return
496 file_fd
497 .write_vectored(&iov_list)
498 .await
499 .map_err(|e|
500 map_error_os!(e, "async_send_to_fd() writev() failed")
501 );
502 }
503}
504
505#[cfg(feature = "use_async")]
506pub(crate) use self::async_portion::*;
507
508pub
518fn truncate(lt: &str) -> &str
519{
520 let ltt =
521 match lt.char_indices().nth(lt.len()-1)
522 {
523 None => lt,
524 Some((idx, _)) => <[..idx],
525 };
526 return ltt;
527}
528
529pub
552fn truncate_n<'t>(lt: &'t str, n: usize) -> &'t str
553{
554 if lt.as_bytes().len() <= n
555 {
556 return lt;
557 }
558
559 let mut nn: usize = 0;
560 let mut cc = lt.chars();
561 let mut ln: usize;
562
563 loop
564 {
565 match cc.next()
566 {
567 Some(r) =>
568 {
569 ln = r.len_utf8();
570 nn += ln;
571
572 if nn == n
573 {
574 return <[..nn];
575 }
576 else if nn > n
577 {
578 return <[..nn-ln];
579 }
580 },
581 None =>
582 return lt,
583 }
584 }
585}
586
587
588#[cfg(test)]
589mod tests
590{
591 use std::borrow::Cow;
592
593 use super::*;
594
595 #[cfg(feature = "use_sync")]
596 #[test]
597 fn test_error_message()
598 {
599 let testmsg = Cow::Borrowed("this is test message!");
605 let testmsg2 = Cow::Borrowed(" this is test message 2!");
606 let newline = "\n";
607 let stderr_lock = std::io::stderr().lock();
608 let res = send_to_fd(stderr_lock, &[testmsg, testmsg2], &newline);
609
610 println!("res: {:?}", res);
611
612 assert_eq!(res.is_ok(), true, "err: {}", res.err().unwrap());
613
614 return;
615 }
616
617 #[test]
618 fn test_truncate()
619 {
620 let test = "cat\n";
621
622 let trunc = truncate(test);
623
624 assert_eq!("cat", trunc);
625 }
626
627 #[test]
628 fn test_priority_shl()
629 {
630 assert_eq!((1 << 5), (1 << Priority::LOG_NOTICE));
631 }
632
633 #[test]
634 fn test_truncate_n()
635 {
636 assert_eq!(truncate_n("abcde", 3), "abc");
637 assert_eq!(truncate_n("ボルテ", 4), "ボ");
638 assert_eq!(truncate_n("ボルテ", 5), "ボ");
639 assert_eq!(truncate_n("ボルテ", 6), "ボル");
640 assert_eq!(truncate_n("abcde", 0), "");
641 assert_eq!(truncate_n("abcde", 5), "abcde");
642 assert_eq!(truncate_n("abcde", 6), "abcde");
643 assert_eq!(truncate_n("ДАТА", 3), "Д");
644 assert_eq!(truncate_n("ДАТА", 4), "ДА");
645 assert_eq!(truncate_n("ДАТА", 1), "");
646 }
647
648}