use libc::{c_int, size_t};
use std::ptr;
use std::collections::BTreeMap;
use ffi::journal as ffi;
use super::Result;
pub type JournalRecord = BTreeMap<String, String>;
pub struct JournalReader {
j: *mut ffi::sd_journal,
}
#[derive(Clone, Debug)]
pub enum JournalFiles {
System,
CurrentUser,
All,
}
pub enum JournalSeek {
Head,
Tail,
}
impl JournalReader {
pub fn open(
files: JournalFiles,
runtime_only: bool,
local_only: bool) -> Result<JournalReader> {
let mut flags: c_int = 0;
if runtime_only {
flags |= ffi::SD_JOURNAL_RUNTIME_ONLY;
}
if local_only {
flags |= ffi::SD_JOURNAL_LOCAL_ONLY;
}
flags |= match files {
JournalFiles::System => ffi::SD_JOURNAL_SYSTEM,
JournalFiles::CurrentUser => ffi::SD_JOURNAL_CURRENT_USER,
JournalFiles::All => 0,
};
let mut journal = JournalReader { j: ptr::null_mut() };
sd_try!(ffi::sd_journal_open(&mut journal.j, flags));
Ok(journal)
}
fn get_record(&mut self) -> Result<Option<JournalRecord>> {
unsafe { ffi::sd_journal_restart_data(self.j) }
let mut ret: JournalRecord = BTreeMap::new();
let mut sz: size_t = 0;
let data: *mut u8 = ptr::null_mut();
while sd_try!(ffi::sd_journal_enumerate_data(self.j, &data, &mut sz)) > 0 {
unsafe {
let b = ::std::slice::from_raw_parts_mut(data, sz as usize);
let field = String::from_utf8_lossy(b);
let mut name_value = field.splitn(2, '=');
let name = name_value.next().unwrap();
let value = name_value.next().unwrap();
ret.insert(From::from(name), From::from(value));
}
}
Ok(Some(ret))
}
pub fn next_record(&mut self) -> Result<Option<JournalRecord>> {
if sd_try!(ffi::sd_journal_next(self.j)) == 0 {
return Ok(None);
}
return self.get_record();
}
pub fn previous_record(&mut self) -> Result<Option<JournalRecord>> {
if sd_try!(ffi::sd_journal_previous(self.j)) == 0 {
return Ok(None);
}
return self.get_record();
}
pub fn seek(&mut self, seek: JournalSeek) -> Result<()> {
match seek {
JournalSeek::Head => sd_try!(ffi::sd_journal_seek_head(self.j)),
JournalSeek::Tail => sd_try!(ffi::sd_journal_seek_tail(self.j)),
};
return Ok(());
}
}
impl Drop for JournalReader {
fn drop(&mut self) {
if !self.j.is_null() {
unsafe {
ffi::sd_journal_close(self.j);
}
}
}
}