33// For the full copyright and license information, please view the LICENSE
44// file that was distributed with this source code.
55
6- use crate :: tui:: stat:: TuiStat ;
6+ use crate :: tui:: stat:: { TimeScale , TuiStat } ;
77use crate :: Settings ;
88use std:: any:: Any ;
99use std:: cmp:: Ordering ;
@@ -24,13 +24,13 @@ pub fn sysinfo() -> &'static RwLock<System> {
2424}
2525
2626pub trait Column {
27- fn as_string ( & self , show_zeros : bool ) -> String ;
27+ fn as_string ( & self , tui_stat : & TuiStat ) -> String ;
2828 fn cmp_dyn ( & self , other : & dyn Column ) -> Ordering ;
2929 fn as_any ( & self ) -> & dyn Any ;
3030}
3131
3232impl Column for String {
33- fn as_string ( & self , _show_zeros : bool ) -> String {
33+ fn as_string ( & self , _tui_stat : & TuiStat ) -> String {
3434 self . clone ( )
3535 }
3636
@@ -47,8 +47,8 @@ impl Column for String {
4747}
4848
4949impl Column for u32 {
50- fn as_string ( & self , show_zeros : bool ) -> String {
51- if !show_zeros && self == & 0 {
50+ fn as_string ( & self , tui_stat : & TuiStat ) -> String {
51+ if !tui_stat . show_zeros && self == & 0 {
5252 return String :: new ( ) ;
5353 }
5454 self . to_string ( )
@@ -67,8 +67,8 @@ impl Column for u32 {
6767}
6868
6969impl Column for Option < i32 > {
70- fn as_string ( & self , show_zeros : bool ) -> String {
71- if !show_zeros && self == & Some ( 0 ) {
70+ fn as_string ( & self , tui_stat : & TuiStat ) -> String {
71+ if !tui_stat . show_zeros && self == & Some ( 0 ) {
7272 return String :: new ( ) ;
7373 }
7474 self . map ( |v| v. to_string ( ) ) . unwrap_or_default ( )
@@ -102,8 +102,8 @@ impl PercentValue {
102102}
103103
104104impl Column for PercentValue {
105- fn as_string ( & self , show_zeros : bool ) -> String {
106- if !show_zeros && self . value == 0.0 {
105+ fn as_string ( & self , tui_stat : & TuiStat ) -> String {
106+ if !tui_stat . show_zeros && self . value == 0.0 {
107107 return String :: new ( ) ;
108108 }
109109 format ! ( "{:.1}" , self . value)
@@ -132,8 +132,8 @@ impl MemValue {
132132}
133133
134134impl Column for MemValue {
135- fn as_string ( & self , show_zeros : bool ) -> String {
136- if !show_zeros && self . value == 0 {
135+ fn as_string ( & self , tui_stat : & TuiStat ) -> String {
136+ if !tui_stat . show_zeros && self . value == 0 {
137137 return String :: new ( ) ;
138138 }
139139 let mem_mb = self . value as f64 / bytesize:: MIB as f64 ;
@@ -156,33 +156,63 @@ impl Column for MemValue {
156156 }
157157}
158158
159- struct TimeMSValue {
160- min : u64 ,
159+ struct TimeValue {
161160 sec : f64 ,
162161}
163162
164- impl TimeMSValue {
165- fn new_boxed ( min : u64 , sec : f64 ) -> Box < Self > {
166- Box :: new ( Self { min , sec } )
163+ impl TimeValue {
164+ fn new_boxed ( sec : f64 ) -> Box < Self > {
165+ Box :: new ( Self { sec } )
167166 }
168167}
169168
170- impl Column for TimeMSValue {
171- fn as_string ( & self , show_zeros : bool ) -> String {
172- if !show_zeros && self . min == 0 && self . sec < 0.01 {
169+ impl Column for TimeValue {
170+ fn as_string ( & self , tui_stat : & TuiStat ) -> String {
171+ if !tui_stat . show_zeros && self . sec < 0.01 {
173172 return String :: new ( ) ;
174173 }
175- format ! ( "{}:{:0>5.2}" , self . min, self . sec)
174+ match tui_stat. time_scale {
175+ TimeScale :: MinSecondCent => {
176+ let min = ( self . sec / 60.0 ) . floor ( ) as u32 ;
177+ let sec = self . sec - ( min * 60 ) as f64 ;
178+ format ! ( "{}:{:0>5.2}" , min, sec)
179+ }
180+ TimeScale :: MinSecond => {
181+ let min = ( self . sec / 60.0 ) . floor ( ) as u32 ;
182+ let sec = ( self . sec - ( min * 60 ) as f64 ) . floor ( ) as u32 ;
183+ format ! ( "{}:{:0>2}" , min, sec)
184+ }
185+ TimeScale :: HourMin => {
186+ let hour = ( self . sec / 3600.0 ) . floor ( ) as u32 ;
187+ let min = ( ( self . sec - ( hour * 3600 ) as f64 ) / 60.0 ) . floor ( ) as u32 ;
188+ format ! ( "{},{:0>2}" , hour, min)
189+ }
190+ TimeScale :: DayHour => {
191+ let day = ( self . sec / 86400.0 ) . floor ( ) as u32 ;
192+ let hour = ( ( self . sec - ( day * 86400 ) as f64 ) / 3600.0 ) . floor ( ) as u32 ;
193+ format ! ( "{}d+{}h" , day, hour)
194+ }
195+ TimeScale :: Day => {
196+ let day = ( self . sec / 86400.0 ) . floor ( ) as u32 ;
197+ format ! ( "{}d" , day)
198+ }
199+ TimeScale :: WeekDay => {
200+ let week = ( self . sec / 604800.0 ) . floor ( ) as u32 ;
201+ let day = ( ( self . sec - ( week * 604800 ) as f64 ) / 86400.0 ) . floor ( ) as u32 ;
202+ format ! ( "{}w+{}d" , week, day)
203+ }
204+ TimeScale :: Week => {
205+ let week = ( self . sec / 604800.0 ) . floor ( ) as u32 ;
206+ format ! ( "{}w" , week)
207+ }
208+ }
176209 }
177210
178211 fn cmp_dyn ( & self , other : & dyn Column ) -> Ordering {
179212 other
180213 . as_any ( )
181- . downcast_ref :: < TimeMSValue > ( )
182- . map ( |o| match self . min . cmp ( & o. min ) {
183- Ordering :: Equal => self . sec . partial_cmp ( & o. sec ) . unwrap_or ( Ordering :: Equal ) ,
184- ord => ord,
185- } )
214+ . downcast_ref :: < TimeValue > ( )
215+ . map ( |o| self . sec . partial_cmp ( & o. sec ) . unwrap_or ( Ordering :: Equal ) )
186216 . unwrap_or ( Ordering :: Equal )
187217 }
188218 fn as_any ( & self ) -> & dyn Any {
@@ -383,18 +413,12 @@ fn s(pid: u32, _stat: Stat) -> Box<dyn Column> {
383413fn time_plus ( pid : u32 , _stat : Stat ) -> Box < dyn Column > {
384414 let binding = sysinfo ( ) . read ( ) . unwrap ( ) ;
385415 let Some ( proc) = binding. process ( Pid :: from_u32 ( pid) ) else {
386- return TimeMSValue :: new_boxed ( 0 , 0.0 ) ;
416+ return TimeValue :: new_boxed ( 0.0 ) ;
387417 } ;
388418
389- let ( min, sec) = {
390- let total = proc. accumulated_cpu_time ( ) ;
391- let minute = total / ( 60 * 1000 ) ;
392- let second = ( total % ( 60 * 1000 ) ) as f64 / 1000.0 ;
419+ let second = proc. accumulated_cpu_time ( ) as f64 / 1000.0 ;
393420
394- ( minute, second)
395- } ;
396-
397- TimeMSValue :: new_boxed ( min, sec)
421+ TimeValue :: new_boxed ( second)
398422}
399423
400424fn mem ( pid : u32 , _stat : Stat ) -> Box < dyn Column > {
@@ -408,8 +432,42 @@ fn mem(pid: u32, _stat: Stat) -> Box<dyn Column> {
408432 )
409433}
410434
411- fn command ( pid : u32 , stat : Stat ) -> Box < dyn Column > {
412- let full_command_line = stat. 1 . full_command_line ;
435+ #[ cfg( target_os = "linux" ) ]
436+ pub ( crate ) fn get_supplementary_groups ( pid : u32 ) -> String {
437+ use sysinfo:: { Gid , Groups } ;
438+
439+ let groups = Groups :: new_with_refreshed_list ( ) ;
440+ let path = PathBuf :: from_str ( & format ! ( "/proc/{pid}/status" ) ) . unwrap ( ) ;
441+ if let Ok ( file) = File :: open ( path) {
442+ let content = read_to_string ( file) . unwrap ( ) ;
443+ for line in content. lines ( ) {
444+ if line. starts_with ( "Groups:" ) {
445+ let groups = line
446+ . split_whitespace ( )
447+ . skip ( 1 )
448+ . filter_map ( |s| Gid :: from_str ( s) . ok ( ) )
449+ . filter_map ( |gid| groups. iter ( ) . find ( |g| g. id ( ) == & gid) )
450+ . map ( |group| group. name ( ) )
451+ . collect :: < Vec < _ > > ( )
452+ . join ( "," ) ;
453+ return groups;
454+ }
455+ }
456+ }
457+ String :: new ( )
458+ }
459+
460+ #[ cfg( target_os = "linux" ) ]
461+ pub ( crate ) fn get_cgroup ( pid : u32 ) -> String {
462+ let path = PathBuf :: from_str ( & format ! ( "/proc/{pid}/cgroup" ) ) . unwrap ( ) ;
463+ if let Ok ( file) = File :: open ( path) {
464+ read_to_string ( file) . unwrap ( )
465+ } else {
466+ String :: new ( )
467+ }
468+ }
469+
470+ pub ( crate ) fn get_command ( pid : u32 , full_command_line : bool ) -> String {
413471 let f = |cmd : & [ OsString ] | -> String {
414472 let binding = cmd
415473 . iter ( )
@@ -444,23 +502,26 @@ fn command(pid: u32, stat: Stat) -> Box<dyn Column> {
444502
445503 let binding = sysinfo ( ) . read ( ) . unwrap ( ) ;
446504 let Some ( proc) = binding. process ( Pid :: from_u32 ( pid) ) else {
447- return Box :: new ( "?" . to_string ( ) ) ;
505+ return "?" . to_string ( ) ;
448506 } ;
449507
450- Box :: new (
451- proc. exe ( )
452- . and_then ( |it| {
453- if full_command_line {
454- it. iter ( ) . next_back ( )
455- } else {
456- it. file_name ( )
457- }
458- } )
459- . map ( |it| it. to_str ( ) . unwrap ( ) . to_string ( ) )
460- . unwrap_or ( if full_command_line {
461- f ( proc. cmd ( ) )
508+ proc. exe ( )
509+ . and_then ( |it| {
510+ if full_command_line {
511+ it. iter ( ) . next_back ( )
462512 } else {
463- proc. name ( ) . to_str ( ) . unwrap ( ) . to_string ( )
464- } ) ,
465- )
513+ it. file_name ( )
514+ }
515+ } )
516+ . map ( |it| it. to_str ( ) . unwrap ( ) . to_string ( ) )
517+ . unwrap_or ( if full_command_line {
518+ f ( proc. cmd ( ) )
519+ } else {
520+ proc. name ( ) . to_str ( ) . unwrap ( ) . to_string ( )
521+ } )
522+ }
523+
524+ fn command ( pid : u32 , stat : Stat ) -> Box < dyn Column > {
525+ let full_command_line = stat. 1 . full_command_line ;
526+ Box :: new ( get_command ( pid, full_command_line) )
466527}
0 commit comments