1use std::borrow::Cow;
16use std::fmt;
17use std::ops::{BitAnd, Shl};
18use std::path::Path;
19use std::sync::LazyLock;
20
21use nix::libc;
22
23
24use crate::portable;
25
26use super::error::SyRes;
27use super::throw_error;
28
29bitflags! {
30 pub struct LogStat: libc::c_int
33 {
34 const LOG_PID = libc::LOG_PID;
36
37 const LOG_CONS = libc::LOG_CONS;
40
41 const LOG_ODELAY = libc::LOG_ODELAY;
45
46 const LOG_NDELAY = libc::LOG_NDELAY;
48
49 const LOG_NOWAIT = libc::LOG_NOWAIT;
52
53 const LOG_PERROR = 0x20;
55 }
56}
57
58bitflags! {
59 pub(crate) struct LogMask: libc::c_int
60 {
61 const LOG_FACMASK = libc::LOG_FACMASK;
62 const LOG_PRIMASK = libc::LOG_PRIMASK;
63 }
64}
65
66bitflags! {
67 pub struct Priority: libc::c_int
69 {
70 const LOG_EMERG = libc::LOG_EMERG;
72
73 const LOG_ALERT = libc::LOG_ALERT;
75
76 const LOG_CRIT = libc::LOG_CRIT;
78
79 const LOG_ERR = libc::LOG_ERR;
81
82 const LOG_WARNING = libc::LOG_WARNING;
84
85 const LOG_NOTICE = libc::LOG_NOTICE;
87
88 const LOG_INFO = libc::LOG_INFO;
90
91 const LOG_DEBUG = libc::LOG_DEBUG;
93 }
94}
95
96impl fmt::Display for Priority
97{
98 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
99 {
100 if self.contains(Self::LOG_DEBUG) == true
103 {
104 write!(f, "[DEBUG]")
105 }
106 else if self.contains(Self::LOG_INFO) == true
107 {
108 write!(f, "[INFO]")
109 }
110 else if self.contains(Self::LOG_NOTICE) == true
111 {
112 write!(f, "[NOTICE]")
113 }
114 else if self.contains(Self::LOG_WARNING) == true
115 {
116 write!(f, "[WARNING]")
117 }
118 else if self.contains(Self::LOG_ERR) == true
119 {
120 write!(f, "[ERR]")
121 }
122 else if self.contains(Self::LOG_CRIT) == true
123 {
124 write!(f, "[CRIT]")
125 }
126 else if self.contains(Self::LOG_ALERT) == true
127 {
128 write!(f, "[ALERT]")
129 }
130 else if self.contains(Self::LOG_EMERG) == true
131 {
132 write!(f, "[EMERG]")
133 }
134 else
135 {
136 write!(f, "[UNKNOWN]")
137 }
138 }
139}
140
141impl Priority
142{
143 pub(crate)
155 fn check_invalid_bits(&mut self) -> SyRes<()>
156 {
157
158 if (self.bits() & !(LogMask::LOG_PRIMASK | LogMask::LOG_FACMASK )) != 0
159 {
160 let pri_old = self.clone();
161
162 *self = unsafe { Self::from_bits_unchecked( self.bits() & (LogMask::LOG_PRIMASK | LogMask::LOG_FACMASK).bits() ) };
163
164 throw_error!("unknwon facility/priority: {:x}", pri_old);
165 }
166
167 return Ok(());
168 }
169
170 pub(crate)
171 fn set_facility(&mut self, f: LogFacility)
172 {
173 *self = unsafe { Self::from_bits_unchecked(self.bits | f.bits() )};
174 }
175}
176
177bitflags! {
178 pub struct LogFacility: libc::c_int
181 {
182 const LOG_KERN = libc::LOG_KERN;
184
185 const LOG_USER = libc::LOG_USER;
187
188 const LOG_MAIL = libc::LOG_MAIL;
190
191 const LOG_DAEMON = libc::LOG_DAEMON;
193
194 const LOG_AUTH = libc::LOG_AUTH;
196
197 const LOG_SYSLOG = libc::LOG_SYSLOG;
199
200 const LOG_LPR = libc::LOG_LPR;
202
203 const LOG_NEWS = libc::LOG_NEWS;
205
206 const LOG_UUCP = libc::LOG_UUCP;
208
209 const LOG_LOCAL0 = libc::LOG_LOCAL0;
211
212 const LOG_LOCAL1 = libc::LOG_LOCAL1;
214
215 const LOG_LOCAL2 = libc::LOG_LOCAL2;
217
218 const LOG_LOCAL3 = libc::LOG_LOCAL3;
220
221 const LOG_LOCAL4 = libc::LOG_LOCAL4;
223
224 const LOG_LOCAL5 = libc::LOG_LOCAL5;
226
227 const LOG_LOCAL6 = libc::LOG_LOCAL6;
229
230 const LOG_LOCAL7 = libc::LOG_LOCAL7;
232 }
233}
234
235pub const MAXHOSTNAMELEN: usize = 256;
237
238pub const LOG_FACMASK: i32 = 0x03f8;
240
241pub const MAXLINE: usize = 8192;
245
246pub const RFC3164_MAX_PAYLOAD_LEN: usize = 1024;
248
249#[cfg(all(feature = "udp_truncate_1024_bytes", feature = "udp_truncate_1440_bytes"))]
250compile_error!("either 'udp_truncate_1024_bytes' or 'udp_truncate_1440_bytes' should be enabled");
251
252#[cfg(feature = "udp_truncate_1024_bytes")]
254pub const RFC5424_UDP_MAX_PKT_LEN: usize = 1024;
255
256#[cfg(any(feature = "udp_truncate_1440_bytes", all(not(feature = "udp_truncate_1440_bytes"), not(feature = "udp_truncate_1024_bytes"))))]
257pub const RFC5424_UDP_MAX_PKT_LEN: usize = 2048;
258
259#[cfg(feature = "tcp_truncate_1024_bytes")]
260pub const RFC5424_TCP_MAX_PKT_LEN: usize = 1024;
261
262#[cfg(feature = "tcp_truncate_2048_bytes")]
263pub const RFC5424_TCP_MAX_PKT_LEN: usize = 2048;
264
265#[cfg(feature = "tcp_truncate_4096_bytes")]
266pub const RFC5424_TCP_MAX_PKT_LEN: usize = 4096;
267
268#[cfg(feature = "tcp_truncate_max_bytes")]
269pub const RFC5424_TCP_MAX_PKT_LEN: usize = MAXLINE;
270
271pub const RFC_MAX_APP_NAME: usize = 48;
273
274pub const IANA_PRIV_ENT_NUM: u64 = 32473;
276
277pub const NILVALUE: &'static str = "-";
279
280pub const ESC_CHAR_REPL: &'static str = "#000";
282
283pub const NILVALUE_B: &'static [u8] = b"-";
285
286pub const WSPACE: &'static str = " ";
288
289pub const OBRACE: &'static str = "[";
291
292pub const CBRACE: &'static str = "]";
294
295pub const QCHAR: &'static str = "\"";
297
298pub const ATSIGN: &'static str = "@";
300
301pub const EQSIGN: &'static str = "=";
303
304pub const NEXTLINE: &'static str = "\n";
305
306pub const PATH_LOG: &'static str = "/var/run/log";
308
309pub const PATH_LOG_PRIV: &'static str = "/var/run/logpriv";
311
312pub const PATH_OLDLOG: &'static str = "/dev/log";
314
315pub const PATH_OSX: &'static str = "/var/run/syslog";
317
318pub static PATH_CONSOLE: LazyLock<&Path> = LazyLock::new(||
326 {
327 Path::new("/dev/console")
328 }
329);
330
331pub static RFC5424_MAX_DGRAM: LazyLock<usize> = LazyLock::new(||
332 {
333 portable::get_local_dgram_maxdgram() as usize
334 }
335);
336
337
338
339#[macro_export]
350macro_rules! LOG_MASK
351{
352 ($($arg:tt)*) => (
353 (1 << $($arg)*)
354 )
355}
356
357#[macro_export]
367macro_rules! LOG_UPTO
368{
369 ($($arg:tt)*) => (
370 ((1 << (($($arg)*) + 1)) - 1)
371 )
372}
373
374pub
376fn get_internal_log() -> libc::c_int
377{
378 return
379 Priority::LOG_ERR.bits() |
380 (LogStat::LOG_CONS| LogStat::LOG_PERROR| LogStat::LOG_PID).bits();
381}
382
383impl Shl<Priority> for i32
384{
385 type Output = i32;
386
387 fn shl(self, rhs: Priority) -> i32
388 {
389 let lhs = self;
390 return lhs << rhs.bits();
391 }
392}
393
394impl BitAnd<Priority> for i32
395{
396 type Output = i32;
397
398 #[inline]
399 fn bitand(self, rhs: Priority) -> i32
400 {
401 return self & rhs.bits();
402 }
403}
404
405impl BitAnd<LogMask> for Priority
406{
407 type Output = Priority;
408
409 #[inline]
410 fn bitand(self, rhs: LogMask) -> Self::Output
411 {
412 return Self {bits: self.bits() & rhs.bits()};
413 }
414}
415
416impl BitAnd<LogMask> for LogFacility
417{
418 type Output = LogFacility;
419
420 #[inline]
421 fn bitand(self, rhs: LogMask) -> Self::Output
422 {
423 return Self {bits: self.bits() & rhs.bits()};
424 }
425}
426
427impl BitAnd<LogMask> for i32
428{
429 type Output = i32;
430
431 #[inline]
432 fn bitand(self, rhs: LogMask) -> i32
433 {
434 return self & rhs.bits();
435 }
436}
437
438#[cfg(feature = "build_sync")]
439pub(crate) mod sync_portion
440{
441 use std::borrow::Cow;
442 use std::io::Write;
443 use std::io::IoSlice;
444 use crate::error::SyRes;
445 use crate::map_error_os;
446
447 pub(crate)
458 fn send_to_fd<W>(mut file_fd: W, msg: &[Cow<'_, str>], newline: &str) -> SyRes<usize>
459 where W: Write
460 {
461 let mut iov_list: Vec<IoSlice<'_>> = Vec::with_capacity(msg.len() + 1);
462
463 msg.iter().for_each(|v| iov_list.push(IoSlice::new(v.as_bytes())));
464 iov_list.push(IoSlice::new(newline.as_bytes()));
465
466 return
467 file_fd
468 .write_vectored(&iov_list)
469 .map_err(|e|
470 map_error_os!(e, "send_to_fd() writev() failed")
471 );
472 }
473}
474
475#[cfg(feature = "build_sync")]
476pub(crate) use self::sync_portion::*;
477
478pub
488fn truncate(lt: &str) -> &str
489{
490 let ltt =
491 match lt.char_indices().nth(lt.len()-1)
492 {
493 None => lt,
494 Some((idx, _)) => <[..idx],
495 };
496 return ltt;
497}
498
499pub
523fn truncate_n<'t>(lt: &'t str, n: usize) -> &'t str
524{
525 if lt.as_bytes().len() <= n
526 {
527 return lt;
528 }
529
530 let mut nn: usize = 0;
531 let mut cc = lt.chars();
532 let mut ln: usize;
533
534 loop
535 {
536 match cc.next()
537 {
538 Some(r) =>
539 {
540 ln = r.len_utf8();
541 nn += ln;
542
543 if nn == n
544 {
545 return <[..nn];
546 }
547 else if nn > n
548 {
549 return <[..nn-ln];
550 }
551 },
552 None =>
553 return lt,
554 }
555 }
556}
557
558pub
567fn check_printable(a: &str) -> SyRes<()>
568{
569 if a.is_empty() == true
570 {
571 throw_error!("empty SD value");
572 }
573
574 for p in a.chars()
575 {
576 if p.is_ascii() == false || p.is_ascii_graphic() == false || p == '@' || p == '=' || p == ']' || p == '\"'
577 {
578 throw_error!("incorrect char: '{:X}' in SD value", p as u64);
579 }
580 }
581
582 return Ok(());
583}
584
585
586pub
587fn escape_chars(st: Cow<'static, str>) -> Cow<'static, str>
588{
589 let mut out = String::with_capacity(st.len());
590
591 for c in st.chars()
592 {
593 if c.is_control() == true
594 {
595 out.push_str(ESC_CHAR_REPL);
596 }
597 else if c == '\"' || c == '\\' || c == ']'
598 {
599 out.push('\\');
600 out.push(c);
601 }
602 else
603 {
604 out.push(c);
605 }
606 }
607
608 if st.len() == out.len()
609 {
610 return st;
611 }
612 else
613 {
614 return Cow::Owned(out);
615 }
616}
617
618
619#[cfg(test)]
620mod tests
621{
622 use std::borrow::Cow;
623
624 use super::*;
625
626 #[cfg(feature = "build_sync")]
627 #[test]
628 fn test_error_message()
629 {
630 let testmsg = Cow::Borrowed("this is test message!");
636 let testmsg2 = Cow::Borrowed(" this is test message 2!");
637 let newline = "\n";
638 let stderr_lock = std::io::stderr().lock();
639 let res = send_to_fd(stderr_lock, &[testmsg, testmsg2], &newline);
640
641 println!("res: {:?}", res);
642
643 assert_eq!(res.is_ok(), true, "err: {}", res.err().unwrap());
644
645 return;
646 }
647
648 #[test]
649 fn test_truncate()
650 {
651 let test = "cat\n";
652
653 let trunc = truncate(test);
654
655 assert_eq!("cat", trunc);
656 }
657
658 #[test]
659 fn test_priority_shl()
660 {
661 assert_eq!((1 << 5), (1 << Priority::LOG_NOTICE));
662 }
663
664 #[test]
665 fn test_truncate_n()
666 {
667 assert_eq!(truncate_n("abcde", 3), "abc");
668 assert_eq!(truncate_n("ボルテ", 4), "ボ");
669 assert_eq!(truncate_n("ボルテ", 5), "ボ");
670 assert_eq!(truncate_n("ボルテ", 6), "ボル");
671 assert_eq!(truncate_n("abcde", 0), "");
672 assert_eq!(truncate_n("abcde", 5), "abcde");
673 assert_eq!(truncate_n("abcde", 6), "abcde");
674 assert_eq!(truncate_n("ДАТА", 3), "Д");
675 assert_eq!(truncate_n("ДАТА", 4), "ДА");
676 assert_eq!(truncate_n("ДАТА", 1), "");
677 }
678
679}