1mod utils;
2use colored::*;
3use glob::glob;
4use regex::Regex;
5use serde::{Deserialize, Serialize};
6use std::default::Default;
7use std::fmt;
8use std::fmt::{Debug, Display};
9use std::fs;
10use std::net::{Ipv4Addr, Ipv6Addr};
11use std::path::Path;
12use std::process::Command;
13use std::str;
14use std::str::FromStr;
15use std::string::String;
16
17fn handle<T: Default, E: Display + Debug>(result: Result<T, E>) -> T {
18 match result {
19 Ok(val) => val,
20 Err(e) => {
21 eprintln!("{:?}", e);
22 Default::default()
23 }
24 }
25}
26
27pub enum SysProperty {
28 CpuInfo,
29 Hostname,
30 OsRelease,
31 Uptime,
32 Mem,
33 NetDev,
34 StorDev,
35 StorMounts,
36 SysBlockDev,
37 Temperature,
38}
39pub enum Memory {
40 SwapTotal,
41 SwapFree,
42 MemTotal,
43 MemFree,
44}
45
46#[derive(Serialize, Deserialize, Debug)]
47pub struct NetworkDevice {
48 name: String,
49 received_bytes: u64,
50 transfered_bytes: u64,
51 ipv4_addr: Ipv4Addr,
52 ipv6_addr: Ipv6Addr,
53}
54impl NetworkDevice {
55 #[allow(dead_code)]
56 fn new() -> NetworkDevice {
57 NetworkDevice {
58 name: "".to_string(),
59 received_bytes: 0,
60 transfered_bytes: 0,
61 ipv4_addr: Ipv4Addr::UNSPECIFIED,
62 ipv6_addr: Ipv6Addr::UNSPECIFIED,
63 }
64 }
65}
66
67#[derive(Serialize, Deserialize, Debug)]
68pub struct Storage {
69 name: String,
70 major: u16,
71 minor: u16,
72 size: u64,
73 partitions: Vec<Partition>,
74}
75impl Storage {
76 #[allow(dead_code)]
77 fn new() -> Storage {
78 Storage {
79 name: "".to_string(),
80 major: 0,
81 minor: 0,
82 size: 0,
83 partitions: vec![],
84 }
85 }
86}
87
88#[derive(Serialize, Deserialize, Debug)]
89pub struct Partition {
90 name: String,
91 major: u16,
92 minor: u16,
93 size: u64,
94 filesystem: String,
95 mountpoint: String,
96}
97
98impl Partition {
99 fn new() -> Partition {
100 Partition {
101 name: "".to_string(),
102 major: 0,
103 minor: 0,
104 size: 0,
105 filesystem: "".to_string(),
106 mountpoint: "".to_string(),
107 }
108 }
109}
110
111#[derive(Serialize, Deserialize, Debug)]
112pub struct VolGroup {
113 name: String,
114 format: String,
115 status: String,
116 size: u64,
117 lvms: Vec<LogVolume>,
118}
119
120impl VolGroup {
121 #[allow(dead_code)]
122 fn new() -> VolGroup {
123 VolGroup {
124 name: "".to_string(),
125 format: "".to_string(),
126 status: "".to_string(),
127 size: 0,
128 lvms: vec![],
129 }
130 }
131}
132
133#[derive(Serialize, Deserialize, Debug)]
134pub struct LogVolume {
135 name: String,
136 vg: String,
137 path: String,
138 status: String,
139 major: u16,
140 minor: u16,
141 size: u64,
142 mountpoint: String,
143}
144
145impl LogVolume {
146 #[allow(dead_code)]
147 fn new() -> LogVolume {
148 LogVolume {
149 name: "".to_string(),
150 vg: "".to_string(),
151 path: "".to_string(),
152 status: "".to_string(),
153 major: 0,
154 minor: 0,
155 size: 0,
156 mountpoint: "".to_string(),
157 }
158 }
159}
160
161#[derive(Serialize, Deserialize, Debug)]
162pub struct Sensor {
163 name: String,
164 temp: f32,
165}
166impl Sensor {
167 #[allow(dead_code)]
168 fn new() -> Sensor {
169 Sensor {
170 name: "".to_string(),
171 temp: 0.,
172 }
173 }
174}
175
176type Sensors = Vec<Sensor>;
177#[derive(Serialize, Deserialize, Debug, Default)]
178pub struct DeviceSensors {
179 name: String,
180 sensors: Sensors,
181}
182impl DeviceSensors {
183 #[allow(dead_code)]
184 fn new() -> DeviceSensors {
185 DeviceSensors {
186 name: "".to_string(),
187 sensors: vec![],
188 }
189 }
190}
191#[derive(Serialize, Deserialize, Debug, Default)]
192pub struct Temperatures {
193 pub devices: Vec<DeviceSensors>,
194}
195
196type Partitions = Vec<Partition>;
197#[derive(Serialize, Deserialize, Debug, Default)]
198pub struct NetworkDevices {
199 pub devices: Vec<NetworkDevice>,
200}
201#[derive(Serialize, Deserialize, Debug, Default)]
202pub struct Storages {
203 pub devices: Vec<Storage>,
204}
205#[derive(Serialize, Deserialize, Debug, Default)]
206pub struct VolGroups {
207 pub vgs: Vec<VolGroup>,
208}
209
210#[derive(Serialize, Deserialize, Debug)]
211pub struct PcInfo {
212 hostname: String,
213 kernel_version: String,
214 uptime: f64,
215 cpu: String,
216 cpu_clock: f32,
217 memory: u64,
218 free_memory: u64,
219 swap: u64,
220 free_swap: u64,
221 pub network_dev: NetworkDevices,
222 pub storage_dev: Storages,
223 pub vgs: VolGroups,
224 graphics_card: String,
225 pub temps: Temperatures,
226}
227impl PcInfo {
228 pub fn new() -> PcInfo {
229 PcInfo {
230 hostname: handle(Get::sysproperty(SysProperty::Hostname)),
231 kernel_version: handle(Get::sysproperty(SysProperty::OsRelease)),
232 uptime: handle(Get::uptime()),
233 cpu: handle(Get::cpu_info()),
234 cpu_clock: handle(Get::cpu_clock()),
235 memory: handle(Get::mem(Memory::MemTotal)),
236 free_memory: handle(Get::mem(Memory::MemFree)),
237 swap: handle(Get::mem(Memory::SwapTotal)),
238 free_swap: handle(Get::mem(Memory::SwapFree)),
239 network_dev: handle(Get::network_dev()),
240 storage_dev: handle(Get::storage_devices()),
241 vgs: handle(Get::vgs()),
242 graphics_card: handle(Get::graphics_card()),
243 temps: handle(Get::temperatures()),
244 }
245 }
246}
247impl Default for PcInfo {
248 fn default() -> PcInfo {
249 PcInfo {
250 hostname: "".to_string(),
251 kernel_version: "".to_string(),
252 uptime: 0.,
253 cpu: "".to_string(),
254 cpu_clock: 0.,
255 memory: 0,
256 free_memory: 0,
257 swap: 0,
258 free_swap: 0,
259 network_dev: NetworkDevices { devices: vec![] },
260 storage_dev: Storages { devices: vec![] },
261 vgs: VolGroups { vgs: vec![] },
262 graphics_card: "".to_string(),
263 temps: Temperatures { devices: vec![] },
264 }
265 }
266}
267
268#[derive(Debug)]
269pub struct Get;
270impl Get {
271 fn path(prop: SysProperty) -> &'static Path {
272 match prop {
273 SysProperty::Hostname => &Path::new("/proc/sys/kernel/hostname"),
274 SysProperty::OsRelease => &Path::new("/proc/sys/kernel/osrelease"),
275 SysProperty::Uptime => &Path::new("/proc/uptime"),
276 SysProperty::Mem => &Path::new("/proc/meminfo"),
277 SysProperty::NetDev => &Path::new("/proc/net/dev"),
278 SysProperty::StorDev => &Path::new("/proc/partitions"),
279 SysProperty::StorMounts => &Path::new("/proc/mounts"),
280 SysProperty::SysBlockDev => &Path::new("/sys/block/*"),
281 SysProperty::CpuInfo => &Path::new("/proc/cpuinfo"),
282 SysProperty::Temperature => &Path::new("/sys/class/hwmon"),
283 }
284 }
285
286 pub fn sysproperty(property: SysProperty) -> Result<String, std::io::Error> {
287 let path = match property {
288 SysProperty::OsRelease => Get::path(SysProperty::OsRelease),
289 SysProperty::Hostname => Get::path(SysProperty::Hostname),
290 _ => &Path::new(""),
291 };
292 Ok(String::from(fs::read_to_string(path)?.trim_end()))
293 }
294
295 pub fn uptime() -> Result<f64, std::io::Error> {
296 let output = fs::read_to_string(Get::path(SysProperty::Uptime))?;
297 Ok(handle(
298 output.split(' ').collect::<Vec<&str>>()[0].parse::<f64>(),
299 ))
300 }
301
302 pub fn cpu_info() -> Result<String, Box<dyn std::error::Error>> {
303 let output = fs::read_to_string(Get::path(SysProperty::CpuInfo))?;
304 let re = Regex::new(r"model name\s*: (.*)")?;
305 Ok(re
306 .captures(&output)
307 .map_or("".to_string(), |x| x[1].to_string()))
308 }
309
310 pub fn mem(target: Memory) -> Result<u64, Box<dyn std::error::Error>> {
311 let output = fs::read_to_string(Get::path(SysProperty::Mem))?;
312 let re = match target {
313 Memory::SwapFree => Regex::new(r"SwapFree:\s*(\d*)")?,
314 Memory::SwapTotal => Regex::new(r"SwapTotal:\s*(\d*)")?,
315 Memory::MemTotal => Regex::new(r"MemTotal:\s*(\d*)")?,
316 Memory::MemFree => Regex::new(r"MemFree:\s*(\d*)")?,
317 };
318 match re.captures(&output).map(|m| handle(m[1].parse::<u64>())) {
319 Some(n) => Ok(n * 1024),
320 _ => Ok(0),
321 }
322 }
323
324 pub fn total_clock_speed() -> Result<f32, Box<dyn std::error::Error>> {
325 let output = fs::read_to_string(Get::path(SysProperty::CpuInfo))?;
326 let re = Regex::new(r"cpu MHz\s*: (.*)")?;
327 Ok(re
328 .captures_iter(&output)
329 .map(|x| handle(x[1].parse::<f32>()))
330 .sum::<f32>())
331 }
332
333 pub fn total_cpu_cores() -> Result<usize, std::io::Error> {
334 Ok(fs::read_to_string(Get::path(SysProperty::CpuInfo))?
335 .rmatches("cpu MHz")
336 .count())
337 }
338
339 pub fn cpu_clock() -> Result<f32, Box<dyn std::error::Error>> {
340 Ok(Get::total_clock_speed()? / Get::total_cpu_cores()? as f32)
341 }
342
343 pub fn network_dev() -> Result<NetworkDevices, Box<dyn std::error::Error>> {
344 let mut devices = vec![];
345 let output = fs::read_to_string(Get::path(SysProperty::NetDev))?;
346 let re =
347 Regex::new(r"([\d\w]*):\s*(\d*)\s*\d*\s*\d*\s*\d*\s*\d*\s*\d*\s*\d*\s*\d*\s*(\d*)")?;
348 for network_dev in re.captures_iter(&output) {
349 devices.push(NetworkDevice {
350 name: network_dev[1].to_string(),
351 received_bytes: handle(network_dev[2].parse::<u64>()),
352 transfered_bytes: handle(network_dev[3].parse::<u64>()),
353 ipv4_addr: Get::ipv4_addr(&network_dev[1])?,
354 ipv6_addr: Get::ipv6_addr(&network_dev[1])?,
355 });
356 }
357 Ok(NetworkDevices { devices })
358 }
359
360 pub fn storage_devices() -> Result<Storages, Box<dyn std::error::Error>> {
361 let mut devices = vec![];
362 let mut sys_block_devs = vec![];
363 for entry in glob(Get::path(SysProperty::SysBlockDev).to_str().unwrap())? {
364 if let Ok(path) = entry {
365 let name = path.strip_prefix("/sys/block/").unwrap();
366 if let Some(str_name) = name.to_str() {
367 sys_block_devs.push(str_name.to_string())
368 }
369 }
370 }
371
372 let output = fs::read_to_string(Get::path(SysProperty::StorDev))?;
373 let re = Regex::new(r"(?m)^\s*(\d*)\s*(\d*)\s*(\d*)\s([\w\d]*)$")?;
374 for storage_dev in re
375 .captures_iter(&output)
376 .filter(|storage_dev| {
377 !(storage_dev[4].starts_with("loop") || storage_dev[4].starts_with("ram"))
378 })
379 .filter(|storage_dev| &storage_dev[2] == "0")
380 {
381 devices.push(Storage {
382 major: handle(storage_dev[1].parse::<u16>()),
383 minor: handle(storage_dev[2].parse::<u16>()),
384 size: handle(storage_dev[3].parse::<u64>()) * 1024,
385 name: storage_dev[4].to_string(),
386 partitions: handle(Get::storage_partitions(&storage_dev[4])),
387 });
388 }
389
390 Ok(Storages { devices })
391 }
392
393 fn storage_partitions(stor_name: &str) -> Result<Partitions, Box<dyn std::error::Error>> {
394 let mut partitions = vec![];
395 let output = fs::read_to_string(Get::path(SysProperty::StorDev))?;
396 let re = Regex::new(r"(?m)^\s*(\d*)\s*(\d*)\s*(\d*)\s(\w*\d+)$")?;
397 let re2 = Regex::new(r"/dev/(\w*)\s(\S*)\s(\S*)")?;
398 let output2 = fs::read_to_string(Get::path(SysProperty::StorMounts))?;
399
400 for storage_dev in re
401 .captures_iter(&output)
402 .filter(|x| x[4].starts_with(stor_name))
403 {
404 let mut partition = Partition::new();
405 let partition_name = &storage_dev[4];
406
407 for found_partition in re2.captures_iter(&output2) {
408 if &found_partition[1] == partition_name {
409 partition.mountpoint = found_partition[2].to_string();
410 partition.filesystem = found_partition[3].to_string();
411 break;
412 } else {
413 partition.mountpoint = "".to_string();
414 partition.filesystem = "".to_string();
415 }
416 }
417 partition.major = handle(storage_dev[1].parse::<u16>());
418 partition.minor = handle(storage_dev[2].parse::<u16>());
419 partition.size = handle(storage_dev[3].parse::<u64>()) * 1024;
420 partition.name = partition_name.to_string();
421 partitions.push(partition);
422 }
423 Ok(partitions)
424 }
425
426 pub fn vgs() -> Result<VolGroups, Box<dyn std::error::Error>> {
427 let mut vgs: Vec<VolGroup> = vec![];
428 let output = fs::read_to_string(Get::path(SysProperty::StorDev))?;
429 let re = Regex::new(r"(?m)\d*\s*dm-")?;
430 if re.captures(&output).is_some() {
431 let cmd = Command::new("vgdisplay").arg("--units").arg("b").output()?;
432 let out = str::from_utf8(&cmd.stdout)?;
433 let re = Regex::new(r"(?m)VG Name\s*(.*)\n.*\n\s*Format\s*(.*)$(?:\n.*){3}\s*VG Status\s*(.*)$(?:\n.*){6}$\s*VG Size\s*(\d*)")?;
434 for vg in re.captures_iter(&out) {
435 vgs.push(VolGroup {
436 name: vg[1].to_string(),
437 format: vg[2].to_string(),
438 status: vg[3].to_string(),
439 size: handle(vg[4].parse::<u64>()),
440 lvms: handle(Get::lvms(vg[1].to_string())),
441 })
442 }
443 }
444
445 Ok(VolGroups { vgs })
446 }
447
448 fn lvms(vg_name: String) -> Result<Vec<LogVolume>, Box<dyn std::error::Error>> {
449 let mut lvms_vec: Vec<LogVolume> = vec![];
450 let cmd = Command::new("lvdisplay").arg("--units").arg("b").output()?;
451 let out = str::from_utf8(&cmd.stdout)?;
452 let re = Regex::new(r"(?m)LV Path\s*(.*)\n\s*LV Name\s*(.*)$\s*VG Name\s*(.*)$(?:\n.*){3}$\s*LV Status\s*(.*)\n.*$\n\s*LV Size\s*(\d*).*$(?:\n.*){5}\s*Block device\s*(\d*):(\d*)$")?;
453 for lvm in re.captures_iter(&out).filter(|lvm| lvm[3] == vg_name) {
454 lvms_vec.push(LogVolume {
455 name: lvm[2].to_string(),
456 path: lvm[1].to_string(),
457 vg: lvm[3].to_string(),
458 status: lvm[4].to_string(),
459 size: handle(lvm[5].parse::<u64>()),
460 major: handle(lvm[6].parse::<u16>()),
461 minor: handle(lvm[7].parse::<u16>()),
462 mountpoint: "".to_string(), })
464 }
465 Ok(lvms_vec)
466 }
467
468 pub fn graphics_card() -> Result<String, Box<dyn std::error::Error>> {
469 let cmd = Command::new("lspci").output()?;
470 let out = str::from_utf8(&cmd.stdout)?;
471 let re = Regex::new(r"(?m)VGA compatible controller:\s*(.*)$")?;
472 Ok(re
473 .captures(&out)
474 .map_or("".to_string(), |vga| vga[1].to_string()))
475 }
476
477 fn ipv4_addr(interface_name: &str) -> Result<Ipv4Addr, Box<dyn std::error::Error>> {
478 let mut iface_dest = "".to_string();
479 let mut ip_addr = Ipv4Addr::UNSPECIFIED;
480 if interface_name == "lo" {
481 Ok(Ipv4Addr::LOCALHOST)
482 } else {
483 let output = fs::read_to_string("/proc/net/route")?;
484 let re = Regex::new(r"(?m)^([\d\w]*)\s*([\d\w]*)")?;
485 for dest in re.captures_iter(&output) {
486 if &dest[1] == interface_name && &dest[2] != "00000000" {
487 iface_dest = utils::conv_hex_to_ip(&dest[2])?;
488 }
489 }
490
491 let output = fs::read_to_string("/proc/net/fib_trie")?;
492 let file = output.split('\n').collect::<Vec<&str>>();
493 let re = Regex::new(r"\|--\s+(.*)")?;
494 let mut found = false;
495 for (i, line) in (&file).iter().enumerate() {
496 if line.to_string().contains(&iface_dest) {
497 found = true;
498 } else if found && line.to_string().contains("/32 host LOCAL") {
499 ip_addr = match re.captures(&file[i - 1]) {
500 Some(n) => Ipv4Addr::from_str(&n[1])?,
501 None => Ipv4Addr::UNSPECIFIED,
502 };
503 break;
504 }
505 }
506 Ok(ip_addr)
507 }
508 }
509
510 fn ipv6_addr(interface_name: &str) -> Result<Ipv6Addr, Box<dyn std::error::Error>> {
511 let mut ip_addr = Ipv6Addr::UNSPECIFIED;
512 if interface_name == "lo" {
513 Ok(Ipv6Addr::LOCALHOST)
514 } else {
515 let output = fs::read_to_string("/proc/net/if_inet6")?;
516 let re = Regex::new(r"(?m)^([\d\w]*)\s\d*\s\d*\s\d*\s\d*\s*(.*)$")?;
517 for capture in re.captures_iter(&output) {
518 if &capture[2] == interface_name {
519 ip_addr = Ipv6Addr::from_str(&format!(
520 "{}:{}:{}:{}:{}:{}:{}:{}",
521 &capture[1][..4],
522 &capture[1][4..8],
523 &capture[1][8..12],
524 &capture[1][12..16],
525 &capture[1][16..20],
526 &capture[1][20..24],
527 &capture[1][24..28],
528 &capture[1][28..32]
529 ))?;
530 break;
531 }
532 }
533 Ok(ip_addr)
534 }
535 }
536
537 pub fn temperatures() -> Result<Temperatures, Box<dyn std::error::Error>> {
538 let paths = fs::read_dir(Get::path(SysProperty::Temperature))?;
540 let mut devices: Vec<DeviceSensors> = vec![];
541 let re = Regex::new(r"temp[\d]+_input")?;
542 for dir_entry in paths {
543 let mut sensor_count = 0;
544 let path = dir_entry?.path();
545 let mut dev = DeviceSensors::new();
546 let mut dev_temps: Vec<Sensor> = vec![];
547 dev.name = fs::read_to_string(path.join("name"))?.trim().to_string();
548 for temp_file in fs::read_dir(&path)? {
549 if re.is_match(&temp_file?.path().to_str().unwrap()) {
550 sensor_count += 1;
551 }
552 }
553 for i in 1..=sensor_count {
554 let mut sensor = Sensor::new();
555 sensor.name = fs::read_to_string(path.join(format!("temp{}_label", i)))
556 .unwrap_or("".to_string())
557 .trim()
558 .to_string();
559 sensor.temp = handle(
560 fs::read_to_string(path.join(format!("temp{}_input", i)))?
561 .trim()
562 .parse::<f32>(),
563 ) / 1000.;
564 dev_temps.push(sensor);
565 }
566 dev.sensors = dev_temps;
567 devices.push(dev);
568 }
569 Ok(Temperatures { devices })
570 }
571}
572
573impl fmt::Display for PcInfo {
574 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
575 write!(
576 f,
577 "┌──────────────────────────────────
578│ HOSTNAME: {}
579│ KERNEL VERSION: {}
580│ UPTIME: {}
581│ CPU: {}
582│ CPU CLOCK: {:.2} MHz
583│ GRAPHICS CARD: {}
584│ MEM: {} {}
585│ MEMFREE: {} {} {}%
586│ SWAP: {} {}
587│ SWAPFREE: {} {} {}%",
588 self.hostname.bold().red(),
589 self.kernel_version.bold(),
590 utils::conv_t(self.uptime).bold(),
591 self.cpu.bold(),
592 self.cpu_clock,
593 self.graphics_card.bold(),
594 utils::conv_b(self.memory).bold(),
595 self.memory.to_string().bold(),
596 utils::conv_b(self.free_memory).bold(),
597 self.free_memory.to_string().bold(),
598 utils::conv_p(self.memory, self.free_memory)
599 .to_string()
600 .bold(),
601 utils::conv_b(self.swap).bold(),
602 self.swap.to_string().bold(),
603 utils::conv_b(self.free_swap).bold(),
604 self.free_swap.to_string().bold(),
605 utils::conv_p(self.swap, self.free_swap).to_string().bold(),
606 )
607 }
608}
609impl fmt::Display for NetworkDevices {
610 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
611 let mut s = String::new();
612 for dev in &self.devices {
613 s.push_str(&dev.to_string());
614 }
615 write!(f, "\n│ NETWORK DEVICE: {}", s)
616 }
617}
618impl fmt::Display for NetworkDevice {
619 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
620 write!(
621 f,
622 "
623│ ├─{}──────────────────────────────────
624│ │ Ipv4: {}
625│ │ Ipv6: {}
626│ │ DOWN: {} {}
627│ │ UP: {} {}",
628 self.name.cyan().bold(),
629 self.ipv4_addr,
630 self.ipv6_addr,
631 utils::conv_b(self.received_bytes),
632 self.received_bytes,
633 utils::conv_b(self.transfered_bytes),
634 self.transfered_bytes
635 )
636 }
637}
638impl fmt::Display for Storages {
639 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
640 let mut s = String::new();
641 for dev in &self.devices {
642 s.push_str(&dev.to_string());
643 }
644 write!(f, "\n│ STORAGE: {}", s)
645 }
646}
647impl fmt::Display for Storage {
648 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
649 let mut partitions = String::new();
650 for p in &self.partitions {
651 partitions.push_str(&p.to_string());
652 }
653 write!(
654 f,
655 "
656│ ├─{}──────────────────────────────────
657│ │ MAJ:MIN: {}:{}
658│ │ SIZE: {} {}
659│ │ PARTITIONS: {}",
660 self.name.red().bold(),
661 self.major,
662 self.minor,
663 utils::conv_b(self.size),
664 self.size,
665 partitions
666 )
667 }
668}
669
670impl fmt::Display for Partition {
671 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
672 write!(
673 f,
674 "
675│ │ ├─{}──────────────────────────────────
676│ │ │ MAJ:MIN: {}:{}
677│ │ │ SIZE: {} {}
678│ │ │ FILESYSTEM: {}
679│ │ │ MOUNTPOINT: {}",
680 self.name.blue().bold(),
681 self.major,
682 self.minor,
683 utils::conv_b(self.size),
684 self.size,
685 self.filesystem,
686 self.mountpoint
687 )
688 }
689}
690impl fmt::Display for VolGroups {
691 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
692 let mut s = String::new();
693 for dev in &self.vgs {
694 s.push_str(&dev.to_string());
695 }
696 write!(f, "\n│ VOLUME GROUPS: {}", s)
697 }
698}
699impl fmt::Display for VolGroup {
700 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
701 let mut lvms = "".to_string();
702 for p in &self.lvms {
703 lvms.push_str(&p.to_string());
704 }
705 write!(
706 f,
707 "
708│ ├─{}──────────────────────────────────
709│ │ FORMAT: {}
710│ │ STATUS: {}
711│ │ SIZE: {}
712│ │ LVMS: {}",
713 self.name.red().bold(),
714 self.format,
715 self.status,
716 self.size,
717 lvms
718 )
719 }
720}
721impl fmt::Display for LogVolume {
722 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
723 write!(
724 f,
725 "
726│ │ ├─{}──────────────────────────────────
727│ │ │ MAJ:MIN: {}:{}
728│ │ │ SIZE: {} {}
729│ │ │ PATH: {}
730│ │ │ STATUS: {}
731│ │ │ MOUNTPOINT: {}",
732 self.name.blue().bold(),
733 self.major,
734 self.minor,
735 utils::conv_b(self.size),
736 self.size,
737 self.path,
738 self.status,
739 self.mountpoint
740 )
741 }
742}
743impl fmt::Display for Temperatures {
744 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
745 let mut s = String::new();
746 for dev in &self.devices {
747 s.push_str(&dev.to_string());
748 }
749 write!(f, "\n│ TEMPERATURES: {}", s)
750 }
751}
752impl fmt::Display for DeviceSensors {
753 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
754 let mut temps = "".to_string();
755 for temp in &self.sensors {
756 temps.push_str(&temp.to_string());
757 }
758 write!(
759 f,
760 "
761│ ├─{}──────────────────────────────────
762│ │ SENSORS: {}",
763 self.name.red().bold(),
764 temps
765 )
766 }
767}
768impl fmt::Display for Sensor {
769 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
770 write!(
771 f,
772 "\n│ │ ├─{} {}°C",
773 self.name.green().bold(),
774 self.temp
775 )
776 }
777}