1use std::{borrow::Cow, ops::{BitAnd, Shl}, path::Path, sync::LazyLock};
20
21use crate::{error::SyRes, portable, throw_error};
22
23#[cfg(target_family = "windows")]
24pub use self::common_eventlog_items::*;
25
26#[cfg(target_family = "unix")]
27pub use self::common_syslog_items::*;
28
29#[cfg(target_family = "windows")]
30pub mod common_eventlog_items
31{
32 use std::fmt;
33
34 use windows::Win32::System::EventLog::{EVENTLOG_ERROR_TYPE, EVENTLOG_INFORMATION_TYPE, EVENTLOG_SUCCESS, EVENTLOG_WARNING_TYPE, REPORT_EVENT_TYPE};
35
36 use crate::{error::SyRes, throw_error};
37
38 bitflags! {
39 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
41 pub struct Priority: i32
42 {
43 const LOG_EMERG = EVENTLOG_WARNING_TYPE.0 as i32;
45
46 const LOG_ALERT = EVENTLOG_WARNING_TYPE.0 as i32;
48
49 const LOG_CRIT = EVENTLOG_WARNING_TYPE.0 as i32;
51
52 const LOG_ERR = EVENTLOG_ERROR_TYPE.0 as i32;
54
55 const LOG_WARNING = EVENTLOG_INFORMATION_TYPE.0 as i32;
57
58 const LOG_NOTICE = EVENTLOG_INFORMATION_TYPE.0 as i32;
60
61 const LOG_INFO = EVENTLOG_SUCCESS.0 as i32;
63
64 const LOG_DEBUG = EVENTLOG_SUCCESS.0 as i32;
66 }
67 }
68
69 impl fmt::Display for Priority
70 {
71 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
72 {
73 if self.contains(Self::LOG_DEBUG) == true
76 {
77 write!(f, "[DEBUG]")
78 }
79 else if self.contains(Self::LOG_INFO) == true
80 {
81 write!(f, "[INFO]")
82 }
83 else if self.contains(Self::LOG_NOTICE) == true
84 {
85 write!(f, "[NOTICE]")
86 }
87 else if self.contains(Self::LOG_WARNING) == true
88 {
89 write!(f, "[WARNING]")
90 }
91 else if self.contains(Self::LOG_ERR) == true
92 {
93 write!(f, "[ERR]")
94 }
95 else if self.contains(Self::LOG_CRIT) == true
96 {
97 write!(f, "[CRIT]")
98 }
99 else if self.contains(Self::LOG_ALERT) == true
100 {
101 write!(f, "[ALERT]")
102 }
103 else if self.contains(Self::LOG_EMERG) == true
104 {
105 write!(f, "[EMERG]")
106 }
107 else
108 {
109 write!(f, "[UNKNOWN]")
110 }
111 }
112 }
113
114 impl From<Priority> for REPORT_EVENT_TYPE
115 {
116 fn from(value: Priority) -> Self
117 {
118 return Self(value.bits() as u16);
119 }
120 }
121
122 impl Priority
123 {
124 pub(crate)
126 fn set_facility(&mut self, f: LogFacility)
127 {
128 *self = Self::from_bits_retain(self.bits() | f.bits() );
129 }
130
131 pub(crate)
143 fn check_invalid_bits(&mut self) -> SyRes<()>
144 {
145
146 if (self.bits() & !(LogMask::LOG_PRIMASK | LogMask::LOG_FACMASK )) != 0
147 {
148 let pri_old = self.clone();
149
150 *self = Self::from_bits_retain(self.bits() & (LogMask::LOG_PRIMASK | LogMask::LOG_FACMASK).bits() );
151
152 throw_error!("unknwon facility/priority: {:x}", pri_old);
153 }
154
155 return Ok(());
156 }
157 }
158
159 bitflags! {
160 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
161 pub(crate) struct LogMask: i32
162 {
163 const LOG_FACMASK = 0x3f8;
164 const LOG_PRIMASK = 7;
165 }
166 }
167
168 bitflags! {
169 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
171 pub struct LogStat: i32
172 {
173 const LOG_PID = 1;
175
176 const LOG_CONS = 2;
179
180 const LOG_ODELAY = 0;
184
185 const LOG_NDELAY = 0;
187
188 const LOG_NOWAIT = 0;
191
192 const LOG_PERROR = 0x20;
194 }
195 }
196
197 #[cfg(feature = "build_sync")]
198 impl LogStat
199 {
200 #[inline]
201 pub(crate)
202 fn send_to_stderr(&self, msg: &str)
203 {
204 if self.intersects(LogStat::LOG_PERROR) == true
205 {
206 eprintln!("{}", msg);
207 }
208 }
209
210 #[inline]
211 pub(crate)
212 fn send_to_syscons(&self, msg_payload: &str)
213 {
214 if self.intersects(LogStat::LOG_CONS)
215 {
216 eprintln!("{}", msg_payload);
217 }
218 }
219 }
220
221 bitflags! {
222 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
225 pub struct LogFacility: i32
226 {
227 const LOG_KERN = 8;
229
230 const LOG_USER = 16;
232
233 const LOG_MAIL = 24;
235
236 const LOG_DAEMON = 32;
238
239 const LOG_AUTH = 40;
241
242 const LOG_SYSLOG = 48;
244
245 const LOG_LPR = 56;
247
248 const LOG_NEWS = 64;
250
251 const LOG_UUCP = 72;
253
254 const LOG_LOCAL0 = 80;
256
257 const LOG_LOCAL1 = 88;
259
260 const LOG_LOCAL2 = 96;
262
263 const LOG_LOCAL3 = 104;
265
266 const LOG_LOCAL4 = 112;
268
269 const LOG_LOCAL5 = 120;
271
272 const LOG_LOCAL6 = 128;
274
275 const LOG_LOCAL7 = 136;
277 }
278 }
279
280 impl LogFacility
281 {
282 pub
283 fn into_win_facility(self) -> u32
284 {
285 return self.bits() as u32 >> 3;
286 }
287 }
288}
289
290#[cfg(target_family = "unix")]
291pub mod common_syslog_items
292{
293 use nix::libc;
294
295 use std::fmt;
296 use crate::error::SyRes;
297
298 use super::throw_error;
299
300 bitflags! {
301 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
303 pub struct LogStat: libc::c_int
304 {
305 const LOG_PID = libc::LOG_PID;
307
308 const LOG_CONS = libc::LOG_CONS;
311
312 const LOG_ODELAY = libc::LOG_ODELAY;
316
317 const LOG_NDELAY = libc::LOG_NDELAY;
319
320 const LOG_NOWAIT = libc::LOG_NOWAIT;
323
324 const LOG_PERROR = 0x20;
326 }
327 }
328
329 #[cfg(feature = "build_sync")]
330 impl LogStat
331 {
332 #[inline]
333 pub(crate)
334 fn send_to_stderr(&self, msg: &str)
335 {
336 if self.intersects(LogStat::LOG_PERROR) == true
337 {
338 let stderr_lock = std::io::stderr().lock();
339 let newline = "\n";
340
341 let _ = send_to_fd(stderr_lock, msg, &newline);
342 }
343 }
344
345 #[inline]
346 pub(crate)
347 fn send_to_syscons(&self, msg_payload: &str)
348 {
349 use std::fs::File;
350 use std::os::unix::fs::OpenOptionsExt;
351
352 if self.intersects(LogStat::LOG_CONS)
353 {
354 use crate::PATH_CONSOLE;
355
356 let syscons =
357 File
358 ::options()
359 .create(false)
360 .read(false)
361 .write(true)
362 .custom_flags(libc::O_NONBLOCK | libc::O_CLOEXEC)
363 .open(*PATH_CONSOLE);
364
365 if let Ok(file) = syscons
366 {
367 let newline = "\n";
368 let _ = send_to_fd(file, msg_payload, newline);
369 }
370 }
371 }
372 }
373
374 bitflags! {
375 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
376 pub(crate) struct LogMask: libc::c_int
377 {
378 const LOG_FACMASK = libc::LOG_FACMASK;
379 const LOG_PRIMASK = libc::LOG_PRIMASK;
380 }
381 }
382
383 bitflags! {
384 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
386 pub struct Priority: libc::c_int
387 {
388 const LOG_EMERG = libc::LOG_EMERG;
390
391 const LOG_ALERT = libc::LOG_ALERT;
393
394 const LOG_CRIT = libc::LOG_CRIT;
396
397 const LOG_ERR = libc::LOG_ERR;
399
400 const LOG_WARNING = libc::LOG_WARNING;
402
403 const LOG_NOTICE = libc::LOG_NOTICE;
405
406 const LOG_INFO = libc::LOG_INFO;
408
409 const LOG_DEBUG = libc::LOG_DEBUG;
411 }
412 }
413
414 impl fmt::Display for Priority
415 {
416 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
417 {
418 if self.contains(Self::LOG_DEBUG) == true
421 {
422 write!(f, "[DEBUG]")
423 }
424 else if self.contains(Self::LOG_INFO) == true
425 {
426 write!(f, "[INFO]")
427 }
428 else if self.contains(Self::LOG_NOTICE) == true
429 {
430 write!(f, "[NOTICE]")
431 }
432 else if self.contains(Self::LOG_WARNING) == true
433 {
434 write!(f, "[WARNING]")
435 }
436 else if self.contains(Self::LOG_ERR) == true
437 {
438 write!(f, "[ERR]")
439 }
440 else if self.contains(Self::LOG_CRIT) == true
441 {
442 write!(f, "[CRIT]")
443 }
444 else if self.contains(Self::LOG_ALERT) == true
445 {
446 write!(f, "[ALERT]")
447 }
448 else if self.contains(Self::LOG_EMERG) == true
449 {
450 write!(f, "[EMERG]")
451 }
452 else
453 {
454 write!(f, "[UNKNOWN]")
455 }
456 }
457 }
458
459 impl Priority
460 {
461 pub(crate)
473 fn check_invalid_bits(&mut self) -> SyRes<()>
474 {
475
476 if (self.bits() & !(LogMask::LOG_PRIMASK | LogMask::LOG_FACMASK )) != 0
477 {
478 let pri_old = self.clone();
479
480 *self = Self::from_bits_retain(self.bits() & (LogMask::LOG_PRIMASK | LogMask::LOG_FACMASK).bits() );
481
482 throw_error!("unknwon facility/priority: {:x}", pri_old);
483 }
484
485 return Ok(());
486 }
487
488 pub(crate)
489 fn set_facility(&mut self, f: LogFacility)
490 {
491 *self = Self::from_bits_retain(self.bits() | f.bits() );
492 }
493 }
494
495 bitflags! {
496 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
499 pub struct LogFacility: libc::c_int
500 {
501 const LOG_KERN = libc::LOG_KERN;
503
504 const LOG_USER = libc::LOG_USER;
506
507 const LOG_MAIL = libc::LOG_MAIL;
509
510 const LOG_DAEMON = libc::LOG_DAEMON;
512
513 const LOG_AUTH = libc::LOG_AUTH;
515
516 const LOG_SYSLOG = libc::LOG_SYSLOG;
518
519 const LOG_LPR = libc::LOG_LPR;
521
522 const LOG_NEWS = libc::LOG_NEWS;
524
525 const LOG_UUCP = libc::LOG_UUCP;
527
528 const LOG_LOCAL0 = libc::LOG_LOCAL0;
530
531 const LOG_LOCAL1 = libc::LOG_LOCAL1;
533
534 const LOG_LOCAL2 = libc::LOG_LOCAL2;
536
537 const LOG_LOCAL3 = libc::LOG_LOCAL3;
539
540 const LOG_LOCAL4 = libc::LOG_LOCAL4;
542
543 const LOG_LOCAL5 = libc::LOG_LOCAL5;
545
546 const LOG_LOCAL6 = libc::LOG_LOCAL6;
548
549 const LOG_LOCAL7 = libc::LOG_LOCAL7;
551 }
552 }
553
554
555
556
557 pub const PATH_LOG: &'static str = "/var/run/log";
559
560 pub const PATH_LOG_PRIV: &'static str = "/var/run/logpriv";
562
563 pub const PATH_OLDLOG: &'static str = "/dev/log";
565
566 pub const PATH_OSX: &'static str = "/var/run/syslog";
568
569 pub
583 fn get_internal_log() -> libc::c_int
584 {
585 return
586 Priority::LOG_ERR.bits() |
587 (LogStat::LOG_CONS| LogStat::LOG_PERROR| LogStat::LOG_PID).bits();
588 }
589
590
591
592 #[cfg(feature = "build_sync")]
593 pub(crate) mod sync_portion
594 {
595 use std::io::Write;
596 use std::io::IoSlice;
597 use crate::error::SyRes;
598 use crate::map_error_os;
599
600 pub(crate)
611 fn send_to_fd<W>(mut file_fd: W, msg: &str, newline: &str) -> SyRes<usize>
612 where W: Write
613 {
614 return
615 file_fd
616 .write_vectored(
617 &[IoSlice::new(msg.as_bytes()), IoSlice::new(newline.as_bytes())]
618 )
619 .map_err(|e|
620 map_error_os!(e, "send_to_fd() writev() failed")
621 );
622 }
623 }
624
625 #[cfg(feature = "build_sync")]
626 pub(crate) use self::sync_portion::*;
627
628 #[cfg(test)]
629 mod tests
630 {
631 use super::*;
632
633 #[cfg(feature = "build_sync")]
634 #[test]
635 fn test_error_message()
636 {
637 let testmsg = "this is test message!";
643 let newline = "\n";
644 let stderr_lock = std::io::stderr().lock();
645 let res = send_to_fd(stderr_lock, testmsg, &newline);
646
647 println!("res: {:?}", res);
648
649 assert_eq!(res.is_ok(), true, "err: {}", res.err().unwrap());
650
651 return;
652 }
653
654 #[test]
655 fn test_priority_shl()
656 {
657 assert_eq!((1 << 5), (1 << Priority::LOG_NOTICE));
658 }
659 }
660}
661
662pub static PATH_CONSOLE: LazyLock<&Path> = LazyLock::new(||
663 {
664 Path::new("/dev/console")
665 }
666);
667
668pub static RFC5424_MAX_DGRAM: LazyLock<usize> = LazyLock::new(||
669 {
670 portable::get_local_dgram_maxdgram() as usize
671 }
672);
673
674
675pub const MAXHOSTNAMELEN: usize = 256;
677
678pub const LOG_FACMASK: i32 = 0x03f8;
680
681pub const MAXLINE: usize = 8192;
685
686pub const RFC3164_MAX_PAYLOAD_LEN: usize = 1024;
688
689pub const WINDOWS_EVENT_REPORT_MAX_PAYLOAD_LEN: usize = 31839;
691
692#[cfg(all(feature = "udp_truncate_1024_bytes", feature = "udp_truncate_1440_bytes"))]
693compile_error!("either 'udp_truncate_1024_bytes' or 'udp_truncate_1440_bytes' should be enabled");
694
695#[cfg(feature = "udp_truncate_1024_bytes")]
697pub const RFC5424_UDP_MAX_PKT_LEN: usize = 1024;
698
699#[cfg(any(feature = "udp_truncate_1440_bytes", all(not(feature = "udp_truncate_1440_bytes"), not(feature = "udp_truncate_1024_bytes"))))]
700pub const RFC5424_UDP_MAX_PKT_LEN: usize = 2048;
701
702#[cfg(feature = "tcp_truncate_1024_bytes")]
703pub const RFC5424_TCP_MAX_PKT_LEN: usize = 1024;
704
705#[cfg(feature = "tcp_truncate_2048_bytes")]
706pub const RFC5424_TCP_MAX_PKT_LEN: usize = 2048;
707
708#[cfg(feature = "tcp_truncate_4096_bytes")]
709pub const RFC5424_TCP_MAX_PKT_LEN: usize = 4096;
710
711#[cfg(feature = "tcp_truncate_max_bytes")]
712pub const RFC5424_TCP_MAX_PKT_LEN: usize = MAXLINE;
713
714pub const RFC_MAX_APP_NAME: usize = 48;
716
717pub const IANA_PRIV_ENT_NUM: u64 = 32473;
719
720pub const NILVALUE: &'static str = "-";
722
723pub const ESC_CHAR_REPL: &'static str = "#000";
725
726pub const NILVALUE_B: &'static [u8] = b"-";
728
729pub const WSPACE: &'static str = " ";
731
732pub const OBRACE: &'static str = "[";
734
735pub const CBRACE: &'static str = "]";
737
738pub const CBRACE_SEM: &'static str = "]:";
740
741pub const QCHAR: &'static str = "\"";
743
744pub const ATSIGN: &'static str = "@";
746
747pub const EQSIGN: &'static str = "=";
749
750pub const NEXTLINE: &'static str = "\n";
751
752 #[macro_export]
763 macro_rules! LOG_MASK
764 {
765 ($($arg:tt)*) => (
766 (1 << $($arg)*)
767 )
768 }
769
770 #[macro_export]
780 macro_rules! LOG_UPTO
781 {
782 ($($arg:tt)*) => (
783 ((1 << (($($arg)*) + 1)) - 1)
784 )
785 }
786
787 impl Shl<Priority> for i32
788 {
789 type Output = i32;
790
791 fn shl(self, rhs: Priority) -> i32
792 {
793 let lhs = self;
794 return lhs << rhs.bits();
795 }
796 }
797
798 impl BitAnd<Priority> for i32
799 {
800 type Output = i32;
801
802 #[inline]
803 fn bitand(self, rhs: Priority) -> i32
804 {
805 return self & rhs.bits();
806 }
807 }
808
809 impl BitAnd<LogMask> for Priority
810 {
811 type Output = Priority;
812
813 #[inline]
814 fn bitand(self, rhs: LogMask) -> Self::Output
815 {
816
817 return Self::from_bits_retain(self.bits() & rhs.bits());
818 }
819 }
820
821 impl BitAnd<LogMask> for LogFacility
822 {
823 type Output = LogFacility;
824
825 #[inline]
826 fn bitand(self, rhs: LogMask) -> Self::Output
827 {
828 return Self::from_bits_retain(self.bits() & rhs.bits());
829 }
830 }
831
832 impl BitAnd<LogMask> for i32
833 {
834 type Output = i32;
835
836 #[inline]
837 fn bitand(self, rhs: LogMask) -> i32
838 {
839 return self & rhs.bits();
840 }
841 }
842
843pub
853fn truncate(lt: &str) -> &str
854{
855 let ltt =
856 match lt.char_indices().nth(lt.len()-1)
857 {
858 None => lt,
859 Some((idx, _)) => <[..idx],
860 };
861 return ltt;
862}
863
864pub
888fn truncate_n<'t>(lt: &'t str, n: usize) -> &'t str
889{
890 if lt.as_bytes().len() <= n
891 {
892 return lt;
893 }
894
895 let mut nn: usize = 0;
896 let mut cc = lt.chars();
897 let mut ln: usize;
898
899 loop
900 {
901 match cc.next()
902 {
903 Some(r) =>
904 {
905 ln = r.len_utf8();
906 nn += ln;
907
908 if nn == n
909 {
910 return <[..nn];
911 }
912 else if nn > n
913 {
914 return <[..nn-ln];
915 }
916 },
917 None =>
918 return lt,
919 }
920 }
921}
922
923pub
932fn check_printable(a: &str) -> SyRes<()>
933{
934 if a.is_empty() == true
935 {
936 throw_error!("empty SD value");
937 }
938
939 for p in a.chars()
940 {
941 if p.is_ascii() == false || p.is_ascii_graphic() == false || p == '@' || p == '=' || p == ']' || p == '\"'
942 {
943 throw_error!("incorrect char: '{:X}' in SD value", p as u64);
944 }
945 }
946
947 return Ok(());
948}
949
950
951pub
952fn escape_chars(st: Cow<'static, str>) -> Cow<'static, str>
953{
954 let mut out = String::with_capacity(st.len());
955
956 for c in st.chars()
957 {
958 if c.is_control() == true
959 {
960 out.push_str(ESC_CHAR_REPL);
961 }
962 else if c == '\"' || c == '\\' || c == ']'
963 {
964 out.push('\\');
965 out.push(c);
966 }
967 else
968 {
969 out.push(c);
970 }
971 }
972
973 if st.len() == out.len()
974 {
975 return st;
976 }
977 else
978 {
979 return Cow::Owned(out);
980 }
981}
982
983
984#[cfg(test)]
985mod tests
986{
987 use super::*;
988
989 #[test]
990 fn test_truncate()
991 {
992 let test = "cat\n";
993
994 let trunc = truncate(test);
995
996 assert_eq!("cat", trunc);
997 }
998
999
1000
1001 #[test]
1002 fn test_truncate_n()
1003 {
1004 assert_eq!(truncate_n("abcde", 3), "abc");
1005 assert_eq!(truncate_n("ボルテ", 4), "ボ");
1006 assert_eq!(truncate_n("ボルテ", 5), "ボ");
1007 assert_eq!(truncate_n("ボルテ", 6), "ボル");
1008 assert_eq!(truncate_n("abcde", 0), "");
1009 assert_eq!(truncate_n("abcde", 5), "abcde");
1010 assert_eq!(truncate_n("abcde", 6), "abcde");
1011 assert_eq!(truncate_n("ДАТА", 3), "Д");
1012 assert_eq!(truncate_n("ДАТА", 4), "ДА");
1013 assert_eq!(truncate_n("ДАТА", 1), "");
1014 }
1015
1016}