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/// ```
924/// use sysinfo::Motherboard;
925///
926/// if let Some(m) = Motherboard::new() {
927/// println!("{m:?}");
928/// }
929/// ```
930pub struct Motherboard {
931 pub(crate) inner: MotherboardInner,
932}
933
934impl Motherboard {
935 /// Creates a new instance of the `Motherboard` type.
936 ///
937 /// ```
938 /// use sysinfo::Motherboard;
939 ///
940 /// if let Some(m) = Motherboard::new() {
941 /// println!("{m:?}");
942 /// }
943 /// ```
944 pub fn new() -> Option<Self> {
945 Some(Self {
946 inner: MotherboardInner::new()?,
947 })
948 }
949
950 /// Returns the motherboard name.
951 ///
952 /// This corresponds to the model identifier assigned by the motherboard's
953 /// manufacturer (e.g. "20BE0061MC").
954 /// This information isn't available on ARM-based macOS systems.
955 ///
956 /// **Important**: this information is computed every time this function is called.
957 ///
958 /// ```no_run
959 /// use sysinfo::Motherboard;
960 ///
961 /// if let Some(m) = Motherboard::new() {
962 /// println!("Motherboard name: {:?}", m.name());
963 /// }
964 /// ```
965 pub fn name(&self) -> Option<String> {
966 self.inner.name()
967 }
968
969 /// Returns the motherboard vendor name.
970 ///
971 /// This corresponds to the name of the motherboard's manufacturer (e.g. "LENOVO").
972 ///
973 /// **Important**: this information is computed every time this function is called.
974 ///
975 /// ```no_run
976 /// use sysinfo::Motherboard;
977 ///
978 /// if let Some(m) = Motherboard::new() {
979 /// println!("Motherboard vendor: {:?}", m.vendor_name());
980 /// }
981 /// ```
982 pub fn vendor_name(&self) -> Option<String> {
983 self.inner.vendor_name()
984 }
985
986 /// Returns the motherboard version.
987 ///
988 /// This corresponds to the version or model number assigned by the motherboard's
989 /// manufacturer (e.g. "0B98401 Pro").
990 /// This information isn't available on ARM-based macOS systems.
991 ///
992 /// **Important**: this information is computed every time this function is called.
993 ///
994 /// ```no_run
995 /// use sysinfo::Motherboard;
996 ///
997 /// if let Some(m) = Motherboard::new() {
998 /// println!("Motherboard version: {:?}", m.version());
999 /// }
1000 /// ```
1001 pub fn version(&self) -> Option<String> {
1002 self.inner.version()
1003 }
1004
1005 /// Returns the motherboard serial number.
1006 ///
1007 /// This corresponds to the serial number assigned by the motherboard's
1008 /// manufacturer (e.g. "W1KS427111E").
1009 ///
1010 /// **Important**: this information is computed every time this function is called.
1011 ///
1012 /// ```no_run
1013 /// use sysinfo::Motherboard;
1014 ///
1015 /// if let Some(m) = Motherboard::new() {
1016 /// println!("Motherboard serial number: {:?}", m.serial_number());
1017 /// }
1018 /// ```
1019 pub fn serial_number(&self) -> Option<String> {
1020 self.inner.serial_number()
1021 }
1022
1023 /// Returns the motherboard asset tag.
1024 ///
1025 /// This corresponds to the identifier assigned by the motherboard's
1026 /// manufacturer to track the physical device for inventory purposes.
1027 ///
1028 /// **Important**: this information is computed every time this function is called.
1029 ///
1030 /// ⚠️ Not supported on macOS/iOS.
1031 ///
1032 /// ```no_run
1033 /// use sysinfo::Motherboard;
1034 ///
1035 /// if let Some(m) = Motherboard::new() {
1036 /// println!("Motherboard asset tag: {:?}", m.asset_tag());
1037 /// }
1038 /// ```
1039 pub fn asset_tag(&self) -> Option<String> {
1040 self.inner.asset_tag()
1041 }
1042}
1043
1044/// This type allows to retrieve product-related information.
1045///
1046/// ```
1047/// use sysinfo::Product;
1048///
1049/// println!("{:?}", Product);
1050/// ```
1051pub struct Product;
1052
1053impl Product {
1054 /// Returns the product name.
1055 ///
1056 /// This corresponds to the product name assigned by the hardware
1057 /// manufacturer (e.g. "20AN").
1058 ///
1059 /// **Important**: this information is computed every time this function is called.
1060 ///
1061 /// ```no_run
1062 /// use sysinfo::Product;
1063 ///
1064 /// println!("Product name: {:?}", Product::name());
1065 /// ```
1066 pub fn name() -> Option<String> {
1067 ProductInner::name()
1068 }
1069
1070 /// Returns the product family identifier.
1071 ///
1072 /// This corresponds to the product family assigned by the hardware
1073 /// manufacturer (e.g. "T440p").
1074 ///
1075 /// **Important**: this information is computed every time this function is called.
1076 ///
1077 /// ```no_run
1078 /// use sysinfo::Product;
1079 ///
1080 /// println!("Product family: {:?}", Product::family());
1081 /// ```
1082 pub fn family() -> Option<String> {
1083 ProductInner::family()
1084 }
1085
1086 /// Returns the product serial number.
1087 ///
1088 /// This corresponds to the serial identifier assigned by the hardware
1089 /// manufacturer (e.g. "W1KS427111E").
1090 ///
1091 /// **Important**: this information is computed every time this function is called.
1092 ///
1093 /// ```no_run
1094 /// use sysinfo::Product;
1095 ///
1096 /// println!("Product serial: {:?}", Product::serial_number());
1097 /// ```
1098 pub fn serial_number() -> Option<String> {
1099 ProductInner::serial_number()
1100 }
1101
1102 /// Returns the product Stock Keeping Unit (SKU).
1103 ///
1104 /// This corresponds to the Stock Keeping Unit assigned by the hardware
1105 /// manufacturer (e.g. "LENOVO_MT_20AN") which identifies a specific
1106 /// model or configuration.
1107 ///
1108 /// **Important**: this information is computed every time this function is called.
1109 ///
1110 /// ⚠️ Not supported on macOS/iOS.
1111 ///
1112 /// ```no_run
1113 /// use sysinfo::Product;
1114 ///
1115 /// println!("Product sku: {:?}", Product::stock_keeping_unit());
1116 /// ```
1117 #[doc(alias = "sku")]
1118 pub fn stock_keeping_unit() -> Option<String> {
1119 ProductInner::stock_keeping_unit()
1120 }
1121
1122 /// Returns the product UUID.
1123 ///
1124 /// This corresponds to the unique identifier assigned by the hardware
1125 /// manufacturer (e.g. "407488fe-960a-43b5-a265-8fd0e9200b8f") which uniquely
1126 /// identifies the physical system.
1127 ///
1128 /// **Important**: this information is computed every time this function is called.
1129 ///
1130 /// ```no_run
1131 /// use sysinfo::Product;
1132 ///
1133 /// println!("Product UUID: {:?}", Product::uuid());
1134 /// ```
1135 pub fn uuid() -> Option<String> {
1136 ProductInner::uuid()
1137 }
1138
1139 /// Returns the product version.
1140 ///
1141 /// This corresponds to the version assigned by the hardware
1142 /// manufacturer (e.g. "Lenovo ThinkPad T440p") which identifies
1143 /// the specific version or revision of the product.
1144 ///
1145 /// **Important**: this information is computed every time this function is called.
1146 ///
1147 /// ```no_run
1148 /// use sysinfo::Product;
1149 ///
1150 /// println!("Product version: {:?}", Product::version());
1151 /// ```
1152 pub fn version() -> Option<String> {
1153 ProductInner::version()
1154 }
1155
1156 /// Returns the product vendor name.
1157 ///
1158 /// This corresponds to the vendor name assigned by the hardware
1159 /// manufacturer (e.g. "LENOVO").
1160 ///
1161 /// **Important**: this information is computed every time this function is called.
1162 ///
1163 /// ```no_run
1164 /// use sysinfo::Product;
1165 ///
1166 /// println!("Vendor name: {:?}", Product::vendor_name());
1167 /// ```
1168 pub fn vendor_name() -> Option<String> {
1169 ProductInner::vendor_name()
1170 }
1171}
1172
1173/// A struct representing system load average value.
1174///
1175/// It is returned by [`System::load_average`][crate::System::load_average].
1176///
1177/// ```no_run
1178/// use sysinfo::System;
1179///
1180/// let load_avg = System::load_average();
1181/// println!(
1182/// "one minute: {}%, five minutes: {}%, fifteen minutes: {}%",
1183/// load_avg.one,
1184/// load_avg.five,
1185/// load_avg.fifteen,
1186/// );
1187/// ```
1188#[repr(C)]
1189#[derive(Default, Debug, Clone)]
1190pub struct LoadAvg {
1191 /// Average load within one minute.
1192 pub one: f64,
1193 /// Average load within five minutes.
1194 pub five: f64,
1195 /// Average load within fifteen minutes.
1196 pub fifteen: f64,
1197}
1198
1199/// An enum representing signals on UNIX-like systems.
1200///
1201/// On non-unix systems, this enum is mostly useless and is only there to keep coherency between
1202/// the different OSes.
1203///
1204/// If you want the list of the supported signals on the current system, use
1205/// [`SUPPORTED_SIGNALS`][crate::SUPPORTED_SIGNALS].
1206#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
1207#[cfg_attr(feature = "serde", derive(serde::Deserialize))]
1208pub enum Signal {
1209 /// Hangup detected on controlling terminal or death of controlling process.
1210 Hangup,
1211 /// Interrupt from keyboard.
1212 Interrupt,
1213 /// Quit from keyboard.
1214 Quit,
1215 /// Illegal instruction.
1216 Illegal,
1217 /// Trace/breakpoint trap.
1218 Trap,
1219 /// Abort signal from C abort function.
1220 Abort,
1221 /// IOT trap. A synonym for SIGABRT.
1222 IOT,
1223 /// Bus error (bad memory access).
1224 Bus,
1225 /// Floating point exception.
1226 FloatingPointException,
1227 /// Kill signal.
1228 Kill,
1229 /// User-defined signal 1.
1230 User1,
1231 /// Invalid memory reference.
1232 Segv,
1233 /// User-defined signal 2.
1234 User2,
1235 /// Broken pipe: write to pipe with no readers.
1236 Pipe,
1237 /// Timer signal from C alarm function.
1238 Alarm,
1239 /// Termination signal.
1240 Term,
1241 /// Child stopped or terminated.
1242 Child,
1243 /// Continue if stopped.
1244 Continue,
1245 /// Stop process.
1246 Stop,
1247 /// Stop typed at terminal.
1248 TSTP,
1249 /// Terminal input for background process.
1250 TTIN,
1251 /// Terminal output for background process.
1252 TTOU,
1253 /// Urgent condition on socket.
1254 Urgent,
1255 /// CPU time limit exceeded.
1256 XCPU,
1257 /// File size limit exceeded.
1258 XFSZ,
1259 /// Virtual alarm clock.
1260 VirtualAlarm,
1261 /// Profiling time expired.
1262 Profiling,
1263 /// Windows resize signal.
1264 Winch,
1265 /// I/O now possible.
1266 IO,
1267 /// Pollable event (Sys V). Synonym for IO
1268 Poll,
1269 /// Power failure (System V).
1270 ///
1271 /// Doesn't exist on apple systems so will be ignored.
1272 Power,
1273 /// Bad argument to routine (SVr4).
1274 Sys,
1275}
1276
1277impl std::fmt::Display for Signal {
1278 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1279 let s = match *self {
1280 Self::Hangup => "Hangup",
1281 Self::Interrupt => "Interrupt",
1282 Self::Quit => "Quit",
1283 Self::Illegal => "Illegal",
1284 Self::Trap => "Trap",
1285 Self::Abort => "Abort",
1286 Self::IOT => "IOT",
1287 Self::Bus => "Bus",
1288 Self::FloatingPointException => "FloatingPointException",
1289 Self::Kill => "Kill",
1290 Self::User1 => "User1",
1291 Self::Segv => "Segv",
1292 Self::User2 => "User2",
1293 Self::Pipe => "Pipe",
1294 Self::Alarm => "Alarm",
1295 Self::Term => "Term",
1296 Self::Child => "Child",
1297 Self::Continue => "Continue",
1298 Self::Stop => "Stop",
1299 Self::TSTP => "TSTP",
1300 Self::TTIN => "TTIN",
1301 Self::TTOU => "TTOU",
1302 Self::Urgent => "Urgent",
1303 Self::XCPU => "XCPU",
1304 Self::XFSZ => "XFSZ",
1305 Self::VirtualAlarm => "VirtualAlarm",
1306 Self::Profiling => "Profiling",
1307 Self::Winch => "Winch",
1308 Self::IO => "IO",
1309 Self::Poll => "Poll",
1310 Self::Power => "Power",
1311 Self::Sys => "Sys",
1312 };
1313 f.write_str(s)
1314 }
1315}
1316
1317/// Contains memory limits for the current process.
1318#[derive(Default, Debug, Clone)]
1319pub struct CGroupLimits {
1320 /// Total memory (in bytes) for the current cgroup.
1321 pub total_memory: u64,
1322 /// Free memory (in bytes) for the current cgroup.
1323 pub free_memory: u64,
1324 /// Free swap (in bytes) for the current cgroup.
1325 pub free_swap: u64,
1326 /// Resident Set Size (RSS) (in bytes) for the current cgroup.
1327 pub rss: u64,
1328}
1329
1330/// Enum describing the different status of a process.
1331#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
1332#[cfg_attr(feature = "serde", derive(serde::Deserialize))]
1333pub enum ProcessStatus {
1334 /// ## Linux
1335 ///
1336 /// Idle kernel thread.
1337 ///
1338 /// ## macOs/FreeBSD
1339 ///
1340 /// Process being created by fork.
1341 ///
1342 /// ## Other OS
1343 ///
1344 /// Not available.
1345 Idle,
1346 /// Running.
1347 Run,
1348 /// ## Linux
1349 ///
1350 /// Sleeping in an interruptible waiting.
1351 ///
1352 /// ## macOS/FreeBSD
1353 ///
1354 /// Sleeping on an address.
1355 ///
1356 /// ## Other OS
1357 ///
1358 /// Not available.
1359 Sleep,
1360 /// ## Linux
1361 ///
1362 /// Stopped (on a signal) or (before Linux 2.6.33) trace stopped.
1363 ///
1364 /// ## macOS/FreeBSD
1365 ///
1366 /// Process debugging or suspension.
1367 ///
1368 /// ## Other OS
1369 ///
1370 /// Not available.
1371 Stop,
1372 /// ## Linux/FreeBSD/macOS
1373 ///
1374 /// Zombie process. Terminated but not reaped by its parent.
1375 ///
1376 /// ## Other OS
1377 ///
1378 /// Not available.
1379 Zombie,
1380 /// ## Linux
1381 ///
1382 /// Tracing stop (Linux 2.6.33 onward). Stopped by debugger during the tracing.
1383 ///
1384 /// ## Other OS
1385 ///
1386 /// Not available.
1387 Tracing,
1388 /// ## Linux
1389 ///
1390 /// Dead/uninterruptible sleep (usually IO).
1391 ///
1392 /// ## FreeBSD
1393 ///
1394 /// A process should never end up in this state.
1395 ///
1396 /// ## Other OS
1397 ///
1398 /// Not available.
1399 Dead,
1400 /// ## Linux
1401 ///
1402 /// Wakekill (Linux 2.6.33 to 3.13 only).
1403 ///
1404 /// ## Other OS
1405 ///
1406 /// Not available.
1407 Wakekill,
1408 /// ## Linux
1409 ///
1410 /// Waking (Linux 2.6.33 to 3.13 only).
1411 ///
1412 /// ## Other OS
1413 ///
1414 /// Not available.
1415 Waking,
1416 /// ## Linux
1417 ///
1418 /// Parked (Linux 3.9 to 3.13 only).
1419 ///
1420 /// ## macOS
1421 ///
1422 /// Halted at a clean point.
1423 ///
1424 /// ## Other OS
1425 ///
1426 /// Not available.
1427 Parked,
1428 /// ## FreeBSD
1429 ///
1430 /// Blocked on a lock.
1431 ///
1432 /// ## Other OS
1433 ///
1434 /// Not available.
1435 LockBlocked,
1436 /// ## Linux
1437 ///
1438 /// Waiting in uninterruptible disk sleep.
1439 ///
1440 /// ## Other OS
1441 ///
1442 /// Not available.
1443 UninterruptibleDiskSleep,
1444 /// Unknown.
1445 Unknown(u32),
1446}
1447
1448/// Enum describing the different kind of threads.
1449#[derive(Clone, Copy, Debug, PartialEq, Eq)]
1450#[cfg_attr(feature = "serde", derive(serde::Deserialize))]
1451pub enum ThreadKind {
1452 /// Kernel thread.
1453 Kernel,
1454 /// User thread.
1455 Userland,
1456}
1457
1458/// Enum describing possible [`Process::kill_and_wait`] errors.
1459#[derive(Clone, Copy, Debug, PartialEq, Eq)]
1460#[cfg_attr(feature = "serde", derive(serde::Deserialize))]
1461pub enum KillError {
1462 /// This signal doesn't exist on this platform.
1463 SignalDoesNotExist,
1464 /// The signal failed to be sent to the target process.
1465 FailedToSendSignal,
1466}
1467
1468/// Struct containing information of a process.
1469///
1470/// ## iOS
1471///
1472/// This information cannot be retrieved on iOS due to sandboxing.
1473///
1474/// ## Apple app store
1475///
1476/// If you are building a macOS Apple app store, it won't be able
1477/// to retrieve this information.
1478///
1479/// ```no_run
1480/// use sysinfo::{Pid, System};
1481///
1482/// let s = System::new_all();
1483/// if let Some(process) = s.process(Pid::from(1337)) {
1484/// println!("{:?}", process.name());
1485/// }
1486/// ```
1487pub struct Process {
1488 pub(crate) inner: ProcessInner,
1489}
1490
1491impl Process {
1492 /// Sends [`Signal::Kill`] to the process (which is the only signal supported on all supported
1493 /// platforms by this crate).
1494 ///
1495 /// Returns `true` if the signal was sent successfully. If you want to wait for this process
1496 /// to end, you can use [`Process::wait`] or directly [`Process::kill_and_wait`].
1497 ///
1498 /// ⚠️ Even if this function returns `true`, it doesn't necessarily mean that the process will
1499 /// be killed. It just means that the signal was sent successfully.
1500 ///
1501 /// ⚠️ Please note that some processes might not be "killable", like if they run with higher
1502 /// levels than the current process for example.
1503 ///
1504 /// If you want to use another signal, take a look at [`Process::kill_with`].
1505 ///
1506 /// To get the list of the supported signals on this system, use
1507 /// [`SUPPORTED_SIGNALS`][crate::SUPPORTED_SIGNALS].
1508 ///
1509 /// ```no_run
1510 /// use sysinfo::{Pid, System};
1511 ///
1512 /// let s = System::new_all();
1513 /// if let Some(process) = s.process(Pid::from(1337)) {
1514 /// process.kill();
1515 /// }
1516 /// ```
1517 pub fn kill(&self) -> bool {
1518 self.kill_with(Signal::Kill).unwrap_or(false)
1519 }
1520
1521 /// Sends the given `signal` to the process. If the signal doesn't exist on this platform,
1522 /// it'll do nothing and will return `None`. Otherwise it'll return `Some(bool)`. The boolean
1523 /// value will depend on whether or not the signal was sent successfully.
1524 ///
1525 /// If you just want to kill the process, use [`Process::kill`] directly. If you want to wait
1526 /// for this process to end, you can use [`Process::wait`] or [`Process::kill_with_and_wait`].
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 /// To get the list of the supported signals on this system, use
1532 /// [`SUPPORTED_SIGNALS`][crate::SUPPORTED_SIGNALS].
1533 ///
1534 /// ```no_run
1535 /// use sysinfo::{Pid, Signal, System};
1536 ///
1537 /// let s = System::new_all();
1538 /// if let Some(process) = s.process(Pid::from(1337)) {
1539 /// if process.kill_with(Signal::Kill).is_none() {
1540 /// println!("This signal isn't supported on this platform");
1541 /// }
1542 /// }
1543 /// ```
1544 pub fn kill_with(&self, signal: Signal) -> Option<bool> {
1545 self.inner.kill_with(signal)
1546 }
1547
1548 /// Sends [`Signal::Kill`] to the process then waits for its termination.
1549 ///
1550 /// Internally, this method is calling [`Process::kill`] then [`Process::wait`].
1551 ///
1552 /// ⚠️ Please note that some processes might not be "killable", like if they run with higher
1553 /// levels than the current process for example. In this case, this method could enter an
1554 /// infinite loop.
1555 ///
1556 /// ```no_run
1557 /// use sysinfo::{Pid, System};
1558 ///
1559 /// let s = System::new_all();
1560 /// if let Some(process) = s.process(Pid::from(1337)) {
1561 /// if let Err(error) = process.kill_and_wait() {
1562 /// println!("`kill_and_wait` failed: {error:?}");
1563 /// }
1564 /// }
1565 /// ```
1566 pub fn kill_and_wait(&self) -> Result<Option<ExitStatus>, KillError> {
1567 self.kill_with_and_wait(Signal::Kill)
1568 }
1569
1570 /// Sends the given `signal` to the process.then waits for its termination.
1571 ///
1572 /// Internally, this method is calling [`Process::kill_with`] then [`Process::wait`].
1573 ///
1574 /// ⚠️ Please note that some processes might not be "killable", like if they run with higher
1575 /// levels than the current process for example. In this case, this method could enter an
1576 /// infinite loop.
1577 ///
1578 /// To get the list of the supported signals on this system, use
1579 /// [`SUPPORTED_SIGNALS`][crate::SUPPORTED_SIGNALS].
1580 ///
1581 /// ```no_run
1582 /// use sysinfo::{Pid, System};
1583 ///
1584 /// let s = System::new_all();
1585 /// if let Some(process) = s.process(Pid::from(1337)) {
1586 /// if let Err(error) = process.kill_and_wait() {
1587 /// println!("`kill_and_wait` failed: {error:?}");
1588 /// }
1589 /// }
1590 /// ```
1591 pub fn kill_with_and_wait(&self, signal: Signal) -> Result<Option<ExitStatus>, KillError> {
1592 match self.inner.kill_with(signal) {
1593 Some(sent) => {
1594 if !sent {
1595 return Err(KillError::FailedToSendSignal);
1596 }
1597 }
1598 None => return Err(KillError::SignalDoesNotExist),
1599 }
1600
1601 Ok(self.inner.wait())
1602 }
1603
1604 /// Waits for process termination and returns its [`ExitStatus`] if it could be retrieved,
1605 /// returns `None` otherwise. It means that as long as the process is alive, this method will
1606 /// not return.
1607 ///
1608 /// ⚠️ On **macOS** and **FreeBSD**, if the process died and a new one took its PID, unless
1609 /// you refreshed, it will wait for the new process to end.
1610 ///
1611 /// On **Windows**, as long as we have a (internal) handle, we can always retrieve the exit
1612 /// status.
1613 ///
1614 /// On **Linux**/**Android**, we check that the start time of the PID we're waiting is the same
1615 /// as the current process'. If not it means the process died and a new one got its PID.
1616 ///
1617 /// ```no_run
1618 /// use sysinfo::{Pid, System};
1619 ///
1620 /// let mut s = System::new_all();
1621 ///
1622 /// if let Some(process) = s.process(Pid::from(1337)) {
1623 /// println!("Waiting for pid 1337");
1624 /// let exit_status = process.wait();
1625 /// println!("Pid 1337 exited with: {exit_status:?}");
1626 /// }
1627 /// ```
1628 pub fn wait(&self) -> Option<ExitStatus> {
1629 self.inner.wait()
1630 }
1631
1632 /// Returns the name of the process.
1633 ///
1634 /// **⚠️ Important ⚠️**
1635 ///
1636 /// On **Linux**, there are two things to know about processes' name:
1637 /// 1. It is limited to 15 characters.
1638 /// 2. It is not always the exe name.
1639 ///
1640 /// If you are looking for a specific process, unless you know what you are
1641 /// doing, in most cases it's better to use [`Process::exe`] instead (which
1642 /// can be empty sometimes!).
1643 ///
1644 /// ```no_run
1645 /// use sysinfo::{Pid, System};
1646 ///
1647 /// let s = System::new_all();
1648 /// if let Some(process) = s.process(Pid::from(1337)) {
1649 /// println!("{:?}", process.name());
1650 /// }
1651 /// ```
1652 pub fn name(&self) -> &OsStr {
1653 self.inner.name()
1654 }
1655
1656 /// Returns the command line.
1657 ///
1658 /// **⚠️ Important ⚠️**
1659 ///
1660 /// On **Windows**, you might need to use `administrator` privileges when running your program
1661 /// to have access to this information.
1662 ///
1663 /// ```no_run
1664 /// use sysinfo::{Pid, System};
1665 ///
1666 /// let s = System::new_all();
1667 /// if let Some(process) = s.process(Pid::from(1337)) {
1668 /// println!("{:?}", process.cmd());
1669 /// }
1670 /// ```
1671 pub fn cmd(&self) -> &[OsString] {
1672 self.inner.cmd()
1673 }
1674
1675 /// Returns the path to the process.
1676 ///
1677 /// ```no_run
1678 /// use sysinfo::{Pid, System};
1679 ///
1680 /// let s = System::new_all();
1681 /// if let Some(process) = s.process(Pid::from(1337)) {
1682 /// println!("{:?}", process.exe());
1683 /// }
1684 /// ```
1685 ///
1686 /// ### Implementation notes
1687 ///
1688 /// On Linux, this method will return an empty path if there
1689 /// was an error trying to read `/proc/<pid>/exe`. This can
1690 /// happen, for example, if the permission levels or UID namespaces
1691 /// between the caller and target processes are different.
1692 ///
1693 /// It is also the case that `cmd[0]` is _not_ usually a correct
1694 /// replacement for this.
1695 /// A process [may change its `cmd[0]` value](https://man7.org/linux/man-pages/man5/proc.5.html)
1696 /// freely, making this an untrustworthy source of information.
1697 pub fn exe(&self) -> Option<&Path> {
1698 self.inner.exe()
1699 }
1700
1701 /// Returns the PID of the process.
1702 ///
1703 /// ```no_run
1704 /// use sysinfo::{Pid, System};
1705 ///
1706 /// let s = System::new_all();
1707 /// if let Some(process) = s.process(Pid::from(1337)) {
1708 /// println!("{}", process.pid());
1709 /// }
1710 /// ```
1711 pub fn pid(&self) -> Pid {
1712 self.inner.pid()
1713 }
1714
1715 /// Returns the environment variables of the process.
1716 ///
1717 /// ```no_run
1718 /// use sysinfo::{Pid, System};
1719 ///
1720 /// let s = System::new_all();
1721 /// if let Some(process) = s.process(Pid::from(1337)) {
1722 /// println!("{:?}", process.environ());
1723 /// }
1724 /// ```
1725 pub fn environ(&self) -> &[OsString] {
1726 self.inner.environ()
1727 }
1728
1729 /// Returns the current working directory.
1730 ///
1731 /// ```no_run
1732 /// use sysinfo::{Pid, System};
1733 ///
1734 /// let s = System::new_all();
1735 /// if let Some(process) = s.process(Pid::from(1337)) {
1736 /// println!("{:?}", process.cwd());
1737 /// }
1738 /// ```
1739 pub fn cwd(&self) -> Option<&Path> {
1740 self.inner.cwd()
1741 }
1742
1743 /// Returns the path of the root directory.
1744 ///
1745 /// ```no_run
1746 /// use sysinfo::{Pid, System};
1747 ///
1748 /// let s = System::new_all();
1749 /// if let Some(process) = s.process(Pid::from(1337)) {
1750 /// println!("{:?}", process.root());
1751 /// }
1752 /// ```
1753 pub fn root(&self) -> Option<&Path> {
1754 self.inner.root()
1755 }
1756
1757 /// Returns the memory usage (in bytes).
1758 ///
1759 /// This method returns the [size of the resident set], that is, the amount of memory that the
1760 /// process allocated and which is currently mapped in physical RAM. It does not include memory
1761 /// that is swapped out, or, in some operating systems, that has been allocated but never used.
1762 ///
1763 /// Thus, it represents exactly the amount of physical RAM that the process is using at the
1764 /// present time, but it might not be a good indicator of the total memory that the process will
1765 /// be using over its lifetime. For that purpose, you can try and use
1766 /// [`virtual_memory`](Process::virtual_memory).
1767 ///
1768 /// ```no_run
1769 /// use sysinfo::{Pid, System};
1770 ///
1771 /// let s = System::new_all();
1772 /// if let Some(process) = s.process(Pid::from(1337)) {
1773 /// println!("{} bytes", process.memory());
1774 /// }
1775 /// ```
1776 ///
1777 /// [size of the resident set]: https://en.wikipedia.org/wiki/Resident_set_size
1778 pub fn memory(&self) -> u64 {
1779 self.inner.memory()
1780 }
1781
1782 /// Returns the virtual memory usage (in bytes).
1783 ///
1784 /// This method returns the [size of virtual memory], that is, the amount of memory that the
1785 /// process can access, whether it is currently mapped in physical RAM or not. It includes
1786 /// physical RAM, allocated but not used regions, swapped-out regions, and even memory
1787 /// associated with [memory-mapped files](https://en.wikipedia.org/wiki/Memory-mapped_file).
1788 ///
1789 /// This value has limitations though. Depending on the operating system and type of process,
1790 /// this value might be a good indicator of the total memory that the process will be using over
1791 /// its lifetime. However, for example, in the version 14 of macOS this value is in the order of
1792 /// the hundreds of gigabytes for every process, and thus not very informative. Moreover, if a
1793 /// process maps into memory a very large file, this value will increase accordingly, even if
1794 /// the process is not actively using the memory.
1795 ///
1796 /// ```no_run
1797 /// use sysinfo::{Pid, System};
1798 ///
1799 /// let s = System::new_all();
1800 /// if let Some(process) = s.process(Pid::from(1337)) {
1801 /// println!("{} bytes", process.virtual_memory());
1802 /// }
1803 /// ```
1804 ///
1805 /// [size of virtual memory]: https://en.wikipedia.org/wiki/Virtual_memory
1806 pub fn virtual_memory(&self) -> u64 {
1807 self.inner.virtual_memory()
1808 }
1809
1810 /// Returns the parent PID.
1811 ///
1812 /// ```no_run
1813 /// use sysinfo::{Pid, System};
1814 ///
1815 /// let s = System::new_all();
1816 /// if let Some(process) = s.process(Pid::from(1337)) {
1817 /// println!("{:?}", process.parent());
1818 /// }
1819 /// ```
1820 pub fn parent(&self) -> Option<Pid> {
1821 self.inner.parent()
1822 }
1823
1824 /// Returns the status of the process.
1825 ///
1826 /// ```no_run
1827 /// use sysinfo::{Pid, System};
1828 ///
1829 /// let s = System::new_all();
1830 /// if let Some(process) = s.process(Pid::from(1337)) {
1831 /// println!("{:?}", process.status());
1832 /// }
1833 /// ```
1834 pub fn status(&self) -> ProcessStatus {
1835 self.inner.status()
1836 }
1837
1838 /// Returns the time where the process was started (in seconds) from epoch.
1839 ///
1840 /// ```no_run
1841 /// use sysinfo::{Pid, System};
1842 ///
1843 /// let s = System::new_all();
1844 /// if let Some(process) = s.process(Pid::from(1337)) {
1845 /// println!("Started at {} seconds", process.start_time());
1846 /// }
1847 /// ```
1848 pub fn start_time(&self) -> u64 {
1849 self.inner.start_time()
1850 }
1851
1852 /// Returns for how much time the process has been running (in seconds).
1853 ///
1854 /// ```no_run
1855 /// use sysinfo::{Pid, System};
1856 ///
1857 /// let s = System::new_all();
1858 /// if let Some(process) = s.process(Pid::from(1337)) {
1859 /// println!("Running since {} seconds", process.run_time());
1860 /// }
1861 /// ```
1862 pub fn run_time(&self) -> u64 {
1863 self.inner.run_time()
1864 }
1865
1866 /// Returns the total CPU usage (in %). Notice that it might be bigger than
1867 /// 100 if run on a multi-core machine.
1868 ///
1869 /// If you want a value between 0% and 100%, divide the returned value by
1870 /// the number of CPUs.
1871 ///
1872 /// ⚠️ To start to have accurate CPU usage, a process needs to be refreshed
1873 /// **twice** because CPU usage computation is based on time diff (process
1874 /// time on a given time period divided by total system time on the same
1875 /// time period).
1876 ///
1877 /// ⚠️ If you want accurate CPU usage number, better leave a bit of time
1878 /// between two calls of this method (take a look at
1879 /// [`MINIMUM_CPU_UPDATE_INTERVAL`][crate::MINIMUM_CPU_UPDATE_INTERVAL] for
1880 /// more information).
1881 ///
1882 /// ```no_run
1883 /// use sysinfo::{Pid, ProcessesToUpdate, ProcessRefreshKind, System};
1884 ///
1885 /// let mut s = System::new_all();
1886 /// // Wait a bit because CPU usage is based on diff.
1887 /// std::thread::sleep(sysinfo::MINIMUM_CPU_UPDATE_INTERVAL);
1888 /// // Refresh CPU usage to get actual value.
1889 /// s.refresh_processes_specifics(
1890 /// ProcessesToUpdate::All,
1891 /// true,
1892 /// ProcessRefreshKind::nothing().with_cpu()
1893 /// );
1894 /// if let Some(process) = s.process(Pid::from(1337)) {
1895 /// println!("{}%", process.cpu_usage());
1896 /// }
1897 /// ```
1898 pub fn cpu_usage(&self) -> f32 {
1899 self.inner.cpu_usage()
1900 }
1901
1902 /// Returns the total accumulated CPU usage (in CPU-milliseconds). Note
1903 /// that it might be bigger than the total clock run time of a process if
1904 /// run on a multi-core machine.
1905 ///
1906 /// ```no_run
1907 /// use sysinfo::{Pid, System};
1908 ///
1909 /// let s = System::new_all();
1910 /// if let Some(process) = s.process(Pid::from(1337)) {
1911 /// println!("{}", process.accumulated_cpu_time());
1912 /// }
1913 /// ```
1914 pub fn accumulated_cpu_time(&self) -> u64 {
1915 self.inner.accumulated_cpu_time()
1916 }
1917
1918 /// Returns number of bytes read and written to disk.
1919 ///
1920 /// ⚠️ On Windows, this method actually returns **ALL** I/O read and
1921 /// written bytes.
1922 ///
1923 /// ⚠️ Files might be cached in memory by your OS, meaning that reading/writing them might not
1924 /// increase the `read_bytes`/`written_bytes` values. You can find more information about it
1925 /// in the `proc_pid_io` manual (`man proc_pid_io` on unix platforms).
1926 ///
1927 /// ```no_run
1928 /// use sysinfo::{Pid, System};
1929 ///
1930 /// let s = System::new_all();
1931 /// if let Some(process) = s.process(Pid::from(1337)) {
1932 /// let disk_usage = process.disk_usage();
1933 /// println!("read bytes : new/total => {}/{}",
1934 /// disk_usage.read_bytes,
1935 /// disk_usage.total_read_bytes,
1936 /// );
1937 /// println!("written bytes: new/total => {}/{}",
1938 /// disk_usage.written_bytes,
1939 /// disk_usage.total_written_bytes,
1940 /// );
1941 /// }
1942 /// ```
1943 pub fn disk_usage(&self) -> DiskUsage {
1944 self.inner.disk_usage()
1945 }
1946
1947 /// Returns the ID of the owner user of this process or `None` if this
1948 /// information couldn't be retrieved. If you want to get the [`User`] from
1949 /// it, take a look at [`Users::get_user_by_id`].
1950 ///
1951 /// [`User`]: crate::User
1952 /// [`Users::get_user_by_id`]: crate::Users::get_user_by_id
1953 ///
1954 /// ```no_run
1955 /// use sysinfo::{Pid, System};
1956 ///
1957 /// let mut s = System::new_all();
1958 ///
1959 /// if let Some(process) = s.process(Pid::from(1337)) {
1960 /// println!("User id for process 1337: {:?}", process.user_id());
1961 /// }
1962 /// ```
1963 pub fn user_id(&self) -> Option<&Uid> {
1964 self.inner.user_id()
1965 }
1966
1967 /// Returns the user ID of the effective owner of this process or `None` if
1968 /// this information couldn't be retrieved. If you want to get the [`User`]
1969 /// from it, take a look at [`Users::get_user_by_id`].
1970 ///
1971 /// If you run something with `sudo`, the real user ID of the launched
1972 /// process will be the ID of the user you are logged in as but effective
1973 /// user ID will be `0` (i-e root).
1974 ///
1975 /// ⚠️ It always returns `None` on Windows.
1976 ///
1977 /// [`User`]: crate::User
1978 /// [`Users::get_user_by_id`]: crate::Users::get_user_by_id
1979 ///
1980 /// ```no_run
1981 /// use sysinfo::{Pid, System};
1982 ///
1983 /// let mut s = System::new_all();
1984 ///
1985 /// if let Some(process) = s.process(Pid::from(1337)) {
1986 /// println!("User id for process 1337: {:?}", process.effective_user_id());
1987 /// }
1988 /// ```
1989 pub fn effective_user_id(&self) -> Option<&Uid> {
1990 self.inner.effective_user_id()
1991 }
1992
1993 /// Returns the process group ID of the process.
1994 ///
1995 /// ⚠️ It always returns `None` on Windows.
1996 ///
1997 /// ```no_run
1998 /// use sysinfo::{Pid, System};
1999 ///
2000 /// let mut s = System::new_all();
2001 ///
2002 /// if let Some(process) = s.process(Pid::from(1337)) {
2003 /// println!("Group ID for process 1337: {:?}", process.group_id());
2004 /// }
2005 /// ```
2006 pub fn group_id(&self) -> Option<Gid> {
2007 self.inner.group_id()
2008 }
2009
2010 /// Returns the effective group ID of the process.
2011 ///
2012 /// If you run something with `sudo`, the real group ID of the launched
2013 /// process will be the primary group ID you are logged in as but effective
2014 /// group ID will be `0` (i-e root).
2015 ///
2016 /// ⚠️ It always returns `None` on Windows.
2017 ///
2018 /// ```no_run
2019 /// use sysinfo::{Pid, System};
2020 ///
2021 /// let mut s = System::new_all();
2022 ///
2023 /// if let Some(process) = s.process(Pid::from(1337)) {
2024 /// println!("User id for process 1337: {:?}", process.effective_group_id());
2025 /// }
2026 /// ```
2027 pub fn effective_group_id(&self) -> Option<Gid> {
2028 self.inner.effective_group_id()
2029 }
2030
2031 /// Returns the session ID for the current process or `None` if it couldn't
2032 /// be retrieved.
2033 ///
2034 /// ⚠️ This information is computed every time this method is called.
2035 ///
2036 /// ```no_run
2037 /// use sysinfo::{Pid, System};
2038 ///
2039 /// let mut s = System::new_all();
2040 ///
2041 /// if let Some(process) = s.process(Pid::from(1337)) {
2042 /// println!("Session ID for process 1337: {:?}", process.session_id());
2043 /// }
2044 /// ```
2045 pub fn session_id(&self) -> Option<Pid> {
2046 self.inner.session_id()
2047 }
2048
2049 /// Tasks run by this process. If there are none, returns `None`.
2050 ///
2051 /// ⚠️ This method always returns `None` on other platforms than Linux.
2052 ///
2053 /// ```no_run
2054 /// use sysinfo::{Pid, System};
2055 ///
2056 /// let mut s = System::new_all();
2057 ///
2058 /// if let Some(process) = s.process(Pid::from(1337)) {
2059 /// if let Some(tasks) = process.tasks() {
2060 /// println!("Listing tasks for process {:?}", process.pid());
2061 /// for task_pid in tasks {
2062 /// if let Some(task) = s.process(*task_pid) {
2063 /// println!("Task {:?}: {:?}", task.pid(), task.name());
2064 /// }
2065 /// }
2066 /// }
2067 /// }
2068 /// ```
2069 pub fn tasks(&self) -> Option<&HashSet<Pid>> {
2070 cfg_if! {
2071 if #[cfg(all(
2072 any(target_os = "linux", target_os = "android"),
2073 not(feature = "unknown-ci")
2074 ))] {
2075 self.inner.tasks.as_ref()
2076 } else {
2077 None
2078 }
2079 }
2080 }
2081
2082 /// If the process is a thread, it'll return `Some` with the kind of thread it is. Returns
2083 /// `None` otherwise.
2084 ///
2085 /// ⚠️ This method always returns `None` on other platforms than Linux.
2086 ///
2087 /// ```no_run
2088 /// use sysinfo::System;
2089 ///
2090 /// let s = System::new_all();
2091 ///
2092 /// for (_, process) in s.processes() {
2093 /// if let Some(thread_kind) = process.thread_kind() {
2094 /// println!("Process {:?} is a {thread_kind:?} thread", process.pid());
2095 /// }
2096 /// }
2097 /// ```
2098 pub fn thread_kind(&self) -> Option<ThreadKind> {
2099 cfg_if! {
2100 if #[cfg(all(
2101 any(target_os = "linux", target_os = "android"),
2102 not(feature = "unknown-ci")
2103 ))] {
2104 self.inner.thread_kind()
2105 } else {
2106 None
2107 }
2108 }
2109 }
2110
2111 /// Returns `true` if the process doesn't exist anymore but was not yet removed from
2112 /// the processes list because the `remove_dead_processes` argument was set to `false`
2113 /// in methods like [`System::refresh_processes`].
2114 ///
2115 /// ```no_run
2116 /// use sysinfo::{ProcessesToUpdate, System};
2117 ///
2118 /// let mut s = System::new_all();
2119 /// // We set the `remove_dead_processes` to `false`.
2120 /// s.refresh_processes(ProcessesToUpdate::All, false);
2121 ///
2122 /// for (_, process) in s.processes() {
2123 /// println!(
2124 /// "Process {:?} {}",
2125 /// process.pid(),
2126 /// if process.exists() { "exists" } else { "doesn't exist" },
2127 /// );
2128 /// }
2129 /// ```
2130 pub fn exists(&self) -> bool {
2131 self.inner.exists()
2132 }
2133
2134 /// Returns the number of open files in the current process.
2135 ///
2136 /// Returns `None` if it failed retrieving the information or if the current system is not
2137 /// supported.
2138 ///
2139 /// **Important**: this information is computed every time this function is called.
2140 ///
2141 /// ```no_run
2142 /// use sysinfo::System;
2143 ///
2144 /// let s = System::new_all();
2145 ///
2146 /// for (_, process) in s.processes() {
2147 /// println!(
2148 /// "Process {:?} {:?}",
2149 /// process.pid(),
2150 /// process.open_files(),
2151 /// );
2152 /// }
2153 /// ```
2154 pub fn open_files(&self) -> Option<usize> {
2155 self.inner.open_files()
2156 }
2157
2158 /// Returns the maximum number of open files for the current process.
2159 ///
2160 /// Returns `None` if it failed retrieving the information or if the current system is not
2161 /// supported.
2162 ///
2163 /// **Important**: this information is computed every time this function is called.
2164 ///
2165 /// ```no_run
2166 /// use sysinfo::System;
2167 ///
2168 /// let s = System::new_all();
2169 ///
2170 /// for (_, process) in s.processes() {
2171 /// println!(
2172 /// "Process {:?} {:?}",
2173 /// process.pid(),
2174 /// process.open_files_limit(),
2175 /// );
2176 /// }
2177 /// ```
2178 pub fn open_files_limit(&self) -> Option<usize> {
2179 self.inner.open_files_limit()
2180 }
2181}
2182
2183macro_rules! pid_decl {
2184 ($typ:ty) => {
2185 #[doc = include_str!("../../md_doc/pid.md")]
2186 #[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
2187 #[repr(transparent)]
2188 pub struct Pid(pub(crate) $typ);
2189
2190 impl From<usize> for Pid {
2191 fn from(v: usize) -> Self {
2192 Self(v as _)
2193 }
2194 }
2195 impl From<Pid> for usize {
2196 fn from(v: Pid) -> Self {
2197 v.0 as _
2198 }
2199 }
2200 impl FromStr for Pid {
2201 type Err = <$typ as FromStr>::Err;
2202 fn from_str(s: &str) -> Result<Self, Self::Err> {
2203 Ok(Self(<$typ>::from_str(s)?))
2204 }
2205 }
2206 impl fmt::Display for Pid {
2207 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2208 write!(f, "{}", self.0)
2209 }
2210 }
2211 impl Pid {
2212 /// Allows to convert [`Pid`][crate::Pid] into [`u32`].
2213 ///
2214 /// ```
2215 /// use sysinfo::Pid;
2216 ///
2217 /// let pid = Pid::from_u32(0);
2218 /// let value: u32 = pid.as_u32();
2219 /// ```
2220 pub fn as_u32(self) -> u32 {
2221 self.0 as _
2222 }
2223 /// Allows to convert a [`u32`] into [`Pid`][crate::Pid].
2224 ///
2225 /// ```
2226 /// use sysinfo::Pid;
2227 ///
2228 /// let pid = Pid::from_u32(0);
2229 /// ```
2230 pub fn from_u32(v: u32) -> Self {
2231 Self(v as _)
2232 }
2233 }
2234 };
2235}
2236
2237cfg_if! {
2238 if #[cfg(all(
2239 not(feature = "unknown-ci"),
2240 any(
2241 target_os = "freebsd",
2242 target_os = "linux",
2243 target_os = "android",
2244 target_os = "macos",
2245 target_os = "ios",
2246 )
2247 ))] {
2248 use libc::pid_t;
2249
2250 pid_decl!(pid_t);
2251 } else {
2252 pid_decl!(usize);
2253 }
2254}
2255
2256/// This enum allows you to specify when you want the related information to be updated.
2257///
2258/// For example if you only want the [`Process::exe()`] information to be refreshed only if it's not
2259/// already set:
2260///
2261/// ```no_run
2262/// use sysinfo::{ProcessesToUpdate, ProcessRefreshKind, System, UpdateKind};
2263///
2264/// let mut system = System::new();
2265/// system.refresh_processes_specifics(
2266/// ProcessesToUpdate::All,
2267/// true,
2268/// ProcessRefreshKind::nothing().with_exe(UpdateKind::OnlyIfNotSet),
2269/// );
2270/// ```
2271#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
2272pub enum UpdateKind {
2273 /// Never update the related information.
2274 #[default]
2275 Never,
2276 /// Always update the related information.
2277 Always,
2278 /// Only update the related information if it was not already set at least once.
2279 OnlyIfNotSet,
2280}
2281
2282impl UpdateKind {
2283 /// If `self` is `OnlyIfNotSet`, `f` is called and its returned value is returned.
2284 #[allow(dead_code)] // Needed for unsupported targets.
2285 pub(crate) fn needs_update(self, f: impl Fn() -> bool) -> bool {
2286 match self {
2287 Self::Never => false,
2288 Self::Always => true,
2289 Self::OnlyIfNotSet => f(),
2290 }
2291 }
2292}
2293
2294/// This enum allows you to specify if you want all processes to be updated or just
2295/// some of them.
2296///
2297/// Example:
2298///
2299/// ```no_run
2300/// use sysinfo::{ProcessesToUpdate, System, get_current_pid};
2301///
2302/// let mut system = System::new();
2303/// // To refresh all processes:
2304/// system.refresh_processes(ProcessesToUpdate::All, true);
2305///
2306/// // To refresh only the current one:
2307/// system.refresh_processes(
2308/// ProcessesToUpdate::Some(&[get_current_pid().unwrap()]),
2309/// true,
2310/// );
2311/// ```
2312#[derive(Clone, Copy, Debug, PartialEq, Eq)]
2313pub enum ProcessesToUpdate<'a> {
2314 /// To refresh all processes.
2315 All,
2316 /// To refresh only the processes with the listed [`Pid`].
2317 ///
2318 /// [`Pid`]: crate::Pid
2319 Some(&'a [Pid]),
2320}
2321
2322/// Used to determine what you want to refresh specifically on the [`Process`] type.
2323///
2324/// When all refresh are ruled out, a [`Process`] will still retrieve the following information:
2325/// * Process ID ([`Pid`])
2326/// * Parent process ID (on Windows it never changes though)
2327/// * Process name
2328/// * Start time
2329///
2330/// ⚠️ Just like all other refresh types, ruling out a refresh doesn't assure you that
2331/// the information won't be retrieved if the information is accessible without needing
2332/// extra computation.
2333///
2334/// ⚠️ ** Linux Specific ** ⚠️
2335/// When using `ProcessRefreshKind::everything()`, in linux we will fetch all relevant
2336/// information from `/proc/<pid>/` as well as all the information from `/proc/<pid>/task/<tid>/`
2337/// folders. This makes the refresh mechanism a lot slower depending on the number of tasks
2338/// each process has.
2339///
2340/// If you don't care about tasks information, use `ProcessRefreshKind::everything().without_tasks()`
2341/// as much as possible.
2342///
2343/// ```
2344/// use sysinfo::{ProcessesToUpdate, ProcessRefreshKind, System};
2345///
2346/// let mut system = System::new();
2347///
2348/// // We don't want to update the CPU information.
2349/// system.refresh_processes_specifics(
2350/// ProcessesToUpdate::All,
2351/// true,
2352/// ProcessRefreshKind::everything().without_cpu(),
2353/// );
2354///
2355/// for (_, proc_) in system.processes() {
2356/// // We use a `==` comparison on float only because we know it's set to 0 here.
2357/// assert_eq!(proc_.cpu_usage(), 0.);
2358/// }
2359/// ```
2360///
2361/// [`Process`]: crate::Process
2362#[derive(Clone, Copy, Debug, PartialEq, Eq)]
2363pub struct ProcessRefreshKind {
2364 cpu: bool,
2365 disk_usage: bool,
2366 memory: bool,
2367 user: UpdateKind,
2368 cwd: UpdateKind,
2369 root: UpdateKind,
2370 environ: UpdateKind,
2371 cmd: UpdateKind,
2372 exe: UpdateKind,
2373 tasks: bool,
2374}
2375
2376/// Creates a new `ProcessRefreshKind` with every refresh set to `false`, except for `tasks`.
2377/// By default, we want to list all processes and tasks are considered processes on their own
2378/// in linux so we still fetch them by default. However, the processes information are not
2379/// refreshed.
2380impl Default for ProcessRefreshKind {
2381 fn default() -> Self {
2382 Self {
2383 cpu: false,
2384 disk_usage: false,
2385 memory: false,
2386 user: UpdateKind::default(),
2387 cwd: UpdateKind::default(),
2388 root: UpdateKind::default(),
2389 environ: UpdateKind::default(),
2390 cmd: UpdateKind::default(),
2391 exe: UpdateKind::default(),
2392 tasks: true, // Process by default includes all tasks.
2393 }
2394 }
2395}
2396
2397impl ProcessRefreshKind {
2398 /// Creates a new `ProcessRefreshKind` with every refresh set to `false`, except for `tasks`.
2399 /// By default, we want to list all processes and tasks are considered processes on their own
2400 /// in linux so we still fetch them by default. However, the processes information are not
2401 /// refreshed.
2402 /// ```
2403 /// use sysinfo::{ProcessRefreshKind, UpdateKind};
2404 ///
2405 /// let r = ProcessRefreshKind::nothing();
2406 ///
2407 /// assert_eq!(r.cpu(), false);
2408 /// assert_eq!(r.user(), UpdateKind::Never);
2409 /// ```
2410 pub fn nothing() -> Self {
2411 Self::default()
2412 }
2413
2414 /// Creates a new `ProcessRefreshKind` with every refresh set to `true` or
2415 /// [`UpdateKind::OnlyIfNotSet`].
2416 ///
2417 /// ```
2418 /// use sysinfo::{ProcessRefreshKind, UpdateKind};
2419 ///
2420 /// let r = ProcessRefreshKind::everything();
2421 ///
2422 /// assert_eq!(r.cpu(), true);
2423 /// assert_eq!(r.user(), UpdateKind::OnlyIfNotSet);
2424 /// ```
2425 pub fn everything() -> Self {
2426 Self {
2427 cpu: true,
2428 disk_usage: true,
2429 memory: true,
2430 user: UpdateKind::OnlyIfNotSet,
2431 cwd: UpdateKind::OnlyIfNotSet,
2432 root: UpdateKind::OnlyIfNotSet,
2433 environ: UpdateKind::OnlyIfNotSet,
2434 cmd: UpdateKind::OnlyIfNotSet,
2435 exe: UpdateKind::OnlyIfNotSet,
2436 tasks: true,
2437 }
2438 }
2439
2440 impl_get_set!(
2441 ProcessRefreshKind,
2442 cpu,
2443 with_cpu,
2444 without_cpu,
2445 "\
2446It will retrieve both CPU usage and CPU accumulated time,"
2447 );
2448 impl_get_set!(
2449 ProcessRefreshKind,
2450 disk_usage,
2451 with_disk_usage,
2452 without_disk_usage
2453 );
2454 impl_get_set!(
2455 ProcessRefreshKind,
2456 user,
2457 with_user,
2458 without_user,
2459 UpdateKind,
2460 "\
2461It will retrieve the following information:
2462
2463 * user ID
2464 * user effective ID (if available on the platform)
2465 * user group ID (if available on the platform)
2466 * user effective ID (if available on the platform)"
2467 );
2468 impl_get_set!(ProcessRefreshKind, memory, with_memory, without_memory);
2469 impl_get_set!(ProcessRefreshKind, cwd, with_cwd, without_cwd, UpdateKind);
2470 impl_get_set!(
2471 ProcessRefreshKind,
2472 root,
2473 with_root,
2474 without_root,
2475 UpdateKind
2476 );
2477 impl_get_set!(
2478 ProcessRefreshKind,
2479 environ,
2480 with_environ,
2481 without_environ,
2482 UpdateKind
2483 );
2484 impl_get_set!(ProcessRefreshKind, cmd, with_cmd, without_cmd, UpdateKind);
2485 impl_get_set!(ProcessRefreshKind, exe, with_exe, without_exe, UpdateKind);
2486 impl_get_set!(ProcessRefreshKind, tasks, with_tasks, without_tasks);
2487}
2488
2489/// Used to determine what you want to refresh specifically on the [`Cpu`] type.
2490///
2491/// ⚠️ Just like all other refresh types, ruling out a refresh doesn't assure you that
2492/// the information won't be retrieved if the information is accessible without needing
2493/// extra computation.
2494///
2495/// ```
2496/// use sysinfo::{CpuRefreshKind, System};
2497///
2498/// let mut system = System::new();
2499///
2500/// // We don't want to update all the CPU information.
2501/// system.refresh_cpu_specifics(CpuRefreshKind::everything().without_frequency());
2502///
2503/// for cpu in system.cpus() {
2504/// assert_eq!(cpu.frequency(), 0);
2505/// }
2506/// ```
2507///
2508/// [`Cpu`]: crate::Cpu
2509#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
2510pub struct CpuRefreshKind {
2511 cpu_usage: bool,
2512 frequency: bool,
2513}
2514
2515impl CpuRefreshKind {
2516 /// Creates a new `CpuRefreshKind` with every refresh set to `false`.
2517 ///
2518 /// ```
2519 /// use sysinfo::CpuRefreshKind;
2520 ///
2521 /// let r = CpuRefreshKind::nothing();
2522 ///
2523 /// assert_eq!(r.frequency(), false);
2524 /// assert_eq!(r.cpu_usage(), false);
2525 /// ```
2526 pub fn nothing() -> Self {
2527 Self::default()
2528 }
2529
2530 /// Creates a new `CpuRefreshKind` with every refresh set to `true`.
2531 ///
2532 /// ```
2533 /// use sysinfo::CpuRefreshKind;
2534 ///
2535 /// let r = CpuRefreshKind::everything();
2536 ///
2537 /// assert_eq!(r.frequency(), true);
2538 /// assert_eq!(r.cpu_usage(), true);
2539 /// ```
2540 pub fn everything() -> Self {
2541 Self {
2542 cpu_usage: true,
2543 frequency: true,
2544 }
2545 }
2546
2547 impl_get_set!(CpuRefreshKind, cpu_usage, with_cpu_usage, without_cpu_usage);
2548 impl_get_set!(CpuRefreshKind, frequency, with_frequency, without_frequency);
2549}
2550
2551/// Used to determine which memory you want to refresh specifically.
2552///
2553/// ⚠️ Just like all other refresh types, ruling out a refresh doesn't assure you that
2554/// the information won't be retrieved if the information is accessible without needing
2555/// extra computation.
2556///
2557/// ```
2558/// use sysinfo::{MemoryRefreshKind, System};
2559///
2560/// let mut system = System::new();
2561///
2562/// // We don't want to update all memories information.
2563/// system.refresh_memory_specifics(MemoryRefreshKind::nothing().with_ram());
2564///
2565/// println!("total RAM: {}", system.total_memory());
2566/// println!("free RAM: {}", system.free_memory());
2567/// ```
2568#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
2569pub struct MemoryRefreshKind {
2570 ram: bool,
2571 swap: bool,
2572}
2573
2574impl MemoryRefreshKind {
2575 /// Creates a new `MemoryRefreshKind` with every refresh set to `false`.
2576 ///
2577 /// ```
2578 /// use sysinfo::MemoryRefreshKind;
2579 ///
2580 /// let r = MemoryRefreshKind::nothing();
2581 ///
2582 /// assert_eq!(r.ram(), false);
2583 /// assert_eq!(r.swap(), false);
2584 /// ```
2585 pub fn nothing() -> Self {
2586 Self::default()
2587 }
2588
2589 /// Creates a new `MemoryRefreshKind` with every refresh set to `true`.
2590 ///
2591 /// ```
2592 /// use sysinfo::MemoryRefreshKind;
2593 ///
2594 /// let r = MemoryRefreshKind::everything();
2595 ///
2596 /// assert_eq!(r.ram(), true);
2597 /// assert_eq!(r.swap(), true);
2598 /// ```
2599 pub fn everything() -> Self {
2600 Self {
2601 ram: true,
2602 swap: true,
2603 }
2604 }
2605
2606 impl_get_set!(MemoryRefreshKind, ram, with_ram, without_ram);
2607 impl_get_set!(MemoryRefreshKind, swap, with_swap, without_swap);
2608}
2609
2610/// Used to determine what you want to refresh specifically on the [`System`][crate::System] type.
2611///
2612/// ⚠️ Just like all other refresh types, ruling out a refresh doesn't assure you that
2613/// the information won't be retrieved if the information is accessible without needing
2614/// extra computation.
2615///
2616/// ```
2617/// use sysinfo::{RefreshKind, System};
2618///
2619/// // We want everything except memory.
2620/// let mut system = System::new_with_specifics(RefreshKind::everything().without_memory());
2621///
2622/// assert_eq!(system.total_memory(), 0);
2623/// # if sysinfo::IS_SUPPORTED_SYSTEM && !cfg!(feature = "apple-sandbox") {
2624/// assert!(system.processes().len() > 0);
2625/// # }
2626/// ```
2627#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
2628pub struct RefreshKind {
2629 processes: Option<ProcessRefreshKind>,
2630 memory: Option<MemoryRefreshKind>,
2631 cpu: Option<CpuRefreshKind>,
2632}
2633
2634impl RefreshKind {
2635 /// Creates a new `RefreshKind` with every refresh set to `false`/`None`.
2636 ///
2637 /// ```
2638 /// use sysinfo::RefreshKind;
2639 ///
2640 /// let r = RefreshKind::nothing();
2641 ///
2642 /// assert_eq!(r.processes().is_some(), false);
2643 /// assert_eq!(r.memory().is_some(), false);
2644 /// assert_eq!(r.cpu().is_some(), false);
2645 /// ```
2646 pub fn nothing() -> Self {
2647 Self::default()
2648 }
2649
2650 /// Creates a new `RefreshKind` with every refresh set to `true`/`Some(...)`.
2651 ///
2652 /// ```
2653 /// use sysinfo::RefreshKind;
2654 ///
2655 /// let r = RefreshKind::everything();
2656 ///
2657 /// assert_eq!(r.processes().is_some(), true);
2658 /// assert_eq!(r.memory().is_some(), true);
2659 /// assert_eq!(r.cpu().is_some(), true);
2660 /// ```
2661 pub fn everything() -> Self {
2662 Self {
2663 processes: Some(ProcessRefreshKind::everything()),
2664 memory: Some(MemoryRefreshKind::everything()),
2665 cpu: Some(CpuRefreshKind::everything()),
2666 }
2667 }
2668
2669 impl_get_set!(
2670 RefreshKind,
2671 processes,
2672 with_processes,
2673 without_processes,
2674 ProcessRefreshKind
2675 );
2676 impl_get_set!(
2677 RefreshKind,
2678 memory,
2679 with_memory,
2680 without_memory,
2681 MemoryRefreshKind
2682 );
2683 impl_get_set!(RefreshKind, cpu, with_cpu, without_cpu, CpuRefreshKind);
2684}
2685
2686/// Returns the pid for the current process.
2687///
2688/// `Err` is returned in case the platform isn't supported.
2689///
2690/// ```no_run
2691/// use sysinfo::get_current_pid;
2692///
2693/// match get_current_pid() {
2694/// Ok(pid) => {
2695/// println!("current pid: {}", pid);
2696/// }
2697/// Err(e) => {
2698/// println!("failed to get current pid: {}", e);
2699/// }
2700/// }
2701/// ```
2702#[allow(clippy::unnecessary_wraps)]
2703pub fn get_current_pid() -> Result<Pid, &'static str> {
2704 cfg_if! {
2705 if #[cfg(feature = "unknown-ci")] {
2706 fn inner() -> Result<Pid, &'static str> {
2707 Err("Unknown platform (CI)")
2708 }
2709 } else if #[cfg(any(
2710 target_os = "freebsd",
2711 target_os = "linux",
2712 target_os = "android",
2713 target_os = "macos",
2714 target_os = "ios",
2715 ))] {
2716 fn inner() -> Result<Pid, &'static str> {
2717 unsafe { Ok(Pid(libc::getpid())) }
2718 }
2719 } else if #[cfg(windows)] {
2720 fn inner() -> Result<Pid, &'static str> {
2721 use windows::Win32::System::Threading::GetCurrentProcessId;
2722
2723 unsafe { Ok(Pid(GetCurrentProcessId() as _)) }
2724 }
2725 } else {
2726 fn inner() -> Result<Pid, &'static str> {
2727 Err("Unknown platform")
2728 }
2729 }
2730 }
2731 inner()
2732}
2733
2734/// Contains all the methods of the [`Cpu`][crate::Cpu] struct.
2735///
2736/// ```no_run
2737/// use sysinfo::{System, RefreshKind, CpuRefreshKind};
2738///
2739/// let mut s = System::new_with_specifics(
2740/// RefreshKind::nothing().with_cpu(CpuRefreshKind::everything()),
2741/// );
2742///
2743/// // Wait a bit because CPU usage is based on diff.
2744/// std::thread::sleep(sysinfo::MINIMUM_CPU_UPDATE_INTERVAL);
2745/// // Refresh CPUs again to get actual value.
2746/// s.refresh_cpu_all();
2747///
2748/// for cpu in s.cpus() {
2749/// println!("{}%", cpu.cpu_usage());
2750/// }
2751/// ```
2752pub struct Cpu {
2753 pub(crate) inner: CpuInner,
2754}
2755
2756impl Cpu {
2757 /// Returns this CPU's usage.
2758 ///
2759 /// Note: You'll need to refresh it at least twice (diff between the first and the second is
2760 /// how CPU usage is computed) at first if you want to have a non-zero value.
2761 ///
2762 /// ```no_run
2763 /// use sysinfo::{System, RefreshKind, CpuRefreshKind};
2764 ///
2765 /// let mut s = System::new_with_specifics(
2766 /// RefreshKind::nothing().with_cpu(CpuRefreshKind::everything()),
2767 /// );
2768 ///
2769 /// // Wait a bit because CPU usage is based on diff.
2770 /// std::thread::sleep(sysinfo::MINIMUM_CPU_UPDATE_INTERVAL);
2771 /// // Refresh CPUs again to get actual value.
2772 /// s.refresh_cpu_all();
2773 ///
2774 /// for cpu in s.cpus() {
2775 /// println!("{}%", cpu.cpu_usage());
2776 /// }
2777 /// ```
2778 pub fn cpu_usage(&self) -> f32 {
2779 self.inner.cpu_usage()
2780 }
2781
2782 /// Returns this CPU's name.
2783 ///
2784 /// ```no_run
2785 /// use sysinfo::{System, RefreshKind, CpuRefreshKind};
2786 ///
2787 /// let s = System::new_with_specifics(
2788 /// RefreshKind::nothing().with_cpu(CpuRefreshKind::everything()),
2789 /// );
2790 /// for cpu in s.cpus() {
2791 /// println!("{}", cpu.name());
2792 /// }
2793 /// ```
2794 pub fn name(&self) -> &str {
2795 self.inner.name()
2796 }
2797
2798 /// Returns the CPU's vendor id.
2799 ///
2800 /// ```no_run
2801 /// use sysinfo::{System, RefreshKind, CpuRefreshKind};
2802 ///
2803 /// let s = System::new_with_specifics(
2804 /// RefreshKind::nothing().with_cpu(CpuRefreshKind::everything()),
2805 /// );
2806 /// for cpu in s.cpus() {
2807 /// println!("{}", cpu.vendor_id());
2808 /// }
2809 /// ```
2810 pub fn vendor_id(&self) -> &str {
2811 self.inner.vendor_id()
2812 }
2813
2814 /// Returns the CPU's brand.
2815 ///
2816 /// ```no_run
2817 /// use sysinfo::{System, RefreshKind, CpuRefreshKind};
2818 ///
2819 /// let s = System::new_with_specifics(
2820 /// RefreshKind::nothing().with_cpu(CpuRefreshKind::everything()),
2821 /// );
2822 /// for cpu in s.cpus() {
2823 /// println!("{}", cpu.brand());
2824 /// }
2825 /// ```
2826 pub fn brand(&self) -> &str {
2827 self.inner.brand()
2828 }
2829
2830 /// Returns the CPU's frequency.
2831 ///
2832 /// ```no_run
2833 /// use sysinfo::{System, RefreshKind, CpuRefreshKind};
2834 ///
2835 /// let s = System::new_with_specifics(
2836 /// RefreshKind::nothing().with_cpu(CpuRefreshKind::everything()),
2837 /// );
2838 /// for cpu in s.cpus() {
2839 /// println!("{}", cpu.frequency());
2840 /// }
2841 /// ```
2842 pub fn frequency(&self) -> u64 {
2843 self.inner.frequency()
2844 }
2845}
2846
2847#[cfg(test)]
2848mod test {
2849 use crate::*;
2850 use std::str::FromStr;
2851
2852 // In case `Process::updated` is misused, `System::refresh_processes` might remove them
2853 // so this test ensures that it doesn't happen.
2854 #[test]
2855 fn check_refresh_process_update() {
2856 if !IS_SUPPORTED_SYSTEM {
2857 return;
2858 }
2859 let mut s = System::new_all();
2860 let total = s.processes().len() as isize;
2861 s.refresh_processes(ProcessesToUpdate::All, false);
2862 let new_total = s.processes().len() as isize;
2863 // There should be almost no difference in the processes count.
2864 assert!(
2865 (new_total - total).abs() <= 5,
2866 "{} <= 5",
2867 (new_total - total).abs()
2868 );
2869 }
2870
2871 #[test]
2872 fn check_cpu_arch() {
2873 assert!(!System::cpu_arch().is_empty());
2874 }
2875
2876 // Ensure that the CPUs frequency isn't retrieved until we ask for it.
2877 #[test]
2878 fn check_cpu_frequency() {
2879 if !IS_SUPPORTED_SYSTEM {
2880 return;
2881 }
2882 let mut s = System::new();
2883 s.refresh_processes(ProcessesToUpdate::All, false);
2884 for proc_ in s.cpus() {
2885 assert_eq!(proc_.frequency(), 0);
2886 }
2887 s.refresh_cpu_usage();
2888 for proc_ in s.cpus() {
2889 assert_eq!(proc_.frequency(), 0);
2890 }
2891 // In a VM, it'll fail.
2892 if std::env::var("APPLE_CI").is_err() && std::env::var("FREEBSD_CI").is_err() {
2893 s.refresh_cpu_specifics(CpuRefreshKind::everything());
2894 for proc_ in s.cpus() {
2895 assert_ne!(proc_.frequency(), 0);
2896 }
2897 }
2898 }
2899
2900 #[test]
2901 fn check_process_memory_usage() {
2902 let mut s = System::new();
2903 s.refresh_specifics(RefreshKind::everything());
2904
2905 if IS_SUPPORTED_SYSTEM {
2906 // No process should have 0 as memory usage.
2907 #[cfg(not(feature = "apple-sandbox"))]
2908 assert!(!s.processes().iter().all(|(_, proc_)| proc_.memory() == 0));
2909 } else {
2910 // There should be no process, but if there is one, its memory usage should be 0.
2911 assert!(s.processes().iter().all(|(_, proc_)| proc_.memory() == 0));
2912 }
2913 }
2914
2915 #[test]
2916 fn check_system_implemented_traits() {
2917 fn check<T: Sized + std::fmt::Debug + Default + Send + Sync>(_: T) {}
2918
2919 check(System::new());
2920 }
2921
2922 #[test]
2923 fn check_memory_usage() {
2924 let mut s = System::new();
2925
2926 assert_eq!(s.total_memory(), 0);
2927 assert_eq!(s.free_memory(), 0);
2928 assert_eq!(s.available_memory(), 0);
2929 assert_eq!(s.used_memory(), 0);
2930 assert_eq!(s.total_swap(), 0);
2931 assert_eq!(s.free_swap(), 0);
2932 assert_eq!(s.used_swap(), 0);
2933
2934 s.refresh_memory();
2935 if IS_SUPPORTED_SYSTEM {
2936 assert!(s.total_memory() > 0);
2937 assert!(s.used_memory() > 0);
2938 if s.total_swap() > 0 {
2939 // I think it's pretty safe to assume that there is still some swap left...
2940 assert!(s.free_swap() > 0);
2941 }
2942 } else {
2943 assert_eq!(s.total_memory(), 0);
2944 assert_eq!(s.used_memory(), 0);
2945 assert_eq!(s.total_swap(), 0);
2946 assert_eq!(s.free_swap(), 0);
2947 }
2948 }
2949
2950 #[cfg(target_os = "linux")]
2951 #[test]
2952 fn check_processes_cpu_usage() {
2953 if !IS_SUPPORTED_SYSTEM {
2954 return;
2955 }
2956 let mut s = System::new();
2957
2958 s.refresh_processes(ProcessesToUpdate::All, false);
2959 // All CPU usage will start at zero until the second refresh
2960 assert!(
2961 s.processes()
2962 .iter()
2963 .all(|(_, proc_)| proc_.cpu_usage() == 0.0)
2964 );
2965
2966 // Wait a bit to update CPU usage values
2967 std::thread::sleep(MINIMUM_CPU_UPDATE_INTERVAL);
2968 s.refresh_processes(ProcessesToUpdate::All, true);
2969 assert!(
2970 s.processes()
2971 .iter()
2972 .all(|(_, proc_)| proc_.cpu_usage() >= 0.0
2973 && proc_.cpu_usage() <= (s.cpus().len() as f32) * 100.0)
2974 );
2975 assert!(
2976 s.processes()
2977 .iter()
2978 .any(|(_, proc_)| proc_.cpu_usage() > 0.0)
2979 );
2980 }
2981
2982 #[test]
2983 fn check_cpu_usage() {
2984 if !IS_SUPPORTED_SYSTEM {
2985 return;
2986 }
2987 let mut s = System::new();
2988 for _ in 0..10 {
2989 s.refresh_cpu_usage();
2990 // Wait a bit to update CPU usage values
2991 std::thread::sleep(MINIMUM_CPU_UPDATE_INTERVAL);
2992 if s.cpus().iter().any(|c| c.cpu_usage() > 0.0) {
2993 // All good!
2994 return;
2995 }
2996 }
2997 panic!("CPU usage is always zero...");
2998 }
2999
3000 #[test]
3001 fn check_system_info() {
3002 // We don't want to test on unsupported systems.
3003 if IS_SUPPORTED_SYSTEM {
3004 assert!(
3005 !System::name()
3006 .expect("Failed to get system name")
3007 .is_empty()
3008 );
3009
3010 assert!(
3011 !System::kernel_version()
3012 .expect("Failed to get kernel version")
3013 .is_empty()
3014 );
3015
3016 assert!(
3017 !System::os_version()
3018 .expect("Failed to get os version")
3019 .is_empty()
3020 );
3021
3022 assert!(
3023 !System::long_os_version()
3024 .expect("Failed to get long OS version")
3025 .is_empty()
3026 );
3027 }
3028
3029 assert!(!System::distribution_id().is_empty());
3030 }
3031
3032 #[test]
3033 fn check_host_name() {
3034 // We don't want to test on unsupported systems.
3035 if IS_SUPPORTED_SYSTEM {
3036 assert!(System::host_name().is_some());
3037 }
3038 }
3039
3040 #[test]
3041 fn check_refresh_process_return_value() {
3042 // We don't want to test on unsupported systems.
3043 if IS_SUPPORTED_SYSTEM {
3044 let _pid = get_current_pid().expect("Failed to get current PID");
3045
3046 #[cfg(not(feature = "apple-sandbox"))]
3047 {
3048 let mut s = System::new();
3049 // First check what happens in case the process isn't already in our process list.
3050 assert_eq!(
3051 s.refresh_processes(ProcessesToUpdate::Some(&[_pid]), true),
3052 1
3053 );
3054 // Then check that it still returns 1 if the process is already in our process list.
3055 assert_eq!(
3056 s.refresh_processes(ProcessesToUpdate::Some(&[_pid]), true),
3057 1
3058 );
3059 }
3060 }
3061 }
3062
3063 #[test]
3064 fn check_cpus_number() {
3065 let mut s = System::new();
3066
3067 // This information isn't retrieved by default.
3068 assert!(s.cpus().is_empty());
3069 if IS_SUPPORTED_SYSTEM {
3070 // The physical cores count is recomputed every time the function is called, so the
3071 // information must be relevant even with nothing initialized.
3072 let physical_cores_count =
3073 System::physical_core_count().expect("failed to get number of physical cores");
3074
3075 s.refresh_cpu_usage();
3076 // The cpus shouldn't be empty anymore.
3077 assert!(!s.cpus().is_empty());
3078
3079 // In case we are running inside a VM, it's possible to not have a physical core, only
3080 // logical ones, which is why we don't test `physical_cores_count > 0`.
3081 let physical_cores_count2 =
3082 System::physical_core_count().expect("failed to get number of physical cores");
3083 assert!(physical_cores_count2 <= s.cpus().len());
3084 assert_eq!(physical_cores_count, physical_cores_count2);
3085 } else {
3086 assert_eq!(System::physical_core_count(), None);
3087 }
3088 assert!(System::physical_core_count().unwrap_or(0) <= s.cpus().len());
3089 }
3090
3091 // This test only exists to ensure that the `Display` and `Debug` traits are implemented on the
3092 // `ProcessStatus` enum on all targets.
3093 #[test]
3094 fn check_display_impl_process_status() {
3095 println!("{} {:?}", ProcessStatus::Parked, ProcessStatus::Idle);
3096 }
3097
3098 #[test]
3099 #[allow(clippy::unnecessary_fallible_conversions)]
3100 fn check_pid_from_impls() {
3101 assert!(crate::Pid::try_from(0usize).is_ok());
3102 // If it doesn't panic, it's fine.
3103 let _ = crate::Pid::from(0);
3104 assert!(crate::Pid::from_str("0").is_ok());
3105 }
3106
3107 #[test]
3108 #[allow(clippy::const_is_empty)]
3109 fn check_nb_supported_signals() {
3110 if IS_SUPPORTED_SYSTEM {
3111 assert!(
3112 !SUPPORTED_SIGNALS.is_empty(),
3113 "SUPPORTED_SIGNALS shouldn't be empty on supported systems!"
3114 );
3115 } else {
3116 assert!(
3117 SUPPORTED_SIGNALS.is_empty(),
3118 "SUPPORTED_SIGNALS should be empty on not support systems!"
3119 );
3120 }
3121 }
3122}
3123
3124#[cfg(doctest)]
3125mod doctest {
3126 // FIXME: Can be removed once negative trait bounds are supported.
3127 /// Check that `Process` doesn't implement `Clone`.
3128 ///
3129 /// First we check that the "basic" code works:
3130 ///
3131 /// ```no_run
3132 /// use sysinfo::{Process, System};
3133 ///
3134 /// let mut s = System::new_all();
3135 /// let p: &Process = s.processes().values().next().unwrap();
3136 /// ```
3137 ///
3138 /// And now we check if it fails when we try to clone it:
3139 ///
3140 /// ```compile_fail
3141 /// use sysinfo::{Process, System};
3142 ///
3143 /// let mut s = System::new_all();
3144 /// let p: &Process = s.processes().values().next().unwrap();
3145 /// let p = (*p).clone();
3146 /// ```
3147 mod process_clone {}
3148
3149 // FIXME: Can be removed once negative trait bounds are supported.
3150 /// Check that `System` doesn't implement `Clone`.
3151 ///
3152 /// First we check that the "basic" code works:
3153 ///
3154 /// ```no_run
3155 /// use sysinfo::{Process, System};
3156 ///
3157 /// let s = System::new();
3158 /// ```
3159 ///
3160 /// And now we check if it fails when we try to clone it:
3161 ///
3162 /// ```compile_fail
3163 /// use sysinfo::{Process, System};
3164 ///
3165 /// let s = System::new();
3166 /// let s = s.clone();
3167 /// ```
3168 mod system_clone {}
3169}