1use anyhow::{Result, anyhow};
36use serde::Serialize;
37use std::fs::read_to_string;
38
39use crate::utils::Size;
40use crate::traits::ToJson;
41
42#[derive(Debug, Serialize, Default, Clone)]
44pub struct RAM {
45 pub total: Size,
47
48 pub free: Size,
51
52 pub available: Size,
55
56 pub buffers: Size,
59
60 pub cached: Size,
63
64 pub swap_cached: Size,
67
68 pub active: Size,
70
71 pub inactive: Size,
73
74 pub active_anon: Size,
76
77 pub inactive_anon: Size,
79
80 pub active_file: Size,
82
83 pub inactive_file: Size,
85
86 pub unevictable: Size,
88
89 pub mlocked: Size,
91
92 pub swap_total: Size,
94
95 pub swap_free: Size,
97
98 pub zswap: Size,
99 pub zswapped: Size,
100
101 pub dirty: Size,
103
104 pub writeback: Size,
106
107 pub anon_pages: Size,
109
110 pub mapped: Size,
113
114 pub shmem: Size,
116
117 pub kreclaimable: Size,
121
122 pub slab: Size,
125
126 pub sreclaimable: Size,
129
130 pub sunreclaim: Size,
132
133 pub kernel_stack: Size,
135
136 pub page_tables: Size,
139
140 pub sec_page_tables: Size,
141
142 pub nfs_unstable: Size,
145
146 pub bounce: Size,
149
150 pub writeback_tmp: Size,
152
153 pub commit_limit: Size,
156
157 pub commited_as: Size,
160
161 pub vmalloc_total: Size,
163
164 pub vmalloc_used: Size,
166
167 pub vmalloc_chunk: Size,
169
170 pub percpu: Size,
173
174 pub hardware_corrupted: Size,
177
178 pub anon_huge_pages: Size,
181
182 pub shmem_huge_pages: Size,
184
185 pub shmem_pmd_mapped: Size,
188
189 pub cma_total: Option<Size>,
191
192 pub cma_free: Option<Size>,
194
195 pub file_huge_pages: Size,
196 pub file_pmd_mapped: Size,
197 pub unaccepted: Size,
198 pub huge_pages_total: u32,
199 pub huge_pages_free: u32,
200 pub huge_pages_rsvd: u32,
201 pub huge_pages_surp: u32,
202 pub huge_page_size: Size,
203 pub huge_tlb: Size,
204 pub direct_map_4k: Size,
205 pub direct_map_2m: Size,
206 pub direct_map_1g: Size,
207}
208
209impl RAM {
210 pub fn new() -> Result<Self> {
211 let chunks = read_to_string("/proc/meminfo")?;
212 let chunks = chunks
213 .lines()
214 .map(|item| {
215 let mut items = item.split(':').map(|item| item.trim());
216 (items.next(), items.next())
217 })
218 .collect::<Vec<_>>();
219 let mut ram = RAM::default();
220 for chunk in chunks {
221 match chunk {
222 (Some(key), Some(val)) => match key {
223 "MemTotal" => ram.total = Size::try_from(val)?,
224 "MemFree" => ram.free = Size::try_from(val)?,
225 "MemAvailable" => ram.available = Size::try_from(val)?,
226 "Buffers" => ram.buffers = Size::try_from(val)?,
227 "Cached" => ram.cached = Size::try_from(val)?,
228 "SwapCached" => ram.swap_cached = Size::try_from(val)?,
229 "Active" => ram.active = Size::try_from(val)?,
230 "Inactive" => ram.inactive = Size::try_from(val)?,
231 "Active(anon)" => ram.active_anon = Size::try_from(val)?,
232 "Inactive(anon)" => ram.inactive_anon = Size::try_from(val)?,
233 "Active(file)" => ram.active_file = Size::try_from(val)?,
234 "Inactive(file)" => ram.inactive_file = Size::try_from(val)?,
235 "Unevictable" => ram.unevictable = Size::try_from(val)?,
236 "Mlocked" => ram.mlocked = Size::try_from(val)?,
237 "SwapTotal" => ram.swap_total = Size::try_from(val)?,
238 "SwapFree" => ram.swap_free = Size::try_from(val)?,
239 "Zswap" => ram.zswap = Size::try_from(val)?,
240 "Zswapped" => ram.zswapped = Size::try_from(val)?,
241 "Dirty" => ram.dirty = Size::try_from(val)?,
242 "Writeback" => ram.writeback = Size::try_from(val)?,
243 "AnonPages" => ram.anon_pages = Size::try_from(val)?,
244 "Mapped" => ram.mapped = Size::try_from(val)?,
245 "Shmem" => ram.shmem = Size::try_from(val)?,
246 "KReclaimable" => ram.kreclaimable = Size::try_from(val)?,
247 "Slab" => ram.slab = Size::try_from(val)?,
248 "SReclaimable" => ram.sreclaimable = Size::try_from(val)?,
249 "SUnreclaim" => ram.sunreclaim = Size::try_from(val)?,
250 "KernelStack" => ram.kernel_stack = Size::try_from(val)?,
251 "PageTables" => ram.page_tables = Size::try_from(val)?,
252 "SecPageTables" => ram.sec_page_tables = Size::try_from(val)?,
253 "NFS_Unstable" => ram.nfs_unstable = Size::try_from(val)?,
254 "Bounce" => ram.bounce = Size::try_from(val)?,
255 "WritebackTmp" => ram.writeback_tmp = Size::try_from(val)?,
256 "CommitLimit" => ram.commit_limit = Size::try_from(val)?,
257 "Committed_AS" => ram.commited_as = Size::try_from(val)?,
258 "VmallocTotal" => ram.vmalloc_total = Size::try_from(val)?,
259 "VmallocUsed" => ram.vmalloc_used = Size::try_from(val)?,
260 "VmallocChunk" => ram.vmalloc_chunk = Size::try_from(val)?,
261 "Percpu" => ram.percpu = Size::try_from(val)?,
262 "HardwareCorrupted" => ram.hardware_corrupted = Size::try_from(val)?,
263 "AnonHugePages" => ram.anon_huge_pages = Size::try_from(val)?,
264 "ShmemHugePages" => ram.shmem_huge_pages = Size::try_from(val)?,
265 "ShmemPmdMapped" => ram.shmem_pmd_mapped = Size::try_from(val)?,
266 "CmaTotal" => ram.cma_total = Size::try_from(val).ok(),
267 "CmaFree" => ram.cma_free = Size::try_from(val).ok(),
268 "FileHugePages" => ram.file_huge_pages = Size::try_from(val)?,
269 "FilePmdMapped" => ram.file_pmd_mapped = Size::try_from(val)?,
270 "Unaccepted" => ram.unaccepted = Size::try_from(val)?,
271 "HugePages_Total" => ram.huge_pages_total = val.parse()?,
272 "HugePages_Free" => ram.huge_pages_free = val.parse()?,
273 "HugePages_Rsvd" => ram.huge_pages_rsvd = val.parse()?,
274 "HugePages_Surp" => ram.huge_pages_surp = val.parse()?,
275 "Hugepagesize" => ram.huge_page_size = Size::try_from(val)?,
276 "Hugetlb" => ram.huge_tlb = Size::try_from(val)?,
277 "DirectMap4k" => ram.direct_map_4k = Size::try_from(val)?,
278 "DirectMap2M" => ram.direct_map_2m = Size::try_from(val)?,
279 "DirectMap1G" => ram.direct_map_1g = Size::try_from(val)?,
280 _ => continue,
281 },
282 _ => {}
283 }
284 }
285 Ok(ram)
286 }
287}
288
289impl ToJson for RAM {}
290
291#[derive(Debug, Serialize)]
293pub struct Swaps {
294 pub swaps: Vec<Swap>,
295}
296
297impl Swaps {
298 pub fn new() -> Result<Self> {
299 let mut swaps = vec![];
300
301 let data = read_to_string("/proc/swaps")?;
302 let items = data.lines().skip(1);
303
304 for swap in items {
305 swaps.push(Swap::try_from(swap)?)
306 }
307
308 Ok(Self { swaps })
309 }
310}
311
312impl ToJson for Swaps {}
313
314#[derive(Debug, Serialize)]
315pub struct Swap {
316 pub filename: String,
318
319 pub swap_type: String,
321
322 pub size: Size,
324
325 pub used: Size,
327
328 pub priority: i8,
330}
331
332impl TryFrom<&str> for Swap {
333 type Error = anyhow::Error;
334
335 fn try_from(value: &str) -> Result<Self> {
336 let data = value.split_whitespace().collect::<Vec<_>>();
337 if data.len() != 5 {
338 return Err(anyhow!("Format of the \"{value}\" string is incorrect!"));
339 }
340
341 Ok(Self {
342 filename: data[0].to_string(),
343 swap_type: data[1].to_string(),
344 size: Size::B(data[2].parse()?),
345 used: Size::B(data[3].parse()?),
346 priority: data[4].parse()?,
347 })
348 }
349}
350impl ToJson for Swap {}