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 .
*/
2014-11-24 21:22:50 +00:00
# include "LinuxProcess.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"
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 */
long long btime ;
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 " ;
2015-03-15 23:29:13 +00:00
ProcessFieldData Process_fields [ ] = {
2015-03-16 04:43:04 +00:00
[ 0 ] = { . name = " " , . title = NULL , . description = NULL , . flags = 0 , } ,
[ PID ] = { . name = " PID " , . title = " PID " , . description = " Process/thread ID " , . flags = 0 , } ,
[ 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 , } ,
2015-03-16 04:43:04 +00:00
[ PPID ] = { . name = " PPID " , . title = " PPID " , . description = " Parent process ID " , . flags = 0 , } ,
[ PGRP ] = { . name = " PGRP " , . title = " PGRP " , . description = " Process group ID " , . flags = 0 , } ,
2017-02-04 23:10:29 +00:00
[ SESSION ] = { . name = " SESSION " , . title = " SID " , . description = " Process's session ID " , . flags = 0 , } ,
2016-10-01 06:09:04 +00:00
[ TTY_NR ] = { . name = " TTY_NR " , . title = " TTY " , . description = " Controlling terminal " , . flags = 0 , } ,
2015-03-16 04:43:04 +00:00
[ TPGID ] = { . name = " TPGID " , . title = " TPGID " , . description = " Process ID of the fg process group of the controlling terminal " , . flags = 0 , } ,
[ FLAGS ] = { . name = " FLAGS " , . title = NULL , . description = NULL , . flags = 0 , } ,
[ MINFLT ] = { . name = " MINFLT " , . title = " MINFLT " , . description = " Number of minor faults which have not required loading a memory page from disk " , . flags = 0 , } ,
[ CMINFLT ] = { . name = " CMINFLT " , . title = " CMINFLT " , . description = " Children processes' minor faults " , . flags = 0 , } ,
[ MAJFLT ] = { . name = " MAJFLT " , . title = " MAJFLT " , . description = " Number of major faults which have required loading a memory page from disk " , . flags = 0 , } ,
[ CMAJFLT ] = { . name = " CMAJFLT " , . title = " CMAJFLT " , . description = " Children processes' major faults " , . flags = 0 , } ,
[ UTIME ] = { . name = " UTIME " , . title = " UTIME+ " , . description = " User CPU time - time the process spent executing in user mode " , . flags = 0 , } ,
[ STIME ] = { . name = " STIME " , . title = " STIME+ " , . description = " System CPU time - time the kernel spent running system calls for this process " , . flags = 0 , } ,
[ CUTIME ] = { . name = " CUTIME " , . title = " CUTIME+ " , . description = " Children processes' user CPU time " , . flags = 0 , } ,
[ CSTIME ] = { . name = " CSTIME " , . title = " CSTIME+ " , . description = " Children processes' system CPU time " , . flags = 0 , } ,
[ 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 , } ,
[ ITREALVALUE ] = { . name = " ITREALVALUE " , . title = NULL , . description = NULL , . flags = 0 , } ,
[ STARTTIME ] = { . name = " STARTTIME " , . title = " START " , . description = " Time the process was started " , . flags = 0 , } ,
[ VSIZE ] = { . name = " VSIZE " , . title = NULL , . description = NULL , . flags = 0 , } ,
[ RSS ] = { . name = " RSS " , . title = NULL , . description = NULL , . flags = 0 , } ,
[ RLIM ] = { . name = " RLIM " , . title = NULL , . description = NULL , . flags = 0 , } ,
[ STARTCODE ] = { . name = " STARTCODE " , . title = NULL , . description = NULL , . flags = 0 , } ,
[ ENDCODE ] = { . name = " ENDCODE " , . title = NULL , . description = NULL , . flags = 0 , } ,
[ STARTSTACK ] = { . name = " STARTSTACK " , . title = NULL , . description = NULL , . flags = 0 , } ,
[ KSTKESP ] = { . name = " KSTKESP " , . title = NULL , . description = NULL , . flags = 0 , } ,
[ KSTKEIP ] = { . name = " KSTKEIP " , . title = NULL , . description = NULL , . flags = 0 , } ,
[ SIGNAL ] = { . name = " SIGNAL " , . title = NULL , . description = NULL , . flags = 0 , } ,
[ BLOCKED ] = { . name = " BLOCKED " , . title = NULL , . description = NULL , . flags = 0 , } ,
[ SSIGIGNORE ] = { . name = " SIGIGNORE " , . title = NULL , . description = NULL , . flags = 0 , } ,
[ SIGCATCH ] = { . name = " SIGCATCH " , . title = NULL , . description = NULL , . flags = 0 , } ,
[ WCHAN ] = { . name = " WCHAN " , . title = NULL , . description = NULL , . flags = 0 , } ,
[ NSWAP ] = { . name = " NSWAP " , . title = NULL , . description = NULL , . flags = 0 , } ,
[ CNSWAP ] = { . name = " CNSWAP " , . title = NULL , . description = NULL , . flags = 0 , } ,
[ EXIT_SIGNAL ] = { . name = " EXIT_SIGNAL " , . title = NULL , . description = NULL , . flags = 0 , } ,
[ PROCESSOR ] = { . name = " PROCESSOR " , . title = " CPU " , . description = " Id of the CPU the process last executed on " , . flags = 0 , } ,
2020-11-20 16:09:34 +00:00
[ M_VIRT ] = { . name = " M_VIRT " , . title = " VIRT " , . description = " Total program size in virtual memory " , . flags = 0 , } ,
2015-03-16 04:43:04 +00:00
[ M_RESIDENT ] = { . name = " M_RESIDENT " , . title = " RES " , . description = " Resident set size, size of the text and data sections, plus stack usage " , . flags = 0 , } ,
[ M_SHARE ] = { . name = " M_SHARE " , . title = " SHR " , . description = " Size of the process's shared pages " , . flags = 0 , } ,
[ M_TRS ] = { . name = " M_TRS " , . title = " CODE " , . description = " Size of the text segment of the process " , . flags = 0 , } ,
[ M_DRS ] = { . name = " M_DRS " , . title = " DATA " , . description = " Size of the data segment plus stack usage of the process " , . flags = 0 , } ,
2020-10-09 13:13:06 +00:00
[ M_LRS ] = { . name = " M_LRS " , . title = " LIB " , . description = " The library size of the process (calculated from memory maps) " , . flags = PROCESS_FLAG_LINUX_LRS_FIX , } ,
2020-09-28 10:01:56 +00:00
[ 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 , } ,
2018-10-07 09:16:12 +00:00
[ ST_UID ] = { . name = " ST_UID " , . title = " UID " , . description = " User ID of the process owner " , . flags = 0 , } ,
2015-03-16 04:43:04 +00:00
[ PERCENT_CPU ] = { . name = " PERCENT_CPU " , . title = " CPU% " , . description = " Percentage of the CPU time the process used in the last sampling " , . flags = 0 , } ,
2020-10-30 16:02:20 +00:00
[ 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 , } ,
2015-03-16 04:43:04 +00:00
[ PERCENT_MEM ] = { . name = " PERCENT_MEM " , . title = " MEM% " , . description = " Percentage of the memory the process is using, based on resident memory size " , . flags = 0 , } ,
[ USER ] = { . name = " USER " , . title = " USER " , . description = " Username of the process owner (or user ID if name cannot be determined) " , . flags = 0 , } ,
[ TIME ] = { . name = " TIME " , . title = " TIME+ " , . description = " Total time the process has spent in user and system time " , . flags = 0 , } ,
[ NLWP ] = { . name = " NLWP " , . title = " NLWP " , . description = " Number of threads in the process " , . flags = 0 , } ,
[ TGID ] = { . name = " TGID " , . title = " TGID " , . description = " Thread group ID (i.e. process ID) " , . flags = 0 , } ,
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 , } ,
[ VPID ] = { . name = " VPID " , . title = " VPID " , . description = " OpenVZ process ID " , . flags = PROCESS_FLAG_LINUX_OPENVZ , } ,
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
2015-03-16 04:43:04 +00:00
[ RCHAR ] = { . name = " RCHAR " , . title = " RD_CHAR " , . description = " Number of bytes the process has read " , . flags = PROCESS_FLAG_IO , } ,
[ WCHAR ] = { . name = " WCHAR " , . title = " WR_CHAR " , . description = " Number of bytes the process has written " , . flags = PROCESS_FLAG_IO , } ,
[ SYSCR ] = { . name = " SYSCR " , . title = " RD_SYSC " , . description = " Number of read(2) syscalls for the process " , . flags = PROCESS_FLAG_IO , } ,
[ SYSCW ] = { . name = " SYSCW " , . title = " WR_SYSC " , . description = " Number of write(2) syscalls for the process " , . flags = PROCESS_FLAG_IO , } ,
[ RBYTES ] = { . name = " RBYTES " , . title = " IO_RBYTES " , . description = " Bytes of read(2) I/O for the process " , . flags = PROCESS_FLAG_IO , } ,
[ WBYTES ] = { . name = " WBYTES " , . title = " IO_WBYTES " , . description = " Bytes of write(2) I/O for the process " , . flags = PROCESS_FLAG_IO , } ,
[ CNCLWB ] = { . name = " CNCLWB " , . title = " IO_CANCEL " , . description = " Bytes of cancelled write(2) I/O " , . flags = PROCESS_FLAG_IO , } ,
[ 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 , } ,
[ 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 , } ,
[ IO_RATE ] = { . name = " IO_RATE " , . title = " DISK R/W " , . description = " Total I/O rate in bytes per second " , . flags = PROCESS_FLAG_IO , } ,
[ CGROUP ] = { . name = " CGROUP " , . title = " CGROUP " , . description = " Which cgroup the process is in " , . flags = PROCESS_FLAG_LINUX_CGROUP , } ,
2020-08-28 12:24:40 +00:00
[ OOM ] = { . name = " OOM " , . title = " OOM " , . description = " OOM (Out-of-Memory) killer score " , . flags = PROCESS_FLAG_LINUX_OOM , } ,
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
[ PERCENT_CPU_DELAY ] = { . name = " PERCENT_CPU_DELAY " , . title = " CPUD% " , . description = " CPU delay % " , . flags = 0 , } ,
[ PERCENT_IO_DELAY ] = { . name = " PERCENT_IO_DELAY " , . title = " IOD% " , . description = " Block I/O delay % " , . flags = 0 , } ,
[ PERCENT_SWAP_DELAY ] = { . name = " PERCENT_SWAP_DELAY " , . title = " SWAPD% " , . description = " Swapin delay % " , . flags = 0 , } ,
# endif
2018-10-09 19:49:29 +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 , } ,
[ M_SWAP ] = { . name = " M_SWAP " , . title = " SWAP " , . description = " Size of the process's swapped pages " , . flags = PROCESS_FLAG_LINUX_SMAPS , } ,
[ 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 , } ,
2020-09-11 13:02:00 +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 , } ,
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-16 04:43:04 +00:00
[ LAST_PROCESSFIELD ] = { . name = " *** report bug! *** " , . title = NULL , . description = NULL , . flags = 0 , } ,
2015-03-15 23:29:13 +00:00
} ;
2015-08-20 03:32:47 +00:00
ProcessPidColumn Process_pidColumns [ ] = {
{ . id = PID , . label = " PID " } ,
{ . id = PPID , . label = " PPID " } ,
# ifdef HAVE_OPENVZ
{ . id = VPID , . label = " VPID " } ,
# endif
{ . id = TPGID , . label = " TPGID " } ,
{ . id = TGID , . label = " TGID " } ,
{ . id = PGRP , . label = " PGRP " } ,
2017-01-31 23:03:55 +00:00
{ . id = SESSION , . label = " SID " } ,
2015-08-20 03:32:47 +00:00
{ . id = 0 , . label = NULL } ,
} ;
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 ) {
return this - > comm ;
}
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 ) ;
2016-10-01 06:09:04 +00:00
free ( this - > ttyDevice ) ;
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
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 * token ;
const char * tokenBase ;
size_t tokenLen ;
const size_t commLen = strlen ( comm ) ;
for ( token = cmdline + cmdlineBasenameOffset ; * token ; ) {
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 ;
} while ( ' \n ' = = * token ) ;
}
}
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 ;
i > = 0 & & cmdline [ i ] = = exe [ j ] ; - - i , - - j )
;
/* full match, with exe suffix being a valid relative path */
if ( i < 0 & & exe [ j ] = = ' / ' ) {
return matchLen ;
}
}
}
/* 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-10-17 10:54:45 +00:00
bool showMergedCommand = this - > settings - > showMergedCommand ;
bool showProgramPath = this - > settings - > showProgramPath ;
bool searchCommInCmdline = this - > settings - > findCommInCmdline ;
bool stripExeFromCmdline = this - > settings - > stripExeFromCmdline ;
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 ;
/* Clear any separators */
mc - > sep1 = 0 ;
mc - > sep2 = 0 ;
/* Clear any highlighting locations */
mc - > baseStart = 0 ;
mc - > baseEnd = 0 ;
mc - > commStart = 0 ;
mc - > commEnd = 0 ;
2020-10-17 10:54:45 +00:00
const char * cmdline = this - > comm ;
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 ;
if ( ! showMergedCommand | | ! procExe | | ! procComm ) { /* fall back to cmdline */
2020-11-23 21:55:56 +00:00
if ( showMergedCommand & & ! procExe & & procComm & & strlen ( procComm ) ) { /* Prefix column with comm */
if ( strncmp ( cmdline + cmdlineBasenameOffset , procComm , MINIMUM ( TASK_COMM_LEN - 1 , strlen ( procComm ) ) ) ! = 0 ) {
mc - > commStart = 0 ;
mc - > commEnd = strlen ( procComm ) ;
str = stpcpy ( str , procComm ) ;
mc - > sep1 = str - strStart ;
str = stpcpy ( str , SEPARATOR ) ;
}
}
2020-10-17 10:54:45 +00:00
if ( showProgramPath ) {
2020-11-23 21:55:56 +00:00
( void ) stpcpyWithNewlineConversion ( str , cmdline ) ;
2020-11-20 18:55:48 +00:00
mc - > baseStart = cmdlineBasenameOffset ;
mc - > baseEnd = lp - > procCmdlineBasenameEnd ;
2020-10-17 10:54:45 +00:00
} else {
2020-11-23 21:55:56 +00:00
( void ) stpcpyWithNewlineConversion ( str , cmdline + cmdlineBasenameOffset ) ;
2020-11-20 18:55:48 +00:00
mc - > baseStart = 0 ;
mc - > baseEnd = lp - > procCmdlineBasenameEnd - cmdlineBasenameOffset ;
2020-10-17 10:54:45 +00:00
}
2020-11-20 18:55:48 +00:00
2020-11-23 21:55:56 +00:00
if ( mc - > sep1 ) {
mc - > baseStart + = str - strStart - SEPARATOR_LEN + 1 ;
mc - > baseEnd + = str - strStart - SEPARATOR_LEN + 1 ;
}
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
/* Start with copying exe */
if ( showProgramPath ) {
2020-11-20 18:55:48 +00:00
str = stpcpy ( str , procExe ) ;
mc - > baseStart = exeBasenameOffset ;
mc - > baseEnd = exeLen ;
2020-10-17 10:54:45 +00:00
} else {
2020-11-20 18:55:48 +00:00
str = stpcpy ( str , procExe + exeBasenameOffset ) ;
mc - > baseStart = 0 ;
mc - > baseEnd = exeBasenameLen ;
2020-10-17 10:54:45 +00:00
}
2020-11-20 18:55:48 +00:00
mc - > sep1 = 0 ;
mc - > sep2 = 0 ;
int commStart = 0 ;
int commEnd = 0 ;
bool commInCmdline = false ;
2020-10-17 10:54:45 +00:00
/* Try to match procComm with procExe's basename: This is reliable (predictable) */
if ( strncmp ( procExe + exeBasenameOffset , procComm , TASK_COMM_LEN - 1 ) = = 0 ) {
2020-11-20 18:55:48 +00:00
commStart = mc - > baseStart ;
commEnd = mc - > baseEnd ;
2020-10-17 10:54:45 +00:00
} else if ( searchCommInCmdline ) {
/* commStart/commEnd will be adjusted later along with cmdline */
commInCmdline = findCommInCmdline ( procComm , cmdline , cmdlineBasenameOffset , & commStart , & commEnd ) ;
}
2020-11-20 18:55:48 +00:00
int matchLen = matchCmdlinePrefixWithExeSuffix ( cmdline , cmdlineBasenameOffset , procExe , exeBasenameOffset , exeBasenameLen ) ;
2020-10-17 10:54:45 +00:00
/* Note: commStart, commEnd are offsets into RichString. But the multibyte
* separator ( with size SEPARATOR_LEN ) has size 1 in RichString . The offset
* adjustments below reflect this . */
if ( commEnd ) {
2020-11-20 18:55:48 +00:00
mc - > unmatchedExe = ! matchLen ;
if ( matchLen ) {
/* strip the matched exe prefix */
2020-10-17 10:54:45 +00:00
cmdline + = matchLen ;
2020-11-20 18:55:48 +00:00
2020-10-17 10:54:45 +00:00
if ( commInCmdline ) {
commStart + = str - strStart - matchLen ;
commEnd + = str - strStart - matchLen ;
}
2020-11-20 18:55:48 +00:00
} else {
/* cmdline will be a separate field */
mc - > sep1 = str - strStart ;
2020-10-17 10:54:45 +00:00
str = stpcpy ( str , SEPARATOR ) ;
2020-11-20 18:55:48 +00:00
2020-10-17 10:54:45 +00:00
if ( commInCmdline ) {
commStart + = str - strStart - SEPARATOR_LEN + 1 ;
commEnd + = str - strStart - SEPARATOR_LEN + 1 ;
}
}
2020-11-20 18:55:48 +00:00
mc - > separateComm = false ; /* procComm merged */
2020-10-17 10:54:45 +00:00
} else {
2020-11-20 18:55:48 +00:00
mc - > sep1 = str - strStart ;
2020-10-17 10:54:45 +00:00
str = stpcpy ( str , SEPARATOR ) ;
2020-11-20 18:55:48 +00:00
commStart = str - strStart - SEPARATOR_LEN + 1 ;
2020-10-17 10:54:45 +00:00
str = stpcpy ( str , procComm ) ;
commEnd = str - strStart - SEPARATOR_LEN + 1 ; /* or commStart + strlen(procComm) */
2020-11-20 18:55:48 +00:00
mc - > unmatchedExe = ! matchLen ;
2020-10-17 10:54:45 +00:00
if ( matchLen ) {
if ( stripExeFromCmdline ) {
cmdline + = matchLen ;
}
}
2020-11-20 18:55:48 +00:00
2020-10-17 10:54:45 +00:00
if ( * cmdline ) {
2020-11-20 18:55:48 +00:00
mc - > sep2 = str - strStart - SEPARATOR_LEN + 1 ;
2020-10-17 10:54:45 +00:00
str = stpcpy ( str , SEPARATOR ) ;
}
2020-11-20 18:55:48 +00:00
mc - > separateComm = true ; /* procComm a separate field */
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-11-20 18:55:48 +00:00
mc - > commStart = commStart ;
mc - > commEnd = commEnd ;
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-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-10-17 10:54:45 +00:00
int baseStart = strStart + lp - > mergedCommand . baseStart ;
int baseEnd = strStart + lp - > mergedCommand . baseEnd ;
2020-11-20 18:55:48 +00:00
int commStart = strStart + lp - > mergedCommand . commStart ;
int commEnd = strStart + lp - > mergedCommand . commEnd ;
int commAttr = CRT_colors [ Process_isUserlandThread ( this ) ? PROCESS_THREAD_COMM : PROCESS_COMM ] ;
2020-10-17 10:54:45 +00:00
bool highlightBaseName = this - > settings - > highlightBaseName ;
2020-11-23 21:55:56 +00:00
if ( lp - > procExeDeleted )
baseAttr = CRT_colors [ FAILED_READ ] ;
2020-10-17 10:54:45 +00:00
RichString_append ( str , attr , lp - > mergedCommand . str ) ;
if ( lp - > mergedCommand . commEnd ) {
2020-12-02 15:06:19 +00:00
if ( ! lp - > mergedCommand . separateComm & & commStart = = baseStart & & highlightBaseName ) {
2020-10-17 10:54:45 +00:00
/* If it was matched with procExe's basename, make it bold if needed */
2020-11-20 18:55:48 +00:00
if ( commEnd > baseEnd ) {
RichString_setAttrn ( str , A_BOLD | baseAttr , baseStart , baseEnd - 1 ) ;
RichString_setAttrn ( str , A_BOLD | commAttr , baseEnd , commEnd - 1 ) ;
} else if ( commEnd < baseEnd ) {
RichString_setAttrn ( str , A_BOLD | commAttr , commStart , commEnd - 1 ) ;
RichString_setAttrn ( str , A_BOLD | baseAttr , commEnd , baseEnd - 1 ) ;
2020-10-17 10:54:45 +00:00
} else {
2020-11-20 18:55:48 +00:00
// Actually should be highlighted commAttr, but marked baseAttr to reduce visual noise
RichString_setAttrn ( str , A_BOLD | baseAttr , commStart , commEnd - 1 ) ;
2020-10-17 10:54:45 +00:00
}
2020-11-20 18:55:48 +00:00
baseStart = baseEnd ;
} else {
RichString_setAttrn ( str , commAttr , commStart , commEnd - 1 ) ;
2020-10-17 10:54:45 +00:00
}
}
2020-11-20 18:55:48 +00:00
2020-10-17 10:54:45 +00:00
if ( baseStart < baseEnd & & highlightBaseName ) {
2020-11-20 07:04:51 +00:00
RichString_setAttrn ( str , baseAttr , baseStart , baseEnd - 1 ) ;
2020-10-17 10:54:45 +00:00
}
2020-11-20 18:55:48 +00:00
if ( mc - > sep1 )
RichString_setAttrn ( str , CRT_colors [ FAILED_READ ] , strStart + mc - > sep1 , strStart + mc - > sep1 ) ;
if ( mc - > sep2 )
RichString_setAttrn ( str , CRT_colors [ FAILED_READ ] , strStart + mc - > sep2 , strStart + mc - > sep2 ) ;
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 , " " ) ;
}
}
n - = ( buf - buffer ) ;
const char * draw = CRT_treeStr [ lastItem ? ( this - > settings - > direction = = 1 ? TREE_STR_BEND : TREE_STR_TEND ) : TREE_STR_RTEE ] ;
xSnprintf ( buf , n , " %s%s " , draw , this - > showChildren ? CRT_treeStr [ TREE_STR_SHUT ] : CRT_treeStr [ TREE_STR_OPEN ] ) ;
RichString_append ( str , CRT_colors [ PROCESS_TREE ] , buffer ) ;
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 ;
2015-03-16 04:43:04 +00:00
switch ( ( int ) field ) {
2016-10-01 06:09:04 +00:00
case TTY_NR : {
if ( lp - > ttyDevice ) {
2017-07-27 19:07:50 +00:00
xSnprintf ( buffer , n , " %-9s " , lp - > ttyDevice + 5 /* skip "/dev/" */ ) ;
2016-10-01 06:09:04 +00:00
} else {
attr = CRT_colors [ PROCESS_SHADOW ] ;
2017-07-27 19:07:50 +00:00
xSnprintf ( buffer , n , " ? " ) ;
2016-10-01 06:09:04 +00:00
}
break ;
}
2015-03-16 04:43:04 +00:00
case CMINFLT : Process_colorNumber ( str , lp - > cminflt , coloring ) ; return ;
case CMAJFLT : Process_colorNumber ( str , lp - > cmajflt , coloring ) ; return ;
2020-10-15 20:37:02 +00:00
case M_DRS : Process_humanNumber ( str , lp - > m_drs * CRT_pageSizeKB , coloring ) ; return ;
case M_DT : Process_humanNumber ( str , lp - > m_dt * CRT_pageSizeKB , coloring ) ; return ;
2020-11-26 18:56:10 +00:00
case M_LRS :
if ( lp - > m_lrs ) {
Process_humanNumber ( str , lp - > m_lrs * CRT_pageSizeKB , coloring ) ;
return ;
}
attr = CRT_colors [ PROCESS_SHADOW ] ;
xSnprintf ( buffer , n , " N/A " ) ;
break ;
2020-10-15 20:37:02 +00:00
case M_TRS : Process_humanNumber ( str , lp - > m_trs * CRT_pageSizeKB , coloring ) ; return ;
case M_SHARE : Process_humanNumber ( str , lp - > m_share * CRT_pageSizeKB , coloring ) ; return ;
2018-10-09 19:49:29 +00:00
case M_PSS : Process_humanNumber ( str , lp - > m_pss , coloring ) ; return ;
case M_SWAP : Process_humanNumber ( str , lp - > m_swap , coloring ) ; return ;
case M_PSSWP : Process_humanNumber ( str , lp - > m_psswp , coloring ) ; return ;
2015-03-16 04:43:04 +00:00
case UTIME : Process_printTime ( str , lp - > utime ) ; return ;
case STIME : Process_printTime ( str , lp - > stime ) ; return ;
case CUTIME : Process_printTime ( str , lp - > cutime ) ; return ;
case CSTIME : Process_printTime ( str , lp - > cstime ) ; return ;
case RCHAR : Process_colorNumber ( str , lp - > io_rchar , coloring ) ; return ;
case WCHAR : Process_colorNumber ( str , lp - > io_wchar , coloring ) ; return ;
case SYSCR : Process_colorNumber ( str , lp - > io_syscr , coloring ) ; return ;
case SYSCW : Process_colorNumber ( str , lp - > io_syscw , coloring ) ; return ;
case RBYTES : Process_colorNumber ( str , lp - > io_read_bytes , coloring ) ; return ;
case WBYTES : Process_colorNumber ( str , lp - > io_write_bytes , coloring ) ; return ;
case CNCLWB : Process_colorNumber ( str , lp - > io_cancelled_write_bytes , coloring ) ; return ;
case IO_READ_RATE : Process_outputRate ( str , buffer , n , lp - > io_rate_read_bps , coloring ) ; return ;
case IO_WRITE_RATE : Process_outputRate ( str , buffer , n , lp - > io_rate_write_bps , coloring ) ; return ;
2016-02-20 04:22:57 +00:00
case IO_RATE : {
2020-09-07 09:53:58 +00:00
double totalRate = NAN ;
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 ;
2016-02-20 04:22:57 +00:00
Process_outputRate ( str , buffer , n , totalRate , coloring ) ; return ;
}
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 ;
2017-07-27 19:07:50 +00:00
case VPID : xSnprintf ( buffer , n , Process_pidFormat , 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 : {
if ( lp - > procComm ) {
attr = CRT_colors [ Process_isUserlandThread ( this ) ? PROCESS_THREAD_COMM : PROCESS_COMM ] ;
/* 15 being (TASK_COMM_LEN - 1) */
xSnprintf ( buffer , n , " %-15.15s " , lp - > procComm ) ;
} else {
2020-11-20 18:57:12 +00:00
attr = CRT_colors [ PROCESS_SHADOW ] ;
2020-11-28 16:42:02 +00:00
xSnprintf ( buffer , n , " %-15.15s " , Process_isKernelThread ( lp ) ? kthreadID : " N/A " ) ;
2020-10-17 10:54:45 +00:00
}
break ;
}
case PROC_EXE : {
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 ] ;
2020-10-17 10:54:45 +00:00
xSnprintf ( buffer , n , " %-15.15s " , lp - > procExe + lp - > procExeBasenameOffset ) ;
} else {
2020-11-20 18:57:12 +00:00
attr = CRT_colors [ PROCESS_SHADOW ] ;
2020-11-28 16:42:02 +00:00
xSnprintf ( buffer , n , " %-15.15s " , Process_isKernelThread ( lp ) ? kthreadID : " N/A " ) ;
2020-10-17 10:54:45 +00:00
}
break ;
}
2020-11-26 16:51:54 +00:00
case CWD :
if ( ! lp - > cwd ) {
xSnprintf ( buffer , n , " %-25s " , " N/A " ) ;
attr = CRT_colors [ PROCESS_SHADOW ] ;
} else if ( String_startsWith ( lp - > cwd , " /proc/ " ) & & strstr ( lp - > cwd , " (deleted) " ) ! = NULL ) {
xSnprintf ( buffer , n , " %-25s " , " main thread terminated " ) ;
attr = CRT_colors [ PROCESS_SHADOW ] ;
} else {
xSnprintf ( buffer , n , " %-25.25s " , lp - > cwd ) ;
}
break ;
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
}
RichString_append ( str , attr , buffer ) ;
}
2020-11-04 16:46:14 +00:00
static long LinuxProcess_compare ( const void * v1 , const void * v2 ) {
2020-09-23 12:15:51 +00:00
const LinuxProcess * p1 , * p2 ;
const Settings * settings = ( ( const Process * ) v1 ) - > settings ;
2020-11-04 16:46:24 +00:00
2015-01-22 01:27:31 +00:00
if ( settings - > direction = = 1 ) {
2020-09-23 12:15:51 +00:00
p1 = ( const LinuxProcess * ) v1 ;
p2 = ( const LinuxProcess * ) v2 ;
2014-11-24 20:55:49 +00:00
} else {
2020-09-23 12:15:51 +00:00
p2 = ( const LinuxProcess * ) v1 ;
p1 = ( const LinuxProcess * ) v2 ;
2014-11-24 20:55:49 +00:00
}
2020-11-04 16:46:24 +00:00
2015-03-16 04:43:04 +00:00
switch ( ( int ) settings - > sortKey ) {
case M_DRS :
2020-11-04 16:46:24 +00:00
return SPACESHIP_NUMBER ( p2 - > m_drs , p1 - > m_drs ) ;
2015-03-16 04:43:04 +00:00
case M_DT :
2020-11-04 16:46:24 +00:00
return SPACESHIP_NUMBER ( p2 - > m_dt , p1 - > m_dt ) ;
2015-03-16 04:43:04 +00:00
case M_LRS :
2020-11-04 16:46:24 +00:00
return SPACESHIP_NUMBER ( p2 - > m_lrs , p1 - > m_lrs ) ;
2015-03-16 04:43:04 +00:00
case M_TRS :
2020-11-04 16:46:24 +00:00
return SPACESHIP_NUMBER ( p2 - > m_trs , p1 - > m_trs ) ;
2015-03-16 04:43:04 +00:00
case M_SHARE :
2020-11-04 16:46:24 +00:00
return SPACESHIP_NUMBER ( p2 - > m_share , p1 - > m_share ) ;
2018-10-09 19:49:29 +00:00
case M_PSS :
2020-11-04 16:46:24 +00:00
return SPACESHIP_NUMBER ( p2 - > m_pss , p1 - > m_pss ) ;
2018-10-09 19:49:29 +00:00
case M_SWAP :
2020-11-04 16:46:24 +00:00
return SPACESHIP_NUMBER ( p2 - > m_swap , p1 - > m_swap ) ;
2018-10-09 19:49:29 +00:00
case M_PSSWP :
2020-11-04 16:46:24 +00:00
return SPACESHIP_NUMBER ( p2 - > m_psswp , p1 - > m_psswp ) ;
case UTIME :
return SPACESHIP_NUMBER ( p2 - > utime , p1 - > utime ) ;
case CUTIME :
return SPACESHIP_NUMBER ( p2 - > cutime , p1 - > cutime ) ;
case STIME :
return SPACESHIP_NUMBER ( p2 - > stime , p1 - > stime ) ;
case CSTIME :
return SPACESHIP_NUMBER ( p2 - > cstime , p1 - > cstime ) ;
case RCHAR :
return SPACESHIP_NUMBER ( p2 - > io_rchar , p1 - > io_rchar ) ;
case WCHAR :
return SPACESHIP_NUMBER ( p2 - > io_wchar , p1 - > io_wchar ) ;
case SYSCR :
return SPACESHIP_NUMBER ( p2 - > io_syscr , p1 - > io_syscr ) ;
case SYSCW :
return SPACESHIP_NUMBER ( p2 - > io_syscw , p1 - > io_syscw ) ;
case RBYTES :
return SPACESHIP_NUMBER ( p2 - > io_read_bytes , p1 - > io_read_bytes ) ;
case WBYTES :
return SPACESHIP_NUMBER ( p2 - > io_write_bytes , p1 - > io_write_bytes ) ;
case CNCLWB :
return SPACESHIP_NUMBER ( p2 - > io_cancelled_write_bytes , p1 - > io_cancelled_write_bytes ) ;
case IO_READ_RATE :
return SPACESHIP_NUMBER ( p2 - > io_rate_read_bps , p1 - > io_rate_read_bps ) ;
case IO_WRITE_RATE :
return SPACESHIP_NUMBER ( p2 - > io_rate_write_bps , p1 - > io_rate_write_bps ) ;
case IO_RATE :
return SPACESHIP_NUMBER ( p2 - > io_rate_read_bps + p2 - > io_rate_write_bps , p1 - > io_rate_read_bps + p1 - > 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 :
2020-11-04 16:46:24 +00:00
return SPACESHIP_NUMBER ( p2 - > vpid , p1 - > vpid ) ;
2015-03-16 04:43:04 +00:00
# endif
# ifdef HAVE_VSERVER
case VXID :
2020-11-04 16:46:24 +00:00
return SPACESHIP_NUMBER ( p2 - > vxid , p1 - > 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 :
2020-11-04 16:46:24 +00:00
return SPACESHIP_NUMBER ( p2 - > oom , p1 - > oom ) ;
2017-12-04 02:15:29 +00:00
# ifdef HAVE_DELAYACCT
case PERCENT_CPU_DELAY :
2020-11-04 16:46:24 +00:00
return SPACESHIP_NUMBER ( p2 - > cpu_delay_percent , p1 - > cpu_delay_percent ) ;
2017-12-04 02:15:29 +00:00
case PERCENT_IO_DELAY :
2020-11-04 16:46:24 +00:00
return SPACESHIP_NUMBER ( p2 - > blkio_delay_percent , p1 - > blkio_delay_percent ) ;
2017-12-04 02:15:29 +00:00
case PERCENT_SWAP_DELAY :
2020-11-04 16:46:24 +00:00
return SPACESHIP_NUMBER ( p2 - > swapin_delay_percent , p1 - > 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 :
2020-11-04 16:46:24 +00:00
return SPACESHIP_NUMBER ( p2 - > ctxt_diff , p1 - > 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 :
2015-04-01 02:23:10 +00:00
return Process_compare ( v1 , v2 ) ;
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 ,
. compare = LinuxProcess_compare
} ,
2020-10-17 10:54:45 +00:00
. writeField = LinuxProcess_writeField ,
. getCommandStr = LinuxProcess_getCommandStr
2020-11-04 16:46:14 +00:00
} ;