syslog_rs/sync/
syslog_sync_internal.rs1use std::io::Error;
18
19use instance_copy_on_write::{ICoW, ICoWRead};
20
21use crate::formatters::{SyslogFormatted, SyslogFormatter};
22use crate::portable;
23use crate::common::*;
24use crate::error::{SyRes, SyslogError};
25use crate::SyslogDestination;
26
27use super::socket::*;
28
29#[cfg(target_family = "unix")]
30use nix::libc;
31
32#[derive(Debug, Clone)]
33pub(crate) struct LogItems
34{
35 pub(crate) logtag: String,
37
38 pub(crate) logpid: String,
40
41 pub(crate) logmask: i32,
43
44 pub(crate) logstat: LogStat,
45
46 pub(crate) facility: LogFacility,
48}
49
50impl LogItems
51{
52 #[inline]
53 pub
54 fn new(ident: Option<&str>, logmask: i32, logstat: LogStat, facility: LogFacility) -> Self
55 {
56 let mut log_inst =
57 Self
58 {
59 logtag: String::new(),
60 logpid: portable::get_pid().to_string(),
61 logmask: logmask,
62 logstat: logstat,
63 facility: LogFacility::empty(),
64 };
65
66 log_inst.set_log_facility(facility);
67 log_inst.set_identity(ident);
68
69 return log_inst;
70 }
71
72 pub(crate)
73 fn set_log_facility(&mut self, facility: LogFacility)
74 {
75 let log_facility =
76 if facility.is_empty() == false &&
77 (facility & !LogMask::LOG_FACMASK).is_empty() == true
78 {
79 facility
80 }
81 else
82 {
83 LogFacility::LOG_USER
85 };
86
87 self.facility = log_facility;
88
89 return;
90 }
91
92 pub(crate)
93 fn set_identity(&mut self, ident: Option<&str>)
94 {
95 let logtag =
96 match ident
97 {
98 Some(r) =>
99 truncate_n(r, RFC_MAX_APP_NAME).to_string(),
100 None =>
101 truncate_n(
102 portable::p_getprogname()
103 .unwrap_or("notavail".to_string())
104 .as_str(),
105 RFC_MAX_APP_NAME
106 )
107 .to_string()
108 };
109
110 self.logtag = logtag;
111
112 return;
113 }
114
115 #[inline]
116 pub
117 fn get_progname(&self) -> &str
118 {
119 return &self.logtag;
120 }
121
122 #[inline]
123 pub
124 fn get_pid(&self) -> &str
125 {
126 return &self.logtag;
127 }
128
129 #[inline]
130 fn is_logmasked(&self, pri: Priority) -> bool
131 {
132 return ((1 << (pri & LogMask::LOG_PRIMASK)) & self.logmask) == 0;
133 }
134
135 pub(crate)
136 fn set_logmask(&mut self, logmask: i32) -> i32
137 {
138 let oldmask = self.logmask;
139
140 if logmask != 0
141 {
142 self.logmask = logmask;
143 }
144
145 return oldmask;
146 }
147
148 pub(crate)
149 fn vsyslog1_msg<F, D>(&self, pri: Priority, fmt: &F) -> Option<(SyslogFormatted, LogStat)>
150 where F: SyslogFormatter, D: SyslogDestination
151 {
152 if self.is_logmasked(pri) == true
162 {
163 return None;
164 }
165
166 let pri_fac = SyslogMsgPriFac::set_facility(pri, self.facility);
168
169 let msg_pid =
178 if self.logstat.intersects(LogStat::LOG_PID) == true
179 {
180 Some(self.logpid.as_str())
181 }
182 else
183 {
184 None
185 };
186
187 let msg_formatted =
189 fmt.vsyslog1_format(D::SocketTap::get_max_msg_size(), pri_fac, &self.logtag, msg_pid);
190
191 self.logstat.send_to_stderr(msg_formatted.get_stderr_output());
193
194 return Some((msg_formatted, self.logstat));
195 }
196}
197
198#[derive(Debug)]
199pub(crate) struct SyslogSocket<D: SyslogDestination>
200{
201 stream: ICoW<D::SocketTap>
202}
203
204impl<D: SyslogDestination> SyslogSocket<D>
205{
206 pub(crate)
207 fn new(logstat: LogStat, net_tap_prov: D) -> SyRes<Self>
208 {
209 let mut sock =
210 D::SocketTap::new(net_tap_prov)?;
211
212 if logstat.contains(LogStat::LOG_NDELAY) == true
213 {
214 sock.connectlog()?;
215 }
216
217 return Ok(
218 Self{ stream: ICoW::new(sock) }
219 );
220 }
221
222 #[inline]
223 pub(crate)
224 fn update_tap_data(&self, tap_data: D) -> SyRes<()>
225 {
226
227 let mut lock =
228 self
229 .stream
230 .clone_copy_exclusivly();
231
232 lock.update_tap_data(tap_data);
235
236 lock.connectlog()?;
237
238 lock.commit();
239
240 return Ok(());
241 }
242
243 #[inline]
244 pub(crate)
245 fn reconnectlog(&self) -> SyRes<()>
246 {
247 let mut lock =
248 self
249 .stream
250 .clone_copy_exclusivly();
251
252 lock.connectlog()?;
254
255 lock.commit();
256
257 return Ok(());
258 }
259
260 #[inline]
261 pub(crate)
262 fn connectlog(&self) -> SyRes<()>
263 {
264 let mut lock =
265 self
266 .stream
267 .clone_copy_exclusivly();
268
269 lock.connectlog()?;
270
271 lock.commit();
272
273 return Ok(());
274 }
275
276 #[inline]
279 pub(crate)
280 fn disconnectlog(&self) -> SyRes<()>
281 {
282 let lock =
283 self
284 .stream
285 .clone_copy_exclusivly();
286
287 lock.commit();
288
289 return Ok(());
290 }
291
292 #[cfg(target_family = "unix")]
294 fn handle_error<'h>(&'h self, stream: ICoWRead<'h, <D as SyslogDestination>::SocketTap>,
295 e: Error) -> Result<ICoWRead<'h, D::SocketTap>, SyslogError>
296 {
297 use std::io::ErrorKind;
298 use std::thread::sleep;
299 use std::time::Duration;
300
301 if e.kind() == ErrorKind::NotConnected
303 {
304 match self.stream.clone_copy_exclus_or_read()
305 {
306 Ok(mut lock) =>
307 {
308 lock.connectlog()?;
309
310 lock.commit();
311
312 return Ok(self.stream.read());
313 },
314 Err(read) =>
315 {
316 return Ok(read);
317 }
318 }
319 }
320 else
321 {
322 if D::DEST_TYPE.is_network() == false
323 {
324 if let Some(libc::ENOBUFS) = e.raw_os_error()
325 {
326 if stream.get_type().is_priv() == true
328 {
329 use nix::errno::Errno;
330
331 use crate::throw_error_errno;
332
333 throw_error_errno!(Errno::ENOBUFS, "Not enough space in priv socket.");
334 }
335
336 sleep(Duration::from_micros(1));
337
338 return Ok(stream);
339 }
340 else
341 {
342 match self.stream.clone_copy_exclus_or_read()
344 {
345 Ok(mut lock) =>
346 {
347 lock.connectlog()?;
348
349 lock.commit();
350
351 return Ok(self.stream.read());
352 },
353 Err(read) =>
354 {
355 return Ok(read);
356 }
357 }
358
359 }
361 }
362 else
363 {
364 match self.stream.clone_copy_exclus_or_read()
365 {
366 Ok(mut lock) =>
367 {
368 lock.connectlog()?;
369
370 lock.commit();
371
372 return Ok(self.stream.read());
373 },
374 Err(read) =>
375 {
376 return Ok(read);
377 }
378 }
379 }
380 }
381 }
382
383 #[cfg(target_family = "windows")]
385 fn handle_error<'h>(&'h self, _stream: ICoWRead<'h, <D as SyslogDestination>::SocketTap>,
386 e: Error) -> Result<ICoWRead<'h, D::SocketTap>, SyslogError>
387 {
388 use crate::DestinationType;
389 use crate::error::SyslogErrCode;
390
391 if D::DEST_TYPE == DestinationType::Local
392 {
393 let Ok(werr) = e.downcast::<windows::core::Error>()
395 else
396 {
397
398
399 return Err(
400 SyslogError::new(SyslogErrCode::InternalError,
401 "error downcast failed".into())
402 );
403 };
404
405 return Err(
406 SyslogError::new(
407 SyslogErrCode::InternalError,
408 werr.message()
409 )
410 );
411 }
412 else if D::DEST_TYPE == DestinationType::Network
413 {
414 match self.stream.clone_copy_exclus_or_read()
415 {
416 Ok(mut lock) =>
417 {
418 lock.connectlog()?;
419
420 lock.commit();
421
422 return Ok(self.stream.read());
423 },
424 Err(read) =>
425 {
426 return Ok(read);
427 }
428 }
429 }
430 else
431 {
432 return Err(
433 SyslogError::new(
434 SyslogErrCode::InternalError,
435 format!("IO error: {}", e)
436 )
437 );
438 }
439
440 }
441
442
443 pub(crate)
452 fn vsyslog1(&self, logstat: LogStat, mut msg_formatted: SyslogFormatted)
453 {
454 let fullmsg = msg_formatted.get_full_msg();
455
456 let mut stream = self.stream.read();
457
458 loop
459 {
460 match stream.send(fullmsg.as_bytes())
461 {
462 Ok(_) =>
463 return,
464 Err(e) =>
465 {
466 match self.handle_error(stream, e)
467 {
468 Ok(read) =>
469 {
470 stream = read;
471
472 continue;
473 },
474 Err(e) =>
475 {
476 logstat.send_to_stderr(&format!("connectlog() failed with {}", e));
477 break;
478 }
479 }
480 }
481 }
482 }
483
484
485 let _ = logstat.send_to_syscons(msg_formatted.get_stderr_output());
489
490 return;
491 }
492
493}
494
495#[cfg(any(feature = "build_with_thread_local", feature = "build_with_queue"))]
496pub mod lockless
497{
498 use std::io::ErrorKind;
499 use std::thread::sleep;
500 use std::time::Duration;
501
502 use super::*;
503
504 #[derive(Debug)]
505 pub(crate) struct SyslogSocketLockless<D: SyslogDestination>
506 {
507 stream: D::SocketTap
508 }
509
510 impl<D: SyslogDestination> SyslogSocketLockless<D>
511 {
512 pub(crate)
513 fn new(logstat: LogStat, net_tap_prov: D) -> SyRes<Self>
514 {
515 let mut sock =
516 D::SocketTap::new(net_tap_prov)?;
517
518 if logstat.contains(LogStat::LOG_NDELAY) == true
519 {
520 sock.connectlog()?;
521 }
522
523 return Ok(
524 Self{ stream: sock }
525 );
526 }
527
528 #[inline]
529 pub(crate)
530 fn update_tap_data(&mut self, tap_data: D) -> SyRes<()>
531 {
532 self.stream.disconnectlog()?;
533 self.stream.update_tap_data(tap_data);
534
535 return self.stream.connectlog();
536 }
537
538 #[inline]
539 pub(crate)
540 fn reconnectlog(&mut self) -> SyRes<()>
541 {
542 self.stream.disconnectlog()?;
543 self.stream.connectlog()?;
544
545 return Ok(());
546 }
547
548 #[inline]
549 pub(crate)
550 fn connectlog(&mut self) -> SyRes<()>
551 {
552 return self.stream.connectlog();
553 }
554
555 #[inline]
558 pub(crate)
559 fn disconnectlog(&mut self) -> SyRes<()>
560 {
561 return self.stream.disconnectlog();
562 }
563
564
565
566 pub(crate)
575 fn vsyslog1(&mut self, logstat: LogStat, mut msg_formatted: SyslogFormatted)
576 {
577 if self.stream.is_connected() == false
578 {
579 if let Err(e) = self.stream.connectlog()
580 {
581 logstat.send_to_stderr(&e.into_inner());
582 }
583 }
584
585 let fullmsg = msg_formatted.get_full_msg();
586
587 let mut repeated = false;
588 loop
589 {
590 match self.stream.send(fullmsg.as_bytes())
591 {
592 Ok(_) =>
593 return,
594 Err(ref e) if e.kind() == ErrorKind::NotConnected =>
595 {
596 break;
597 },
598 Err(ref e) if e.kind() == ErrorKind::Deadlock =>
600 {
601 logstat.send_to_stderr(&e.to_string());
602 break;
603 },
604 Err(err) =>
605 {
606 if D::DEST_TYPE.is_network() == false
607 {
608 #[cfg(target_family = "unix")]
609 {
610 if let Some(libc::ENOBUFS) = err.raw_os_error()
611 {
612 if self.stream.get_type().is_priv() == true
614 {
615 break;
616 }
617
618 sleep(Duration::from_micros(1));
619 }
620 else
621 {
622 let _ = self.stream.disconnectlog();
624 if let Err(e) = self.stream.connectlog()
625 {
626 logstat.send_to_stderr(&e.into_inner());
627 break;
628 }
629 }
630 }
631
632 #[cfg(target_family = "windows")]
633 {
634 let Ok(werr) = err.downcast::<windows::core::Error>()
635 else
636 {
637 logstat.send_to_stderr("error downcast failed");
638 break;
639 };
640
641 logstat.send_to_stderr(&werr.message());
642 break;
643 }
644
645 }
647 else
648 {
649 if repeated == false
650 {
651 repeated = true;
652
653 let _ = self.stream.disconnectlog();
654 if let Err(e) = self.stream.connectlog()
655 {
656 logstat.send_to_stderr(&e.into_inner());
657 break;
658 }
659 }
660 else
661 {
662 logstat.send_to_stderr("syslog: can not send to remote server");
663 break;
664 }
665 }
666
667 }
668 }
669 }
670
671
672 let _ = logstat.send_to_syscons(msg_formatted.get_stderr_output());
676
677 return;
678 }
679
680 }
681}
682
683#[cfg(any(feature = "build_with_thread_local", feature = "build_with_queue"))]
684pub use self::lockless::*;
685
686
687
688#[cfg(test)]
689mod tests
690{
691 use crate::LOG_MASK;
692
693 use super::*;
694
695 #[test]
696 fn test_log_cons()
697 {
698
699
700 let msg = "header msg message payload";
703
704 let lsts = LogStat::LOG_CONS;
705
706 lsts.send_to_syscons(msg);
707
708 return;
709 }
710
711 #[test]
712 fn test_bit_operations()
713 {
714
715 let correct =
716 LogItems::new(Some("test1"), 0xFF, LogStat::LOG_PID, LogFacility::LOG_DAEMON);
717
718 assert_eq!(correct.facility, LogFacility::LOG_DAEMON);
719 assert_eq!((correct.facility & !LogFacility::LOG_DAEMON), LogFacility::empty());
720 }
721
722 #[test]
737 fn test_set_priority()
738 {
739 let mut correct =
740 LogItems::new(Some("test1"), 0xFF, LogStat::LOG_PID, LogFacility::LOG_DAEMON);
741
742 let ret = correct.set_logmask(LOG_MASK!(Priority::LOG_ERR));
743
744 assert_eq!(ret, 0xff);
745
746 let ret = correct.set_logmask(LOG_MASK!(Priority::LOG_ERR));
747
748 assert_eq!(ret, LOG_MASK!(Priority::LOG_ERR));
749
750 let ret = correct.is_logmasked(Priority::LOG_WARNING);
751 assert_eq!(ret, true);
752
753 let ret = correct.is_logmasked(Priority::LOG_ERR);
754 assert_eq!(ret, false);
755
756 let ret = correct.is_logmasked(Priority::LOG_CRIT);
757 assert_eq!(ret, true);
758 }
759}
760