1#[macro_use]
8extern crate serde_derive;
9extern crate bincode;
10extern crate libc;
11
12use bincode::{deserialize, serialize};
13use libc::{getpwuid, passwd};
14use std::ffi::CStr;
15use std::io::Read;
16use std::string::String;
17use std::time::{Duration, SystemTime, UNIX_EPOCH};
18use std::{fmt, mem, result};
19use std::ops::Deref;
20
21const AFORK: u8 = 0x01;
22const ASU: u8 = 0x02;
23const ACORE: u8 = 0x08;
24const AXSIG: u8 = 0x10;
25
26pub type Result<T> = result::Result<T, Error>;
27
28#[derive(Debug)]
29pub enum Error {
30 InvalidFile,
31 BadReader,
32 Er,
33}
34
35impl From<std::string::FromUtf8Error> for Error {
36 fn from(_: std::string::FromUtf8Error) -> Error {
37 Error::Er
38 }
39}
40
41impl From<std::ffi::OsString> for Error {
42 fn from(_: std::ffi::OsString) -> Error {
43 Error::Er
44 }
45}
46
47impl From<std::io::Error> for Error {
48 fn from(_: std::io::Error) -> Error {
49 Error::BadReader
50 }
51}
52
53impl From<std::boxed::Box<bincode::ErrorKind>> for Error {
54 fn from(_: std::boxed::Box<bincode::ErrorKind>) -> Error {
55 Error::BadReader
56 }
57}
58
59impl fmt::Display for Error {
60 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
61 match *self {
62 Error::InvalidFile => write!(f, "Invalid file"),
63 Error::BadReader => write!(f, "Invalid reader"),
64 Error::Er => write!(f, "Invalid data"),
65 }
66 }
67}
68
69#[derive(Serialize, Deserialize, PartialEq, Debug)]
70struct AcctV3Inner {
71 ac_flag: u8,
72 ac_version: u8,
73 ac_tty: u16,
74 ac_exitcode: u32,
75 ac_uid: u32,
76 ac_gid: u32,
77 ac_pid: u32,
78 ac_ppid: u32,
79 ac_btime: u32,
80 ac_etime: f32,
81 ac_utime: u16,
82 ac_stime: u16,
83 ac_mem: u16,
84 ac_io: u16,
85 ac_rw: u16,
86 ac_minflt: u16,
87 ac_majflt: u16,
88 ac_swaps: u16,
89 ac_comm: [u8; 16],
90}
91
92impl AcctV3Inner {
93 fn load_from_slice(buf: &[u8]) -> Result<AcctV3Inner> {
94 let acct: AcctV3Inner = deserialize(buf)?;
95
96 Ok(acct)
97 }
98
99 fn command(&self) -> Result<String> {
100 let res = String::from_utf8(self.ac_comm.to_vec())?;
101 Ok(res)
102 }
103
104 fn is_valid(&self) -> bool {
105 self.ac_version == 3
106 }
107}
108
109#[derive(Debug)]
113pub struct AcctV3 {
114 inner: AcctV3Inner,
115 pub username: String,
117 pub command: String,
119 pub creation_time: SystemTime,
121}
122
123impl AcctV3 {
124 pub fn from_slice(buf: &[u8]) -> Result<AcctV3> {
126 let inner = AcctV3Inner::load_from_slice(buf)?;
127 let command = inner.command()?;
128 let pw: passwd = unsafe { *getpwuid(inner.ac_uid) };
130 let username = unsafe { CStr::from_ptr(pw.pw_name) };
131 let username = username.to_str().unwrap().to_string();
132
133 let ctime = inner.ac_btime as u64;
134 let creation_time = UNIX_EPOCH + Duration::from_secs(ctime);
135
136 Ok(AcctV3 {
137 inner: inner,
138 command: command,
139 username: username,
140 creation_time: creation_time,
141 })
142 }
143
144 fn is_valid(&self) -> bool {
145 self.inner.is_valid()
146 }
147
148 pub fn was_forked(&self) -> bool {
150 self.inner.ac_flag & AFORK == AFORK
151 }
152
153 pub fn was_super_user(&self) -> bool {
155 self.inner.ac_flag & ASU == ASU
156 }
157
158 pub fn was_core_dumped(&self) -> bool {
160 self.inner.ac_flag & ACORE == ACORE
161 }
162
163 pub fn was_killed(&self) -> bool {
165 self.inner.ac_flag & AXSIG == AXSIG
166 }
167}
168
169pub struct AcctFile {
171 records: Vec<AcctV3>,
173}
174
175impl AcctFile {
176 fn is_valid(buf: &[u8]) -> bool {
177 buf.len() % mem::size_of::<AcctV3Inner>() == 0
178 }
179
180 pub fn new<R: Read + ?Sized>(reader: &mut R) -> Result<AcctFile> {
182 let size = mem::size_of::<AcctV3Inner>();
183 let mut all: Vec<AcctV3> = Vec::new();
184 let mut buf: Vec<u8> = Vec::new();
185 reader.read_to_end(&mut buf)?;
186
187 if !AcctFile::is_valid(&buf) {
188 return Err(Error::Er);
189 }
190
191 for chunk in (0..buf.len()).step_by(size) {
192 let acct = AcctV3::from_slice(&buf[chunk..chunk + size])?;
193 if acct.is_valid() {
194 all.push(acct);
195 }
196 }
197
198 Ok(AcctFile { records: all })
199 }
200
201 pub fn into_bytes(self) -> Result<Vec<u8>> {
204 let mut all_bytes: Vec<u8> = Vec::new();
205 for acct in self.records {
206 let mut buf = serialize(&acct.inner)?;
207 all_bytes.append(&mut buf);
208 }
209
210 Ok(all_bytes)
211 }
212}
213
214impl Deref for AcctFile {
215 type Target = Vec<AcctV3>;
216
217 fn deref(&self) -> &Self::Target {
218 &self.records
219 }
220}
221
222pub fn expand_time(time: u16) -> u16 {
223 let ret: u16 = (time & 0x1fff) << (((time >> 13) & 0x7) * 3);
224
225 ret
226}