sysinfo/common/system.rs
1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use std::collections::{HashMap, HashSet};
4use std::ffi::{OsStr, OsString};
5use std::fmt;
6use std::path::Path;
7use std::process::ExitStatus;
8use std::str::FromStr;
9
10use crate::common::DiskUsage;
11use crate::common::impl_get_set::impl_get_set;
12use crate::{CpuInner, Gid, MotherboardInner, ProcessInner, ProductInner, SystemInner, Uid};
13
14/// Type containing system's information such as processes, memory and CPU.
15///
16/// ⚠️ On newer Android versions, there are restrictions on which system information
17/// a non-system application has access to. So CPU information might not be available.
18///
19/// ```
20/// use sysinfo::System;
21///
22/// if sysinfo::IS_SUPPORTED_SYSTEM {
23/// println!("System: {:?}", System::new_all());
24/// } else {
25/// println!("This OS isn't supported (yet?).");
26/// }
27/// ```
28pub struct System {
29 pub(crate) inner: SystemInner,
30}
31
32impl Default for System {
33 fn default() -> System {
34 System::new()
35 }
36}
37
38impl System {
39 /// Creates a new [`System`] instance with nothing loaded.
40 ///
41 /// Use one of the refresh methods (like [`refresh_all`]) to update its internal information.
42 ///
43 /// [`System`]: crate::System
44 /// [`refresh_all`]: #method.refresh_all
45 ///
46 /// ```no_run
47 /// use sysinfo::System;
48 ///
49 /// let s = System::new();
50 /// ```
51 pub fn new() -> Self {
52 Self::new_with_specifics(RefreshKind::nothing())
53 }
54
55 /// Creates a new [`System`] instance with everything loaded.
56 ///
57 /// It is an equivalent of [`System::new_with_specifics`]`(`[`RefreshKind::everything`]`())`.
58 ///
59 /// [`System`]: crate::System
60 ///
61 /// ```no_run
62 /// use sysinfo::System;
63 ///
64 /// let s = System::new_all();
65 /// ```
66 pub fn new_all() -> Self {
67 Self::new_with_specifics(RefreshKind::everything())
68 }
69
70 /// Creates a new [`System`] instance and refresh the data corresponding to the
71 /// given [`RefreshKind`].
72 ///
73 /// [`System`]: crate::System
74 ///
75 /// ```
76 /// use sysinfo::{ProcessRefreshKind, RefreshKind, System};
77 ///
78 /// // We want to only refresh processes.
79 /// let mut system = System::new_with_specifics(
80 /// RefreshKind::nothing().with_processes(ProcessRefreshKind::everything()),
81 /// );
82 ///
83 /// # if sysinfo::IS_SUPPORTED_SYSTEM && !cfg!(feature = "apple-sandbox") {
84 /// assert!(!system.processes().is_empty());
85 /// # }
86 /// ```
87 pub fn new_with_specifics(refreshes: RefreshKind) -> Self {
88 let mut s = Self {
89 inner: SystemInner::new(),
90 };
91 s.refresh_specifics(refreshes);
92 s
93 }
94
95 /// Refreshes according to the given [`RefreshKind`]. It calls the corresponding
96 /// "refresh_" methods.
97 ///
98 /// It will remove dead processes if [`RefreshKind::processes`] returns `Some`.
99 /// If you want to keep dead processes, use [`System::refresh_processes_specifics`]
100 /// directly.
101 ///
102 /// ```
103 /// use sysinfo::{ProcessRefreshKind, RefreshKind, System};
104 ///
105 /// let mut s = System::new_all();
106 ///
107 /// // Let's just update processes:
108 /// s.refresh_specifics(
109 /// RefreshKind::nothing().with_processes(ProcessRefreshKind::everything()),
110 /// );
111 /// ```
112 pub fn refresh_specifics(&mut self, refreshes: RefreshKind) {
113 if let Some(kind) = refreshes.memory() {
114 self.refresh_memory_specifics(kind);
115 }
116 if let Some(kind) = refreshes.cpu() {
117 self.refresh_cpu_specifics(kind);
118 }
119 if let Some(kind) = refreshes.processes() {
120 self.refresh_processes_specifics(ProcessesToUpdate::All, true, kind);
121 }
122 }
123
124 /// Refreshes all system and processes information.
125 ///
126 /// It is the same as calling `system.refresh_specifics(RefreshKind::everything())`.
127 ///
128 /// Don't forget to take a look at [`ProcessRefreshKind::everything`] method to see what it
129 /// will update for processes more in details.
130 ///
131 /// It will remove dead processes. If you want to keep dead processes, use
132 /// [`System::refresh_processes_specifics`] directly.
133 ///
134 /// ```no_run
135 /// use sysinfo::System;
136 ///
137 /// let mut s = System::new();
138 /// s.refresh_all();
139 /// ```
140 pub fn refresh_all(&mut self) {
141 self.refresh_specifics(RefreshKind::everything());
142 }
143
144 /// Refreshes RAM and SWAP usage.
145 ///
146 /// It is the same as calling `system.refresh_memory_specifics(MemoryRefreshKind::everything())`.
147 ///
148 /// If you don't want to refresh both, take a look at [`System::refresh_memory_specifics`].
149 ///
150 /// ```no_run
151 /// use sysinfo::System;
152 ///
153 /// let mut s = System::new();
154 /// s.refresh_memory();
155 /// ```
156 pub fn refresh_memory(&mut self) {
157 self.refresh_memory_specifics(MemoryRefreshKind::everything())
158 }
159
160 /// Refreshes system memory specific information.
161 ///
162 /// ```no_run
163 /// use sysinfo::{MemoryRefreshKind, System};
164 ///
165 /// let mut s = System::new();
166 /// s.refresh_memory_specifics(MemoryRefreshKind::nothing().with_ram());
167 /// ```
168 pub fn refresh_memory_specifics(&mut self, refresh_kind: MemoryRefreshKind) {
169 self.inner.refresh_memory_specifics(refresh_kind)
170 }
171
172 /// Refreshes CPUs usage.
173 ///
174 /// ⚠️ Please note that the result will very likely be inaccurate at the first call.
175 /// You need to call this method at least twice (with a bit of time between each call, like
176 /// 200 ms, take a look at [`MINIMUM_CPU_UPDATE_INTERVAL`] for more information)
177 /// to get accurate value as it uses previous results to compute the next value.
178 ///
179 /// Calling this method is the same as calling
180 /// `system.refresh_cpu_specifics(CpuRefreshKind::nothing().with_cpu_usage())`.
181 ///
182 /// ```no_run
183 /// use sysinfo::System;
184 ///
185 /// let mut s = System::new_all();
186 /// // Wait a bit because CPU usage is based on diff.
187 /// std::thread::sleep(sysinfo::MINIMUM_CPU_UPDATE_INTERVAL);
188 /// // Refresh CPUs again.
189 /// s.refresh_cpu_usage();
190 /// ```
191 ///
192 /// [`MINIMUM_CPU_UPDATE_INTERVAL`]: crate::MINIMUM_CPU_UPDATE_INTERVAL
193 pub fn refresh_cpu_usage(&mut self) {
194 self.refresh_cpu_specifics(CpuRefreshKind::nothing().with_cpu_usage())
195 }
196
197 /// Refreshes CPUs frequency information.
198 ///
199 /// Calling this method is the same as calling
200 /// `system.refresh_cpu_specifics(CpuRefreshKind::nothing().with_frequency())`.
201 ///
202 /// ```no_run
203 /// use sysinfo::System;
204 ///
205 /// let mut s = System::new_all();
206 /// s.refresh_cpu_frequency();
207 /// ```
208 pub fn refresh_cpu_frequency(&mut self) {
209 self.refresh_cpu_specifics(CpuRefreshKind::nothing().with_frequency())
210 }
211
212 /// Refreshes the list of CPU.
213 ///
214 /// Normally, this should almost never be needed as it's pretty rare for a computer
215 /// to add a CPU while running, but it's possible on some computers which shutdown
216 /// CPU if the load is low enough.
217 ///
218 /// The `refresh_kind` argument tells what information you want to be retrieved
219 /// for each CPU.
220 ///
221 /// ```no_run
222 /// use sysinfo::{CpuRefreshKind, System};
223 ///
224 /// let mut s = System::new_all();
225 /// // We already have the list of CPU filled, but we want to recompute it
226 /// // in case new CPUs were added.
227 /// s.refresh_cpu_list(CpuRefreshKind::everything());
228 /// ```
229 pub fn refresh_cpu_list(&mut self, refresh_kind: CpuRefreshKind) {
230 self.inner.refresh_cpu_list(refresh_kind);
231 }
232
233 /// Refreshes all information related to CPUs information. It does not refresh the CPU list.
234 /// If you want to refresh the CPU list, use [`System::refresh_cpu_list`] instead.
235 ///
236 /// If you only want the CPU usage, use [`System::refresh_cpu_usage`] instead.
237 ///
238 /// ⚠️ Please note that the result will be inaccurate at the first call.
239 /// You need to call this method at least twice (with a bit of time between each call, like
240 /// 200 ms, take a look at [`MINIMUM_CPU_UPDATE_INTERVAL`] for more information)
241 /// to get accurate value as it uses previous results to compute the next value.
242 ///
243 /// Calling this method is the same as calling
244 /// `system.refresh_cpu_specifics(CpuRefreshKind::everything())`.
245 ///
246 /// ```no_run
247 /// use sysinfo::System;
248 ///
249 /// let mut s = System::new_all();
250 /// s.refresh_cpu_all();
251 /// ```
252 ///
253 /// [`MINIMUM_CPU_UPDATE_INTERVAL`]: crate::MINIMUM_CPU_UPDATE_INTERVAL
254 pub fn refresh_cpu_all(&mut self) {
255 self.refresh_cpu_specifics(CpuRefreshKind::everything())
256 }
257
258 /// Refreshes CPUs specific information. It does not refresh the CPU list.
259 /// If you want to refresh the CPU list, use [`System::refresh_cpu_list`] instead.
260 ///
261 /// ```no_run
262 /// use sysinfo::{System, CpuRefreshKind};
263 ///
264 /// let mut s = System::new_all();
265 /// s.refresh_cpu_specifics(CpuRefreshKind::everything());
266 /// ```
267 pub fn refresh_cpu_specifics(&mut self, refresh_kind: CpuRefreshKind) {
268 self.inner.refresh_cpu_specifics(refresh_kind)
269 }
270
271 /// Gets all processes and updates their information, along with all the tasks each process has.
272 ///
273 /// It does the same as:
274 ///
275 /// ```no_run
276 /// # use sysinfo::{ProcessesToUpdate, ProcessRefreshKind, System, UpdateKind};
277 /// # let mut system = System::new();
278 /// system.refresh_processes_specifics(
279 /// ProcessesToUpdate::All,
280 /// true,
281 /// ProcessRefreshKind::nothing()
282 /// .with_memory()
283 /// .with_cpu()
284 /// .with_disk_usage()
285 /// .with_exe(UpdateKind::OnlyIfNotSet)
286 /// );
287 /// ```
288 ///
289 /// ⚠️ `remove_dead_processes` works as follows: if an updated process is dead, then it is
290 /// removed. So if you refresh pids 1, 2 and 3. If 2 and 7 are dead, only 2 will be removed
291 /// since 7 is not part of the update.
292 ///
293 /// ⚠️ On Linux, `sysinfo` keeps the `stat` files open by default. You can change this behaviour
294 /// by using [`set_open_files_limit`][crate::set_open_files_limit].
295 ///
296 /// ⚠️ On Linux, if you dont need the tasks of each process, you can use
297 /// `refresh_processes_specifics` with `ProcessRefreshKind::everything().without_tasks()`.
298 /// Refreshing all processes and their tasks can be quite expensive. For more information
299 /// see [`ProcessRefreshKind`].
300 ///
301 /// Example:
302 ///
303 /// ```no_run
304 /// use sysinfo::{ProcessesToUpdate, System};
305 ///
306 /// let mut s = System::new_all();
307 /// s.refresh_processes(ProcessesToUpdate::All, true);
308 /// ```
309 pub fn refresh_processes(
310 &mut self,
311 processes_to_update: ProcessesToUpdate<'_>,
312 remove_dead_processes: bool,
313 ) -> usize {
314 self.refresh_processes_specifics(
315 processes_to_update,
316 remove_dead_processes,
317 ProcessRefreshKind::nothing()
318 .with_memory()
319 .with_cpu()
320 .with_disk_usage()
321 .with_exe(UpdateKind::OnlyIfNotSet)
322 .with_tasks(),
323 )
324 }
325
326 /// Gets all processes and updates the specified information.
327 ///
328 /// Returns the number of updated processes.
329 ///
330 /// ⚠️ `remove_dead_processes` works as follows: if an updated process is dead, then it is
331 /// removed. So if you refresh pids 1, 2 and 3. If 2 and 7 are dead, only 2 will be removed
332 /// since 7 is not part of the update.
333 ///
334 /// ⚠️ On Linux, `sysinfo` keeps the `stat` files open by default. You can change this behaviour
335 /// by using [`set_open_files_limit`][crate::set_open_files_limit].
336 ///
337 /// ```no_run
338 /// use sysinfo::{ProcessesToUpdate, ProcessRefreshKind, System};
339 ///
340 /// let mut s = System::new_all();
341 /// s.refresh_processes_specifics(
342 /// ProcessesToUpdate::All,
343 /// true,
344 /// ProcessRefreshKind::everything(),
345 /// );
346 /// ```
347 pub fn refresh_processes_specifics(
348 &mut self,
349 processes_to_update: ProcessesToUpdate<'_>,
350 remove_dead_processes: bool,
351 refresh_kind: ProcessRefreshKind,
352 ) -> usize {
353 fn update_and_remove(pid: &Pid, processes: &mut HashMap<Pid, Process>) {
354 let updated = if let Some(proc) = processes.get_mut(pid) {
355 proc.inner.switch_updated()
356 } else {
357 return;
358 };
359 if !updated {
360 processes.remove(pid);
361 }
362 }
363 fn update(pid: &Pid, processes: &mut HashMap<Pid, Process>) {
364 if let Some(proc) = processes.get_mut(pid)
365 && !proc.inner.switch_updated()
366 {
367 proc.inner.set_nonexistent();
368 }
369 }
370
371 let nb_updated = self
372 .inner
373 .refresh_processes_specifics(processes_to_update, refresh_kind);
374 let processes = self.inner.processes_mut();
375 match processes_to_update {
376 ProcessesToUpdate::All => {
377 if remove_dead_processes {
378 processes.retain(|_, v| v.inner.switch_updated());
379 } else {
380 for proc in processes.values_mut() {
381 proc.inner.switch_updated();
382 }
383 }
384 }
385 ProcessesToUpdate::Some(pids) => {
386 let call = if remove_dead_processes {
387 update_and_remove
388 } else {
389 update
390 };
391 for pid in pids {
392 call(pid, processes);
393 }
394 }
395 }
396 nb_updated
397 }
398
399 /// Returns the process list.
400 ///
401 /// ```no_run
402 /// use sysinfo::System;
403 ///
404 /// let s = System::new_all();
405 /// for (pid, process) in s.processes() {
406 /// println!("{} {:?}", pid, process.name());
407 /// }
408 /// ```
409 pub fn processes(&self) -> &HashMap<Pid, Process> {
410 self.inner.processes()
411 }
412
413 /// Returns the process corresponding to the given `pid` or `None` if no such process exists.
414 ///
415 /// ```no_run
416 /// use sysinfo::{Pid, System};
417 ///
418 /// let s = System::new_all();
419 /// if let Some(process) = s.process(Pid::from(1337)) {
420 /// println!("{:?}", process.name());
421 /// }
422 /// ```
423 pub fn process(&self, pid: Pid) -> Option<&Process> {
424 self.inner.process(pid)
425 }
426
427 /// Returns an iterator of process containing the given `name`.
428 ///
429 /// If you want only the processes with exactly the given `name`, take a look at
430 /// [`System::processes_by_exact_name`].
431 ///
432 /// **⚠️ Important ⚠️**
433 ///
434 /// On **Linux**, there are two things to know about processes' name:
435 /// 1. It is limited to 15 characters.
436 /// 2. It is not always the exe name.
437 ///
438 /// ```no_run
439 /// use sysinfo::System;
440 ///
441 /// let s = System::new_all();
442 /// for process in s.processes_by_name("htop".as_ref()) {
443 /// println!("{} {:?}", process.pid(), process.name());
444 /// }
445 /// ```
446 pub fn processes_by_name<'a: 'b, 'b>(
447 &'a self,
448 name: &'b OsStr,
449 ) -> impl Iterator<Item = &'a Process> + 'b {
450 let finder = memchr::memmem::Finder::new(name.as_encoded_bytes());
451 self.processes()
452 .values()
453 .filter(move |val: &&Process| finder.find(val.name().as_encoded_bytes()).is_some())
454 }
455
456 /// Returns an iterator of processes with exactly the given `name`.
457 ///
458 /// If you instead want the processes containing `name`, take a look at
459 /// [`System::processes_by_name`].
460 ///
461 /// **⚠️ Important ⚠️**
462 ///
463 /// On **Linux**, there are two things to know about processes' name:
464 /// 1. It is limited to 15 characters.
465 /// 2. It is not always the exe name.
466 ///
467 /// ```no_run
468 /// use sysinfo::System;
469 ///
470 /// let s = System::new_all();
471 /// for process in s.processes_by_exact_name("htop".as_ref()) {
472 /// println!("{} {:?}", process.pid(), process.name());
473 /// }
474 /// ```
475 pub fn processes_by_exact_name<'a: 'b, 'b>(
476 &'a self,
477 name: &'b OsStr,
478 ) -> impl Iterator<Item = &'a Process> + 'b {
479 self.processes()
480 .values()
481 .filter(move |val: &&Process| val.name() == name)
482 }
483
484 /// Returns "global" CPUs usage (aka the addition of all the CPUs).
485 ///
486 /// To have up-to-date information, you need to call [`System::refresh_cpu_specifics`] or
487 /// [`System::refresh_specifics`] with `cpu` enabled.
488 ///
489 /// ```no_run
490 /// use sysinfo::{CpuRefreshKind, RefreshKind, System};
491 ///
492 /// let mut s = System::new_with_specifics(
493 /// RefreshKind::nothing().with_cpu(CpuRefreshKind::everything()),
494 /// );
495 /// // Wait a bit because CPU usage is based on diff.
496 /// std::thread::sleep(sysinfo::MINIMUM_CPU_UPDATE_INTERVAL);
497 /// // Refresh CPUs again to get actual value.
498 /// s.refresh_cpu_usage();
499 /// println!("{}%", s.global_cpu_usage());
500 /// ```
501 pub fn global_cpu_usage(&self) -> f32 {
502 self.inner.global_cpu_usage()
503 }
504
505 /// Returns the list of the CPUs.
506 ///
507 /// By default, the list of CPUs is empty until you call [`System::refresh_cpu_specifics`] or
508 /// [`System::refresh_specifics`] with `cpu` enabled.
509 ///
510 /// ```no_run
511 /// use sysinfo::{CpuRefreshKind, RefreshKind, System};
512 ///
513 /// let mut s = System::new_with_specifics(
514 /// RefreshKind::nothing().with_cpu(CpuRefreshKind::everything()),
515 /// );
516 /// // Wait a bit because CPU usage is based on diff.
517 /// std::thread::sleep(sysinfo::MINIMUM_CPU_UPDATE_INTERVAL);
518 /// // Refresh CPUs again to get actual value.
519 /// s.refresh_cpu_usage();
520 /// for cpu in s.cpus() {
521 /// println!("{}%", cpu.cpu_usage());
522 /// }
523 /// ```
524 pub fn cpus(&self) -> &[Cpu] {
525 self.inner.cpus()
526 }
527
528 /// Returns the RAM size in bytes.
529 ///
530 /// ```no_run
531 /// use sysinfo::System;
532 ///
533 /// let s = System::new_all();
534 /// println!("{} bytes", s.total_memory());
535 /// ```
536 ///
537 /// On Linux, if you want to see this information with the limit of your cgroup, take a look
538 /// at [`cgroup_limits`](System::cgroup_limits).
539 pub fn total_memory(&self) -> u64 {
540 self.inner.total_memory()
541 }
542
543 /// Returns the amount of free RAM in bytes.
544 ///
545 /// Generally, "free" memory refers to unallocated memory whereas "available" memory refers to
546 /// memory that is available for (re)use.
547 ///
548 /// Side note: Windows doesn't report "free" memory so this method returns the same value
549 /// as [`available_memory`](System::available_memory).
550 ///
551 /// ```no_run
552 /// use sysinfo::System;
553 ///
554 /// let s = System::new_all();
555 /// println!("{} bytes", s.free_memory());
556 /// ```
557 pub fn free_memory(&self) -> u64 {
558 self.inner.free_memory()
559 }
560
561 /// Returns the amount of available RAM in bytes.
562 ///
563 /// Generally, "free" memory refers to unallocated memory whereas "available" memory refers to
564 /// memory that is available for (re)use.
565 ///
566 /// ⚠️ Windows and FreeBSD don't report "available" memory so [`System::free_memory`]
567 /// returns the same value as this method.
568 ///
569 /// ```no_run
570 /// use sysinfo::System;
571 ///
572 /// let s = System::new_all();
573 /// println!("{} bytes", s.available_memory());
574 /// ```
575 pub fn available_memory(&self) -> u64 {
576 self.inner.available_memory()
577 }
578
579 /// Returns the amount of used RAM in bytes.
580 ///
581 /// ```no_run
582 /// use sysinfo::System;
583 ///
584 /// let s = System::new_all();
585 /// println!("{} bytes", s.used_memory());
586 /// ```
587 pub fn used_memory(&self) -> u64 {
588 self.inner.used_memory()
589 }
590
591 /// Returns the SWAP size in bytes.
592 ///
593 /// ```no_run
594 /// use sysinfo::System;
595 ///
596 /// let s = System::new_all();
597 /// println!("{} bytes", s.total_swap());
598 /// ```
599 pub fn total_swap(&self) -> u64 {
600 self.inner.total_swap()
601 }
602
603 /// Returns the amount of free SWAP in bytes.
604 ///
605 /// ```no_run
606 /// use sysinfo::System;
607 ///
608 /// let s = System::new_all();
609 /// println!("{} bytes", s.free_swap());
610 /// ```
611 pub fn free_swap(&self) -> u64 {
612 self.inner.free_swap()
613 }
614
615 /// Returns the amount of used SWAP in bytes.
616 ///
617 /// ```no_run
618 /// use sysinfo::System;
619 ///
620 /// let s = System::new_all();
621 /// println!("{} bytes", s.used_swap());
622 /// ```
623 pub fn used_swap(&self) -> u64 {
624 self.inner.used_swap()
625 }
626
627 /// Retrieves the limits for the current cgroup (if any), otherwise it returns `None`.
628 ///
629 /// This information is computed every time the method is called.
630 ///
631 /// ⚠️ You need to have run [`refresh_memory`](System::refresh_memory) at least once before
632 /// calling this method.
633 ///
634 /// ⚠️ This method is only implemented for Linux. It always returns `None` for all other
635 /// systems.
636 ///
637 /// ```no_run
638 /// use sysinfo::System;
639 ///
640 /// let s = System::new_all();
641 /// println!("limits: {:?}", s.cgroup_limits());
642 /// ```
643 pub fn cgroup_limits(&self) -> Option<CGroupLimits> {
644 self.inner.cgroup_limits()
645 }
646
647 /// Returns system uptime (in seconds).
648 ///
649 /// **Important**: this information is computed every time this function is called.
650 ///
651 /// ```no_run
652 /// use sysinfo::System;
653 ///
654 /// println!("System running since {} seconds", System::uptime());
655 /// ```
656 pub fn uptime() -> u64 {
657 SystemInner::uptime()
658 }
659
660 /// Returns the time (in seconds) when the system booted since UNIX epoch.
661 ///
662 /// **Important**: this information is computed every time this function is called.
663 ///
664 /// ```no_run
665 /// use sysinfo::System;
666 ///
667 /// println!("System booted at {} seconds", System::boot_time());
668 /// ```
669 pub fn boot_time() -> u64 {
670 SystemInner::boot_time()
671 }
672
673 /// Returns the system load average value.
674 ///
675 /// **Important**: this information is computed every time this function is called.
676 ///
677 /// ⚠️ This is currently not working on **Windows**.
678 ///
679 /// ```no_run
680 /// use sysinfo::System;
681 ///
682 /// let load_avg = System::load_average();
683 /// println!(
684 /// "one minute: {}%, five minutes: {}%, fifteen minutes: {}%",
685 /// load_avg.one,
686 /// load_avg.five,
687 /// load_avg.fifteen,
688 /// );
689 /// ```
690 pub fn load_average() -> LoadAvg {
691 SystemInner::load_average()
692 }
693
694 /// Returns the system name.
695 ///
696 /// | example platform | value of `System::name()` |
697 /// |---|---|
698 /// | linux laptop | "Ubuntu" |
699 /// | android phone | "Pixel 9 Pro" |
700 /// | apple laptop | "Darwin" |
701 /// | windows server | "Windows" |
702 ///
703 /// **Important**: this information is computed every time this function is called.
704 ///
705 /// ```no_run
706 /// use sysinfo::System;
707 ///
708 /// println!("OS: {:?}", System::name());
709 /// ```
710 pub fn name() -> Option<String> {
711 SystemInner::name()
712 }
713
714 /// Returns the system's kernel version.
715 ///
716 /// | example platform | value of `System::kernel_version()` |
717 /// |---|---|
718 /// | linux laptop | "6.8.0-48-generic" |
719 /// | android phone | "6.1.84-android14-11" |
720 /// | apple laptop | "24.1.0" |
721 /// | windows server | "20348" |
722 ///
723 /// **Important**: this information is computed every time this function is called.
724 ///
725 /// ```no_run
726 /// use sysinfo::System;
727 ///
728 /// println!("kernel version: {:?}", System::kernel_version());
729 /// ```
730 pub fn kernel_version() -> Option<String> {
731 SystemInner::kernel_version()
732 }
733
734 /// Returns the system version (e.g. for macOS this will return 15.1 rather than the kernel
735 /// version).
736 ///
737 /// | example platform | value of `System::os_version()` |
738 /// |---|---|
739 /// | linux laptop | "24.04" |
740 /// | android phone | "15" |
741 /// | apple laptop | "15.1.1" |
742 /// | windows server | "10 (20348)" |
743 ///
744 /// **Important**: this information is computed every time this function is called.
745 ///
746 /// ```no_run
747 /// use sysinfo::System;
748 ///
749 /// println!("OS version: {:?}", System::os_version());
750 /// ```
751 pub fn os_version() -> Option<String> {
752 SystemInner::os_version()
753 }
754
755 /// Returns the system long os version.
756 ///
757 /// | example platform | value of `System::long_os_version()` |
758 /// |---|---|
759 /// | linux laptop | "Linux (Ubuntu 24.04)" |
760 /// | android phone | "Android 15 on Pixel 9 Pro" |
761 /// | apple laptop | "macOS 15.1.1 Sequoia" |
762 /// | windows server | "Windows Server 2022 Datacenter" |
763 ///
764 /// **Important**: this information is computed every time this function is called.
765 ///
766 /// ```no_run
767 /// use sysinfo::System;
768 ///
769 /// println!("Long OS Version: {:?}", System::long_os_version());
770 /// ```
771 pub fn long_os_version() -> Option<String> {
772 SystemInner::long_os_version()
773 }
774
775 /// Returns the distribution id as defined by os-release,
776 /// or [`std::env::consts::OS`].
777 ///
778 /// See also
779 /// - <https://www.freedesktop.org/software/systemd/man/os-release.html#ID=>
780 /// - <https://doc.rust-lang.org/std/env/consts/constant.OS.html>
781 ///
782 /// | example platform | value of `System::distribution_id()` |
783 /// |---|---|
784 /// | linux laptop | "ubuntu" |
785 /// | android phone | "android" |
786 /// | apple laptop | "macos" |
787 /// | windows server | "windows" |
788 ///
789 /// **Important**: this information is computed every time this function is called.
790 ///
791 /// ```no_run
792 /// use sysinfo::System;
793 ///
794 /// println!("Distribution ID: {:?}", System::distribution_id());
795 /// ```
796 pub fn distribution_id() -> String {
797 SystemInner::distribution_id()
798 }
799
800 /// Returns the distribution ids of operating systems that are closely
801 /// related to the local operating system in regards to packaging and
802 /// programming interfaces, for example listing one or more OS identifiers
803 /// the local OS is a derivative from.
804 ///
805 /// See also
806 /// - <https://www.freedesktop.org/software/systemd/man/latest/os-release.html#ID_LIKE=>
807 ///
808 /// | example platform | value of `System::distribution_id_like()` |
809 /// |---|---|
810 /// | android phone | [] |
811 /// | archlinux laptop | [] |
812 /// | centos server | ["rhel", "fedora"] |
813 /// | ubuntu laptop | ["debian"] |
814 /// | windows laptop | [] |
815 ///
816 /// **Important**: this information is computed every time this function is called.
817 ///
818 /// ```no_run
819 /// use sysinfo::System;
820 ///
821 /// println!("Distribution ID_LIKE: {:?}", System::distribution_id_like());
822 /// ```
823 pub fn distribution_id_like() -> Vec<String> {
824 SystemInner::distribution_id_like()
825 }
826
827 /// Provides kernel version following this string format:
828 ///
829 /// | Platform | Result |
830 /// |-|-|
831 /// | Windows | Windows OS Build 20348.2227 |
832 /// | Linux | Linux 6.12.13-200.fc41.x86_64 |
833 /// | Android | Android 612.13-200 |
834 /// | MacOS | Darwin 21.6.0 |
835 /// | FreeBSD | FreeBSD 199506 |
836 ///
837 /// If any of the information is not available, it will be replaced with "unknown".
838 ///
839 /// **Important**: this information is computed every time this function is called.
840 ///
841 /// ```no_run
842 /// use sysinfo::System;
843 ///
844 /// println!("Kernel long version: {}", System::kernel_long_version());
845 /// ```
846 ///
847 /// [distribution_id]: System::distribution_id
848 /// [kernel_version]: System::kernel_version
849 pub fn kernel_long_version() -> String {
850 let kernel_version = match System::kernel_version() {
851 None => "unknown".to_string(),
852 Some(s) => s,
853 };
854 let kernel_name = SystemInner::kernel_name().unwrap_or("Unknown");
855 if cfg!(windows) {
856 format!("{kernel_name} OS Build {kernel_version}")
857 } else {
858 format!("{kernel_name} {kernel_version}")
859 }
860 }
861
862 /// Returns the system hostname based off DNS.
863 ///
864 /// **Important**: this information is computed every time this function is called.
865 ///
866 /// ```no_run
867 /// use sysinfo::System;
868 ///
869 /// println!("Hostname: {:?}", System::host_name());
870 /// ```
871 pub fn host_name() -> Option<String> {
872 SystemInner::host_name()
873 }
874
875 /// Returns the CPU architecture (eg. x86, amd64, aarch64, ...).
876 ///
877 /// **Important**: this information is computed every time this function is called.
878 ///
879 /// ```no_run
880 /// use sysinfo::System;
881 ///
882 /// println!("CPU Architecture: {:?}", System::cpu_arch());
883 /// ```
884 pub fn cpu_arch() -> String {
885 SystemInner::cpu_arch().unwrap_or_else(|| std::env::consts::ARCH.to_owned())
886 }
887
888 /// Returns the number of physical cores on the CPU or `None` if it couldn't get it.
889 ///
890 /// In case there are multiple CPUs, it will combine the physical core count of all the CPUs.
891 ///
892 /// **Important**: this information is computed every time this function is called.
893 ///
894 /// ```no_run
895 /// use sysinfo::System;
896 ///
897 /// let s = System::new();
898 /// println!("{:?}", System::physical_core_count());
899 /// ```
900 pub fn physical_core_count() -> Option<usize> {
901 SystemInner::physical_core_count()
902 }
903
904 /// Returns the (default) maximum number of open files for a process.
905 ///
906 /// Returns `None` if it failed retrieving the information or if the current system is not
907 /// supported.
908 ///
909 /// **Important**: this information is computed every time this function is called.
910 ///
911 /// ```no_run
912 /// use sysinfo::System;
913 ///
914 /// println!("Max open files: {:?}", System::open_files_limit());
915 /// ```
916 pub fn open_files_limit() -> Option<usize> {
917 SystemInner::open_files_limit()
918 }
919}
920
921/// This type allows to retrieve motherboard-related information.
922///
923/// ⚠️ Not implemented on NetBSD.
924///
925/// ```
926/// use sysinfo::Motherboard;
927///
928/// if let Some(m) = Motherboard::new() {
929/// println!("{m:?}");
930/// }
931/// ```
932pub struct Motherboard {
933 pub(crate) inner: MotherboardInner,
934}
935
936impl Motherboard {
937 /// Creates a new instance of the `Motherboard` type.
938 ///
939 /// ```
940 /// use sysinfo::Motherboard;
941 ///
942 /// if let Some(m) = Motherboard::new() {
943 /// println!("{m:?}");
944 /// }
945 /// ```
946 pub fn new() -> Option<Self> {
947 Some(Self {
948 inner: MotherboardInner::new()?,
949 })
950 }
951
952 /// Returns the motherboard name.
953 ///
954 /// This corresponds to the model identifier assigned by the motherboard's
955 /// manufacturer (e.g. "20BE0061MC").
956 /// This information isn't available on ARM-based macOS systems.
957 ///
958 /// **Important**: this information is computed every time this function is called.
959 ///
960 /// ```no_run
961 /// use sysinfo::Motherboard;
962 ///
963 /// if let Some(m) = Motherboard::new() {
964 /// println!("Motherboard name: {:?}", m.name());
965 /// }
966 /// ```
967 pub fn name(&self) -> Option<String> {
968 self.inner.name()
969 }
970
971 /// Returns the motherboard vendor name.
972 ///
973 /// This corresponds to the name of the motherboard's manufacturer (e.g. "LENOVO").
974 ///
975 /// **Important**: this information is computed every time this function is called.
976 ///
977 /// ```no_run
978 /// use sysinfo::Motherboard;
979 ///
980 /// if let Some(m) = Motherboard::new() {
981 /// println!("Motherboard vendor: {:?}", m.vendor_name());
982 /// }
983 /// ```
984 pub fn vendor_name(&self) -> Option<String> {
985 self.inner.vendor_name()
986 }
987
988 /// Returns the motherboard version.
989 ///
990 /// This corresponds to the version or model number assigned by the motherboard's
991 /// manufacturer (e.g. "0B98401 Pro").
992 /// This information isn't available on ARM-based macOS systems.
993 ///
994 /// **Important**: this information is computed every time this function is called.
995 ///
996 /// ```no_run
997 /// use sysinfo::Motherboard;
998 ///
999 /// if let Some(m) = Motherboard::new() {
1000 /// println!("Motherboard version: {:?}", m.version());
1001 /// }
1002 /// ```
1003 pub fn version(&self) -> Option<String> {
1004 self.inner.version()
1005 }
1006
1007 /// Returns the motherboard serial number.
1008 ///
1009 /// This corresponds to the serial number assigned by the motherboard's
1010 /// manufacturer (e.g. "W1KS427111E").
1011 ///
1012 /// **Important**: this information is computed every time this function is called.
1013 ///
1014 /// ```no_run
1015 /// use sysinfo::Motherboard;
1016 ///
1017 /// if let Some(m) = Motherboard::new() {
1018 /// println!("Motherboard serial number: {:?}", m.serial_number());
1019 /// }
1020 /// ```
1021 pub fn serial_number(&self) -> Option<String> {
1022 self.inner.serial_number()
1023 }
1024
1025 /// Returns the motherboard asset tag.
1026 ///
1027 /// This corresponds to the identifier assigned by the motherboard's
1028 /// manufacturer to track the physical device for inventory purposes.
1029 ///
1030 /// **Important**: this information is computed every time this function is called.
1031 ///
1032 /// ⚠️ Not supported on macOS/iOS.
1033 ///
1034 /// ```no_run
1035 /// use sysinfo::Motherboard;
1036 ///
1037 /// if let Some(m) = Motherboard::new() {
1038 /// println!("Motherboard asset tag: {:?}", m.asset_tag());
1039 /// }
1040 /// ```
1041 pub fn asset_tag(&self) -> Option<String> {
1042 self.inner.asset_tag()
1043 }
1044}
1045
1046/// This type allows to retrieve product-related information.
1047///
1048/// ⚠️ Not implemented on NetBSD.
1049///
1050/// ```
1051/// use sysinfo::Product;
1052///
1053/// println!("{:?}", Product);
1054/// ```
1055pub struct Product;
1056
1057impl Product {
1058 /// Returns the product name.
1059 ///
1060 /// This corresponds to the product name assigned by the hardware
1061 /// manufacturer (e.g. "20AN").
1062 ///
1063 /// **Important**: this information is computed every time this function is called.
1064 ///
1065 /// ```no_run
1066 /// use sysinfo::Product;
1067 ///
1068 /// println!("Product name: {:?}", Product::name());
1069 /// ```
1070 pub fn name() -> Option<String> {
1071 ProductInner::name()
1072 }
1073
1074 /// Returns the product family identifier.
1075 ///
1076 /// This corresponds to the product family assigned by the hardware
1077 /// manufacturer (e.g. "T440p").
1078 ///
1079 /// **Important**: this information is computed every time this function is called.
1080 ///
1081 /// ```no_run
1082 /// use sysinfo::Product;
1083 ///
1084 /// println!("Product family: {:?}", Product::family());
1085 /// ```
1086 pub fn family() -> Option<String> {
1087 ProductInner::family()
1088 }
1089
1090 /// Returns the product serial number.
1091 ///
1092 /// This corresponds to the serial identifier assigned by the hardware
1093 /// manufacturer (e.g. "W1KS427111E").
1094 ///
1095 /// **Important**: this information is computed every time this function is called.
1096 ///
1097 /// ```no_run
1098 /// use sysinfo::Product;
1099 ///
1100 /// println!("Product serial: {:?}", Product::serial_number());
1101 /// ```
1102 pub fn serial_number() -> Option<String> {
1103 ProductInner::serial_number()
1104 }
1105
1106 /// Returns the product Stock Keeping Unit (SKU).
1107 ///
1108 /// This corresponds to the Stock Keeping Unit assigned by the hardware
1109 /// manufacturer (e.g. "LENOVO_MT_20AN") which identifies a specific
1110 /// model or configuration.
1111 ///
1112 /// **Important**: this information is computed every time this function is called.
1113 ///
1114 /// ⚠️ Not supported on macOS/iOS.
1115 ///
1116 /// ```no_run
1117 /// use sysinfo::Product;
1118 ///
1119 /// println!("Product sku: {:?}", Product::stock_keeping_unit());
1120 /// ```
1121 #[doc(alias = "sku")]
1122 pub fn stock_keeping_unit() -> Option<String> {
1123 ProductInner::stock_keeping_unit()
1124 }
1125
1126 /// Returns the product UUID.
1127 ///
1128 /// This corresponds to the unique identifier assigned by the hardware
1129 /// manufacturer (e.g. "407488fe-960a-43b5-a265-8fd0e9200b8f") which uniquely
1130 /// identifies the physical system.
1131 ///
1132 /// **Important**: this information is computed every time this function is called.
1133 ///
1134 /// ```no_run
1135 /// use sysinfo::Product;
1136 ///
1137 /// println!("Product UUID: {:?}", Product::uuid());
1138 /// ```
1139 pub fn uuid() -> Option<String> {
1140 ProductInner::uuid()
1141 }
1142
1143 /// Returns the product version.
1144 ///
1145 /// This corresponds to the version assigned by the hardware
1146 /// manufacturer (e.g. "Lenovo ThinkPad T440p") which identifies
1147 /// the specific version or revision of the product.
1148 ///
1149 /// **Important**: this information is computed every time this function is called.
1150 ///
1151 /// ```no_run
1152 /// use sysinfo::Product;
1153 ///
1154 /// println!("Product version: {:?}", Product::version());
1155 /// ```
1156 pub fn version() -> Option<String> {
1157 ProductInner::version()
1158 }
1159
1160 /// Returns the product vendor name.
1161 ///
1162 /// This corresponds to the vendor name assigned by the hardware
1163 /// manufacturer (e.g. "LENOVO").
1164 ///
1165 /// **Important**: this information is computed every time this function is called.
1166 ///
1167 /// ```no_run
1168 /// use sysinfo::Product;
1169 ///
1170 /// println!("Vendor name: {:?}", Product::vendor_name());
1171 /// ```
1172 pub fn vendor_name() -> Option<String> {
1173 ProductInner::vendor_name()
1174 }
1175}
1176
1177/// A struct representing system load average value.
1178///
1179/// It is returned by [`System::load_average`][crate::System::load_average].
1180///
1181/// ```no_run
1182/// use sysinfo::System;
1183///
1184/// let load_avg = System::load_average();
1185/// println!(
1186/// "one minute: {}%, five minutes: {}%, fifteen minutes: {}%",
1187/// load_avg.one,
1188/// load_avg.five,
1189/// load_avg.fifteen,
1190/// );
1191/// ```
1192#[repr(C)]
1193#[derive(Default, Debug, Clone)]
1194pub struct LoadAvg {
1195 /// Average load within one minute.
1196 pub one: f64,
1197 /// Average load within five minutes.
1198 pub five: f64,
1199 /// Average load within fifteen minutes.
1200 pub fifteen: f64,
1201}
1202
1203/// An enum representing signals on UNIX-like systems.
1204///
1205/// On non-unix systems, this enum is mostly useless and is only there to keep coherency between
1206/// the different OSes.
1207///
1208/// If you want the list of the supported signals on the current system, use
1209/// [`SUPPORTED_SIGNALS`][crate::SUPPORTED_SIGNALS].
1210#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
1211#[cfg_attr(feature = "serde", derive(serde::Deserialize))]
1212pub enum Signal {
1213 /// Hangup detected on controlling terminal or death of controlling process.
1214 Hangup,
1215 /// Interrupt from keyboard.
1216 Interrupt,
1217 /// Quit from keyboard.
1218 Quit,
1219 /// Illegal instruction.
1220 Illegal,
1221 /// Trace/breakpoint trap.
1222 Trap,
1223 /// Abort signal from C abort function.
1224 Abort,
1225 /// IOT trap. A synonym for SIGABRT.
1226 IOT,
1227 /// Bus error (bad memory access).
1228 Bus,
1229 /// Floating point exception.
1230 FloatingPointException,
1231 /// Kill signal.
1232 Kill,
1233 /// User-defined signal 1.
1234 User1,
1235 /// Invalid memory reference.
1236 Segv,
1237 /// User-defined signal 2.
1238 User2,
1239 /// Broken pipe: write to pipe with no readers.
1240 Pipe,
1241 /// Timer signal from C alarm function.
1242 Alarm,
1243 /// Termination signal.
1244 Term,
1245 /// Child stopped or terminated.
1246 Child,
1247 /// Continue if stopped.
1248 Continue,
1249 /// Stop process.
1250 Stop,
1251 /// Stop typed at terminal.
1252 TSTP,
1253 /// Terminal input for background process.
1254 TTIN,
1255 /// Terminal output for background process.
1256 TTOU,
1257 /// Urgent condition on socket.
1258 Urgent,
1259 /// CPU time limit exceeded.
1260 XCPU,
1261 /// File size limit exceeded.
1262 XFSZ,
1263 /// Virtual alarm clock.
1264 VirtualAlarm,
1265 /// Profiling time expired.
1266 Profiling,
1267 /// Windows resize signal.
1268 Winch,
1269 /// I/O now possible.
1270 IO,
1271 /// Pollable event (Sys V). Synonym for IO
1272 Poll,
1273 /// Power failure (System V).
1274 ///
1275 /// Doesn't exist on apple systems so will be ignored.
1276 Power,
1277 /// Bad argument to routine (SVr4).
1278 Sys,
1279}
1280
1281impl std::fmt::Display for Signal {
1282 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1283 let s = match *self {
1284 Self::Hangup => "Hangup",
1285 Self::Interrupt => "Interrupt",
1286 Self::Quit => "Quit",
1287 Self::Illegal => "Illegal",
1288 Self::Trap => "Trap",
1289 Self::Abort => "Abort",
1290 Self::IOT => "IOT",
1291 Self::Bus => "Bus",
1292 Self::FloatingPointException => "FloatingPointException",
1293 Self::Kill => "Kill",
1294 Self::User1 => "User1",
1295 Self::Segv => "Segv",
1296 Self::User2 => "User2",
1297 Self::Pipe => "Pipe",
1298 Self::Alarm => "Alarm",
1299 Self::Term => "Term",
1300 Self::Child => "Child",
1301 Self::Continue => "Continue",
1302 Self::Stop => "Stop",
1303 Self::TSTP => "TSTP",
1304 Self::TTIN => "TTIN",
1305 Self::TTOU => "TTOU",
1306 Self::Urgent => "Urgent",
1307 Self::XCPU => "XCPU",
1308 Self::XFSZ => "XFSZ",
1309 Self::VirtualAlarm => "VirtualAlarm",
1310 Self::Profiling => "Profiling",
1311 Self::Winch => "Winch",
1312 Self::IO => "IO",
1313 Self::Poll => "Poll",
1314 Self::Power => "Power",
1315 Self::Sys => "Sys",
1316 };
1317 f.write_str(s)
1318 }
1319}
1320
1321/// Contains memory limits for the current process.
1322#[derive(Default, Debug, Clone)]
1323pub struct CGroupLimits {
1324 /// Total memory (in bytes) for the current cgroup.
1325 pub total_memory: u64,
1326 /// Free memory (in bytes) for the current cgroup.
1327 pub free_memory: u64,
1328 /// Free swap (in bytes) for the current cgroup.
1329 pub free_swap: u64,
1330 /// Resident Set Size (RSS) (in bytes) for the current cgroup.
1331 pub rss: u64,
1332}
1333
1334/// Enum describing the different status of a process.
1335#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
1336#[cfg_attr(feature = "serde", derive(serde::Deserialize))]
1337pub enum ProcessStatus {
1338 /// ## Linux
1339 ///
1340 /// Idle kernel thread.
1341 ///
1342 /// ## macOs/FreeBSD
1343 ///
1344 /// Process being created by fork.
1345 ///
1346 /// ## Other OS
1347 ///
1348 /// Not available.
1349 Idle,
1350 /// Running.
1351 Run,
1352 /// ## Linux
1353 ///
1354 /// Sleeping in an interruptible waiting.
1355 ///
1356 /// ## macOS/FreeBSD
1357 ///
1358 /// Sleeping on an address.
1359 ///
1360 /// ## Other OS
1361 ///
1362 /// Not available.
1363 Sleep,
1364 /// ## Linux
1365 ///
1366 /// Stopped (on a signal) or (before Linux 2.6.33) trace stopped.
1367 ///
1368 /// ## macOS/FreeBSD
1369 ///
1370 /// Process debugging or suspension.
1371 ///
1372 /// ## Other OS
1373 ///
1374 /// Not available.
1375 Stop,
1376 /// ## Linux/FreeBSD/macOS
1377 ///
1378 /// Zombie process. Terminated but not reaped by its parent.
1379 ///
1380 /// ## Other OS
1381 ///
1382 /// Not available.
1383 Zombie,
1384 /// ## Linux
1385 ///
1386 /// Tracing stop (Linux 2.6.33 onward). Stopped by debugger during the tracing.
1387 ///
1388 /// ## NetBSD
1389 ///
1390 /// The process is being traced or debugged.
1391 ///
1392 /// ## Other OS
1393 ///
1394 /// Not available.
1395 Tracing,
1396 /// ## Linux
1397 ///
1398 /// Dead/uninterruptible sleep (usually IO).
1399 ///
1400 /// ## FreeBSD
1401 ///
1402 /// A process should never end up in this state.
1403 ///
1404 /// ## Other OS
1405 ///
1406 /// Not available.
1407 Dead,
1408 /// ## Linux
1409 ///
1410 /// Wakekill (Linux 2.6.33 to 3.13 only).
1411 ///
1412 /// ## Other OS
1413 ///
1414 /// Not available.
1415 Wakekill,
1416 /// ## Linux
1417 ///
1418 /// Waking (Linux 2.6.33 to 3.13 only).
1419 ///
1420 /// ## Other OS
1421 ///
1422 /// Not available.
1423 Waking,
1424 /// ## Linux
1425 ///
1426 /// Parked (Linux 3.9 to 3.13 only).
1427 ///
1428 /// ## macOS
1429 ///
1430 /// Halted at a clean point.
1431 ///
1432 /// ## Other OS
1433 ///
1434 /// Not available.
1435 Parked,
1436 /// ## FreeBSD
1437 ///
1438 /// Blocked on a lock.
1439 ///
1440 /// ## Other OS
1441 ///
1442 /// Not available.
1443 LockBlocked,
1444 /// ## Linux
1445 ///
1446 /// Waiting in uninterruptible disk sleep.
1447 ///
1448 /// ## Other OS
1449 ///
1450 /// Not available.
1451 UninterruptibleDiskSleep,
1452 /// ## NetBSD
1453 ///
1454 /// Suspended process.
1455 ///
1456 /// ## Other OS
1457 ///
1458 /// Not available.
1459 Suspended,
1460 /// Unknown.
1461 Unknown(u32),
1462}
1463
1464/// Enum describing the different kind of threads.
1465#[derive(Clone, Copy, Debug, PartialEq, Eq)]
1466#[cfg_attr(feature = "serde", derive(serde::Deserialize))]
1467pub enum ThreadKind {
1468 /// Kernel thread.
1469 Kernel,
1470 /// User thread.
1471 Userland,
1472}
1473
1474/// Enum describing possible [`Process::kill_and_wait`] errors.
1475#[derive(Clone, Copy, Debug, PartialEq, Eq)]
1476#[cfg_attr(feature = "serde", derive(serde::Deserialize))]
1477pub enum KillError {
1478 /// This signal doesn't exist on this platform.
1479 SignalDoesNotExist,
1480 /// The signal failed to be sent to the target process.
1481 FailedToSendSignal,
1482}
1483
1484impl core::fmt::Display for KillError {
1485 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1486 match self {
1487 Self::SignalDoesNotExist => f.write_str("signal does not exist"),
1488 Self::FailedToSendSignal => f.write_str("failed to send signal"),
1489 }
1490 }
1491}
1492
1493impl core::error::Error for KillError {}
1494
1495/// Struct containing information of a process.
1496///
1497/// ## iOS
1498///
1499/// This information cannot be retrieved on iOS due to sandboxing.
1500///
1501/// ## Apple app store
1502///
1503/// If you are building a macOS Apple app store, it won't be able
1504/// to retrieve this information.
1505///
1506/// ```no_run
1507/// use sysinfo::{Pid, System};
1508///
1509/// let s = System::new_all();
1510/// if let Some(process) = s.process(Pid::from(1337)) {
1511/// println!("{:?}", process.name());
1512/// }
1513/// ```
1514pub struct Process {
1515 pub(crate) inner: ProcessInner,
1516}
1517
1518impl Process {
1519 /// Sends [`Signal::Kill`] to the process (which is the only signal supported on all supported
1520 /// platforms by this crate).
1521 ///
1522 /// Returns `true` if the signal was sent successfully. If you want to wait for this process
1523 /// to end, you can use [`Process::wait`] or directly [`Process::kill_and_wait`].
1524 ///
1525 /// ⚠️ Even if this function returns `true`, it doesn't necessarily mean that the process will
1526 /// be killed. It just means that the signal was sent successfully.
1527 ///
1528 /// ⚠️ Please note that some processes might not be "killable", like if they run with higher
1529 /// levels than the current process for example.
1530 ///
1531 /// If you want to use another signal, take a look at [`Process::kill_with`].
1532 ///
1533 /// To get the list of the supported signals on this system, use
1534 /// [`SUPPORTED_SIGNALS`][crate::SUPPORTED_SIGNALS].
1535 ///
1536 /// ```no_run
1537 /// use sysinfo::{Pid, System};
1538 ///
1539 /// let s = System::new_all();
1540 /// if let Some(process) = s.process(Pid::from(1337)) {
1541 /// process.kill();
1542 /// }
1543 /// ```
1544 pub fn kill(&self) -> bool {
1545 self.kill_with(Signal::Kill).unwrap_or(false)
1546 }
1547
1548 /// Sends the given `signal` to the process. If the signal doesn't exist on this platform,
1549 /// it'll do nothing and will return `None`. Otherwise it'll return `Some(bool)`. The boolean
1550 /// value will depend on whether or not the signal was sent successfully.
1551 ///
1552 /// If you just want to kill the process, use [`Process::kill`] directly. If you want to wait
1553 /// for this process to end, you can use [`Process::wait`] or [`Process::kill_with_and_wait`].
1554 ///
1555 /// ⚠️ Please note that some processes might not be "killable", like if they run with higher
1556 /// levels than the current process for example.
1557 ///
1558 /// To get the list of the supported signals on this system, use
1559 /// [`SUPPORTED_SIGNALS`][crate::SUPPORTED_SIGNALS].
1560 ///
1561 /// ```no_run
1562 /// use sysinfo::{Pid, Signal, System};
1563 ///
1564 /// let s = System::new_all();
1565 /// if let Some(process) = s.process(Pid::from(1337)) {
1566 /// if process.kill_with(Signal::Kill).is_none() {
1567 /// println!("This signal isn't supported on this platform");
1568 /// }
1569 /// }
1570 /// ```
1571 pub fn kill_with(&self, signal: Signal) -> Option<bool> {
1572 self.inner.kill_with(signal)
1573 }
1574
1575 /// Sends [`Signal::Kill`] to the process then waits for its termination.
1576 ///
1577 /// Internally, this method is calling [`Process::kill`] then [`Process::wait`].
1578 ///
1579 /// ⚠️ Please note that some processes might not be "killable", like if they run with higher
1580 /// levels than the current process for example. In this case, this method could enter an
1581 /// infinite loop.
1582 ///
1583 /// ```no_run
1584 /// use sysinfo::{Pid, System};
1585 ///
1586 /// let s = System::new_all();
1587 /// if let Some(process) = s.process(Pid::from(1337)) {
1588 /// if let Err(error) = process.kill_and_wait() {
1589 /// println!("`kill_and_wait` failed: {error:?}");
1590 /// }
1591 /// }
1592 /// ```
1593 pub fn kill_and_wait(&self) -> Result<Option<ExitStatus>, KillError> {
1594 self.kill_with_and_wait(Signal::Kill)
1595 }
1596
1597 /// Sends the given `signal` to the process.then waits for its termination.
1598 ///
1599 /// Internally, this method is calling [`Process::kill_with`] then [`Process::wait`].
1600 ///
1601 /// ⚠️ Please note that some processes might not be "killable", like if they run with higher
1602 /// levels than the current process for example. In this case, this method could enter an
1603 /// infinite loop.
1604 ///
1605 /// To get the list of the supported signals on this system, use
1606 /// [`SUPPORTED_SIGNALS`][crate::SUPPORTED_SIGNALS].
1607 ///
1608 /// ```no_run
1609 /// use sysinfo::{Pid, System};
1610 ///
1611 /// let s = System::new_all();
1612 /// if let Some(process) = s.process(Pid::from(1337)) {
1613 /// if let Err(error) = process.kill_and_wait() {
1614 /// println!("`kill_and_wait` failed: {error:?}");
1615 /// }
1616 /// }
1617 /// ```
1618 pub fn kill_with_and_wait(&self, signal: Signal) -> Result<Option<ExitStatus>, KillError> {
1619 match self.inner.kill_with(signal) {
1620 Some(sent) => {
1621 if !sent {
1622 return Err(KillError::FailedToSendSignal);
1623 }
1624 }
1625 None => return Err(KillError::SignalDoesNotExist),
1626 }
1627
1628 Ok(self.inner.wait())
1629 }
1630
1631 /// Waits for process termination and returns its [`ExitStatus`] if it could be retrieved,
1632 /// returns `None` otherwise. It means that as long as the process is alive, this method will
1633 /// not return.
1634 ///
1635 /// ⚠️ On **macOS** and **FreeBSD**, if the process died and a new one took its PID, unless
1636 /// you refreshed, it will wait for the new process to end.
1637 ///
1638 /// On **Windows**, as long as we have a (internal) handle, we can always retrieve the exit
1639 /// status.
1640 ///
1641 /// On **Linux**/**Android**, we check that the start time of the PID we're waiting is the same
1642 /// as the current process'. If not it means the process died and a new one got its PID.
1643 ///
1644 /// ```no_run
1645 /// use sysinfo::{Pid, System};
1646 ///
1647 /// let mut s = System::new_all();
1648 ///
1649 /// if let Some(process) = s.process(Pid::from(1337)) {
1650 /// println!("Waiting for pid 1337");
1651 /// let exit_status = process.wait();
1652 /// println!("Pid 1337 exited with: {exit_status:?}");
1653 /// }
1654 /// ```
1655 pub fn wait(&self) -> Option<ExitStatus> {
1656 self.inner.wait()
1657 }
1658
1659 /// Returns the name of the process.
1660 ///
1661 /// **⚠️ Important ⚠️**
1662 ///
1663 /// On **Linux**, there are two things to know about processes' name:
1664 /// 1. It is limited to 15 characters.
1665 /// 2. It is not always the exe name.
1666 ///
1667 /// If you are looking for a specific process, unless you know what you are
1668 /// doing, in most cases it's better to use [`Process::exe`] instead (which
1669 /// can be empty sometimes!).
1670 ///
1671 /// ```no_run
1672 /// use sysinfo::{Pid, System};
1673 ///
1674 /// let s = System::new_all();
1675 /// if let Some(process) = s.process(Pid::from(1337)) {
1676 /// println!("{:?}", process.name());
1677 /// }
1678 /// ```
1679 pub fn name(&self) -> &OsStr {
1680 self.inner.name()
1681 }
1682
1683 /// Returns the command line.
1684 ///
1685 /// **⚠️ Important ⚠️**
1686 ///
1687 /// On **Windows**, you might need to use `administrator` privileges when running your program
1688 /// to have access to this information.
1689 ///
1690 /// ```no_run
1691 /// use sysinfo::{Pid, System};
1692 ///
1693 /// let s = System::new_all();
1694 /// if let Some(process) = s.process(Pid::from(1337)) {
1695 /// println!("{:?}", process.cmd());
1696 /// }
1697 /// ```
1698 pub fn cmd(&self) -> &[OsString] {
1699 self.inner.cmd()
1700 }
1701
1702 /// Returns the path to the process.
1703 ///
1704 /// ```no_run
1705 /// use sysinfo::{Pid, System};
1706 ///
1707 /// let s = System::new_all();
1708 /// if let Some(process) = s.process(Pid::from(1337)) {
1709 /// println!("{:?}", process.exe());
1710 /// }
1711 /// ```
1712 ///
1713 /// ### Implementation notes
1714 ///
1715 /// On Linux, this method will return an empty path if there
1716 /// was an error trying to read `/proc/<pid>/exe`. This can
1717 /// happen, for example, if the permission levels or UID namespaces
1718 /// between the caller and target processes are different.
1719 ///
1720 /// It is also the case that `cmd[0]` is _not_ usually a correct
1721 /// replacement for this.
1722 /// A process [may change its `cmd[0]` value](https://man7.org/linux/man-pages/man5/proc.5.html)
1723 /// freely, making this an untrustworthy source of information.
1724 pub fn exe(&self) -> Option<&Path> {
1725 self.inner.exe()
1726 }
1727
1728 /// Returns the PID of the process.
1729 ///
1730 /// ```no_run
1731 /// use sysinfo::{Pid, System};
1732 ///
1733 /// let s = System::new_all();
1734 /// if let Some(process) = s.process(Pid::from(1337)) {
1735 /// println!("{}", process.pid());
1736 /// }
1737 /// ```
1738 pub fn pid(&self) -> Pid {
1739 self.inner.pid()
1740 }
1741
1742 /// Returns the environment variables of the process.
1743 ///
1744 /// ```no_run
1745 /// use sysinfo::{Pid, System};
1746 ///
1747 /// let s = System::new_all();
1748 /// if let Some(process) = s.process(Pid::from(1337)) {
1749 /// println!("{:?}", process.environ());
1750 /// }
1751 /// ```
1752 pub fn environ(&self) -> &[OsString] {
1753 self.inner.environ()
1754 }
1755
1756 /// Returns the current working directory.
1757 ///
1758 /// ```no_run
1759 /// use sysinfo::{Pid, System};
1760 ///
1761 /// let s = System::new_all();
1762 /// if let Some(process) = s.process(Pid::from(1337)) {
1763 /// println!("{:?}", process.cwd());
1764 /// }
1765 /// ```
1766 pub fn cwd(&self) -> Option<&Path> {
1767 self.inner.cwd()
1768 }
1769
1770 /// Returns the path of the root directory.
1771 ///
1772 /// ⚠️ Not implemented in NetBSD.
1773 ///
1774 /// ```no_run
1775 /// use sysinfo::{Pid, System};
1776 ///
1777 /// let s = System::new_all();
1778 /// if let Some(process) = s.process(Pid::from(1337)) {
1779 /// println!("{:?}", process.root());
1780 /// }
1781 /// ```
1782 pub fn root(&self) -> Option<&Path> {
1783 self.inner.root()
1784 }
1785
1786 /// Returns the memory usage (in bytes).
1787 ///
1788 /// This method returns the [size of the resident set], that is, the amount of memory that the
1789 /// process allocated and which is currently mapped in physical RAM. It does not include memory
1790 /// that is swapped out, or, in some operating systems, that has been allocated but never used.
1791 ///
1792 /// Thus, it represents exactly the amount of physical RAM that the process is using at the
1793 /// present time, but it might not be a good indicator of the total memory that the process will
1794 /// be using over its lifetime. For that purpose, you can try and use
1795 /// [`virtual_memory`](Process::virtual_memory).
1796 ///
1797 /// ```no_run
1798 /// use sysinfo::{Pid, System};
1799 ///
1800 /// let s = System::new_all();
1801 /// if let Some(process) = s.process(Pid::from(1337)) {
1802 /// println!("{} bytes", process.memory());
1803 /// }
1804 /// ```
1805 ///
1806 /// [size of the resident set]: https://en.wikipedia.org/wiki/Resident_set_size
1807 pub fn memory(&self) -> u64 {
1808 self.inner.memory()
1809 }
1810
1811 /// Returns the virtual memory usage (in bytes).
1812 ///
1813 /// This method returns the [size of virtual memory], that is, the amount of memory that the
1814 /// process can access, whether it is currently mapped in physical RAM or not. It includes
1815 /// physical RAM, allocated but not used regions, swapped-out regions, and even memory
1816 /// associated with [memory-mapped files](https://en.wikipedia.org/wiki/Memory-mapped_file).
1817 ///
1818 /// This value has limitations though. Depending on the operating system and type of process,
1819 /// this value might be a good indicator of the total memory that the process will be using over
1820 /// its lifetime. However, for example, in the version 14 of macOS this value is in the order of
1821 /// the hundreds of gigabytes for every process, and thus not very informative. Moreover, if a
1822 /// process maps into memory a very large file, this value will increase accordingly, even if
1823 /// the process is not actively using the memory.
1824 ///
1825 /// ```no_run
1826 /// use sysinfo::{Pid, System};
1827 ///
1828 /// let s = System::new_all();
1829 /// if let Some(process) = s.process(Pid::from(1337)) {
1830 /// println!("{} bytes", process.virtual_memory());
1831 /// }
1832 /// ```
1833 ///
1834 /// [size of virtual memory]: https://en.wikipedia.org/wiki/Virtual_memory
1835 pub fn virtual_memory(&self) -> u64 {
1836 self.inner.virtual_memory()
1837 }
1838
1839 /// Returns the parent PID.
1840 ///
1841 /// ```no_run
1842 /// use sysinfo::{Pid, System};
1843 ///
1844 /// let s = System::new_all();
1845 /// if let Some(process) = s.process(Pid::from(1337)) {
1846 /// println!("{:?}", process.parent());
1847 /// }
1848 /// ```
1849 pub fn parent(&self) -> Option<Pid> {
1850 self.inner.parent()
1851 }
1852
1853 /// Returns the status of the process.
1854 ///
1855 /// ```no_run
1856 /// use sysinfo::{Pid, System};
1857 ///
1858 /// let s = System::new_all();
1859 /// if let Some(process) = s.process(Pid::from(1337)) {
1860 /// println!("{:?}", process.status());
1861 /// }
1862 /// ```
1863 pub fn status(&self) -> ProcessStatus {
1864 self.inner.status()
1865 }
1866
1867 /// Returns the time where the process was started (in seconds) from epoch.
1868 ///
1869 /// ```no_run
1870 /// use sysinfo::{Pid, System};
1871 ///
1872 /// let s = System::new_all();
1873 /// if let Some(process) = s.process(Pid::from(1337)) {
1874 /// println!("Started at {} seconds", process.start_time());
1875 /// }
1876 /// ```
1877 pub fn start_time(&self) -> u64 {
1878 self.inner.start_time()
1879 }
1880
1881 /// Returns for how much time the process has been running (in seconds).
1882 ///
1883 /// ```no_run
1884 /// use sysinfo::{Pid, System};
1885 ///
1886 /// let s = System::new_all();
1887 /// if let Some(process) = s.process(Pid::from(1337)) {
1888 /// println!("Running since {} seconds", process.run_time());
1889 /// }
1890 /// ```
1891 pub fn run_time(&self) -> u64 {
1892 self.inner.run_time()
1893 }
1894
1895 /// Returns the total CPU usage (in %). Notice that it might be bigger than
1896 /// 100 if run on a multi-core machine.
1897 ///
1898 /// If you want a value between 0% and 100%, divide the returned value by
1899 /// the number of CPUs.
1900 ///
1901 /// ⚠️ To start to have accurate CPU usage, a process needs to be refreshed
1902 /// **twice** because CPU usage computation is based on time diff (process
1903 /// time on a given time period divided by total system time on the same
1904 /// time period).
1905 ///
1906 /// ⚠️ If you want accurate CPU usage number, better leave a bit of time
1907 /// between two calls of this method (take a look at
1908 /// [`MINIMUM_CPU_UPDATE_INTERVAL`][crate::MINIMUM_CPU_UPDATE_INTERVAL] for
1909 /// more information).
1910 ///
1911 /// ```no_run
1912 /// use sysinfo::{Pid, ProcessesToUpdate, ProcessRefreshKind, System};
1913 ///
1914 /// let mut s = System::new_all();
1915 /// // Wait a bit because CPU usage is based on diff.
1916 /// std::thread::sleep(sysinfo::MINIMUM_CPU_UPDATE_INTERVAL);
1917 /// // Refresh CPU usage to get actual value.
1918 /// s.refresh_processes_specifics(
1919 /// ProcessesToUpdate::All,
1920 /// true,
1921 /// ProcessRefreshKind::nothing().with_cpu()
1922 /// );
1923 /// if let Some(process) = s.process(Pid::from(1337)) {
1924 /// println!("{}%", process.cpu_usage());
1925 /// }
1926 /// ```
1927 pub fn cpu_usage(&self) -> f32 {
1928 self.inner.cpu_usage()
1929 }
1930
1931 /// Returns the total accumulated CPU usage (in CPU-milliseconds). Note
1932 /// that it might be bigger than the total clock run time of a process if
1933 /// run on a multi-core machine.
1934 ///
1935 /// ```no_run
1936 /// use sysinfo::{Pid, System};
1937 ///
1938 /// let s = System::new_all();
1939 /// if let Some(process) = s.process(Pid::from(1337)) {
1940 /// println!("{}", process.accumulated_cpu_time());
1941 /// }
1942 /// ```
1943 pub fn accumulated_cpu_time(&self) -> u64 {
1944 self.inner.accumulated_cpu_time()
1945 }
1946
1947 /// Returns number of bytes read and written to disk.
1948 ///
1949 /// ⚠️ On Windows, this method actually returns **ALL** I/O read and
1950 /// written bytes.
1951 ///
1952 /// ⚠️ Files might be cached in memory by your OS, meaning that reading/writing them might not
1953 /// increase the `read_bytes`/`written_bytes` values. You can find more information about it
1954 /// in the `proc_pid_io` manual (`man proc_pid_io` on unix platforms).
1955 ///
1956 /// ```no_run
1957 /// use sysinfo::{Pid, System};
1958 ///
1959 /// let s = System::new_all();
1960 /// if let Some(process) = s.process(Pid::from(1337)) {
1961 /// let disk_usage = process.disk_usage();
1962 /// println!("read bytes : new/total => {}/{}",
1963 /// disk_usage.read_bytes,
1964 /// disk_usage.total_read_bytes,
1965 /// );
1966 /// println!("written bytes: new/total => {}/{}",
1967 /// disk_usage.written_bytes,
1968 /// disk_usage.total_written_bytes,
1969 /// );
1970 /// }
1971 /// ```
1972 pub fn disk_usage(&self) -> DiskUsage {
1973 self.inner.disk_usage()
1974 }
1975
1976 /// Returns the ID of the owner user of this process or `None` if this
1977 /// information couldn't be retrieved. If you want to get the [`User`] from
1978 /// it, take a look at [`Users::get_user_by_id`].
1979 ///
1980 /// [`User`]: crate::User
1981 /// [`Users::get_user_by_id`]: crate::Users::get_user_by_id
1982 ///
1983 /// ```no_run
1984 /// use sysinfo::{Pid, System};
1985 ///
1986 /// let mut s = System::new_all();
1987 ///
1988 /// if let Some(process) = s.process(Pid::from(1337)) {
1989 /// println!("User id for process 1337: {:?}", process.user_id());
1990 /// }
1991 /// ```
1992 pub fn user_id(&self) -> Option<&Uid> {
1993 self.inner.user_id()
1994 }
1995
1996 /// Returns the user ID of the effective owner of this process or `None` if
1997 /// this information couldn't be retrieved. If you want to get the [`User`]
1998 /// from it, take a look at [`Users::get_user_by_id`].
1999 ///
2000 /// If you run something with `sudo`, the real user ID of the launched
2001 /// process will be the ID of the user you are logged in as but effective
2002 /// user ID will be `0` (i-e root).
2003 ///
2004 /// ⚠️ It always returns `None` on Windows.
2005 ///
2006 /// [`User`]: crate::User
2007 /// [`Users::get_user_by_id`]: crate::Users::get_user_by_id
2008 ///
2009 /// ```no_run
2010 /// use sysinfo::{Pid, System};
2011 ///
2012 /// let mut s = System::new_all();
2013 ///
2014 /// if let Some(process) = s.process(Pid::from(1337)) {
2015 /// println!("User id for process 1337: {:?}", process.effective_user_id());
2016 /// }
2017 /// ```
2018 pub fn effective_user_id(&self) -> Option<&Uid> {
2019 self.inner.effective_user_id()
2020 }
2021
2022 /// Returns the process group ID of the process.
2023 ///
2024 /// ⚠️ It always returns `None` on Windows.
2025 ///
2026 /// ```no_run
2027 /// use sysinfo::{Pid, System};
2028 ///
2029 /// let mut s = System::new_all();
2030 ///
2031 /// if let Some(process) = s.process(Pid::from(1337)) {
2032 /// println!("Group ID for process 1337: {:?}", process.group_id());
2033 /// }
2034 /// ```
2035 pub fn group_id(&self) -> Option<Gid> {
2036 self.inner.group_id()
2037 }
2038
2039 /// Returns the effective group ID of the process.
2040 ///
2041 /// If you run something with `sudo`, the real group ID of the launched
2042 /// process will be the primary group ID you are logged in as but effective
2043 /// group ID will be `0` (i-e root).
2044 ///
2045 /// ⚠️ It always returns `None` on Windows.
2046 ///
2047 /// ```no_run
2048 /// use sysinfo::{Pid, System};
2049 ///
2050 /// let mut s = System::new_all();
2051 ///
2052 /// if let Some(process) = s.process(Pid::from(1337)) {
2053 /// println!("User id for process 1337: {:?}", process.effective_group_id());
2054 /// }
2055 /// ```
2056 pub fn effective_group_id(&self) -> Option<Gid> {
2057 self.inner.effective_group_id()
2058 }
2059
2060 /// Returns the session ID for the current process or `None` if it couldn't
2061 /// be retrieved.
2062 ///
2063 /// ⚠️ This information is computed every time this method is called.
2064 ///
2065 /// ```no_run
2066 /// use sysinfo::{Pid, System};
2067 ///
2068 /// let mut s = System::new_all();
2069 ///
2070 /// if let Some(process) = s.process(Pid::from(1337)) {
2071 /// println!("Session ID for process 1337: {:?}", process.session_id());
2072 /// }
2073 /// ```
2074 pub fn session_id(&self) -> Option<Pid> {
2075 self.inner.session_id()
2076 }
2077
2078 /// Tasks run by this process. If there are none, returns `None`.
2079 ///
2080 /// ⚠️ This method always returns `None` on other platforms than Linux.
2081 ///
2082 /// ```no_run
2083 /// use sysinfo::{Pid, System};
2084 ///
2085 /// let mut s = System::new_all();
2086 ///
2087 /// if let Some(process) = s.process(Pid::from(1337)) {
2088 /// if let Some(tasks) = process.tasks() {
2089 /// println!("Listing tasks for process {:?}", process.pid());
2090 /// for task_pid in tasks {
2091 /// if let Some(task) = s.process(*task_pid) {
2092 /// println!("Task {:?}: {:?}", task.pid(), task.name());
2093 /// }
2094 /// }
2095 /// }
2096 /// }
2097 /// ```
2098 pub fn tasks(&self) -> Option<&HashSet<Pid>> {
2099 cfg_if! {
2100 if #[cfg(all(
2101 any(target_os = "linux", target_os = "android"),
2102 not(feature = "unknown-ci")
2103 ))] {
2104 self.inner.tasks.as_ref()
2105 } else {
2106 None
2107 }
2108 }
2109 }
2110
2111 /// If the process is a thread, it'll return `Some` with the kind of thread it is. Returns
2112 /// `None` otherwise.
2113 ///
2114 /// ⚠️ This method always returns `None` on other platforms than Linux.
2115 ///
2116 /// ```no_run
2117 /// use sysinfo::System;
2118 ///
2119 /// let s = System::new_all();
2120 ///
2121 /// for (_, process) in s.processes() {
2122 /// if let Some(thread_kind) = process.thread_kind() {
2123 /// println!("Process {:?} is a {thread_kind:?} thread", process.pid());
2124 /// }
2125 /// }
2126 /// ```
2127 pub fn thread_kind(&self) -> Option<ThreadKind> {
2128 cfg_if! {
2129 if #[cfg(all(
2130 any(target_os = "linux", target_os = "android"),
2131 not(feature = "unknown-ci")
2132 ))] {
2133 self.inner.thread_kind()
2134 } else {
2135 None
2136 }
2137 }
2138 }
2139
2140 /// Returns `true` if the process doesn't exist anymore but was not yet removed from
2141 /// the processes list because the `remove_dead_processes` argument was set to `false`
2142 /// in methods like [`System::refresh_processes`].
2143 ///
2144 /// ```no_run
2145 /// use sysinfo::{ProcessesToUpdate, System};
2146 ///
2147 /// let mut s = System::new_all();
2148 /// // We set the `remove_dead_processes` to `false`.
2149 /// s.refresh_processes(ProcessesToUpdate::All, false);
2150 ///
2151 /// for (_, process) in s.processes() {
2152 /// println!(
2153 /// "Process {:?} {}",
2154 /// process.pid(),
2155 /// if process.exists() { "exists" } else { "doesn't exist" },
2156 /// );
2157 /// }
2158 /// ```
2159 pub fn exists(&self) -> bool {
2160 self.inner.exists()
2161 }
2162
2163 /// Returns the number of open files in the current process.
2164 ///
2165 /// Returns `None` if it failed retrieving the information or if the current system is not
2166 /// supported.
2167 ///
2168 /// **Important**: this information is computed every time this function is called.
2169 ///
2170 /// ⚠️ Not implemented on NetBSD.
2171 ///
2172 /// ```no_run
2173 /// use sysinfo::System;
2174 ///
2175 /// let s = System::new_all();
2176 ///
2177 /// for (_, process) in s.processes() {
2178 /// println!(
2179 /// "Process {:?} {:?}",
2180 /// process.pid(),
2181 /// process.open_files(),
2182 /// );
2183 /// }
2184 /// ```
2185 pub fn open_files(&self) -> Option<usize> {
2186 self.inner.open_files()
2187 }
2188
2189 /// Returns the maximum number of open files for the current process.
2190 ///
2191 /// Returns `None` if it failed retrieving the information or if the current system is not
2192 /// supported.
2193 ///
2194 /// **Important**: this information is computed every time this function is called.
2195 ///
2196 /// ```no_run
2197 /// use sysinfo::System;
2198 ///
2199 /// let s = System::new_all();
2200 ///
2201 /// for (_, process) in s.processes() {
2202 /// println!(
2203 /// "Process {:?} {:?}",
2204 /// process.pid(),
2205 /// process.open_files_limit(),
2206 /// );
2207 /// }
2208 /// ```
2209 pub fn open_files_limit(&self) -> Option<usize> {
2210 self.inner.open_files_limit()
2211 }
2212}
2213
2214macro_rules! pid_decl {
2215 ($typ:ty) => {
2216 #[doc = include_str!("../../md_doc/pid.md")]
2217 #[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
2218 #[repr(transparent)]
2219 pub struct Pid(pub(crate) $typ);
2220
2221 impl From<usize> for Pid {
2222 fn from(v: usize) -> Self {
2223 Self(v as _)
2224 }
2225 }
2226 impl From<Pid> for usize {
2227 fn from(v: Pid) -> Self {
2228 v.0 as _
2229 }
2230 }
2231 impl FromStr for Pid {
2232 type Err = <$typ as FromStr>::Err;
2233 fn from_str(s: &str) -> Result<Self, Self::Err> {
2234 Ok(Self(<$typ>::from_str(s)?))
2235 }
2236 }
2237 impl fmt::Display for Pid {
2238 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2239 write!(f, "{}", self.0)
2240 }
2241 }
2242 impl Pid {
2243 /// Allows to convert [`Pid`][crate::Pid] into [`u32`].
2244 ///
2245 /// ```
2246 /// use sysinfo::Pid;
2247 ///
2248 /// let pid = Pid::from_u32(0);
2249 /// let value: u32 = pid.as_u32();
2250 /// ```
2251 pub fn as_u32(self) -> u32 {
2252 self.0 as _
2253 }
2254 /// Allows to convert a [`u32`] into [`Pid`][crate::Pid].
2255 ///
2256 /// ```
2257 /// use sysinfo::Pid;
2258 ///
2259 /// let pid = Pid::from_u32(0);
2260 /// ```
2261 pub fn from_u32(v: u32) -> Self {
2262 Self(v as _)
2263 }
2264 }
2265 };
2266}
2267
2268cfg_if! {
2269 if #[cfg(all(
2270 not(feature = "unknown-ci"),
2271 any(
2272 target_os = "freebsd",
2273 target_os = "netbsd",
2274 target_os = "linux",
2275 target_os = "android",
2276 target_os = "macos",
2277 target_os = "ios",
2278 )
2279 ))] {
2280 use libc::pid_t;
2281
2282 pid_decl!(pid_t);
2283 } else {
2284 pid_decl!(usize);
2285 }
2286}
2287
2288/// This enum allows you to specify when you want the related information to be updated.
2289///
2290/// For example if you only want the [`Process::exe()`] information to be refreshed only if it's not
2291/// already set:
2292///
2293/// ```no_run
2294/// use sysinfo::{ProcessesToUpdate, ProcessRefreshKind, System, UpdateKind};
2295///
2296/// let mut system = System::new();
2297/// system.refresh_processes_specifics(
2298/// ProcessesToUpdate::All,
2299/// true,
2300/// ProcessRefreshKind::nothing().with_exe(UpdateKind::OnlyIfNotSet),
2301/// );
2302/// ```
2303#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
2304pub enum UpdateKind {
2305 /// Never update the related information.
2306 #[default]
2307 Never,
2308 /// Always update the related information.
2309 Always,
2310 /// Only update the related information if it was not already set at least once.
2311 OnlyIfNotSet,
2312}
2313
2314impl UpdateKind {
2315 /// If `self` is `OnlyIfNotSet`, `f` is called and its returned value is returned.
2316 #[allow(dead_code)] // Needed for unsupported targets.
2317 pub(crate) fn needs_update(self, f: impl Fn() -> bool) -> bool {
2318 match self {
2319 Self::Never => false,
2320 Self::Always => true,
2321 Self::OnlyIfNotSet => f(),
2322 }
2323 }
2324}
2325
2326/// This enum allows you to specify if you want all processes to be updated or just
2327/// some of them.
2328///
2329/// Example:
2330///
2331/// ```no_run
2332/// use sysinfo::{ProcessesToUpdate, System, get_current_pid};
2333///
2334/// let mut system = System::new();
2335/// // To refresh all processes:
2336/// system.refresh_processes(ProcessesToUpdate::All, true);
2337///
2338/// // To refresh only the current one:
2339/// system.refresh_processes(
2340/// ProcessesToUpdate::Some(&[get_current_pid().unwrap()]),
2341/// true,
2342/// );
2343/// ```
2344#[derive(Clone, Copy, Debug, PartialEq, Eq)]
2345pub enum ProcessesToUpdate<'a> {
2346 /// To refresh all processes.
2347 All,
2348 /// To refresh only the processes with the listed [`Pid`].
2349 ///
2350 /// [`Pid`]: crate::Pid
2351 Some(&'a [Pid]),
2352}
2353
2354/// Used to determine what you want to refresh specifically on the [`Process`] type.
2355///
2356/// When all refresh are ruled out, a [`Process`] will still retrieve the following information:
2357/// * Process ID ([`Pid`])
2358/// * Parent process ID (on Windows it never changes though)
2359/// * Process name
2360/// * Start time
2361///
2362/// ⚠️ Just like all other refresh types, ruling out a refresh doesn't assure you that
2363/// the information won't be retrieved if the information is accessible without needing
2364/// extra computation.
2365///
2366/// ⚠️ ** Linux Specific ** ⚠️
2367/// When using `ProcessRefreshKind::everything()`, in linux we will fetch all relevant
2368/// information from `/proc/<pid>/` as well as all the information from `/proc/<pid>/task/<tid>/`
2369/// folders. This makes the refresh mechanism a lot slower depending on the number of tasks
2370/// each process has.
2371///
2372/// If you don't care about tasks information, use `ProcessRefreshKind::everything().without_tasks()`
2373/// as much as possible.
2374///
2375/// ```
2376/// use sysinfo::{ProcessesToUpdate, ProcessRefreshKind, System};
2377///
2378/// let mut system = System::new();
2379///
2380/// // We don't want to update the CPU information.
2381/// system.refresh_processes_specifics(
2382/// ProcessesToUpdate::All,
2383/// true,
2384/// ProcessRefreshKind::everything().without_cpu(),
2385/// );
2386///
2387/// for (_, proc_) in system.processes() {
2388/// // We use a `==` comparison on float only because we know it's set to 0 here.
2389/// assert_eq!(proc_.cpu_usage(), 0.);
2390/// }
2391/// ```
2392///
2393/// [`Process`]: crate::Process
2394#[derive(Clone, Copy, Debug, PartialEq, Eq)]
2395pub struct ProcessRefreshKind {
2396 cpu: bool,
2397 disk_usage: bool,
2398 memory: bool,
2399 user: UpdateKind,
2400 cwd: UpdateKind,
2401 root: UpdateKind,
2402 environ: UpdateKind,
2403 cmd: UpdateKind,
2404 exe: UpdateKind,
2405 tasks: bool,
2406}
2407
2408/// Creates a new `ProcessRefreshKind` with every refresh set to `false`, except for `tasks`.
2409/// By default, we want to list all processes and tasks are considered processes on their own
2410/// in linux so we still fetch them by default. However, the processes information are not
2411/// refreshed.
2412impl Default for ProcessRefreshKind {
2413 fn default() -> Self {
2414 Self {
2415 cpu: false,
2416 disk_usage: false,
2417 memory: false,
2418 user: UpdateKind::default(),
2419 cwd: UpdateKind::default(),
2420 root: UpdateKind::default(),
2421 environ: UpdateKind::default(),
2422 cmd: UpdateKind::default(),
2423 exe: UpdateKind::default(),
2424 tasks: true, // Process by default includes all tasks.
2425 }
2426 }
2427}
2428
2429impl ProcessRefreshKind {
2430 /// Creates a new `ProcessRefreshKind` with every refresh set to `false`, except for `tasks`.
2431 /// By default, we want to list all processes and tasks are considered processes on their own
2432 /// in linux so we still fetch them by default. However, the processes information are not
2433 /// refreshed.
2434 /// ```
2435 /// use sysinfo::{ProcessRefreshKind, UpdateKind};
2436 ///
2437 /// let r = ProcessRefreshKind::nothing();
2438 ///
2439 /// assert_eq!(r.cpu(), false);
2440 /// assert_eq!(r.user(), UpdateKind::Never);
2441 /// ```
2442 pub fn nothing() -> Self {
2443 Self::default()
2444 }
2445
2446 /// Creates a new `ProcessRefreshKind` with every refresh set to `true` or
2447 /// [`UpdateKind::OnlyIfNotSet`].
2448 ///
2449 /// ```
2450 /// use sysinfo::{ProcessRefreshKind, UpdateKind};
2451 ///
2452 /// let r = ProcessRefreshKind::everything();
2453 ///
2454 /// assert_eq!(r.cpu(), true);
2455 /// assert_eq!(r.user(), UpdateKind::OnlyIfNotSet);
2456 /// ```
2457 pub fn everything() -> Self {
2458 Self {
2459 cpu: true,
2460 disk_usage: true,
2461 memory: true,
2462 user: UpdateKind::OnlyIfNotSet,
2463 cwd: UpdateKind::OnlyIfNotSet,
2464 root: UpdateKind::OnlyIfNotSet,
2465 environ: UpdateKind::OnlyIfNotSet,
2466 cmd: UpdateKind::OnlyIfNotSet,
2467 exe: UpdateKind::OnlyIfNotSet,
2468 tasks: true,
2469 }
2470 }
2471
2472 impl_get_set!(
2473 ProcessRefreshKind,
2474 cpu,
2475 with_cpu,
2476 without_cpu,
2477 "\
2478It will retrieve both CPU usage and CPU accumulated time,"
2479 );
2480 impl_get_set!(
2481 ProcessRefreshKind,
2482 disk_usage,
2483 with_disk_usage,
2484 without_disk_usage
2485 );
2486 impl_get_set!(
2487 ProcessRefreshKind,
2488 user,
2489 with_user,
2490 without_user,
2491 UpdateKind,
2492 "\
2493It will retrieve the following information:
2494
2495 * user ID
2496 * user effective ID (if available on the platform)
2497 * user group ID (if available on the platform)
2498 * user effective ID (if available on the platform)"
2499 );
2500 impl_get_set!(ProcessRefreshKind, memory, with_memory, without_memory);
2501 impl_get_set!(ProcessRefreshKind, cwd, with_cwd, without_cwd, UpdateKind);
2502 impl_get_set!(
2503 ProcessRefreshKind,
2504 root,
2505 with_root,
2506 without_root,
2507 UpdateKind
2508 );
2509 impl_get_set!(
2510 ProcessRefreshKind,
2511 environ,
2512 with_environ,
2513 without_environ,
2514 UpdateKind
2515 );
2516 impl_get_set!(ProcessRefreshKind, cmd, with_cmd, without_cmd, UpdateKind);
2517 impl_get_set!(ProcessRefreshKind, exe, with_exe, without_exe, UpdateKind);
2518 impl_get_set!(ProcessRefreshKind, tasks, with_tasks, without_tasks);
2519}
2520
2521/// Used to determine what you want to refresh specifically on the [`Cpu`] type.
2522///
2523/// ⚠️ Just like all other refresh types, ruling out a refresh doesn't assure you that
2524/// the information won't be retrieved if the information is accessible without needing
2525/// extra computation.
2526///
2527/// ```
2528/// use sysinfo::{CpuRefreshKind, System};
2529///
2530/// let mut system = System::new();
2531///
2532/// // We don't want to update all the CPU information.
2533/// system.refresh_cpu_specifics(CpuRefreshKind::everything().without_frequency());
2534///
2535/// for cpu in system.cpus() {
2536/// assert_eq!(cpu.frequency(), 0);
2537/// }
2538/// ```
2539///
2540/// [`Cpu`]: crate::Cpu
2541#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
2542pub struct CpuRefreshKind {
2543 cpu_usage: bool,
2544 frequency: bool,
2545}
2546
2547impl CpuRefreshKind {
2548 /// Creates a new `CpuRefreshKind` with every refresh set to `false`.
2549 ///
2550 /// ```
2551 /// use sysinfo::CpuRefreshKind;
2552 ///
2553 /// let r = CpuRefreshKind::nothing();
2554 ///
2555 /// assert_eq!(r.frequency(), false);
2556 /// assert_eq!(r.cpu_usage(), false);
2557 /// ```
2558 pub fn nothing() -> Self {
2559 Self::default()
2560 }
2561
2562 /// Creates a new `CpuRefreshKind` with every refresh set to `true`.
2563 ///
2564 /// ```
2565 /// use sysinfo::CpuRefreshKind;
2566 ///
2567 /// let r = CpuRefreshKind::everything();
2568 ///
2569 /// assert_eq!(r.frequency(), true);
2570 /// assert_eq!(r.cpu_usage(), true);
2571 /// ```
2572 pub fn everything() -> Self {
2573 Self {
2574 cpu_usage: true,
2575 frequency: true,
2576 }
2577 }
2578
2579 impl_get_set!(CpuRefreshKind, cpu_usage, with_cpu_usage, without_cpu_usage);
2580 impl_get_set!(CpuRefreshKind, frequency, with_frequency, without_frequency);
2581}
2582
2583/// Used to determine which memory you want to refresh specifically.
2584///
2585/// ⚠️ Just like all other refresh types, ruling out a refresh doesn't assure you that
2586/// the information won't be retrieved if the information is accessible without needing
2587/// extra computation.
2588///
2589/// ```
2590/// use sysinfo::{MemoryRefreshKind, System};
2591///
2592/// let mut system = System::new();
2593///
2594/// // We don't want to update all memories information.
2595/// system.refresh_memory_specifics(MemoryRefreshKind::nothing().with_ram());
2596///
2597/// println!("total RAM: {}", system.total_memory());
2598/// println!("free RAM: {}", system.free_memory());
2599/// ```
2600#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
2601pub struct MemoryRefreshKind {
2602 ram: bool,
2603 swap: bool,
2604}
2605
2606impl MemoryRefreshKind {
2607 /// Creates a new `MemoryRefreshKind` with every refresh set to `false`.
2608 ///
2609 /// ```
2610 /// use sysinfo::MemoryRefreshKind;
2611 ///
2612 /// let r = MemoryRefreshKind::nothing();
2613 ///
2614 /// assert_eq!(r.ram(), false);
2615 /// assert_eq!(r.swap(), false);
2616 /// ```
2617 pub fn nothing() -> Self {
2618 Self::default()
2619 }
2620
2621 /// Creates a new `MemoryRefreshKind` with every refresh set to `true`.
2622 ///
2623 /// ```
2624 /// use sysinfo::MemoryRefreshKind;
2625 ///
2626 /// let r = MemoryRefreshKind::everything();
2627 ///
2628 /// assert_eq!(r.ram(), true);
2629 /// assert_eq!(r.swap(), true);
2630 /// ```
2631 pub fn everything() -> Self {
2632 Self {
2633 ram: true,
2634 swap: true,
2635 }
2636 }
2637
2638 impl_get_set!(MemoryRefreshKind, ram, with_ram, without_ram);
2639 impl_get_set!(MemoryRefreshKind, swap, with_swap, without_swap);
2640}
2641
2642/// Used to determine what you want to refresh specifically on the [`System`][crate::System] type.
2643///
2644/// ⚠️ Just like all other refresh types, ruling out a refresh doesn't assure you that
2645/// the information won't be retrieved if the information is accessible without needing
2646/// extra computation.
2647///
2648/// ```
2649/// use sysinfo::{RefreshKind, System};
2650///
2651/// // We want everything except memory.
2652/// let mut system = System::new_with_specifics(RefreshKind::everything().without_memory());
2653///
2654/// assert_eq!(system.total_memory(), 0);
2655/// # if sysinfo::IS_SUPPORTED_SYSTEM && !cfg!(feature = "apple-sandbox") {
2656/// assert!(system.processes().len() > 0);
2657/// # }
2658/// ```
2659#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
2660pub struct RefreshKind {
2661 processes: Option<ProcessRefreshKind>,
2662 memory: Option<MemoryRefreshKind>,
2663 cpu: Option<CpuRefreshKind>,
2664}
2665
2666impl RefreshKind {
2667 /// Creates a new `RefreshKind` with every refresh set to `false`/`None`.
2668 ///
2669 /// ```
2670 /// use sysinfo::RefreshKind;
2671 ///
2672 /// let r = RefreshKind::nothing();
2673 ///
2674 /// assert_eq!(r.processes().is_some(), false);
2675 /// assert_eq!(r.memory().is_some(), false);
2676 /// assert_eq!(r.cpu().is_some(), false);
2677 /// ```
2678 pub fn nothing() -> Self {
2679 Self::default()
2680 }
2681
2682 /// Creates a new `RefreshKind` with every refresh set to `true`/`Some(...)`.
2683 ///
2684 /// ```
2685 /// use sysinfo::RefreshKind;
2686 ///
2687 /// let r = RefreshKind::everything();
2688 ///
2689 /// assert_eq!(r.processes().is_some(), true);
2690 /// assert_eq!(r.memory().is_some(), true);
2691 /// assert_eq!(r.cpu().is_some(), true);
2692 /// ```
2693 pub fn everything() -> Self {
2694 Self {
2695 processes: Some(ProcessRefreshKind::everything()),
2696 memory: Some(MemoryRefreshKind::everything()),
2697 cpu: Some(CpuRefreshKind::everything()),
2698 }
2699 }
2700
2701 impl_get_set!(
2702 RefreshKind,
2703 processes,
2704 with_processes,
2705 without_processes,
2706 ProcessRefreshKind
2707 );
2708 impl_get_set!(
2709 RefreshKind,
2710 memory,
2711 with_memory,
2712 without_memory,
2713 MemoryRefreshKind
2714 );
2715 impl_get_set!(RefreshKind, cpu, with_cpu, without_cpu, CpuRefreshKind);
2716}
2717
2718/// Returns the pid for the current process.
2719///
2720/// `Err` is returned in case the platform isn't supported.
2721///
2722/// ```no_run
2723/// use sysinfo::get_current_pid;
2724///
2725/// match get_current_pid() {
2726/// Ok(pid) => {
2727/// println!("current pid: {}", pid);
2728/// }
2729/// Err(e) => {
2730/// println!("failed to get current pid: {}", e);
2731/// }
2732/// }
2733/// ```
2734#[allow(clippy::unnecessary_wraps)]
2735pub fn get_current_pid() -> Result<Pid, &'static str> {
2736 cfg_if! {
2737 if #[cfg(feature = "unknown-ci")] {
2738 fn inner() -> Result<Pid, &'static str> {
2739 Err("Unknown platform (CI)")
2740 }
2741 } else if #[cfg(any(
2742 target_os = "freebsd",
2743 target_os = "netbsd",
2744 target_os = "linux",
2745 target_os = "android",
2746 target_os = "macos",
2747 target_os = "ios",
2748 ))] {
2749 fn inner() -> Result<Pid, &'static str> {
2750 unsafe { Ok(Pid(libc::getpid())) }
2751 }
2752 } else if #[cfg(windows)] {
2753 fn inner() -> Result<Pid, &'static str> {
2754 use windows::Win32::System::Threading::GetCurrentProcessId;
2755
2756 unsafe { Ok(Pid(GetCurrentProcessId() as _)) }
2757 }
2758 } else {
2759 fn inner() -> Result<Pid, &'static str> {
2760 Err("Unknown platform")
2761 }
2762 }
2763 }
2764 inner()
2765}
2766
2767/// Contains all the methods of the [`Cpu`][crate::Cpu] struct.
2768///
2769/// ```no_run
2770/// use sysinfo::{System, RefreshKind, CpuRefreshKind};
2771///
2772/// let mut s = System::new_with_specifics(
2773/// RefreshKind::nothing().with_cpu(CpuRefreshKind::everything()),
2774/// );
2775///
2776/// // Wait a bit because CPU usage is based on diff.
2777/// std::thread::sleep(sysinfo::MINIMUM_CPU_UPDATE_INTERVAL);
2778/// // Refresh CPUs again to get actual value.
2779/// s.refresh_cpu_all();
2780///
2781/// for cpu in s.cpus() {
2782/// println!("{}%", cpu.cpu_usage());
2783/// }
2784/// ```
2785pub struct Cpu {
2786 pub(crate) inner: CpuInner,
2787}
2788
2789impl Cpu {
2790 /// Returns this CPU's usage.
2791 ///
2792 /// Note: You'll need to refresh it at least twice (diff between the first and the second is
2793 /// how CPU usage is computed) at first if you want to have a non-zero value.
2794 ///
2795 /// ```no_run
2796 /// use sysinfo::{System, RefreshKind, CpuRefreshKind};
2797 ///
2798 /// let mut s = System::new_with_specifics(
2799 /// RefreshKind::nothing().with_cpu(CpuRefreshKind::everything()),
2800 /// );
2801 ///
2802 /// // Wait a bit because CPU usage is based on diff.
2803 /// std::thread::sleep(sysinfo::MINIMUM_CPU_UPDATE_INTERVAL);
2804 /// // Refresh CPUs again to get actual value.
2805 /// s.refresh_cpu_all();
2806 ///
2807 /// for cpu in s.cpus() {
2808 /// println!("{}%", cpu.cpu_usage());
2809 /// }
2810 /// ```
2811 pub fn cpu_usage(&self) -> f32 {
2812 self.inner.cpu_usage()
2813 }
2814
2815 /// Returns this CPU's name.
2816 ///
2817 /// ```no_run
2818 /// use sysinfo::{System, RefreshKind, CpuRefreshKind};
2819 ///
2820 /// let s = System::new_with_specifics(
2821 /// RefreshKind::nothing().with_cpu(CpuRefreshKind::everything()),
2822 /// );
2823 /// for cpu in s.cpus() {
2824 /// println!("{}", cpu.name());
2825 /// }
2826 /// ```
2827 pub fn name(&self) -> &str {
2828 self.inner.name()
2829 }
2830
2831 /// Returns the CPU's vendor id.
2832 ///
2833 /// ```no_run
2834 /// use sysinfo::{System, RefreshKind, CpuRefreshKind};
2835 ///
2836 /// let s = System::new_with_specifics(
2837 /// RefreshKind::nothing().with_cpu(CpuRefreshKind::everything()),
2838 /// );
2839 /// for cpu in s.cpus() {
2840 /// println!("{}", cpu.vendor_id());
2841 /// }
2842 /// ```
2843 pub fn vendor_id(&self) -> &str {
2844 self.inner.vendor_id()
2845 }
2846
2847 /// Returns the CPU's brand.
2848 ///
2849 /// ```no_run
2850 /// use sysinfo::{System, RefreshKind, CpuRefreshKind};
2851 ///
2852 /// let s = System::new_with_specifics(
2853 /// RefreshKind::nothing().with_cpu(CpuRefreshKind::everything()),
2854 /// );
2855 /// for cpu in s.cpus() {
2856 /// println!("{}", cpu.brand());
2857 /// }
2858 /// ```
2859 pub fn brand(&self) -> &str {
2860 self.inner.brand()
2861 }
2862
2863 /// Returns the CPU's frequency (in MHz).
2864 ///
2865 /// ```no_run
2866 /// use sysinfo::{System, RefreshKind, CpuRefreshKind};
2867 ///
2868 /// let s = System::new_with_specifics(
2869 /// RefreshKind::nothing().with_cpu(CpuRefreshKind::everything()),
2870 /// );
2871 /// for cpu in s.cpus() {
2872 /// println!("{}", cpu.frequency());
2873 /// }
2874 /// ```
2875 pub fn frequency(&self) -> u64 {
2876 self.inner.frequency()
2877 }
2878}
2879
2880#[cfg(test)]
2881mod test {
2882 use crate::*;
2883 use std::str::FromStr;
2884
2885 // In case `Process::updated` is misused, `System::refresh_processes` might remove them
2886 // so this test ensures that it doesn't happen.
2887 #[test]
2888 fn check_refresh_process_update() {
2889 if !IS_SUPPORTED_SYSTEM {
2890 return;
2891 }
2892 let mut s = System::new_all();
2893 let total = s.processes().len() as isize;
2894 s.refresh_processes(ProcessesToUpdate::All, false);
2895 let new_total = s.processes().len() as isize;
2896 // There should be almost no difference in the processes count.
2897 assert!(
2898 (new_total - total).abs() <= 5,
2899 "{} <= 5",
2900 (new_total - total).abs()
2901 );
2902 }
2903
2904 #[test]
2905 fn check_cpu_arch() {
2906 assert!(!System::cpu_arch().is_empty());
2907 }
2908
2909 // Ensure that the CPUs frequency isn't retrieved until we ask for it.
2910 #[test]
2911 fn check_cpu_frequency() {
2912 if !IS_SUPPORTED_SYSTEM {
2913 return;
2914 }
2915 let mut s = System::new();
2916 s.refresh_processes(ProcessesToUpdate::All, false);
2917 for proc_ in s.cpus() {
2918 assert_eq!(proc_.frequency(), 0);
2919 }
2920 s.refresh_cpu_usage();
2921 for proc_ in s.cpus() {
2922 assert_eq!(proc_.frequency(), 0);
2923 }
2924 // In a VM, it'll fail.
2925 if std::env::var("APPLE_CI").is_ok()
2926 || std::env::var("FREEBSD_CI").is_ok()
2927 || std::env::var("NETBSD_CI").is_ok()
2928 {
2929 return;
2930 }
2931 s.refresh_cpu_specifics(CpuRefreshKind::everything());
2932 for proc_ in s.cpus() {
2933 assert_ne!(proc_.frequency(), 0);
2934 }
2935 }
2936
2937 #[test]
2938 fn check_process_memory_usage() {
2939 let mut s = System::new();
2940 s.refresh_specifics(RefreshKind::everything());
2941
2942 if IS_SUPPORTED_SYSTEM {
2943 // No process should have 0 as memory usage.
2944 #[cfg(not(feature = "apple-sandbox"))]
2945 assert!(!s.processes().iter().all(|(_, proc_)| proc_.memory() == 0));
2946 } else {
2947 // There should be no process, but if there is one, its memory usage should be 0.
2948 assert!(s.processes().iter().all(|(_, proc_)| proc_.memory() == 0));
2949 }
2950 }
2951
2952 #[test]
2953 fn check_system_implemented_traits() {
2954 fn check<T: Sized + std::fmt::Debug + Default + Send + Sync>(_: T) {}
2955
2956 check(System::new());
2957 }
2958
2959 #[test]
2960 fn check_memory_usage() {
2961 let mut s = System::new();
2962
2963 assert_eq!(s.total_memory(), 0);
2964 assert_eq!(s.free_memory(), 0);
2965 assert_eq!(s.available_memory(), 0);
2966 assert_eq!(s.used_memory(), 0);
2967 assert_eq!(s.total_swap(), 0);
2968 assert_eq!(s.free_swap(), 0);
2969 assert_eq!(s.used_swap(), 0);
2970
2971 s.refresh_memory();
2972 if IS_SUPPORTED_SYSTEM {
2973 assert!(s.total_memory() > 0);
2974 assert!(s.used_memory() > 0);
2975 if s.total_swap() > 0 {
2976 // I think it's pretty safe to assume that there is still some swap left...
2977 assert!(s.free_swap() > 0);
2978 }
2979 } else {
2980 assert_eq!(s.total_memory(), 0);
2981 assert_eq!(s.used_memory(), 0);
2982 assert_eq!(s.total_swap(), 0);
2983 assert_eq!(s.free_swap(), 0);
2984 }
2985 }
2986
2987 #[cfg(target_os = "linux")]
2988 #[test]
2989 fn check_processes_cpu_usage() {
2990 if !IS_SUPPORTED_SYSTEM {
2991 return;
2992 }
2993 let mut s = System::new();
2994
2995 s.refresh_processes(ProcessesToUpdate::All, false);
2996 // All CPU usage will start at zero until the second refresh
2997 assert!(
2998 s.processes()
2999 .iter()
3000 .all(|(_, proc_)| proc_.cpu_usage() == 0.0)
3001 );
3002
3003 // Wait a bit to update CPU usage values
3004 std::thread::sleep(MINIMUM_CPU_UPDATE_INTERVAL);
3005 s.refresh_processes(ProcessesToUpdate::All, true);
3006 assert!(
3007 s.processes()
3008 .iter()
3009 .all(|(_, proc_)| proc_.cpu_usage() >= 0.0
3010 && proc_.cpu_usage() <= (s.cpus().len() as f32) * 100.0)
3011 );
3012 assert!(
3013 s.processes()
3014 .iter()
3015 .any(|(_, proc_)| proc_.cpu_usage() > 0.0)
3016 );
3017 }
3018
3019 #[test]
3020 fn check_cpu_usage() {
3021 if !IS_SUPPORTED_SYSTEM {
3022 return;
3023 }
3024 let mut s = System::new();
3025 for _ in 0..10 {
3026 s.refresh_cpu_usage();
3027 // Wait a bit to update CPU usage values
3028 std::thread::sleep(MINIMUM_CPU_UPDATE_INTERVAL);
3029 if s.cpus().iter().any(|c| c.cpu_usage() > 0.0) {
3030 // All good!
3031 return;
3032 }
3033 }
3034 panic!("CPU usage is always zero...");
3035 }
3036
3037 #[test]
3038 fn check_system_info() {
3039 // We don't want to test on unsupported systems.
3040 if IS_SUPPORTED_SYSTEM {
3041 assert!(
3042 !System::name()
3043 .expect("Failed to get system name")
3044 .is_empty()
3045 );
3046
3047 assert!(
3048 !System::kernel_version()
3049 .expect("Failed to get kernel version")
3050 .is_empty()
3051 );
3052
3053 assert!(
3054 !System::os_version()
3055 .expect("Failed to get os version")
3056 .is_empty()
3057 );
3058
3059 assert!(
3060 !System::long_os_version()
3061 .expect("Failed to get long OS version")
3062 .is_empty()
3063 );
3064 }
3065
3066 assert!(!System::distribution_id().is_empty());
3067 }
3068
3069 #[test]
3070 fn check_host_name() {
3071 // We don't want to test on unsupported systems.
3072 if IS_SUPPORTED_SYSTEM {
3073 assert!(System::host_name().is_some());
3074 }
3075 }
3076
3077 #[test]
3078 fn check_refresh_process_return_value() {
3079 // We don't want to test on unsupported systems.
3080 if IS_SUPPORTED_SYSTEM {
3081 let _pid = get_current_pid().expect("Failed to get current PID");
3082
3083 #[cfg(not(feature = "apple-sandbox"))]
3084 {
3085 let mut s = System::new();
3086 // First check what happens in case the process isn't already in our process list.
3087 assert_eq!(
3088 s.refresh_processes(ProcessesToUpdate::Some(&[_pid]), true),
3089 1
3090 );
3091 // Then check that it still returns 1 if the process is already in our process list.
3092 assert_eq!(
3093 s.refresh_processes(ProcessesToUpdate::Some(&[_pid]), true),
3094 1
3095 );
3096 }
3097 }
3098 }
3099
3100 #[test]
3101 fn check_cpus_number() {
3102 let mut s = System::new();
3103
3104 // This information isn't retrieved by default.
3105 assert!(s.cpus().is_empty());
3106 if IS_SUPPORTED_SYSTEM {
3107 // The physical cores count is recomputed every time the function is called, so the
3108 // information must be relevant even with nothing initialized.
3109 let physical_cores_count =
3110 System::physical_core_count().expect("failed to get number of physical cores");
3111
3112 s.refresh_cpu_usage();
3113 // The cpus shouldn't be empty anymore.
3114 assert!(!s.cpus().is_empty());
3115
3116 // In case we are running inside a VM, it's possible to not have a physical core, only
3117 // logical ones, which is why we don't test `physical_cores_count > 0`.
3118 let physical_cores_count2 =
3119 System::physical_core_count().expect("failed to get number of physical cores");
3120 assert!(physical_cores_count2 <= s.cpus().len());
3121 assert_eq!(physical_cores_count, physical_cores_count2);
3122 } else {
3123 assert_eq!(System::physical_core_count(), None);
3124 }
3125 assert!(System::physical_core_count().unwrap_or(0) <= s.cpus().len());
3126 }
3127
3128 // This test only exists to ensure that the `Display` and `Debug` traits are implemented on the
3129 // `ProcessStatus` enum on all targets.
3130 #[test]
3131 fn check_display_impl_process_status() {
3132 println!("{} {:?}", ProcessStatus::Parked, ProcessStatus::Idle);
3133 }
3134
3135 #[test]
3136 #[allow(clippy::unnecessary_fallible_conversions)]
3137 fn check_pid_from_impls() {
3138 assert!(crate::Pid::try_from(0usize).is_ok());
3139 // If it doesn't panic, it's fine.
3140 let _ = crate::Pid::from(0);
3141 assert!(crate::Pid::from_str("0").is_ok());
3142 }
3143
3144 #[test]
3145 #[allow(clippy::const_is_empty)]
3146 fn check_nb_supported_signals() {
3147 if IS_SUPPORTED_SYSTEM {
3148 assert!(
3149 !SUPPORTED_SIGNALS.is_empty(),
3150 "SUPPORTED_SIGNALS shouldn't be empty on supported systems!"
3151 );
3152 } else {
3153 assert!(
3154 SUPPORTED_SIGNALS.is_empty(),
3155 "SUPPORTED_SIGNALS should be empty on not support systems!"
3156 );
3157 }
3158 }
3159}
3160
3161#[cfg(doctest)]
3162mod doctest {
3163 // FIXME: Can be removed once negative trait bounds are supported.
3164 /// Check that `Process` doesn't implement `Clone`.
3165 ///
3166 /// First we check that the "basic" code works:
3167 ///
3168 /// ```no_run
3169 /// use sysinfo::{Process, System};
3170 ///
3171 /// let mut s = System::new_all();
3172 /// let p: &Process = s.processes().values().next().unwrap();
3173 /// ```
3174 ///
3175 /// And now we check if it fails when we try to clone it:
3176 ///
3177 /// ```compile_fail
3178 /// use sysinfo::{Process, System};
3179 ///
3180 /// let mut s = System::new_all();
3181 /// let p: &Process = s.processes().values().next().unwrap();
3182 /// let p = (*p).clone();
3183 /// ```
3184 mod process_clone {}
3185
3186 // FIXME: Can be removed once negative trait bounds are supported.
3187 /// Check that `System` doesn't implement `Clone`.
3188 ///
3189 /// First we check that the "basic" code works:
3190 ///
3191 /// ```no_run
3192 /// use sysinfo::{Process, System};
3193 ///
3194 /// let s = System::new();
3195 /// ```
3196 ///
3197 /// And now we check if it fails when we try to clone it:
3198 ///
3199 /// ```compile_fail
3200 /// use sysinfo::{Process, System};
3201 ///
3202 /// let s = System::new();
3203 /// let s = s.clone();
3204 /// ```
3205 mod system_clone {}
3206}