2014-11-24 20:55:49 +00:00
/*
htop - LinuxProcess . c
( C ) 2014 Hisham H . Muhammad
2020-08-19 23:35:24 +00:00
( C ) 2020 Red Hat , Inc . All Rights Reserved .
2020-10-05 07:51:32 +00:00
Released under the GNU GPLv2 , see the COPYING file
2014-11-24 20:55:49 +00:00
in the source distribution for its full text .
*/
2021-04-29 18:13:36 +00:00
# include "linux/LinuxProcess.h"
2014-11-24 21:22:50 +00:00
2021-04-29 15:12:43 +00:00
# include <assert.h>
2020-09-19 11:55:23 +00:00
# include <math.h>
# include <stdio.h>
2015-02-20 16:52:10 +00:00
# include <stdlib.h>
2020-12-06 14:22:41 +00:00
# include <string.h>
2020-09-19 11:55:23 +00:00
# include <syscall.h>
# include <unistd.h>
# include "CRT.h"
2020-11-18 13:26:30 +00:00
# include "Macros.h"
2020-09-19 11:55:23 +00:00
# include "Process.h"
# include "ProvideCurses.h"
2020-11-18 13:26:30 +00:00
# include "RichString.h"
2020-09-19 11:55:23 +00:00
# include "XUtils.h"
2021-04-29 18:13:36 +00:00
# include "linux/IOPriority.h"
2014-11-24 20:55:49 +00:00
2020-10-14 18:21:09 +00:00
2020-07-10 00:35:32 +00:00
/* semi-global */
2020-12-10 00:57:48 +00:00
int pageSize ;
int pageSizeKB ;
2018-08-19 04:29:03 +00:00
2020-10-17 10:54:45 +00:00
/* Used to identify kernel threads in Comm and Exe columns */
static const char * const kthreadID = " KTHREAD " ;
2020-12-15 18:44:52 +00:00
const ProcessFieldData Process_fields [ LAST_PROCESSFIELD ] = {
2015-03-16 04:43:04 +00:00
[ 0 ] = { . name = " " , . title = NULL , . description = NULL , . flags = 0 , } ,
2020-12-15 18:44:52 +00:00
[ PID ] = { . name = " PID " , . title = " PID " , . description = " Process/thread ID " , . flags = 0 , . pidColumn = true , } ,
2015-03-16 04:43:04 +00:00
[ COMM ] = { . name = " Command " , . title = " Command " , . description = " Command line " , . flags = 0 , } ,
2018-01-14 09:08:20 +00:00
[ STATE ] = { . name = " STATE " , . title = " S " , . description = " Process state (S sleeping, R running, D disk, Z zombie, T traced, W paging, I idle) " , . flags = 0 , } ,
2020-12-15 18:44:52 +00:00
[ PPID ] = { . name = " PPID " , . title = " PPID " , . description = " Parent process ID " , . flags = 0 , . pidColumn = true , } ,
[ PGRP ] = { . name = " PGRP " , . title = " PGRP " , . description = " Process group ID " , . flags = 0 , . pidColumn = true , } ,
[ SESSION ] = { . name = " SESSION " , . title = " SID " , . description = " Process's session ID " , . flags = 0 , . pidColumn = true , } ,
2021-03-21 18:40:56 +00:00
[ TTY ] = { . name = " TTY " , . title = " TTY " , . description = " Controlling terminal " , . flags = 0 , } ,
2020-12-15 18:44:52 +00:00
[ TPGID ] = { . name = " TPGID " , . title = " TPGID " , . description = " Process ID of the fg process group of the controlling terminal " , . flags = 0 , . pidColumn = true , } ,
2021-01-21 13:27:23 +00:00
[ MINFLT ] = { . name = " MINFLT " , . title = " MINFLT " , . description = " Number of minor faults which have not required loading a memory page from disk " , . flags = 0 , . defaultSortDesc = true , } ,
[ CMINFLT ] = { . name = " CMINFLT " , . title = " CMINFLT " , . description = " Children processes' minor faults " , . flags = 0 , . defaultSortDesc = true , } ,
2021-01-21 19:57:34 +00:00
[ MAJFLT ] = { . name = " MAJFLT " , . title = " MAJFLT " , . description = " Number of major faults which have required loading a memory page from disk " , . flags = 0 , . defaultSortDesc = true , } ,
[ CMAJFLT ] = { . name = " CMAJFLT " , . title = " CMAJFLT " , . description = " Children processes' major faults " , . flags = 0 , . defaultSortDesc = true , } ,
[ UTIME ] = { . name = " UTIME " , . title = " UTIME+ " , . description = " User CPU time - time the process spent executing in user mode " , . flags = 0 , . defaultSortDesc = true , } ,
[ STIME ] = { . name = " STIME " , . title = " STIME+ " , . description = " System CPU time - time the kernel spent running system calls for this process " , . flags = 0 , . defaultSortDesc = true , } ,
[ CUTIME ] = { . name = " CUTIME " , . title = " CUTIME+ " , . description = " Children processes' user CPU time " , . flags = 0 , . defaultSortDesc = true , } ,
[ CSTIME ] = { . name = " CSTIME " , . title = " CSTIME+ " , . description = " Children processes' system CPU time " , . flags = 0 , . defaultSortDesc = true , } ,
2015-03-16 04:43:04 +00:00
[ PRIORITY ] = { . name = " PRIORITY " , . title = " PRI " , . description = " Kernel's internal priority for the process " , . flags = 0 , } ,
[ NICE ] = { . name = " NICE " , . title = " NI " , . description = " Nice value (the higher the value, the more it lets other processes take priority) " , . flags = 0 , } ,
[ STARTTIME ] = { . name = " STARTTIME " , . title = " START " , . description = " Time the process was started " , . flags = 0 , } ,
[ PROCESSOR ] = { . name = " PROCESSOR " , . title = " CPU " , . description = " Id of the CPU the process last executed on " , . flags = 0 , } ,
2021-01-21 13:27:23 +00:00
[ M_VIRT ] = { . name = " M_VIRT " , . title = " VIRT " , . description = " Total program size in virtual memory " , . flags = 0 , . defaultSortDesc = true , } ,
[ M_RESIDENT ] = { . name = " M_RESIDENT " , . title = " RES " , . description = " Resident set size, size of the text and data sections, plus stack usage " , . flags = 0 , . defaultSortDesc = true , } ,
[ M_SHARE ] = { . name = " M_SHARE " , . title = " SHR " , . description = " Size of the process's shared pages " , . flags = 0 , . defaultSortDesc = true , } ,
[ M_TRS ] = { . name = " M_TRS " , . title = " CODE " , . description = " Size of the text segment of the process " , . flags = 0 , . defaultSortDesc = true , } ,
[ M_DRS ] = { . name = " M_DRS " , . title = " DATA " , . description = " Size of the data segment plus stack usage of the process " , . flags = 0 , . defaultSortDesc = true , } ,
[ M_LRS ] = { . name = " M_LRS " , . title = " LIB " , . description = " The library size of the process (calculated from memory maps) " , . flags = PROCESS_FLAG_LINUX_LRS_FIX , . defaultSortDesc = true , } ,
[ M_DT ] = { . name = " M_DT " , . title = " DIRTY " , . description = " Size of the dirty pages of the process (unused since Linux 2.6; always 0) " , . flags = 0 , . defaultSortDesc = true , } ,
2018-10-07 09:16:12 +00:00
[ ST_UID ] = { . name = " ST_UID " , . title = " UID " , . description = " User ID of the process owner " , . flags = 0 , } ,
2021-01-21 13:27:23 +00:00
[ PERCENT_CPU ] = { . name = " PERCENT_CPU " , . title = " CPU% " , . description = " Percentage of the CPU time the process used in the last sampling " , . flags = 0 , . defaultSortDesc = true , } ,
[ PERCENT_NORM_CPU ] = { . name = " PERCENT_NORM_CPU " , . title = " NCPU% " , . description = " Normalized percentage of the CPU time the process used in the last sampling (normalized by cpu count) " , . flags = 0 , . defaultSortDesc = true , } ,
[ PERCENT_MEM ] = { . name = " PERCENT_MEM " , . title = " MEM% " , . description = " Percentage of the memory the process is using, based on resident memory size " , . flags = 0 , . defaultSortDesc = true , } ,
2015-03-16 04:43:04 +00:00
[ USER ] = { . name = " USER " , . title = " USER " , . description = " Username of the process owner (or user ID if name cannot be determined) " , . flags = 0 , } ,
2021-01-21 13:27:23 +00:00
[ TIME ] = { . name = " TIME " , . title = " TIME+ " , . description = " Total time the process has spent in user and system time " , . flags = 0 , . defaultSortDesc = true , } ,
[ NLWP ] = { . name = " NLWP " , . title = " NLWP " , . description = " Number of threads in the process " , . flags = 0 , . defaultSortDesc = true , } ,
2020-12-15 18:44:52 +00:00
[ TGID ] = { . name = " TGID " , . title = " TGID " , . description = " Thread group ID (i.e. process ID) " , . flags = 0 , . pidColumn = true , } ,
2015-03-15 23:29:13 +00:00
# ifdef HAVE_OPENVZ
2020-09-30 21:46:52 +00:00
[ CTID ] = { . name = " CTID " , . title = " CTID " , . description = " OpenVZ container ID (a.k.a. virtual environment ID) " , . flags = PROCESS_FLAG_LINUX_OPENVZ , } ,
2020-12-15 18:44:52 +00:00
[ VPID ] = { . name = " VPID " , . title = " VPID " , . description = " OpenVZ process ID " , . flags = PROCESS_FLAG_LINUX_OPENVZ , . pidColumn = true , } ,
2015-03-15 23:29:13 +00:00
# endif
# ifdef HAVE_VSERVER
2015-03-16 04:43:04 +00:00
[ VXID ] = { . name = " VXID " , . title = " VXID " , . description = " VServer process ID " , . flags = PROCESS_FLAG_LINUX_VSERVER , } ,
2015-03-15 23:29:13 +00:00
# endif
2021-01-27 14:11:48 +00:00
[ RCHAR ] = { . name = " RCHAR " , . title = " RCHAR " , . description = " Number of bytes the process has read " , . flags = PROCESS_FLAG_IO , . defaultSortDesc = true , } ,
[ WCHAR ] = { . name = " WCHAR " , . title = " WCHAR " , . description = " Number of bytes the process has written " , . flags = PROCESS_FLAG_IO , . defaultSortDesc = true , } ,
[ SYSCR ] = { . name = " SYSCR " , . title = " READ_SYSC " , . description = " Number of read(2) syscalls for the process " , . flags = PROCESS_FLAG_IO , . defaultSortDesc = true , } ,
[ SYSCW ] = { . name = " SYSCW " , . title = " WRITE_SYSC " , . description = " Number of write(2) syscalls for the process " , . flags = PROCESS_FLAG_IO , . defaultSortDesc = true , } ,
[ RBYTES ] = { . name = " RBYTES " , . title = " IO_R " , . description = " Bytes of read(2) I/O for the process " , . flags = PROCESS_FLAG_IO , . defaultSortDesc = true , } ,
[ WBYTES ] = { . name = " WBYTES " , . title = " IO_W " , . description = " Bytes of write(2) I/O for the process " , . flags = PROCESS_FLAG_IO , . defaultSortDesc = true , } ,
[ CNCLWB ] = { . name = " CNCLWB " , . title = " IO_C " , . description = " Bytes of cancelled write(2) I/O " , . flags = PROCESS_FLAG_IO , . defaultSortDesc = true , } ,
2021-04-26 15:57:47 +00:00
[ IO_READ_RATE ] = { . name = " IO_READ_RATE " , . title = " DISK READ " , . description = " The I/O rate of read(2) in bytes per second for the process " , . flags = PROCESS_FLAG_IO , . defaultSortDesc = true , } ,
2021-01-21 19:57:34 +00:00
[ IO_WRITE_RATE ] = { . name = " IO_WRITE_RATE " , . title = " DISK WRITE " , . description = " The I/O rate of write(2) in bytes per second for the process " , . flags = PROCESS_FLAG_IO , . defaultSortDesc = true , } ,
[ IO_RATE ] = { . name = " IO_RATE " , . title = " DISK R/W " , . description = " Total I/O rate in bytes per second " , . flags = PROCESS_FLAG_IO , . defaultSortDesc = true , } ,
2015-03-16 04:43:04 +00:00
[ CGROUP ] = { . name = " CGROUP " , . title = " CGROUP " , . description = " Which cgroup the process is in " , . flags = PROCESS_FLAG_LINUX_CGROUP , } ,
2021-01-21 19:57:34 +00:00
[ OOM ] = { . name = " OOM " , . title = " OOM " , . description = " OOM (Out-of-Memory) killer score " , . flags = PROCESS_FLAG_LINUX_OOM , . defaultSortDesc = true , } ,
2015-03-16 04:43:04 +00:00
[ IO_PRIORITY ] = { . name = " IO_PRIORITY " , . title = " IO " , . description = " I/O priority " , . flags = PROCESS_FLAG_LINUX_IOPRIO , } ,
2017-12-04 02:15:29 +00:00
# ifdef HAVE_DELAYACCT
2021-01-21 19:57:34 +00:00
[ PERCENT_CPU_DELAY ] = { . name = " PERCENT_CPU_DELAY " , . title = " CPUD% " , . description = " CPU delay % " , . flags = PROCESS_FLAG_LINUX_DELAYACCT , . defaultSortDesc = true , } ,
[ PERCENT_IO_DELAY ] = { . name = " PERCENT_IO_DELAY " , . title = " IOD% " , . description = " Block I/O delay % " , . flags = PROCESS_FLAG_LINUX_DELAYACCT , . defaultSortDesc = true , } ,
[ PERCENT_SWAP_DELAY ] = { . name = " PERCENT_SWAP_DELAY " , . title = " SWAPD% " , . description = " Swapin delay % " , . flags = PROCESS_FLAG_LINUX_DELAYACCT , . defaultSortDesc = true , } ,
2017-12-04 02:15:29 +00:00
# endif
2021-02-02 07:57:21 +00:00
[ M_PSS ] = { . name = " M_PSS " , . title = " PSS " , . description = " proportional set size, same as M_RESIDENT but each page is divided by the number of processes sharing it " , . flags = PROCESS_FLAG_LINUX_SMAPS , . defaultSortDesc = true , } ,
2021-01-21 19:57:34 +00:00
[ M_SWAP ] = { . name = " M_SWAP " , . title = " SWAP " , . description = " Size of the process's swapped pages " , . flags = PROCESS_FLAG_LINUX_SMAPS , . defaultSortDesc = true , } ,
2021-02-02 07:57:21 +00:00
[ M_PSSWP ] = { . name = " M_PSSWP " , . title = " PSSWP " , . description = " shows proportional swap share of this mapping, unlike \" Swap \" , this does not take into account swapped out page of underlying shmem objects " , . flags = PROCESS_FLAG_LINUX_SMAPS , . defaultSortDesc = true , } ,
2021-01-21 19:57:34 +00:00
[ CTXT ] = { . name = " CTXT " , . title = " CTXT " , . description = " Context switches (incremental sum of voluntary_ctxt_switches and nonvoluntary_ctxt_switches) " , . flags = PROCESS_FLAG_LINUX_CTXT , . defaultSortDesc = true , } ,
2020-09-28 10:06:13 +00:00
[ SECATTR ] = { . name = " SECATTR " , . title = " Security Attribute " , . description = " Security attribute of the process (e.g. SELinux or AppArmor) " , . flags = PROCESS_FLAG_LINUX_SECATTR , } ,
2020-10-17 10:54:45 +00:00
[ PROC_COMM ] = { . name = " COMM " , . title = " COMM " , . description = " comm string of the process from /proc/[pid]/comm " , . flags = 0 , } ,
[ PROC_EXE ] = { . name = " EXE " , . title = " EXE " , . description = " Basename of exe of the process from /proc/[pid]/exe " , . flags = 0 , } ,
2020-11-26 16:51:54 +00:00
[ CWD ] = { . name = " CWD " , . title = " CWD " , . description = " The current working directory of the process " , . flags = PROCESS_FLAG_LINUX_CWD , } ,
2015-03-15 23:29:13 +00:00
} ;
2020-10-17 10:54:45 +00:00
/* This function returns the string displayed in Command column, so that sorting
* happens on what is displayed - whether comm , full path , basename , etc . . So
* this follows LinuxProcess_writeField ( COMM ) and LinuxProcess_writeCommand */
static const char * LinuxProcess_getCommandStr ( const Process * this ) {
const LinuxProcess * lp = ( const LinuxProcess * ) this ;
if ( ( Process_isUserlandThread ( this ) & & this - > settings - > showThreadNames ) | | ! lp - > mergedCommand . str ) {
2020-12-19 15:21:08 +00:00
return this - > cmdline ;
2020-10-17 10:54:45 +00:00
}
return lp - > mergedCommand . str ;
}
2020-10-21 19:26:05 +00:00
Process * LinuxProcess_new ( const Settings * settings ) {
2016-02-02 14:53:02 +00:00
LinuxProcess * this = xCalloc ( 1 , sizeof ( LinuxProcess ) ) ;
2015-04-01 02:23:10 +00:00
Object_setClass ( this , Class ( LinuxProcess ) ) ;
2015-02-20 16:52:10 +00:00
Process_init ( & this - > super , settings ) ;
2020-10-21 19:26:05 +00:00
return & this - > super ;
2015-02-20 16:52:10 +00:00
}
2015-03-16 04:43:04 +00:00
void Process_delete ( Object * cast ) {
2015-03-08 22:45:56 +00:00
LinuxProcess * this = ( LinuxProcess * ) cast ;
2015-02-20 16:52:10 +00:00
Process_done ( ( Process * ) cast ) ;
2015-03-16 04:43:04 +00:00
free ( this - > cgroup ) ;
2020-09-30 21:46:52 +00:00
# ifdef HAVE_OPENVZ
free ( this - > ctid ) ;
2015-03-16 04:43:04 +00:00
# endif
2020-11-26 16:51:54 +00:00
free ( this - > cwd ) ;
2020-09-28 10:06:13 +00:00
free ( this - > secattr ) ;
2020-10-17 10:54:45 +00:00
free ( this - > procExe ) ;
free ( this - > procComm ) ;
free ( this - > mergedCommand . str ) ;
2015-02-20 16:52:10 +00:00
free ( this ) ;
}
2014-11-24 20:55:49 +00:00
/*
[ 1 ] Note that before kernel 2.6 .26 a process that has not asked for
an io priority formally uses " none " as scheduling class , but the
io scheduler will treat such processes as if it were in the best
effort class . The priority within the best effort class will be
dynamically derived from the cpu nice level of the process :
io_priority = ( cpu_nice + 20 ) / 5. - - From ionice ( 1 ) man page
*/
2020-10-27 20:26:39 +00:00
static int LinuxProcess_effectiveIOPriority ( const LinuxProcess * this ) {
2020-11-01 00:09:51 +00:00
if ( IOPriority_class ( this - > ioPriority ) = = IOPRIO_CLASS_NONE ) {
2020-10-27 20:26:39 +00:00
return IOPriority_tuple ( IOPRIO_CLASS_BE , ( this - > super . nice + 20 ) / 5 ) ;
2020-11-01 00:09:51 +00:00
}
2020-10-27 20:26:39 +00:00
return this - > ioPriority ;
}
2014-11-24 20:55:49 +00:00
2020-12-15 18:44:44 +00:00
# ifdef __ANDROID__
# define SYS_ioprio_get __NR_ioprio_get
# define SYS_ioprio_set __NR_ioprio_set
# endif
2014-11-24 21:22:50 +00:00
IOPriority LinuxProcess_updateIOPriority ( LinuxProcess * this ) {
2016-02-14 14:05:35 +00:00
IOPriority ioprio = 0 ;
// Other OSes masquerading as Linux (NetBSD?) don't have this syscall
# ifdef SYS_ioprio_get
ioprio = syscall ( SYS_ioprio_get , IOPRIO_WHO_PROCESS , this - > super . pid ) ;
# endif
2014-11-24 20:55:49 +00:00
this - > ioPriority = ioprio ;
return ioprio ;
}
2020-10-27 10:46:29 +00:00
bool LinuxProcess_setIOPriority ( Process * this , Arg ioprio ) {
2016-02-14 14:05:35 +00:00
// Other OSes masquerading as Linux (NetBSD?) don't have this syscall
# ifdef SYS_ioprio_set
2020-10-27 10:46:29 +00:00
syscall ( SYS_ioprio_set , IOPRIO_WHO_PROCESS , this - > pid , ioprio . i ) ;
2016-02-14 14:05:35 +00:00
# endif
2020-10-27 10:46:29 +00:00
return ( LinuxProcess_updateIOPriority ( ( LinuxProcess * ) this ) = = ioprio . i ) ;
2014-11-24 20:55:49 +00:00
}
2017-12-04 02:15:29 +00:00
# ifdef HAVE_DELAYACCT
2020-11-19 13:43:04 +00:00
static void LinuxProcess_printDelay ( float delay_percent , char * buffer , int n ) {
2020-10-31 21:14:27 +00:00
if ( isnan ( delay_percent ) ) {
xSnprintf ( buffer , n , " N/A " ) ;
} else {
xSnprintf ( buffer , n , " %4.1f " , delay_percent ) ;
}
2017-12-04 02:15:29 +00:00
}
# endif
2020-10-17 10:54:45 +00:00
/*
TASK_COMM_LEN is defined to be 16 for / proc / [ pid ] / comm in man proc ( 5 ) , but it is
not available in an userspace header - so define it . Note : when colorizing a
basename with the comm prefix , the entire basename ( not just the comm prefix ) is
colorized for better readability , and it is implicit that only upto
( TASK_COMM_LEN - 1 ) could be comm
*/
# define TASK_COMM_LEN 16
static bool findCommInCmdline ( const char * comm , const char * cmdline , int cmdlineBasenameOffset , int * pCommStart , int * pCommEnd ) {
/* Try to find procComm in tokenized cmdline - this might in rare cases
* mis - identify a string or fail , if comm or cmdline had been unsuitably
* modified by the process */
const char * tokenBase ;
size_t tokenLen ;
const size_t commLen = strlen ( comm ) ;
2021-02-01 21:09:39 +00:00
if ( cmdlineBasenameOffset < 0 )
return false ;
2021-01-05 22:47:20 +00:00
for ( const char * token = cmdline + cmdlineBasenameOffset ; * token ; ) {
2020-10-17 10:54:45 +00:00
for ( tokenBase = token ; * token & & * token ! = ' \n ' ; + + token ) {
if ( * token = = ' / ' ) {
tokenBase = token + 1 ;
}
}
tokenLen = token - tokenBase ;
2020-11-09 17:42:24 +00:00
if ( ( tokenLen = = commLen | | ( tokenLen > commLen & & commLen = = ( TASK_COMM_LEN - 1 ) ) ) & &
2020-10-17 10:54:45 +00:00
strncmp ( tokenBase , comm , commLen ) = = 0 ) {
* pCommStart = tokenBase - cmdline ;
* pCommEnd = token - cmdline ;
return true ;
}
if ( * token ) {
do {
+ + token ;
2020-12-12 11:21:22 +00:00
} while ( * token & & ' \n ' = = * token ) ;
2020-10-17 10:54:45 +00:00
}
}
return false ;
}
static int matchCmdlinePrefixWithExeSuffix ( const char * cmdline , int cmdlineBaseOffset , const char * exe , int exeBaseOffset , int exeBaseLen ) {
int matchLen ; /* matching length to be returned */
char delim ; /* delimiter following basename */
/* cmdline prefix is an absolute path: it must match whole exe. */
if ( cmdline [ 0 ] = = ' / ' ) {
matchLen = exeBaseLen + exeBaseOffset ;
if ( strncmp ( cmdline , exe , matchLen ) = = 0 ) {
delim = cmdline [ matchLen ] ;
if ( delim = = 0 | | delim = = ' \n ' | | delim = = ' ' ) {
return matchLen ;
}
}
return 0 ;
}
/* cmdline prefix is a relative path: We need to first match the basename at
* cmdlineBaseOffset and then reverse match the cmdline prefix with the exe
* suffix . But there is a catch : Some processes modify their cmdline in ways
* that make htop ' s identification of the basename in cmdline unreliable .
* For e . g . / usr / libexec / gdm - session - worker modifies its cmdline to
* " gdm-session-worker [pam/gdm-autologin] " and htop ends up with
* procCmdlineBasenameOffset at " gdm-autologin] " . This issue could arise with
* chrome as well as it stores in cmdline its concatenated argument vector ,
* without NUL delimiter between the arguments ( which may contain a ' / ' )
*
* So if needed , we adjust cmdlineBaseOffset to the previous ( if any )
* component of the cmdline relative path , and retry the procedure . */
bool delimFound ; /* if valid basename delimiter found */
do {
/* match basename */
matchLen = exeBaseLen + cmdlineBaseOffset ;
if ( cmdlineBaseOffset < exeBaseOffset & &
strncmp ( cmdline + cmdlineBaseOffset , exe + exeBaseOffset , exeBaseLen ) = = 0 ) {
delim = cmdline [ matchLen ] ;
if ( delim = = 0 | | delim = = ' \n ' | | delim = = ' ' ) {
int i , j ;
/* reverse match the cmdline prefix and exe suffix */
for ( i = cmdlineBaseOffset - 1 , j = exeBaseOffset - 1 ;
2020-12-12 11:21:22 +00:00
i > = 0 & & j > = 0 & & cmdline [ i ] = = exe [ j ] ; - - i , - - j )
2020-10-17 10:54:45 +00:00
;
/* full match, with exe suffix being a valid relative path */
2020-12-12 11:21:22 +00:00
if ( i < 0 & & j > = 0 & & exe [ j ] = = ' / ' ) {
2020-10-17 10:54:45 +00:00
return matchLen ;
}
}
}
2020-12-12 11:21:22 +00:00
2020-10-17 10:54:45 +00:00
/* Try to find the previous potential cmdlineBaseOffset - it would be
* preceded by ' / ' or nothing , and delimited by ' ' or ' \n ' */
for ( delimFound = false , cmdlineBaseOffset - = 2 ; cmdlineBaseOffset > 0 ; - - cmdlineBaseOffset ) {
if ( delimFound ) {
if ( cmdline [ cmdlineBaseOffset - 1 ] = = ' / ' ) {
break ;
}
} else if ( cmdline [ cmdlineBaseOffset ] = = ' ' | | cmdline [ cmdlineBaseOffset ] = = ' \n ' ) {
delimFound = true ;
}
}
} while ( delimFound ) ;
return 0 ;
}
/* stpcpy, but also converts newlines to spaces */
static inline char * stpcpyWithNewlineConversion ( char * dstStr , const char * srcStr ) {
for ( ; * srcStr ; + + srcStr ) {
* dstStr + + = ( * srcStr = = ' \n ' ) ? ' ' : * srcStr ;
}
* dstStr = 0 ;
return dstStr ;
}
/*
This function makes the merged Command string . It also stores the offsets of the
basename , comm w . r . t the merged Command string - these offsets will be used by
LinuxProcess_writeCommand ( ) for coloring . The merged Command string is also
returned by LinuxProcess_getCommandStr ( ) for searching , sorting and filtering .
*/
void LinuxProcess_makeCommandStr ( Process * this ) {
LinuxProcess * lp = ( LinuxProcess * ) this ;
2020-11-20 18:55:48 +00:00
LinuxProcessMergedCommand * mc = & lp - > mergedCommand ;
2020-12-12 11:21:22 +00:00
const Settings * settings = this - > settings ;
2020-11-20 18:55:48 +00:00
2020-12-12 11:21:22 +00:00
bool showMergedCommand = settings - > showMergedCommand ;
bool showProgramPath = settings - > showProgramPath ;
bool searchCommInCmdline = settings - > findCommInCmdline ;
bool stripExeFromCmdline = settings - > stripExeFromCmdline ;
2020-10-17 10:54:45 +00:00
2020-11-20 18:55:48 +00:00
/* lp->mergedCommand.str needs updating only if its state or contents changed.
* Its content is based on the fields cmdline , comm , and exe . */
if (
mc - > prevMergeSet = = showMergedCommand & &
mc - > prevPathSet = = showProgramPath & &
mc - > prevCommSet = = searchCommInCmdline & &
mc - > prevCmdlineSet = = stripExeFromCmdline & &
! mc - > cmdlineChanged & &
! mc - > commChanged & &
! mc - > exeChanged
) {
2020-10-17 10:54:45 +00:00
return ;
}
/* The field separtor "│" has been chosen such that it will not match any
2020-11-09 16:37:02 +00:00
* valid string used for searching or filtering */
2020-10-17 10:54:45 +00:00
const char * SEPARATOR = CRT_treeStr [ TREE_STR_VERT ] ;
const int SEPARATOR_LEN = strlen ( SEPARATOR ) ;
2020-11-20 18:55:48 +00:00
/* Check for any changed fields since we last built this string */
if ( mc - > cmdlineChanged | | mc - > commChanged | | mc - > exeChanged ) {
free ( mc - > str ) ;
2020-11-28 19:53:49 +00:00
/* Accommodate the column text, two field separators and terminating NUL */
2020-11-20 18:55:48 +00:00
mc - > str = xCalloc ( 1 , mc - > maxLen + 2 * SEPARATOR_LEN + 1 ) ;
2020-10-17 10:54:45 +00:00
}
2020-11-20 18:55:48 +00:00
/* Preserve the settings used in this run */
mc - > prevMergeSet = showMergedCommand ;
mc - > prevPathSet = showProgramPath ;
mc - > prevCommSet = searchCommInCmdline ;
mc - > prevCmdlineSet = stripExeFromCmdline ;
/* Mark everything as unchanged */
mc - > cmdlineChanged = false ;
mc - > commChanged = false ;
mc - > exeChanged = false ;
2020-12-12 11:21:22 +00:00
/* Reset all locations that need extra handling when actually displaying */
mc - > highlightCount = 0 ;
memset ( mc - > highlights , 0 , sizeof ( mc - > highlights ) ) ;
size_t mbMismatch = 0 ;
# define WRITE_HIGHLIGHT(_offset, _length, _attr, _flags) \
do { \
/* Check if we still have capacity */ \
assert ( mc - > highlightCount < ARRAYSIZE ( mc - > highlights ) ) ; \
if ( mc - > highlightCount > = ARRAYSIZE ( mc - > highlights ) ) \
continue ; \
\
mc - > highlights [ mc - > highlightCount ] . offset = str - strStart + _offset - mbMismatch ; \
mc - > highlights [ mc - > highlightCount ] . length = _length ; \
mc - > highlights [ mc - > highlightCount ] . attr = _attr ; \
mc - > highlights [ mc - > highlightCount ] . flags = _flags ; \
mc - > highlightCount + + ; \
} while ( 0 )
# define WRITE_SEPARATOR \
do { \
WRITE_HIGHLIGHT ( 0 , 1 , CRT_colors [ FAILED_READ ] , CMDLINE_HIGHLIGHT_FLAG_SEPARATOR ) ; \
mbMismatch + = SEPARATOR_LEN - 1 ; \
str = stpcpy ( str , SEPARATOR ) ; \
} while ( 0 )
const int baseAttr = Process_isThread ( this ) ? CRT_colors [ PROCESS_THREAD_BASENAME ] : CRT_colors [ PROCESS_BASENAME ] ;
const int commAttr = Process_isThread ( this ) ? CRT_colors [ PROCESS_THREAD_COMM ] : CRT_colors [ PROCESS_COMM ] ;
const int delAttr = CRT_colors [ FAILED_READ ] ;
/* Establish some shortcuts to data we need */
2020-12-19 15:21:08 +00:00
const char * cmdline = this - > cmdline ;
2020-10-17 10:54:45 +00:00
const char * procExe = lp - > procExe ;
const char * procComm = lp - > procComm ;
2020-11-20 18:55:48 +00:00
char * strStart = mc - > str ;
char * str = strStart ;
2020-10-17 10:54:45 +00:00
int cmdlineBasenameOffset = lp - > procCmdlineBasenameOffset ;
2020-12-21 21:29:18 +00:00
int cmdlineBasenameEnd = lp - > procCmdlineBasenameEnd ;
if ( ! cmdline ) {
cmdlineBasenameOffset = 0 ;
cmdlineBasenameEnd = 0 ;
cmdline = " (zombie) " ;
}
2020-10-17 10:54:45 +00:00
2020-12-21 21:35:38 +00:00
assert ( cmdlineBasenameOffset > = 0 ) ;
2020-12-22 05:58:17 +00:00
assert ( cmdlineBasenameOffset < = ( int ) strlen ( cmdline ) ) ;
2020-12-21 21:35:38 +00:00
2020-12-12 11:21:22 +00:00
if ( ! showMergedCommand | | ! procExe | | ! procComm ) { /* fall back to cmdline */
if ( showMergedCommand & & ! procExe & & procComm & & strlen ( procComm ) ) { /* Prefix column with comm */
2020-11-23 21:55:56 +00:00
if ( strncmp ( cmdline + cmdlineBasenameOffset , procComm , MINIMUM ( TASK_COMM_LEN - 1 , strlen ( procComm ) ) ) ! = 0 ) {
2020-12-12 11:21:22 +00:00
WRITE_HIGHLIGHT ( 0 , strlen ( procComm ) , commAttr , CMDLINE_HIGHLIGHT_FLAG_COMM ) ;
2020-11-23 21:55:56 +00:00
str = stpcpy ( str , procComm ) ;
2020-12-12 11:21:22 +00:00
WRITE_SEPARATOR ;
2020-11-23 21:55:56 +00:00
}
}
2020-10-17 10:54:45 +00:00
if ( showProgramPath ) {
2020-12-12 11:21:22 +00:00
WRITE_HIGHLIGHT ( cmdlineBasenameOffset , cmdlineBasenameEnd - cmdlineBasenameOffset , baseAttr , CMDLINE_HIGHLIGHT_FLAG_BASENAME ) ;
( void ) stpcpyWithNewlineConversion ( str , cmdline ) ;
2020-10-17 10:54:45 +00:00
} else {
2020-12-12 11:21:22 +00:00
WRITE_HIGHLIGHT ( 0 , cmdlineBasenameEnd - cmdlineBasenameOffset , baseAttr , CMDLINE_HIGHLIGHT_FLAG_BASENAME ) ;
( void ) stpcpyWithNewlineConversion ( str , cmdline + cmdlineBasenameOffset ) ;
2020-11-23 21:55:56 +00:00
}
2020-10-17 10:54:45 +00:00
return ;
}
int exeLen = lp - > procExeLen ;
2020-11-20 18:55:48 +00:00
int exeBasenameOffset = lp - > procExeBasenameOffset ;
int exeBasenameLen = exeLen - exeBasenameOffset ;
2020-10-17 10:54:45 +00:00
2020-12-21 21:35:38 +00:00
assert ( exeBasenameOffset > = 0 ) ;
2020-12-22 05:58:17 +00:00
assert ( exeBasenameOffset < = ( int ) strlen ( procExe ) ) ;
2020-12-21 21:35:38 +00:00
2020-12-12 11:21:22 +00:00
bool haveCommInExe = false ;
if ( procExe & & procComm ) {
haveCommInExe = strncmp ( procExe + exeBasenameOffset , procComm , TASK_COMM_LEN - 1 ) = = 0 ;
}
2020-10-17 10:54:45 +00:00
/* Start with copying exe */
if ( showProgramPath ) {
2020-12-12 11:21:22 +00:00
if ( haveCommInExe )
WRITE_HIGHLIGHT ( exeBasenameOffset , exeBasenameLen , commAttr , CMDLINE_HIGHLIGHT_FLAG_COMM ) ;
WRITE_HIGHLIGHT ( exeBasenameOffset , exeBasenameLen , baseAttr , CMDLINE_HIGHLIGHT_FLAG_BASENAME ) ;
if ( lp - > procExeDeleted )
WRITE_HIGHLIGHT ( exeBasenameOffset , exeBasenameLen , delAttr , CMDLINE_HIGHLIGHT_FLAG_DELETED ) ;
2020-11-20 18:55:48 +00:00
str = stpcpy ( str , procExe ) ;
2020-10-17 10:54:45 +00:00
} else {
2020-12-12 11:21:22 +00:00
if ( haveCommInExe )
WRITE_HIGHLIGHT ( 0 , exeBasenameLen , commAttr , CMDLINE_HIGHLIGHT_FLAG_COMM ) ;
WRITE_HIGHLIGHT ( 0 , exeBasenameLen , baseAttr , CMDLINE_HIGHLIGHT_FLAG_BASENAME ) ;
if ( lp - > procExeDeleted )
WRITE_HIGHLIGHT ( 0 , exeBasenameLen , delAttr , CMDLINE_HIGHLIGHT_FLAG_DELETED ) ;
2020-11-20 18:55:48 +00:00
str = stpcpy ( str , procExe + exeBasenameOffset ) ;
2020-10-17 10:54:45 +00:00
}
2020-12-12 11:21:22 +00:00
bool haveCommInCmdline = false ;
2020-11-20 18:55:48 +00:00
int commStart = 0 ;
int commEnd = 0 ;
2020-10-17 10:54:45 +00:00
/* Try to match procComm with procExe's basename: This is reliable (predictable) */
2020-12-12 11:21:22 +00:00
if ( searchCommInCmdline ) {
2020-10-17 10:54:45 +00:00
/* commStart/commEnd will be adjusted later along with cmdline */
2020-12-12 11:21:22 +00:00
haveCommInCmdline = findCommInCmdline ( procComm , cmdline , cmdlineBasenameOffset , & commStart , & commEnd ) ;
2020-10-17 10:54:45 +00:00
}
2020-11-20 18:55:48 +00:00
int matchLen = matchCmdlinePrefixWithExeSuffix ( cmdline , cmdlineBasenameOffset , procExe , exeBasenameOffset , exeBasenameLen ) ;
2020-12-12 11:21:22 +00:00
bool haveCommField = false ;
2020-11-20 18:55:48 +00:00
2020-12-12 11:21:22 +00:00
if ( ! haveCommInExe & & ! haveCommInCmdline & & procComm ) {
WRITE_SEPARATOR ;
WRITE_HIGHLIGHT ( 0 , strlen ( procComm ) , commAttr , CMDLINE_HIGHLIGHT_FLAG_COMM ) ;
2020-10-17 10:54:45 +00:00
str = stpcpy ( str , procComm ) ;
2020-12-12 11:21:22 +00:00
haveCommField = true ;
}
2020-11-20 18:55:48 +00:00
2020-12-12 11:21:22 +00:00
if ( matchLen ) {
/* strip the matched exe prefix */
cmdline + = matchLen ;
2020-11-20 18:55:48 +00:00
2020-12-12 11:21:22 +00:00
commStart - = matchLen ;
commEnd - = matchLen ;
}
2020-11-20 18:55:48 +00:00
2020-12-12 11:21:22 +00:00
if ( ! matchLen | | ( haveCommField & & * cmdline ) ) {
/* cmdline will be a separate field */
WRITE_SEPARATOR ;
2020-10-17 10:54:45 +00:00
}
2020-12-12 11:21:22 +00:00
if ( ! haveCommInExe & & haveCommInCmdline & & ! haveCommField )
WRITE_HIGHLIGHT ( commStart , commEnd - commStart , commAttr , CMDLINE_HIGHLIGHT_FLAG_COMM ) ;
2020-10-17 10:54:45 +00:00
/* Display cmdline if it hasn't been consumed by procExe */
if ( * cmdline ) {
( void ) stpcpyWithNewlineConversion ( str , cmdline ) ;
}
2020-12-12 11:21:22 +00:00
# undef WRITE_SEPARATOR
# undef WRITE_HIGHLIGHT
2020-10-17 10:54:45 +00:00
}
2020-11-20 07:04:51 +00:00
static void LinuxProcess_writeCommand ( const Process * this , int attr , int baseAttr , RichString * str ) {
2020-12-12 11:21:22 +00:00
( void ) baseAttr ;
2020-10-17 10:54:45 +00:00
const LinuxProcess * lp = ( const LinuxProcess * ) this ;
2020-11-20 18:55:48 +00:00
const LinuxProcessMergedCommand * mc = & lp - > mergedCommand ;
2020-10-17 10:54:45 +00:00
int strStart = RichString_size ( str ) ;
2020-11-20 18:55:48 +00:00
2020-12-12 11:21:22 +00:00
// int commAttr = CRT_colors[Process_isUserlandThread(this) ? PROCESS_THREAD_COMM : PROCESS_COMM];
2020-11-20 18:55:48 +00:00
2020-12-12 11:21:22 +00:00
const bool highlightBaseName = this - > settings - > highlightBaseName ;
const bool highlightSeparator = true ;
const bool highlightDeleted = true ;
2020-11-20 18:55:48 +00:00
2020-12-12 11:21:22 +00:00
RichString_appendWide ( str , attr , lp - > mergedCommand . str ) ;
2020-10-17 10:54:45 +00:00
2020-12-12 11:21:22 +00:00
for ( size_t i = 0 , hlCount = CLAMP ( mc - > highlightCount , 0 , ARRAYSIZE ( mc - > highlights ) ) ; i < hlCount ; i + + )
{
const LinuxProcessCmdlineHighlight * hl = & mc - > highlights [ i ] ;
2020-11-23 21:55:56 +00:00
2020-12-12 11:21:22 +00:00
if ( ! hl - > length )
continue ;
2020-10-17 10:54:45 +00:00
2020-12-12 11:21:22 +00:00
if ( hl - > flags & CMDLINE_HIGHLIGHT_FLAG_SEPARATOR )
if ( ! highlightSeparator )
continue ;
2020-11-20 18:55:48 +00:00
2020-12-12 11:21:22 +00:00
if ( hl - > flags & CMDLINE_HIGHLIGHT_FLAG_BASENAME )
if ( ! highlightBaseName )
continue ;
2020-11-20 18:55:48 +00:00
2020-12-12 11:21:22 +00:00
if ( hl - > flags & CMDLINE_HIGHLIGHT_FLAG_DELETED )
if ( ! highlightDeleted )
continue ;
2020-11-20 18:55:48 +00:00
2020-12-12 11:21:22 +00:00
RichString_setAttrn ( str , hl - > attr , strStart + hl - > offset , hl - > length ) ;
}
2020-10-17 10:54:45 +00:00
}
static void LinuxProcess_writeCommandField ( const Process * this , RichString * str , char * buffer , int n , int attr ) {
/* This code is from Process_writeField for COMM, but we invoke
* LinuxProcess_writeCommand to display
* / proc / pid / exe ( or its basename ) │ / proc / pid / comm │ / proc / pid / cmdline */
int baseattr = CRT_colors [ PROCESS_BASENAME ] ;
if ( this - > settings - > highlightThreads & & Process_isThread ( this ) ) {
attr = CRT_colors [ PROCESS_THREAD ] ;
baseattr = CRT_colors [ PROCESS_THREAD_BASENAME ] ;
}
if ( ! this - > settings - > treeView | | this - > indent = = 0 ) {
LinuxProcess_writeCommand ( this , attr , baseattr , str ) ;
} else {
char * buf = buffer ;
int maxIndent = 0 ;
bool lastItem = ( this - > indent < 0 ) ;
int indent = ( this - > indent < 0 ? - this - > indent : this - > indent ) ;
int vertLen = strlen ( CRT_treeStr [ TREE_STR_VERT ] ) ;
for ( int i = 0 ; i < 32 ; i + + ) {
if ( indent & ( 1U < < i ) ) {
maxIndent = i + 1 ;
}
}
for ( int i = 0 ; i < maxIndent - 1 ; i + + ) {
if ( indent & ( 1 < < i ) ) {
if ( buf - buffer + ( vertLen + 3 ) > n ) {
break ;
}
buf = stpcpy ( buf , CRT_treeStr [ TREE_STR_VERT ] ) ;
buf = stpcpy ( buf , " " ) ;
} else {
if ( buf - buffer + 4 > n ) {
break ;
}
buf = stpcpy ( buf , " " ) ;
}
}
2020-12-08 20:24:19 +00:00
2020-10-17 10:54:45 +00:00
n - = ( buf - buffer ) ;
2020-12-08 20:24:19 +00:00
const char * draw = CRT_treeStr [ lastItem ? TREE_STR_BEND : TREE_STR_RTEE ] ;
2020-10-17 10:54:45 +00:00
xSnprintf ( buf , n , " %s%s " , draw , this - > showChildren ? CRT_treeStr [ TREE_STR_SHUT ] : CRT_treeStr [ TREE_STR_OPEN ] ) ;
2020-12-04 13:44:57 +00:00
RichString_appendWide ( str , CRT_colors [ PROCESS_TREE ] , buffer ) ;
2020-10-17 10:54:45 +00:00
LinuxProcess_writeCommand ( this , attr , baseattr , str ) ;
}
}
2020-11-04 16:46:14 +00:00
static void LinuxProcess_writeField ( const Process * this , RichString * str , ProcessField field ) {
2020-10-21 19:26:01 +00:00
const LinuxProcess * lp = ( const LinuxProcess * ) this ;
2015-03-16 04:43:04 +00:00
bool coloring = this - > settings - > highlightMegabytes ;
2014-11-24 21:22:50 +00:00
char buffer [ 256 ] ; buffer [ 255 ] = ' \0 ' ;
int attr = CRT_colors [ DEFAULT_COLOR ] ;
2020-11-24 17:37:13 +00:00
size_t n = sizeof ( buffer ) - 1 ;
2020-12-15 18:44:48 +00:00
switch ( field ) {
2021-04-14 18:16:16 +00:00
case CMINFLT : Process_printCount ( str , lp - > cminflt , coloring ) ; return ;
case CMAJFLT : Process_printCount ( str , lp - > cmajflt , coloring ) ; return ;
2021-04-26 15:57:47 +00:00
case M_DRS : Process_printBytes ( str , lp - > m_drs * pageSize , coloring ) ; return ;
case M_DT : Process_printBytes ( str , lp - > m_dt * pageSize , coloring ) ; return ;
2020-11-26 18:56:10 +00:00
case M_LRS :
if ( lp - > m_lrs ) {
2021-04-26 15:57:47 +00:00
Process_printBytes ( str , lp - > m_lrs * pageSize , coloring ) ;
2020-11-26 18:56:10 +00:00
return ;
}
attr = CRT_colors [ PROCESS_SHADOW ] ;
xSnprintf ( buffer , n , " N/A " ) ;
break ;
2021-04-26 15:57:47 +00:00
case M_TRS : Process_printBytes ( str , lp - > m_trs * pageSize , coloring ) ; return ;
case M_SHARE : Process_printBytes ( str , lp - > m_share * pageSize , coloring ) ; return ;
2021-04-14 18:16:16 +00:00
case M_PSS : Process_printKBytes ( str , lp - > m_pss , coloring ) ; return ;
case M_SWAP : Process_printKBytes ( str , lp - > m_swap , coloring ) ; return ;
case M_PSSWP : Process_printKBytes ( str , lp - > m_psswp , coloring ) ; return ;
case UTIME : Process_printTime ( str , lp - > utime , coloring ) ; return ;
case STIME : Process_printTime ( str , lp - > stime , coloring ) ; return ;
case CUTIME : Process_printTime ( str , lp - > cutime , coloring ) ; return ;
case CSTIME : Process_printTime ( str , lp - > cstime , coloring ) ; return ;
2021-04-26 15:57:47 +00:00
case RCHAR : Process_printBytes ( str , lp - > io_rchar , coloring ) ; return ;
case WCHAR : Process_printBytes ( str , lp - > io_wchar , coloring ) ; return ;
2021-04-14 18:16:16 +00:00
case SYSCR : Process_printCount ( str , lp - > io_syscr , coloring ) ; return ;
case SYSCW : Process_printCount ( str , lp - > io_syscw , coloring ) ; return ;
2021-04-26 15:57:47 +00:00
case RBYTES : Process_printBytes ( str , lp - > io_read_bytes , coloring ) ; return ;
case WBYTES : Process_printBytes ( str , lp - > io_write_bytes , coloring ) ; return ;
case CNCLWB : Process_printBytes ( str , lp - > io_cancelled_write_bytes , coloring ) ; return ;
2021-04-14 18:16:16 +00:00
case IO_READ_RATE : Process_printRate ( str , lp - > io_rate_read_bps , coloring ) ; return ;
case IO_WRITE_RATE : Process_printRate ( str , lp - > io_rate_write_bps , coloring ) ; return ;
2016-02-20 04:22:57 +00:00
case IO_RATE : {
2021-02-28 20:43:53 +00:00
double totalRate ;
2020-10-31 19:52:20 +00:00
if ( ! isnan ( lp - > io_rate_read_bps ) & & ! isnan ( lp - > io_rate_write_bps ) )
2020-09-07 09:53:58 +00:00
totalRate = lp - > io_rate_read_bps + lp - > io_rate_write_bps ;
2020-10-31 19:52:20 +00:00
else if ( ! isnan ( lp - > io_rate_read_bps ) )
2020-09-07 09:53:58 +00:00
totalRate = lp - > io_rate_read_bps ;
2020-10-31 19:52:20 +00:00
else if ( ! isnan ( lp - > io_rate_write_bps ) )
2020-09-07 09:53:58 +00:00
totalRate = lp - > io_rate_write_bps ;
else
totalRate = NAN ;
2021-04-14 18:16:16 +00:00
Process_printRate ( str , totalRate , coloring ) ; return ;
2016-02-20 04:22:57 +00:00
}
2015-03-16 04:43:04 +00:00
# ifdef HAVE_OPENVZ
2020-09-30 21:46:52 +00:00
case CTID : xSnprintf ( buffer , n , " %-8s " , lp - > ctid ? lp - > ctid : " " ) ; break ;
2020-12-15 18:44:52 +00:00
case VPID : xSnprintf ( buffer , n , " %*d " , Process_pidDigits , lp - > vpid ) ; break ;
2015-03-16 04:43:04 +00:00
# endif
# ifdef HAVE_VSERVER
2017-07-27 19:07:50 +00:00
case VXID : xSnprintf ( buffer , n , " %5u " , lp - > vxid ) ; break ;
2015-03-16 04:43:04 +00:00
# endif
2020-09-21 11:47:39 +00:00
case CGROUP : xSnprintf ( buffer , n , " %-10s " , lp - > cgroup ? lp - > cgroup : " " ) ; break ;
2020-08-28 12:24:40 +00:00
case OOM : xSnprintf ( buffer , n , " %4u " , lp - > oom ) ; break ;
2014-11-24 20:55:49 +00:00
case IO_PRIORITY : {
2015-01-22 01:27:31 +00:00
int klass = IOPriority_class ( lp - > ioPriority ) ;
2014-11-24 20:55:49 +00:00
if ( klass = = IOPRIO_CLASS_NONE ) {
// see note [1] above
2017-07-27 19:07:50 +00:00
xSnprintf ( buffer , n , " B%1d " , ( int ) ( this - > nice + 20 ) / 5 ) ;
2014-11-24 20:55:49 +00:00
} else if ( klass = = IOPRIO_CLASS_BE ) {
2017-07-27 19:07:50 +00:00
xSnprintf ( buffer , n , " B%1d " , IOPriority_data ( lp - > ioPriority ) ) ;
2014-11-24 20:55:49 +00:00
} else if ( klass = = IOPRIO_CLASS_RT ) {
attr = CRT_colors [ PROCESS_HIGH_PRIORITY ] ;
2017-07-27 19:07:50 +00:00
xSnprintf ( buffer , n , " R%1d " , IOPriority_data ( lp - > ioPriority ) ) ;
2017-07-05 18:18:02 +00:00
} else if ( klass = = IOPRIO_CLASS_IDLE ) {
2019-10-31 16:39:12 +00:00
attr = CRT_colors [ PROCESS_LOW_PRIORITY ] ;
2017-07-27 19:07:50 +00:00
xSnprintf ( buffer , n , " id " ) ;
2014-11-24 20:55:49 +00:00
} else {
2017-07-27 19:07:50 +00:00
xSnprintf ( buffer , n , " ?? " ) ;
2014-11-24 20:55:49 +00:00
}
break ;
}
2017-12-04 02:15:29 +00:00
# ifdef HAVE_DELAYACCT
case PERCENT_CPU_DELAY : LinuxProcess_printDelay ( lp - > cpu_delay_percent , buffer , n ) ; break ;
case PERCENT_IO_DELAY : LinuxProcess_printDelay ( lp - > blkio_delay_percent , buffer , n ) ; break ;
case PERCENT_SWAP_DELAY : LinuxProcess_printDelay ( lp - > swapin_delay_percent , buffer , n ) ; break ;
# endif
2020-09-11 13:02:00 +00:00
case CTXT :
2020-11-01 00:09:51 +00:00
if ( lp - > ctxt_diff > 1000 ) {
2020-09-11 13:02:00 +00:00
attr | = A_BOLD ;
2020-11-01 00:09:51 +00:00
}
2020-09-11 13:02:00 +00:00
xSnprintf ( buffer , n , " %5lu " , lp - > ctxt_diff ) ;
break ;
2020-09-28 10:06:13 +00:00
case SECATTR : snprintf ( buffer , n , " %-30s " , lp - > secattr ? lp - > secattr : " ? " ) ; break ;
2020-10-17 10:54:45 +00:00
case COMM : {
if ( ( Process_isUserlandThread ( this ) & & this - > settings - > showThreadNames ) | | ! lp - > mergedCommand . str ) {
Process_writeField ( this , str , field ) ;
} else {
LinuxProcess_writeCommandField ( this , str , buffer , n , attr ) ;
}
return ;
}
case PROC_COMM : {
2021-01-10 14:57:46 +00:00
const char * procComm ;
2020-10-17 10:54:45 +00:00
if ( lp - > procComm ) {
attr = CRT_colors [ Process_isUserlandThread ( this ) ? PROCESS_THREAD_COMM : PROCESS_COMM ] ;
2021-01-10 14:57:46 +00:00
procComm = lp - > procComm ;
2020-10-17 10:54:45 +00:00
} else {
2020-11-20 18:57:12 +00:00
attr = CRT_colors [ PROCESS_SHADOW ] ;
2021-01-10 14:57:46 +00:00
procComm = Process_isKernelThread ( lp ) ? kthreadID : " N/A " ;
2020-10-17 10:54:45 +00:00
}
2021-01-10 14:57:46 +00:00
/* 15 being (TASK_COMM_LEN - 1) */
Process_printLeftAlignedField ( str , attr , procComm , 15 ) ;
return ;
2020-10-17 10:54:45 +00:00
}
case PROC_EXE : {
2021-01-10 14:57:46 +00:00
const char * procExe ;
2020-10-17 10:54:45 +00:00
if ( lp - > procExe ) {
attr = CRT_colors [ Process_isUserlandThread ( this ) ? PROCESS_THREAD_BASENAME : PROCESS_BASENAME ] ;
2020-11-23 21:55:56 +00:00
if ( lp - > procExeDeleted )
attr = CRT_colors [ FAILED_READ ] ;
2021-01-10 14:57:46 +00:00
procExe = lp - > procExe + lp - > procExeBasenameOffset ;
2020-10-17 10:54:45 +00:00
} else {
2020-11-20 18:57:12 +00:00
attr = CRT_colors [ PROCESS_SHADOW ] ;
2021-01-10 14:57:46 +00:00
procExe = Process_isKernelThread ( lp ) ? kthreadID : " N/A " ;
2020-10-17 10:54:45 +00:00
}
2021-01-10 14:57:46 +00:00
Process_printLeftAlignedField ( str , attr , procExe , 15 ) ;
return ;
2020-10-17 10:54:45 +00:00
}
2021-01-10 14:57:46 +00:00
case CWD : {
const char * cwd ;
2020-11-26 16:51:54 +00:00
if ( ! lp - > cwd ) {
attr = CRT_colors [ PROCESS_SHADOW ] ;
2021-01-10 14:57:46 +00:00
cwd = " N/A " ;
2020-11-26 16:51:54 +00:00
} else if ( String_startsWith ( lp - > cwd , " /proc/ " ) & & strstr ( lp - > cwd , " (deleted) " ) ! = NULL ) {
attr = CRT_colors [ PROCESS_SHADOW ] ;
2021-01-10 14:57:46 +00:00
cwd = " main thread terminated " ;
2020-11-26 16:51:54 +00:00
} else {
2021-01-10 14:57:46 +00:00
cwd = lp - > cwd ;
2020-11-26 16:51:54 +00:00
}
2021-01-10 14:57:46 +00:00
Process_printLeftAlignedField ( str , attr , cwd , 25 ) ;
return ;
}
2014-11-24 20:55:49 +00:00
default :
2020-09-28 10:17:52 +00:00
Process_writeField ( this , str , field ) ;
2015-01-22 01:27:31 +00:00
return ;
2014-11-24 20:55:49 +00:00
}
2021-04-14 18:55:48 +00:00
RichString_appendAscii ( str , attr , buffer ) ;
2014-11-24 20:55:49 +00:00
}
2021-01-27 14:11:48 +00:00
static double adjustNaN ( double num ) {
if ( isnan ( num ) )
return - 0.0005 ;
return num ;
}
2020-12-23 12:02:32 +00:00
static int LinuxProcess_compareByKey ( const Process * v1 , const Process * v2 , ProcessField key ) {
2020-12-17 23:09:55 +00:00
const LinuxProcess * p1 = ( const LinuxProcess * ) v1 ;
const LinuxProcess * p2 = ( const LinuxProcess * ) v2 ;
2020-11-04 16:46:24 +00:00
2020-12-15 18:44:48 +00:00
switch ( key ) {
2015-03-16 04:43:04 +00:00
case M_DRS :
2021-01-21 13:27:23 +00:00
return SPACESHIP_NUMBER ( p1 - > m_drs , p2 - > m_drs ) ;
2015-03-16 04:43:04 +00:00
case M_DT :
2021-01-21 13:27:23 +00:00
return SPACESHIP_NUMBER ( p1 - > m_dt , p2 - > m_dt ) ;
2015-03-16 04:43:04 +00:00
case M_LRS :
2021-01-21 13:27:23 +00:00
return SPACESHIP_NUMBER ( p1 - > m_lrs , p2 - > m_lrs ) ;
2015-03-16 04:43:04 +00:00
case M_TRS :
2021-01-21 13:27:23 +00:00
return SPACESHIP_NUMBER ( p1 - > m_trs , p2 - > m_trs ) ;
2015-03-16 04:43:04 +00:00
case M_SHARE :
2021-01-21 13:27:23 +00:00
return SPACESHIP_NUMBER ( p1 - > m_share , p2 - > m_share ) ;
2018-10-09 19:49:29 +00:00
case M_PSS :
2021-01-21 13:27:23 +00:00
return SPACESHIP_NUMBER ( p1 - > m_pss , p2 - > m_pss ) ;
2018-10-09 19:49:29 +00:00
case M_SWAP :
2021-01-21 13:27:23 +00:00
return SPACESHIP_NUMBER ( p1 - > m_swap , p2 - > m_swap ) ;
2018-10-09 19:49:29 +00:00
case M_PSSWP :
2021-01-21 13:27:23 +00:00
return SPACESHIP_NUMBER ( p1 - > m_psswp , p2 - > m_psswp ) ;
2020-11-04 16:46:24 +00:00
case UTIME :
2021-01-21 13:27:23 +00:00
return SPACESHIP_NUMBER ( p1 - > utime , p2 - > utime ) ;
2020-11-04 16:46:24 +00:00
case CUTIME :
2021-01-21 13:27:23 +00:00
return SPACESHIP_NUMBER ( p1 - > cutime , p2 - > cutime ) ;
2020-11-04 16:46:24 +00:00
case STIME :
2021-01-21 13:27:23 +00:00
return SPACESHIP_NUMBER ( p1 - > stime , p2 - > stime ) ;
2020-11-04 16:46:24 +00:00
case CSTIME :
2021-01-21 13:27:23 +00:00
return SPACESHIP_NUMBER ( p1 - > cstime , p2 - > cstime ) ;
2020-11-04 16:46:24 +00:00
case RCHAR :
2021-01-21 13:27:23 +00:00
return SPACESHIP_NUMBER ( p1 - > io_rchar , p2 - > io_rchar ) ;
2020-11-04 16:46:24 +00:00
case WCHAR :
2021-01-21 13:27:23 +00:00
return SPACESHIP_NUMBER ( p1 - > io_wchar , p2 - > io_wchar ) ;
2020-11-04 16:46:24 +00:00
case SYSCR :
2021-01-21 13:27:23 +00:00
return SPACESHIP_NUMBER ( p1 - > io_syscr , p2 - > io_syscr ) ;
2020-11-04 16:46:24 +00:00
case SYSCW :
2021-01-21 13:27:23 +00:00
return SPACESHIP_NUMBER ( p1 - > io_syscw , p2 - > io_syscw ) ;
2020-11-04 16:46:24 +00:00
case RBYTES :
2021-01-21 13:27:23 +00:00
return SPACESHIP_NUMBER ( p1 - > io_read_bytes , p2 - > io_read_bytes ) ;
2020-11-04 16:46:24 +00:00
case WBYTES :
2021-01-21 13:27:23 +00:00
return SPACESHIP_NUMBER ( p1 - > io_write_bytes , p2 - > io_write_bytes ) ;
2020-11-04 16:46:24 +00:00
case CNCLWB :
2021-01-21 13:27:23 +00:00
return SPACESHIP_NUMBER ( p1 - > io_cancelled_write_bytes , p2 - > io_cancelled_write_bytes ) ;
2020-11-04 16:46:24 +00:00
case IO_READ_RATE :
2021-01-27 14:11:48 +00:00
return SPACESHIP_NUMBER ( adjustNaN ( p1 - > io_rate_read_bps ) , adjustNaN ( p2 - > io_rate_read_bps ) ) ;
2020-11-04 16:46:24 +00:00
case IO_WRITE_RATE :
2021-01-27 14:11:48 +00:00
return SPACESHIP_NUMBER ( adjustNaN ( p1 - > io_rate_write_bps ) , adjustNaN ( p2 - > io_rate_write_bps ) ) ;
2020-11-04 16:46:24 +00:00
case IO_RATE :
2021-01-27 14:11:48 +00:00
return SPACESHIP_NUMBER ( adjustNaN ( p1 - > io_rate_read_bps ) + adjustNaN ( p1 - > io_rate_write_bps ) , adjustNaN ( p2 - > io_rate_read_bps ) + adjustNaN ( p2 - > io_rate_write_bps ) ) ;
2015-03-16 04:43:04 +00:00
# ifdef HAVE_OPENVZ
case CTID :
2020-11-04 16:46:24 +00:00
return SPACESHIP_NULLSTR ( p1 - > ctid , p2 - > ctid ) ;
2015-03-16 04:43:04 +00:00
case VPID :
2021-01-21 13:27:23 +00:00
return SPACESHIP_NUMBER ( p1 - > vpid , p2 - > vpid ) ;
2015-03-16 04:43:04 +00:00
# endif
# ifdef HAVE_VSERVER
case VXID :
2021-01-21 13:27:23 +00:00
return SPACESHIP_NUMBER ( p1 - > vxid , p2 - > vxid ) ;
2015-03-16 04:43:04 +00:00
# endif
case CGROUP :
2020-11-04 16:46:24 +00:00
return SPACESHIP_NULLSTR ( p1 - > cgroup , p2 - > cgroup ) ;
2015-03-16 04:43:04 +00:00
case OOM :
2021-01-21 13:27:23 +00:00
return SPACESHIP_NUMBER ( p1 - > oom , p2 - > oom ) ;
2017-12-04 02:15:29 +00:00
# ifdef HAVE_DELAYACCT
case PERCENT_CPU_DELAY :
2021-01-21 13:27:23 +00:00
return SPACESHIP_NUMBER ( p1 - > cpu_delay_percent , p2 - > cpu_delay_percent ) ;
2017-12-04 02:15:29 +00:00
case PERCENT_IO_DELAY :
2021-01-21 13:27:23 +00:00
return SPACESHIP_NUMBER ( p1 - > blkio_delay_percent , p2 - > blkio_delay_percent ) ;
2017-12-04 02:15:29 +00:00
case PERCENT_SWAP_DELAY :
2021-01-21 13:27:23 +00:00
return SPACESHIP_NUMBER ( p1 - > swapin_delay_percent , p2 - > swapin_delay_percent ) ;
2017-12-04 02:15:29 +00:00
# endif
2014-11-24 20:55:49 +00:00
case IO_PRIORITY :
2020-11-04 16:46:24 +00:00
return SPACESHIP_NUMBER ( LinuxProcess_effectiveIOPriority ( p1 ) , LinuxProcess_effectiveIOPriority ( p2 ) ) ;
2020-09-11 13:02:00 +00:00
case CTXT :
2021-01-21 13:27:23 +00:00
return SPACESHIP_NUMBER ( p1 - > ctxt_diff , p2 - > ctxt_diff ) ;
2020-09-28 10:06:13 +00:00
case SECATTR :
2020-11-04 16:46:24 +00:00
return SPACESHIP_NULLSTR ( p1 - > secattr , p2 - > secattr ) ;
2020-10-17 10:54:45 +00:00
case PROC_COMM : {
const char * comm1 = p1 - > procComm ? p1 - > procComm : ( Process_isKernelThread ( p1 ) ? kthreadID : " " ) ;
const char * comm2 = p2 - > procComm ? p2 - > procComm : ( Process_isKernelThread ( p2 ) ? kthreadID : " " ) ;
return strcmp ( comm1 , comm2 ) ;
}
case PROC_EXE : {
const char * exe1 = p1 - > procExe ? ( p1 - > procExe + p1 - > procExeBasenameOffset ) : ( Process_isKernelThread ( p1 ) ? kthreadID : " " ) ;
const char * exe2 = p2 - > procExe ? ( p2 - > procExe + p2 - > procExeBasenameOffset ) : ( Process_isKernelThread ( p2 ) ? kthreadID : " " ) ;
return strcmp ( exe1 , exe2 ) ;
}
2020-11-26 16:51:54 +00:00
case CWD :
return SPACESHIP_NULLSTR ( p1 - > cwd , p2 - > cwd ) ;
2014-11-24 20:55:49 +00:00
default :
2020-12-18 21:12:26 +00:00
return Process_compareByKey_Base ( v1 , v2 , key ) ;
2014-11-24 20:55:49 +00:00
}
2015-03-16 04:43:04 +00:00
}
2020-10-07 17:02:15 +00:00
bool Process_isThread ( const Process * this ) {
2015-03-16 04:43:04 +00:00
return ( Process_isUserlandThread ( this ) | | Process_isKernelThread ( this ) ) ;
2014-11-24 20:55:49 +00:00
}
2020-11-04 16:46:14 +00:00
const ProcessClass LinuxProcess_class = {
. super = {
. extends = Class ( Process ) ,
. display = Process_display ,
. delete = Process_delete ,
2020-12-17 23:09:55 +00:00
. compare = Process_compare
2020-11-04 16:46:14 +00:00
} ,
2020-10-17 10:54:45 +00:00
. writeField = LinuxProcess_writeField ,
2020-12-17 23:09:55 +00:00
. getCommandStr = LinuxProcess_getCommandStr ,
. compareByKey = LinuxProcess_compareByKey
2020-11-04 16:46:14 +00:00
} ;