blob: f0fc67fa6949af2d3d8eeab56bd3119ea9ff7caf [file] [log] [blame]
Hisham Muhammadd6231ba2006-03-04 18:16:49 +00001/*
2htop - Process.c
Hisham Muhammadb1b3f572015-03-21 16:52:54 -03003(C) 2004-2015 Hisham H. Muhammad
Nathan Scott500fb282020-08-20 09:35:24 +10004(C) 2020 Red Hat, Inc. All Rights Reserved.
Daniel Lange94ad1112021-09-22 11:33:00 +02005Released under the GNU GPLv2+, see the COPYING file
Hisham Muhammadd6231ba2006-03-04 18:16:49 +00006in the source distribution for its full text.
7*/
8
Benny Baumann0f526292020-09-19 13:55:23 +02009#include "config.h" // IWYU pragma: keep
Hisham Muhammad272e2d92015-03-16 23:01:48 -030010
Benny Baumann0f526292020-09-19 13:55:23 +020011#include "Process.h"
12
13#include <assert.h>
14#include <limits.h>
15#include <math.h>
16#include <signal.h>
17#include <stdbool.h>
18#include <stdio.h>
19#include <stdlib.h>
mayurdahibhate1b74dfe2021-04-29 20:42:43 +053020#include <string.h>
Benny Baumann0f526292020-09-19 13:55:23 +020021#include <time.h>
22#include <unistd.h>
23#include <sys/resource.h>
Explorer0935129712018-12-30 12:18:27 +080024
Hisham Muhammadd6231ba2006-03-04 18:16:49 +000025#include "CRT.h"
Christian Göttsche7cf52772020-11-18 14:26:30 +010026#include "Macros.h"
Hisham Muhammadb4f6b112014-11-27 20:10:23 -020027#include "Platform.h"
Christian Göttsche7cf52772020-11-18 14:26:30 +010028#include "ProcessList.h"
Sohaib Mohamed6f2021f2021-07-11 03:11:29 +020029#include "DynamicColumn.h"
Benny Baumann0f526292020-09-19 13:55:23 +020030#include "RichString.h"
31#include "Settings.h"
Benny Baumann872e5422020-10-14 20:21:09 +020032#include "XUtils.h"
Hisham Muhammadd6231ba2006-03-04 18:16:49 +000033
Benny Baumann0f526292020-09-19 13:55:23 +020034#if defined(MAJOR_IN_MKDEV)
Kang-Che Sung (宋岡哲)c01f40e2018-02-26 21:15:05 +080035#include <sys/mkdev.h>
Kang-Che Sung (宋岡哲)c01f40e2018-02-26 21:15:05 +080036#endif
Hisham Muhammadd6231ba2006-03-04 18:16:49 +000037
Benny Baumann0f526292020-09-19 13:55:23 +020038
Benny Baumannaa8552b2021-04-18 19:25:56 +020039/* Used to identify kernel threads in Comm and Exe columns */
Benny Baumann976c6122021-07-14 19:24:18 +020040static const char* const kthreadID = "KTHREAD";
Benny Baumannaa8552b2021-04-18 19:25:56 +020041
Christian Göttsche42073ba2020-11-04 17:46:04 +010042static uid_t Process_getuid = (uid_t)-1;
Hisham Muhammadeb2803c2006-07-12 01:35:59 +000043
Christian Göttsche9f68c8d2020-12-15 19:44:52 +010044int Process_pidDigits = 7;
Hisham Muhammad94280102015-08-20 00:32:47 -030045
46void Process_setupColumnWidths() {
47 int maxPid = Platform_getMaxPid();
Benny Baumann45869512020-11-01 01:09:51 +010048 if (maxPid == -1)
49 return;
50
Christian Göttsche9f68c8d2020-12-15 19:44:52 +010051 Process_pidDigits = ceil(log10(maxPid));
52 assert(Process_pidDigits <= PROCESS_MAX_PID_DIGITS);
Hisham Muhammad94280102015-08-20 00:32:47 -030053}
54
Christian Göttscheb41e4d92021-04-14 20:16:16 +020055void Process_printBytes(RichString* str, unsigned long long number, bool coloring) {
56 char buffer[16];
Hisham Muhammadd6231ba2006-03-04 18:16:49 +000057 int len;
Daniel Flanagandd334442019-10-31 11:39:12 -050058
Christian Göttschefdaa15b2021-01-27 15:11:48 +010059 int largeNumberColor = coloring ? CRT_colors[LARGE_NUMBER] : CRT_colors[PROCESS];
60 int processMegabytesColor = coloring ? CRT_colors[PROCESS_MEGABYTES] : CRT_colors[PROCESS];
61 int processGigabytesColor = coloring ? CRT_colors[PROCESS_GIGABYTES] : CRT_colors[PROCESS];
62 int shadowColor = coloring ? CRT_colors[PROCESS_SHADOW] : CRT_colors[PROCESS];
Hisham Muhammada939cdf2014-04-24 15:00:09 -030063 int processColor = CRT_colors[PROCESS];
Daniel Flanagandd334442019-10-31 11:39:12 -050064
Christian Göttschefdaa15b2021-01-27 15:11:48 +010065 if (number == ULLONG_MAX) {
66 //Invalid number
67 RichString_appendAscii(str, shadowColor, " N/A ");
Christian Göttscheb41e4d92021-04-14 20:16:16 +020068 return;
69 }
70
71 number /= ONE_K;
72
73 if (number < 1000) {
Benny Baumann40441dc2020-09-13 23:50:24 +020074 //Plain number, no markings
Daniel Lange7899ae22020-11-28 17:57:51 +010075 len = xSnprintf(buffer, sizeof(buffer), "%5llu ", number);
Christian Göttsche157086e2020-12-04 14:44:57 +010076 RichString_appendnAscii(str, processColor, buffer, len);
Benny Baumann40441dc2020-09-13 23:50:24 +020077 } else if (number < 100000) {
78 //2 digit MB, 3 digit KB
Benny Baumann0d85af22021-07-14 19:18:27 +020079 len = xSnprintf(buffer, sizeof(buffer), "%2llu", number / 1000);
Christian Göttsche157086e2020-12-04 14:44:57 +010080 RichString_appendnAscii(str, processMegabytesColor, buffer, len);
Hisham Muhammadd6231ba2006-03-04 18:16:49 +000081 number %= 1000;
Daniel Lange7899ae22020-11-28 17:57:51 +010082 len = xSnprintf(buffer, sizeof(buffer), "%03llu ", number);
Christian Göttsche157086e2020-12-04 14:44:57 +010083 RichString_appendnAscii(str, processColor, buffer, len);
Benny Baumann40441dc2020-09-13 23:50:24 +020084 } else if (number < 1000 * ONE_K) {
85 //3 digit MB
86 number /= ONE_K;
Daniel Lange7899ae22020-11-28 17:57:51 +010087 len = xSnprintf(buffer, sizeof(buffer), "%4lluM ", number);
Christian Göttsche157086e2020-12-04 14:44:57 +010088 RichString_appendnAscii(str, processMegabytesColor, buffer, len);
Benny Baumann40441dc2020-09-13 23:50:24 +020089 } else if (number < 10000 * ONE_K) {
90 //1 digit GB, 3 digit MB
91 number /= ONE_K;
Benny Baumann0d85af22021-07-14 19:18:27 +020092 len = xSnprintf(buffer, sizeof(buffer), "%1llu", number / 1000);
Christian Göttsche157086e2020-12-04 14:44:57 +010093 RichString_appendnAscii(str, processGigabytesColor, buffer, len);
Benny Baumann40441dc2020-09-13 23:50:24 +020094 number %= 1000;
Daniel Lange7899ae22020-11-28 17:57:51 +010095 len = xSnprintf(buffer, sizeof(buffer), "%03lluM ", number);
Christian Göttsche157086e2020-12-04 14:44:57 +010096 RichString_appendnAscii(str, processMegabytesColor, buffer, len);
Benny Baumanne0e59972020-09-20 19:54:53 +020097 } else if (number < 100000 * ONE_K) {
Benny Baumann40441dc2020-09-13 23:50:24 +020098 //2 digit GB, 1 digit MB
99 number /= 100 * ONE_K;
Benny Baumann0d85af22021-07-14 19:18:27 +0200100 len = xSnprintf(buffer, sizeof(buffer), "%2llu", number / 10);
Christian Göttsche157086e2020-12-04 14:44:57 +0100101 RichString_appendnAscii(str, processGigabytesColor, buffer, len);
Benny Baumann40441dc2020-09-13 23:50:24 +0200102 number %= 10;
Christian Göttschecd305b42020-11-29 14:14:46 +0100103 len = xSnprintf(buffer, sizeof(buffer), ".%1llu", number);
Christian Göttsche157086e2020-12-04 14:44:57 +0100104 RichString_appendnAscii(str, processMegabytesColor, buffer, len);
105 RichString_appendAscii(str, processGigabytesColor, "G ");
Benny Baumann40441dc2020-09-13 23:50:24 +0200106 } else if (number < 1000 * ONE_M) {
107 //3 digit GB
108 number /= ONE_M;
Daniel Lange7899ae22020-11-28 17:57:51 +0100109 len = xSnprintf(buffer, sizeof(buffer), "%4lluG ", number);
Christian Göttsche157086e2020-12-04 14:44:57 +0100110 RichString_appendnAscii(str, processGigabytesColor, buffer, len);
Michael Wittenab3171d2020-09-29 14:04:22 +0000111 } else if (number < 10000ULL * ONE_M) {
Benny Baumann40441dc2020-09-13 23:50:24 +0200112 //1 digit TB, 3 digit GB
113 number /= ONE_M;
Benny Baumann0d85af22021-07-14 19:18:27 +0200114 len = xSnprintf(buffer, sizeof(buffer), "%1llu", number / 1000);
Christian Göttsche157086e2020-12-04 14:44:57 +0100115 RichString_appendnAscii(str, largeNumberColor, buffer, len);
Benny Baumann40441dc2020-09-13 23:50:24 +0200116 number %= 1000;
Daniel Lange7899ae22020-11-28 17:57:51 +0100117 len = xSnprintf(buffer, sizeof(buffer), "%03lluG ", number);
Christian Göttsche157086e2020-12-04 14:44:57 +0100118 RichString_appendnAscii(str, processGigabytesColor, buffer, len);
Christian Göttscheb41e4d92021-04-14 20:16:16 +0200119 } else if (number < 100000 * ONE_M) {
120 //2 digit TB, 1 digit GB
121 number /= 100 * ONE_M;
Benny Baumann0d85af22021-07-14 19:18:27 +0200122 len = xSnprintf(buffer, sizeof(buffer), "%2llu", number / 10);
Christian Göttscheb41e4d92021-04-14 20:16:16 +0200123 RichString_appendnAscii(str, largeNumberColor, buffer, len);
124 number %= 10;
125 len = xSnprintf(buffer, sizeof(buffer), ".%1llu", number);
126 RichString_appendnAscii(str, processGigabytesColor, buffer, len);
127 RichString_appendAscii(str, largeNumberColor, "T ");
128 } else if (number < 10000ULL * ONE_G) {
129 //3 digit TB or 1 digit PB, 3 digit TB
130 number /= ONE_G;
131 len = xSnprintf(buffer, sizeof(buffer), "%4lluT ", number);
132 RichString_appendnAscii(str, largeNumberColor, buffer, len);
Benny Baumann40441dc2020-09-13 23:50:24 +0200133 } else {
Christian Göttscheb41e4d92021-04-14 20:16:16 +0200134 //2 digit PB and above
Benny Baumann0d85af22021-07-14 19:18:27 +0200135 len = xSnprintf(buffer, sizeof(buffer), "%4.1lfP ", (double)number / ONE_T);
Christian Göttsche157086e2020-12-04 14:44:57 +0100136 RichString_appendnAscii(str, largeNumberColor, buffer, len);
Hisham Muhammadd6231ba2006-03-04 18:16:49 +0000137 }
138}
139
Christian Göttscheb41e4d92021-04-14 20:16:16 +0200140void Process_printKBytes(RichString* str, unsigned long long number, bool coloring) {
141 if (number == ULLONG_MAX)
142 Process_printBytes(str, ULLONG_MAX, coloring);
143 else
144 Process_printBytes(str, number * ONE_K, coloring);
145}
146
147void Process_printCount(RichString* str, unsigned long long number, bool coloring) {
Daniel Lange7899ae22020-11-28 17:57:51 +0100148 char buffer[13];
Hisham Muhammada939cdf2014-04-24 15:00:09 -0300149
Christian Göttschefee744a2021-01-27 15:11:46 +0100150 int largeNumberColor = coloring ? CRT_colors[LARGE_NUMBER] : CRT_colors[PROCESS];
151 int processMegabytesColor = coloring ? CRT_colors[PROCESS_MEGABYTES] : CRT_colors[PROCESS];
Hisham Muhammada939cdf2014-04-24 15:00:09 -0300152 int processColor = CRT_colors[PROCESS];
Christian Göttschefee744a2021-01-27 15:11:46 +0100153 int processShadowColor = coloring ? CRT_colors[PROCESS_SHADOW] : CRT_colors[PROCESS];
Hisham Muhammada939cdf2014-04-24 15:00:09 -0300154
Michael Wittenab3171d2020-09-29 14:04:22 +0000155 if (number == ULLONG_MAX) {
Christian Göttsche157086e2020-12-04 14:44:57 +0100156 RichString_appendAscii(str, CRT_colors[PROCESS_SHADOW], " N/A ");
adrien1018536941f2018-12-30 20:18:35 +0800157 } else if (number >= 100000LL * ONE_DECIMAL_T) {
Benny Baumann0b29e502020-11-28 17:42:02 +0100158 xSnprintf(buffer, sizeof(buffer), "%11llu ", number / ONE_DECIMAL_G);
Christian Göttsche157086e2020-12-04 14:44:57 +0100159 RichString_appendnAscii(str, largeNumberColor, buffer, 12);
adrien1018536941f2018-12-30 20:18:35 +0800160 } else if (number >= 100LL * ONE_DECIMAL_T) {
Benny Baumann0b29e502020-11-28 17:42:02 +0100161 xSnprintf(buffer, sizeof(buffer), "%11llu ", number / ONE_DECIMAL_M);
Christian Göttsche157086e2020-12-04 14:44:57 +0100162 RichString_appendnAscii(str, largeNumberColor, buffer, 8);
Benny Baumann0d85af22021-07-14 19:18:27 +0200163 RichString_appendnAscii(str, processMegabytesColor, buffer + 8, 4);
adrien1018536941f2018-12-30 20:18:35 +0800164 } else if (number >= 10LL * ONE_DECIMAL_G) {
Benny Baumann0b29e502020-11-28 17:42:02 +0100165 xSnprintf(buffer, sizeof(buffer), "%11llu ", number / ONE_DECIMAL_K);
Christian Göttsche157086e2020-12-04 14:44:57 +0100166 RichString_appendnAscii(str, largeNumberColor, buffer, 5);
Benny Baumann0d85af22021-07-14 19:18:27 +0200167 RichString_appendnAscii(str, processMegabytesColor, buffer + 5, 3);
168 RichString_appendnAscii(str, processColor, buffer + 8, 4);
Hisham Muhammad9b351402011-05-26 16:31:18 +0000169 } else {
Benny Baumann0b29e502020-11-28 17:42:02 +0100170 xSnprintf(buffer, sizeof(buffer), "%11llu ", number);
Christian Göttsche157086e2020-12-04 14:44:57 +0100171 RichString_appendnAscii(str, largeNumberColor, buffer, 2);
Benny Baumann0d85af22021-07-14 19:18:27 +0200172 RichString_appendnAscii(str, processMegabytesColor, buffer + 2, 3);
173 RichString_appendnAscii(str, processColor, buffer + 5, 3);
174 RichString_appendnAscii(str, processShadowColor, buffer + 8, 4);
Hisham Muhammad9b351402011-05-26 16:31:18 +0000175 }
176}
177
Christian Göttscheb41e4d92021-04-14 20:16:16 +0200178void Process_printTime(RichString* str, unsigned long long totalHundredths, bool coloring) {
179 char buffer[10];
180 int len;
Hisham Muhammadd6231ba2006-03-04 18:16:49 +0000181
Christian Göttscheb41e4d92021-04-14 20:16:16 +0200182 unsigned long long totalSeconds = totalHundredths / 100;
Hisham Muhammad272e2d92015-03-16 23:01:48 -0300183 unsigned long long hours = totalSeconds / 3600;
David Zarzyckif3d9eca2021-04-10 08:02:59 -0400184 unsigned long long days = totalSeconds / 86400;
Hisham Muhammad272e2d92015-03-16 23:01:48 -0300185 int minutes = (totalSeconds / 60) % 60;
186 int seconds = totalSeconds % 60;
187 int hundredths = totalHundredths - (totalSeconds * 100);
Christian Göttscheb41e4d92021-04-14 20:16:16 +0200188
189 int yearColor = coloring ? CRT_colors[LARGE_NUMBER] : CRT_colors[PROCESS];
190 int dayColor = coloring ? CRT_colors[PROCESS_GIGABYTES] : CRT_colors[PROCESS];
191 int hourColor = coloring ? CRT_colors[PROCESS_MEGABYTES] : CRT_colors[PROCESS];
192 int defColor = CRT_colors[PROCESS];
193
194 if (days >= /* Ignore leapyears */365) {
195 int years = days / 365;
196 int daysLeft = days - 365 * years;
197
198 if (daysLeft >= 100) {
199 len = xSnprintf(buffer, sizeof(buffer), "%3dy", years);
200 RichString_appendnAscii(str, yearColor, buffer, len);
201 len = xSnprintf(buffer, sizeof(buffer), "%3dd ", daysLeft);
202 RichString_appendnAscii(str, dayColor, buffer, len);
203 } else if (daysLeft >= 10) {
204 len = xSnprintf(buffer, sizeof(buffer), "%4dy", years);
205 RichString_appendnAscii(str, yearColor, buffer, len);
206 len = xSnprintf(buffer, sizeof(buffer), "%2dd ", daysLeft);
207 RichString_appendnAscii(str, dayColor, buffer, len);
Hisham Muhammad9c44f582011-12-14 23:29:07 +0000208 } else {
Christian Göttscheb41e4d92021-04-14 20:16:16 +0200209 len = xSnprintf(buffer, sizeof(buffer), "%5dy", years);
210 RichString_appendnAscii(str, yearColor, buffer, len);
211 len = xSnprintf(buffer, sizeof(buffer), "%1dd ", daysLeft);
212 RichString_appendnAscii(str, dayColor, buffer, len);
Hisham Muhammad9c44f582011-12-14 23:29:07 +0000213 }
Christian Göttscheb41e4d92021-04-14 20:16:16 +0200214 } else if (days >= 100) {
215 int hoursLeft = hours - days * 24;
216
217 if (hoursLeft >= 10) {
218 len = xSnprintf(buffer, sizeof(buffer), "%4llud", days);
219 RichString_appendnAscii(str, dayColor, buffer, len);
220 len = xSnprintf(buffer, sizeof(buffer), "%2dh ", hoursLeft);
221 RichString_appendnAscii(str, hourColor, buffer, len);
222 } else {
223 len = xSnprintf(buffer, sizeof(buffer), "%5llud", days);
224 RichString_appendnAscii(str, dayColor, buffer, len);
225 len = xSnprintf(buffer, sizeof(buffer), "%1dh ", hoursLeft);
226 RichString_appendnAscii(str, hourColor, buffer, len);
227 }
228 } else if (hours >= 100) {
229 int minutesLeft = totalSeconds / 60 - hours * 60;
230
231 if (minutesLeft >= 10) {
232 len = xSnprintf(buffer, sizeof(buffer), "%4lluh", hours);
233 RichString_appendnAscii(str, hourColor, buffer, len);
234 len = xSnprintf(buffer, sizeof(buffer), "%2dm ", minutesLeft);
235 RichString_appendnAscii(str, defColor, buffer, len);
236 } else {
237 len = xSnprintf(buffer, sizeof(buffer), "%5lluh", hours);
238 RichString_appendnAscii(str, hourColor, buffer, len);
239 len = xSnprintf(buffer, sizeof(buffer), "%1dm ", minutesLeft);
240 RichString_appendnAscii(str, defColor, buffer, len);
241 }
242 } else if (hours > 0) {
243 len = xSnprintf(buffer, sizeof(buffer), "%2lluh", hours);
244 RichString_appendnAscii(str, hourColor, buffer, len);
245 len = xSnprintf(buffer, sizeof(buffer), "%02d:%02d ", minutes, seconds);
246 RichString_appendnAscii(str, defColor, buffer, len);
247 } else {
248 len = xSnprintf(buffer, sizeof(buffer), "%2d:%02d.%02d ", minutes, seconds, hundredths);
249 RichString_appendnAscii(str, defColor, buffer, len);
Hisham Muhammadd6231ba2006-03-04 18:16:49 +0000250 }
Hisham Muhammadd6231ba2006-03-04 18:16:49 +0000251}
252
Christian Göttschea63cfc82020-10-13 14:26:40 +0200253void Process_fillStarttimeBuffer(Process* this) {
254 struct tm date;
255 (void) localtime_r(&this->starttime_ctime, &date);
256 strftime(this->starttime_show, sizeof(this->starttime_show) - 1, (this->starttime_ctime > (time(NULL) - 86400)) ? "%R " : "%b%d ", &date);
257}
258
Benny Baumannbcb18ef2021-04-10 13:31:39 +0200259/*
260 * TASK_COMM_LEN is defined to be 16 for /proc/[pid]/comm in man proc(5), but it is
261 * not available in an userspace header - so define it.
262 *
263 * Note: This is taken from LINUX headers, but implicitly taken for other platforms
264 * for sake of brevity.
265 *
266 * Note: when colorizing a basename with the comm prefix, the entire basename
267 * (not just the comm prefix) is colorized for better readability, and it is
268 * implicit that only upto (TASK_COMM_LEN - 1) could be comm.
269 */
270#define TASK_COMM_LEN 16
Tobias Geerinckx-Rice293eec42015-07-29 21:14:29 +0200271
Benny Baumann976c6122021-07-14 19:24:18 +0200272static bool findCommInCmdline(const char* comm, const char* cmdline, int cmdlineBasenameStart, int* pCommStart, int* pCommEnd) {
Benny Baumannbcb18ef2021-04-10 13:31:39 +0200273 /* Try to find procComm in tokenized cmdline - this might in rare cases
274 * mis-identify a string or fail, if comm or cmdline had been unsuitably
275 * modified by the process */
Benny Baumann976c6122021-07-14 19:24:18 +0200276 const char* tokenBase;
Benny Baumannbcb18ef2021-04-10 13:31:39 +0200277 size_t tokenLen;
278 const size_t commLen = strlen(comm);
279
280 if (cmdlineBasenameStart < 0)
281 return false;
282
Benny Baumann976c6122021-07-14 19:24:18 +0200283 for (const char* token = cmdline + cmdlineBasenameStart; *token;) {
Benny Baumannbcb18ef2021-04-10 13:31:39 +0200284 for (tokenBase = token; *token && *token != '\n'; ++token) {
285 if (*token == '/') {
286 tokenBase = token + 1;
Hisham Muhammadf2a190b2014-02-27 17:11:23 -0300287 }
Hisham Muhammadd6231ba2006-03-04 18:16:49 +0000288 }
Benny Baumannbcb18ef2021-04-10 13:31:39 +0200289 tokenLen = token - tokenBase;
290
291 if ((tokenLen == commLen || (tokenLen > commLen && commLen == (TASK_COMM_LEN - 1))) &&
292 strncmp(tokenBase, comm, commLen) == 0) {
293 *pCommStart = tokenBase - cmdline;
294 *pCommEnd = token - cmdline;
295 return true;
296 }
297
298 if (*token) {
299 do {
300 ++token;
301 } while (*token && '\n' == *token);
Tobias Geerinckx-Rice293eec42015-07-29 21:14:29 +0200302 }
Hisham Muhammadd6231ba2006-03-04 18:16:49 +0000303 }
Benny Baumannbcb18ef2021-04-10 13:31:39 +0200304 return false;
305}
Tobias Geerinckx-Rice293eec42015-07-29 21:14:29 +0200306
Benny Baumann976c6122021-07-14 19:24:18 +0200307static int matchCmdlinePrefixWithExeSuffix(const char* cmdline, int cmdlineBaseOffset, const char* exe, int exeBaseOffset, int exeBaseLen) {
Benny Baumannbcb18ef2021-04-10 13:31:39 +0200308 int matchLen; /* matching length to be returned */
309 char delim; /* delimiter following basename */
Tobias Geerinckx-Rice293eec42015-07-29 21:14:29 +0200310
Benny Baumannbcb18ef2021-04-10 13:31:39 +0200311 /* cmdline prefix is an absolute path: it must match whole exe. */
312 if (cmdline[0] == '/') {
313 matchLen = exeBaseLen + exeBaseOffset;
314 if (strncmp(cmdline, exe, matchLen) == 0) {
315 delim = cmdline[matchLen];
316 if (delim == 0 || delim == '\n' || delim == ' ') {
317 return matchLen;
318 }
319 }
320 return 0;
321 }
322
323 /* cmdline prefix is a relative path: We need to first match the basename at
324 * cmdlineBaseOffset and then reverse match the cmdline prefix with the exe
325 * suffix. But there is a catch: Some processes modify their cmdline in ways
326 * that make htop's identification of the basename in cmdline unreliable.
327 * For e.g. /usr/libexec/gdm-session-worker modifies its cmdline to
328 * "gdm-session-worker [pam/gdm-autologin]" and htop ends up with
329 * proccmdlineBasenameEnd at "gdm-autologin]". This issue could arise with
330 * chrome as well as it stores in cmdline its concatenated argument vector,
331 * without NUL delimiter between the arguments (which may contain a '/')
332 *
333 * So if needed, we adjust cmdlineBaseOffset to the previous (if any)
334 * component of the cmdline relative path, and retry the procedure. */
335 bool delimFound; /* if valid basename delimiter found */
336 do {
337 /* match basename */
338 matchLen = exeBaseLen + cmdlineBaseOffset;
339 if (cmdlineBaseOffset < exeBaseOffset &&
340 strncmp(cmdline + cmdlineBaseOffset, exe + exeBaseOffset, exeBaseLen) == 0) {
341 delim = cmdline[matchLen];
342 if (delim == 0 || delim == '\n' || delim == ' ') {
343 int i, j;
344 /* reverse match the cmdline prefix and exe suffix */
345 for (i = cmdlineBaseOffset - 1, j = exeBaseOffset - 1;
346 i >= 0 && j >= 0 && cmdline[i] == exe[j]; --i, --j)
347 ;
348
349 /* full match, with exe suffix being a valid relative path */
350 if (i < 0 && j >= 0 && exe[j] == '/')
351 return matchLen;
352 }
353 }
354
355 /* Try to find the previous potential cmdlineBaseOffset - it would be
356 * preceded by '/' or nothing, and delimited by ' ' or '\n' */
357 for (delimFound = false, cmdlineBaseOffset -= 2; cmdlineBaseOffset > 0; --cmdlineBaseOffset) {
358 if (delimFound) {
359 if (cmdline[cmdlineBaseOffset - 1] == '/') {
360 break;
361 }
362 } else if (cmdline[cmdlineBaseOffset] == ' ' || cmdline[cmdlineBaseOffset] == '\n') {
363 delimFound = true;
364 }
365 }
366 } while (delimFound);
367
368 return 0;
369}
370
371/* stpcpy, but also converts newlines to spaces */
Benny Baumann976c6122021-07-14 19:24:18 +0200372static inline char* stpcpyWithNewlineConversion(char* dstStr, const char* srcStr) {
Benny Baumannbcb18ef2021-04-10 13:31:39 +0200373 for (; *srcStr; ++srcStr) {
374 *dstStr++ = (*srcStr == '\n') ? ' ' : *srcStr;
375 }
376 *dstStr = 0;
377 return dstStr;
378}
379
380/*
381 * This function makes the merged Command string. It also stores the offsets of the
382 * basename, comm w.r.t the merged Command string - these offsets will be used by
383 * Process_writeCommand() for coloring. The merged Command string is also
384 * returned by Process_getCommandStr() for searching, sorting and filtering.
385 */
Benny Baumann976c6122021-07-14 19:24:18 +0200386void Process_makeCommandStr(Process* this) {
387 ProcessMergedCommand* mc = &this->mergedCommand;
388 const Settings* settings = this->settings;
Benny Baumannbcb18ef2021-04-10 13:31:39 +0200389
390 bool showMergedCommand = settings->showMergedCommand;
391 bool showProgramPath = settings->showProgramPath;
392 bool searchCommInCmdline = settings->findCommInCmdline;
393 bool stripExeFromCmdline = settings->stripExeFromCmdline;
Benny Baumann7bfd62b2021-07-17 20:59:50 +0200394 bool showThreadNames = settings->showThreadNames;
Benny Baumannbcb18ef2021-04-10 13:31:39 +0200395
Benny Baumanna61a2e62021-04-18 18:10:04 +0200396 /* Nothing to do to (Re)Generate the Command string, if the process is:
397 * - a kernel thread, or
398 * - a zombie from before being under htop's watch, or
399 * - a user thread and showThreadNames is not set */
400 if (Process_isKernelThread(this))
401 return;
402 if (this->state == 'Z' && !this->mergedCommand.str)
403 return;
Christian Göttschece27f832021-08-08 16:04:26 +0200404 if (Process_isUserlandThread(this) && settings->showThreadNames && (showThreadNames == mc->prevShowThreadNames))
Benny Baumanna61a2e62021-04-18 18:10:04 +0200405 return;
406
Benny Baumannbcb18ef2021-04-10 13:31:39 +0200407 /* this->mergedCommand.str needs updating only if its state or contents changed.
408 * Its content is based on the fields cmdline, comm, and exe. */
409 if (
Benny Baumann458749d2021-07-14 19:15:09 +0200410 mc->prevMergeSet == showMergedCommand &&
411 mc->prevPathSet == showProgramPath &&
412 mc->prevCommSet == searchCommInCmdline &&
413 mc->prevCmdlineSet == stripExeFromCmdline &&
Benny Baumann7bfd62b2021-07-17 20:59:50 +0200414 mc->prevShowThreadNames == showThreadNames &&
Benny Baumann458749d2021-07-14 19:15:09 +0200415 !mc->cmdlineChanged &&
416 !mc->commChanged &&
417 !mc->exeChanged
Benny Baumannbcb18ef2021-04-10 13:31:39 +0200418 ) {
419 return;
420 }
421
422 /* The field separtor "│" has been chosen such that it will not match any
423 * valid string used for searching or filtering */
Benny Baumann976c6122021-07-14 19:24:18 +0200424 const char* SEPARATOR = CRT_treeStr[TREE_STR_VERT];
Benny Baumannbcb18ef2021-04-10 13:31:39 +0200425 const int SEPARATOR_LEN = strlen(SEPARATOR);
426
427 /* Check for any changed fields since we last built this string */
428 if (mc->cmdlineChanged || mc->commChanged || mc->exeChanged) {
429 free(mc->str);
430 /* Accommodate the column text, two field separators and terminating NUL */
Benny Baumann7ef58f22021-05-17 23:15:24 +0200431 size_t maxLen = 2 * SEPARATOR_LEN + 1;
432 maxLen += this->cmdline ? strlen(this->cmdline) : strlen("(zombie)");
433 maxLen += this->procComm ? strlen(this->procComm) : 0;
434 maxLen += this->procExe ? strlen(this->procExe) : 0;
435
436 mc->str = xCalloc(1, maxLen);
Benny Baumannbcb18ef2021-04-10 13:31:39 +0200437 }
438
439 /* Preserve the settings used in this run */
440 mc->prevMergeSet = showMergedCommand;
441 mc->prevPathSet = showProgramPath;
442 mc->prevCommSet = searchCommInCmdline;
443 mc->prevCmdlineSet = stripExeFromCmdline;
Benny Baumann7bfd62b2021-07-17 20:59:50 +0200444 mc->prevShowThreadNames = showThreadNames;
Benny Baumannbcb18ef2021-04-10 13:31:39 +0200445
446 /* Mark everything as unchanged */
447 mc->cmdlineChanged = false;
448 mc->commChanged = false;
449 mc->exeChanged = false;
450
451 /* Reset all locations that need extra handling when actually displaying */
452 mc->highlightCount = 0;
453 memset(mc->highlights, 0, sizeof(mc->highlights));
454
455 size_t mbMismatch = 0;
Benny Baumann9a781552021-05-15 21:54:46 +0200456 #define WRITE_HIGHLIGHT(_offset, _length, _attr, _flags) \
457 do { \
458 /* Check if we still have capacity */ \
459 assert(mc->highlightCount < ARRAYSIZE(mc->highlights)); \
460 if (mc->highlightCount >= ARRAYSIZE(mc->highlights)) \
Christian Göttsche5dec9472021-08-22 17:14:36 +0200461 break; \
Benny Baumann9a781552021-05-15 21:54:46 +0200462 \
463 mc->highlights[mc->highlightCount].offset = str - strStart + (_offset) - mbMismatch; \
464 mc->highlights[mc->highlightCount].length = _length; \
465 mc->highlights[mc->highlightCount].attr = _attr; \
466 mc->highlights[mc->highlightCount].flags = _flags; \
467 mc->highlightCount++; \
Benny Baumannbcb18ef2021-04-10 13:31:39 +0200468 } while (0)
469
Benny Baumann9a781552021-05-15 21:54:46 +0200470 #define WRITE_SEPARATOR \
471 do { \
472 WRITE_HIGHLIGHT(0, 1, CRT_colors[FAILED_READ], CMDLINE_HIGHLIGHT_FLAG_SEPARATOR); \
473 mbMismatch += SEPARATOR_LEN - 1; \
474 str = stpcpy(str, SEPARATOR); \
Benny Baumannbcb18ef2021-04-10 13:31:39 +0200475 } while (0)
476
477 const int baseAttr = Process_isThread(this) ? CRT_colors[PROCESS_THREAD_BASENAME] : CRT_colors[PROCESS_BASENAME];
478 const int commAttr = Process_isThread(this) ? CRT_colors[PROCESS_THREAD_COMM] : CRT_colors[PROCESS_COMM];
Christian Göttsche81541252021-04-04 18:07:26 +0200479 const int delExeAttr = CRT_colors[FAILED_READ];
480 const int delLibAttr = CRT_colors[PROCESS_TAG];
Benny Baumannbcb18ef2021-04-10 13:31:39 +0200481
482 /* Establish some shortcuts to data we need */
Benny Baumann976c6122021-07-14 19:24:18 +0200483 const char* cmdline = this->cmdline;
484 const char* procComm = this->procComm;
485 const char* procExe = this->procExe;
Benny Baumannbcb18ef2021-04-10 13:31:39 +0200486
Benny Baumann976c6122021-07-14 19:24:18 +0200487 char* strStart = mc->str;
488 char* str = strStart;
Benny Baumannbcb18ef2021-04-10 13:31:39 +0200489
490 int cmdlineBasenameStart = this->cmdlineBasenameStart;
491 int cmdlineBasenameEnd = this->cmdlineBasenameEnd;
492
493 if (!cmdline) {
494 cmdlineBasenameStart = 0;
495 cmdlineBasenameEnd = 0;
496 cmdline = "(zombie)";
497 }
498
499 assert(cmdlineBasenameStart >= 0);
500 assert(cmdlineBasenameStart <= (int)strlen(cmdline));
501
502 if (!showMergedCommand || !procExe || !procComm) { /* fall back to cmdline */
Christian Göttschece27f832021-08-08 16:04:26 +0200503 if (showMergedCommand && (!Process_isUserlandThread(this) || showThreadNames) && !procExe && procComm && strlen(procComm)) { /* Prefix column with comm */
Benny Baumannbcb18ef2021-04-10 13:31:39 +0200504 if (strncmp(cmdline + cmdlineBasenameStart, procComm, MINIMUM(TASK_COMM_LEN - 1, strlen(procComm))) != 0) {
505 WRITE_HIGHLIGHT(0, strlen(procComm), commAttr, CMDLINE_HIGHLIGHT_FLAG_COMM);
506 str = stpcpy(str, procComm);
507
508 WRITE_SEPARATOR;
509 }
510 }
511
Benny Baumann2824e292021-05-15 21:55:14 +0200512 if (cmdlineBasenameEnd > cmdlineBasenameStart)
513 WRITE_HIGHLIGHT(showProgramPath ? cmdlineBasenameStart : 0, cmdlineBasenameEnd - cmdlineBasenameStart, baseAttr, CMDLINE_HIGHLIGHT_FLAG_BASENAME);
Benny Baumannb7248f62021-10-06 16:38:45 +0200514
515 if (this->procExeDeleted)
516 WRITE_HIGHLIGHT(showProgramPath ? cmdlineBasenameStart : 0, cmdlineBasenameEnd - cmdlineBasenameStart, delExeAttr, CMDLINE_HIGHLIGHT_FLAG_DELETED);
517 else if (this->usesDeletedLib)
518 WRITE_HIGHLIGHT(showProgramPath ? cmdlineBasenameStart : 0, cmdlineBasenameEnd - cmdlineBasenameStart, delLibAttr, CMDLINE_HIGHLIGHT_FLAG_DELETED);
519
Benny Baumann2824e292021-05-15 21:55:14 +0200520 (void)stpcpyWithNewlineConversion(str, cmdline + (showProgramPath ? 0 : cmdlineBasenameStart));
Benny Baumannbcb18ef2021-04-10 13:31:39 +0200521
522 return;
523 }
524
525 int exeLen = strlen(this->procExe);
526 int exeBasenameOffset = this->procExeBasenameOffset;
527 int exeBasenameLen = exeLen - exeBasenameOffset;
528
529 assert(exeBasenameOffset >= 0);
530 assert(exeBasenameOffset <= (int)strlen(procExe));
531
532 bool haveCommInExe = false;
Christian Göttschece27f832021-08-08 16:04:26 +0200533 if (procExe && procComm && (!Process_isUserlandThread(this) || showThreadNames)) {
Benny Baumannbcb18ef2021-04-10 13:31:39 +0200534 haveCommInExe = strncmp(procExe + exeBasenameOffset, procComm, TASK_COMM_LEN - 1) == 0;
535 }
536
537 /* Start with copying exe */
538 if (showProgramPath) {
539 if (haveCommInExe)
540 WRITE_HIGHLIGHT(exeBasenameOffset, exeBasenameLen, commAttr, CMDLINE_HIGHLIGHT_FLAG_COMM);
541 WRITE_HIGHLIGHT(exeBasenameOffset, exeBasenameLen, baseAttr, CMDLINE_HIGHLIGHT_FLAG_BASENAME);
542 if (this->procExeDeleted)
Christian Göttsche81541252021-04-04 18:07:26 +0200543 WRITE_HIGHLIGHT(exeBasenameOffset, exeBasenameLen, delExeAttr, CMDLINE_HIGHLIGHT_FLAG_DELETED);
544 else if (this->usesDeletedLib)
545 WRITE_HIGHLIGHT(exeBasenameOffset, exeBasenameLen, delLibAttr, CMDLINE_HIGHLIGHT_FLAG_DELETED);
Benny Baumannbcb18ef2021-04-10 13:31:39 +0200546 str = stpcpy(str, procExe);
547 } else {
548 if (haveCommInExe)
549 WRITE_HIGHLIGHT(0, exeBasenameLen, commAttr, CMDLINE_HIGHLIGHT_FLAG_COMM);
550 WRITE_HIGHLIGHT(0, exeBasenameLen, baseAttr, CMDLINE_HIGHLIGHT_FLAG_BASENAME);
551 if (this->procExeDeleted)
Christian Göttsche81541252021-04-04 18:07:26 +0200552 WRITE_HIGHLIGHT(0, exeBasenameLen, delExeAttr, CMDLINE_HIGHLIGHT_FLAG_DELETED);
553 else if (this->usesDeletedLib)
554 WRITE_HIGHLIGHT(0, exeBasenameLen, delLibAttr, CMDLINE_HIGHLIGHT_FLAG_DELETED);
Benny Baumannbcb18ef2021-04-10 13:31:39 +0200555 str = stpcpy(str, procExe + exeBasenameOffset);
556 }
557
558 bool haveCommInCmdline = false;
559 int commStart = 0;
560 int commEnd = 0;
561
562 /* Try to match procComm with procExe's basename: This is reliable (predictable) */
563 if (searchCommInCmdline) {
564 /* commStart/commEnd will be adjusted later along with cmdline */
Christian Göttschece27f832021-08-08 16:04:26 +0200565 haveCommInCmdline = (!Process_isUserlandThread(this) || showThreadNames) && findCommInCmdline(procComm, cmdline, cmdlineBasenameStart, &commStart, &commEnd);
Benny Baumannbcb18ef2021-04-10 13:31:39 +0200566 }
567
568 int matchLen = matchCmdlinePrefixWithExeSuffix(cmdline, cmdlineBasenameStart, procExe, exeBasenameOffset, exeBasenameLen);
569
570 bool haveCommField = false;
571
Christian Göttschece27f832021-08-08 16:04:26 +0200572 if (!haveCommInExe && !haveCommInCmdline && procComm && (!Process_isUserlandThread(this) || showThreadNames)) {
Benny Baumannbcb18ef2021-04-10 13:31:39 +0200573 WRITE_SEPARATOR;
574 WRITE_HIGHLIGHT(0, strlen(procComm), commAttr, CMDLINE_HIGHLIGHT_FLAG_COMM);
575 str = stpcpy(str, procComm);
576 haveCommField = true;
577 }
578
579 if (matchLen) {
580 /* strip the matched exe prefix */
581 cmdline += matchLen;
582
583 commStart -= matchLen;
584 commEnd -= matchLen;
585 }
586
587 if (!matchLen || (haveCommField && *cmdline)) {
588 /* cmdline will be a separate field */
589 WRITE_SEPARATOR;
590 }
591
Christian Göttschece27f832021-08-08 16:04:26 +0200592 if (!haveCommInExe && haveCommInCmdline && !haveCommField && (!Process_isUserlandThread(this) || showThreadNames))
Benny Baumannbcb18ef2021-04-10 13:31:39 +0200593 WRITE_HIGHLIGHT(commStart, commEnd - commStart, commAttr, CMDLINE_HIGHLIGHT_FLAG_COMM);
594
595 /* Display cmdline if it hasn't been consumed by procExe */
596 if (*cmdline)
597 (void)stpcpyWithNewlineConversion(str, cmdline);
598
599 #undef WRITE_SEPARATOR
600 #undef WRITE_HIGHLIGHT
601}
602
603void Process_writeCommand(const Process* this, int attr, int baseAttr, RichString* str) {
604 (void)baseAttr;
605
Benny Baumann976c6122021-07-14 19:24:18 +0200606 const ProcessMergedCommand* mc = &this->mergedCommand;
Benny Baumannbcb18ef2021-04-10 13:31:39 +0200607
608 int strStart = RichString_size(str);
609
610 const bool highlightBaseName = this->settings->highlightBaseName;
611 const bool highlightSeparator = true;
Benny Baumannbf07c712020-12-19 16:46:00 +0100612 const bool highlightDeleted = this->settings->highlightDeletedExe;
Benny Baumannbcb18ef2021-04-10 13:31:39 +0200613
614 if (!this->mergedCommand.str) {
615 int len = 0;
616 const char* cmdline = this->cmdline;
617
618 if (highlightBaseName || !this->settings->showProgramPath) {
619 int basename = 0;
620 for (int i = 0; i < this->cmdlineBasenameEnd; i++) {
621 if (cmdline[i] == '/') {
622 basename = i + 1;
623 } else if (cmdline[i] == ':') {
624 len = i + 1;
625 break;
626 }
627 }
628 if (len == 0) {
629 if (this->settings->showProgramPath) {
630 strStart += basename;
631 } else {
632 cmdline += basename;
633 }
634 len = this->cmdlineBasenameEnd - basename;
635 }
636 }
637
638 RichString_appendWide(str, attr, cmdline);
639
640 if (this->settings->highlightBaseName) {
641 RichString_setAttrn(str, baseAttr, strStart, len);
642 }
643
644 return;
645 }
646
647 RichString_appendWide(str, attr, this->mergedCommand.str);
648
649 for (size_t i = 0, hlCount = CLAMP(mc->highlightCount, 0, ARRAYSIZE(mc->highlights)); i < hlCount; i++) {
Benny Baumann976c6122021-07-14 19:24:18 +0200650 const ProcessCmdlineHighlight* hl = &mc->highlights[i];
Benny Baumannbcb18ef2021-04-10 13:31:39 +0200651
652 if (!hl->length)
653 continue;
654
655 if (hl->flags & CMDLINE_HIGHLIGHT_FLAG_SEPARATOR)
656 if (!highlightSeparator)
657 continue;
658
659 if (hl->flags & CMDLINE_HIGHLIGHT_FLAG_BASENAME)
660 if (!highlightBaseName)
661 continue;
662
663 if (hl->flags & CMDLINE_HIGHLIGHT_FLAG_DELETED)
664 if (!highlightDeleted)
665 continue;
666
667 RichString_setAttrn(str, hl->attr, strStart + hl->offset, hl->length);
Benny Baumann45869512020-11-01 01:09:51 +0100668 }
Hisham Muhammadd6231ba2006-03-04 18:16:49 +0000669}
670
Christian Göttscheb41e4d92021-04-14 20:16:16 +0200671void Process_printRate(RichString* str, double rate, bool coloring) {
672 char buffer[16];
673
Hisham Muhammad3383d8e2015-01-21 23:27:31 -0200674 int largeNumberColor = CRT_colors[LARGE_NUMBER];
675 int processMegabytesColor = CRT_colors[PROCESS_MEGABYTES];
676 int processColor = CRT_colors[PROCESS];
Christian Göttscheb41e4d92021-04-14 20:16:16 +0200677 int shadowColor = CRT_colors[PROCESS_SHADOW];
Benny Baumann0b29e502020-11-28 17:42:02 +0100678
Hisham Muhammad3383d8e2015-01-21 23:27:31 -0200679 if (!coloring) {
680 largeNumberColor = CRT_colors[PROCESS];
681 processMegabytesColor = CRT_colors[PROCESS];
Hisham Muhammad2338ad52008-03-14 18:50:49 +0000682 }
Benny Baumann0b29e502020-11-28 17:42:02 +0100683
Benny Baumann29ec1152020-09-07 11:53:58 +0200684 if (isnan(rate)) {
Christian Göttscheb41e4d92021-04-14 20:16:16 +0200685 RichString_appendAscii(str, shadowColor, " N/A ");
686 } else if (rate < 0.005) {
687 int len = snprintf(buffer, sizeof(buffer), "%7.2f B/s ", rate);
688 RichString_appendnAscii(str, shadowColor, buffer, len);
Hisham797bcd02016-02-20 02:22:57 -0200689 } else if (rate < ONE_K) {
Christian Göttscheb41e4d92021-04-14 20:16:16 +0200690 int len = snprintf(buffer, sizeof(buffer), "%7.2f B/s ", rate);
Christian Göttsche157086e2020-12-04 14:44:57 +0100691 RichString_appendnAscii(str, processColor, buffer, len);
adrien1018536941f2018-12-30 20:18:35 +0800692 } else if (rate < ONE_M) {
Christian Göttscheb41e4d92021-04-14 20:16:16 +0200693 int len = snprintf(buffer, sizeof(buffer), "%7.2f K/s ", rate / ONE_K);
Christian Göttsche157086e2020-12-04 14:44:57 +0100694 RichString_appendnAscii(str, processColor, buffer, len);
adrien1018536941f2018-12-30 20:18:35 +0800695 } else if (rate < ONE_G) {
Christian Göttscheb41e4d92021-04-14 20:16:16 +0200696 int len = snprintf(buffer, sizeof(buffer), "%7.2f M/s ", rate / ONE_M);
Christian Göttsche157086e2020-12-04 14:44:57 +0100697 RichString_appendnAscii(str, processMegabytesColor, buffer, len);
adrien1018536941f2018-12-30 20:18:35 +0800698 } else if (rate < ONE_T) {
Christian Göttscheb41e4d92021-04-14 20:16:16 +0200699 int len = snprintf(buffer, sizeof(buffer), "%7.2f G/s ", rate / ONE_G);
700 RichString_appendnAscii(str, largeNumberColor, buffer, len);
701 } else if (rate < ONE_P) {
702 int len = snprintf(buffer, sizeof(buffer), "%7.2f T/s ", rate / ONE_T);
Christian Göttsche157086e2020-12-04 14:44:57 +0100703 RichString_appendnAscii(str, largeNumberColor, buffer, len);
Hisham Muhammad3383d8e2015-01-21 23:27:31 -0200704 } else {
Christian Göttscheb41e4d92021-04-14 20:16:16 +0200705 int len = snprintf(buffer, sizeof(buffer), "%7.2f P/s ", rate / ONE_P);
Christian Göttsche157086e2020-12-04 14:44:57 +0100706 RichString_appendnAscii(str, largeNumberColor, buffer, len);
Hisham Muhammad3383d8e2015-01-21 23:27:31 -0200707 }
Hisham Muhammad2338ad52008-03-14 18:50:49 +0000708}
709
Christian Göttschea5db1392021-01-10 15:57:46 +0100710void Process_printLeftAlignedField(RichString* str, int attr, const char* content, unsigned int width) {
Christian Göttsche08ac22d2021-01-14 09:59:11 +0100711 int columns = width;
712 RichString_appendnWideColumns(str, attr, content, strlen(content), &columns);
713 RichString_appendChr(str, attr, ' ', width + 1 - columns);
Christian Göttschea5db1392021-01-10 15:57:46 +0100714}
715
Hisham Muhammad556d7c02021-09-03 12:44:19 +1000716void Process_printPercentage(float val, char* buffer, int n, int* attr) {
717 if (val >= 0) {
718 if (val < 99.9F) {
719 if (val < 0.05F) {
720 *attr = CRT_colors[PROCESS_SHADOW];
721 }
722 xSnprintf(buffer, n, "%4.1f ", val);
723 } else if (val < 999) {
Benny Baumann3f805cf2021-09-05 08:46:01 +0200724 *attr = CRT_colors[PROCESS_MEGABYTES];
Hisham Muhammad556d7c02021-09-03 12:44:19 +1000725 xSnprintf(buffer, n, "%3d. ", (int)val);
726 } else {
Nathan Scottbe824482021-09-14 11:16:34 +1000727 *attr = CRT_colors[PROCESS_MEGABYTES];
Hisham Muhammad556d7c02021-09-03 12:44:19 +1000728 xSnprintf(buffer, n, "%4d ", (int)val);
729 }
730 } else {
731 *attr = CRT_colors[PROCESS_SHADOW];
732 xSnprintf(buffer, n, " N/A ");
733 }
734}
735
Christian Göttsche79ad39c2020-10-06 12:28:11 +0200736void Process_writeField(const Process* this, RichString* str, ProcessField field) {
Christian Göttschefee744a2021-01-27 15:11:46 +0100737 char buffer[256];
738 size_t n = sizeof(buffer);
Hisham Muhammadd6231ba2006-03-04 18:16:49 +0000739 int attr = CRT_colors[DEFAULT_COLOR];
Hisham Muhammad3383d8e2015-01-21 23:27:31 -0200740 bool coloring = this->settings->highlightMegabytes;
Hisham Muhammadd6231ba2006-03-04 18:16:49 +0000741
742 switch (field) {
Hisham Muhammadd6231ba2006-03-04 18:16:49 +0000743 case COMM: {
Christian Göttschefee744a2021-01-27 15:11:46 +0100744 int baseattr = CRT_colors[PROCESS_BASENAME];
Hisham Muhammad3383d8e2015-01-21 23:27:31 -0200745 if (this->settings->highlightThreads && Process_isThread(this)) {
Hisham Muhammad93f091c2008-03-08 23:39:48 +0000746 attr = CRT_colors[PROCESS_THREAD];
747 baseattr = CRT_colors[PROCESS_THREAD_BASENAME];
748 }
Hisham Muhammad3383d8e2015-01-21 23:27:31 -0200749 if (!this->settings->treeView || this->indent == 0) {
Hisham Muhammad93f091c2008-03-08 23:39:48 +0000750 Process_writeCommand(this, attr, baseattr, str);
Hisham Muhammadd6231ba2006-03-04 18:16:49 +0000751 return;
Hisham Muhammadd6231ba2006-03-04 18:16:49 +0000752 }
Christian Göttschefee744a2021-01-27 15:11:46 +0100753
754 char* buf = buffer;
755 int maxIndent = 0;
756 bool lastItem = (this->indent < 0);
757 int indent = (this->indent < 0 ? -this->indent : this->indent);
758
759 for (int i = 0; i < 32; i++) {
760 if (indent & (1U << i)) {
Benny Baumann0d85af22021-07-14 19:18:27 +0200761 maxIndent = i + 1;
Christian Göttschefee744a2021-01-27 15:11:46 +0100762 }
763 }
764
765 for (int i = 0; i < maxIndent - 1; i++) {
766 int written, ret;
767 if (indent & (1 << i)) {
768 ret = xSnprintf(buf, n, "%s ", CRT_treeStr[TREE_STR_VERT]);
769 } else {
770 ret = xSnprintf(buf, n, " ");
771 }
772 if (ret < 0 || (size_t)ret >= n) {
773 written = n;
774 } else {
775 written = ret;
776 }
777 buf += written;
778 n -= written;
779 }
780
781 const char* draw = CRT_treeStr[lastItem ? TREE_STR_BEND : TREE_STR_RTEE];
782 xSnprintf(buf, n, "%s%s ", draw, this->showChildren ? CRT_treeStr[TREE_STR_SHUT] : CRT_treeStr[TREE_STR_OPEN] );
783 RichString_appendWide(str, CRT_colors[PROCESS_TREE], buffer);
784 Process_writeCommand(this, attr, baseattr, str);
785 return;
Hisham Muhammadd6231ba2006-03-04 18:16:49 +0000786 }
Benny Baumannaa8552b2021-04-18 19:25:56 +0200787 case PROC_COMM: {
788 const char* procComm;
789 if (this->procComm) {
790 attr = CRT_colors[Process_isUserlandThread(this) ? PROCESS_THREAD_COMM : PROCESS_COMM];
791 procComm = this->procComm;
792 } else {
793 attr = CRT_colors[PROCESS_SHADOW];
794 procComm = Process_isKernelThread(this) ? kthreadID : "N/A";
795 }
796
797 Process_printLeftAlignedField(str, attr, procComm, TASK_COMM_LEN - 1);
798 return;
799 }
800 case PROC_EXE: {
801 const char* procExe;
802 if (this->procExe) {
803 attr = CRT_colors[Process_isUserlandThread(this) ? PROCESS_THREAD_BASENAME : PROCESS_BASENAME];
Benny Baumannde1d0632021-06-10 23:23:03 +0200804 if (this->settings->highlightDeletedExe) {
805 if (this->procExeDeleted)
806 attr = CRT_colors[FAILED_READ];
807 else if (this->usesDeletedLib)
808 attr = CRT_colors[PROCESS_TAG];
809 }
Benny Baumannaa8552b2021-04-18 19:25:56 +0200810 procExe = this->procExe + this->procExeBasenameOffset;
811 } else {
812 attr = CRT_colors[PROCESS_SHADOW];
813 procExe = Process_isKernelThread(this) ? kthreadID : "N/A";
814 }
815
816 Process_printLeftAlignedField(str, attr, procExe, TASK_COMM_LEN - 1);
817 return;
818 }
Benny Baumannb6ff5c82021-05-25 19:02:12 +0200819 case CWD: {
820 const char* cwd;
821 if (!this->procCwd) {
822 attr = CRT_colors[PROCESS_SHADOW];
823 cwd = "N/A";
824 } else if (String_startsWith(this->procCwd, "/proc/") && strstr(this->procCwd, " (deleted)") != NULL) {
825 attr = CRT_colors[PROCESS_SHADOW];
826 cwd = "main thread terminated";
827 } else {
828 cwd = this->procCwd;
829 }
830 Process_printLeftAlignedField(str, attr, cwd, 25);
831 return;
832 }
Christian Göttsche550a1412021-05-02 13:29:39 +0200833 case ELAPSED: Process_printTime(str, /* convert to hundreds of a second */ this->processList->realtimeMs / 10 - 100 * this->starttime_ctime, coloring); return;
Christian Göttscheb41e4d92021-04-14 20:16:16 +0200834 case MAJFLT: Process_printCount(str, this->majflt, coloring); return;
835 case MINFLT: Process_printCount(str, this->minflt, coloring); return;
836 case M_RESIDENT: Process_printKBytes(str, this->m_resident, coloring); return;
837 case M_VIRT: Process_printKBytes(str, this->m_virt, coloring); return;
Christian Göttschefee744a2021-01-27 15:11:46 +0100838 case NICE:
Hisham Muhammad09e241f2017-07-27 16:07:50 -0300839 xSnprintf(buffer, n, "%3ld ", this->nice);
Hisham Muhammadbe1700c2015-03-16 01:43:04 -0300840 attr = this->nice < 0 ? CRT_colors[PROCESS_HIGH_PRIORITY]
841 : this->nice > 0 ? CRT_colors[PROCESS_LOW_PRIORITY]
Christian Göttschefee744a2021-01-27 15:11:46 +0100842 : CRT_colors[PROCESS_SHADOW];
843 break;
844 case NLWP:
845 if (this->nlwp == 1)
846 attr = CRT_colors[PROCESS_SHADOW];
847
848 xSnprintf(buffer, n, "%4ld ", this->nlwp);
849 break;
Hisham Muhammad556d7c02021-09-03 12:44:19 +1000850 case PERCENT_CPU: Process_printPercentage(this->percent_cpu, buffer, n, &attr); break;
Christian Göttschefee744a2021-01-27 15:11:46 +0100851 case PERCENT_NORM_CPU: {
Hisham Muhammad556d7c02021-09-03 12:44:19 +1000852 float cpuPercentage = this->percent_cpu / this->processList->activeCPUs;
853 Process_printPercentage(cpuPercentage, buffer, n, &attr);
Hisham Muhammadbe1700c2015-03-16 01:43:04 -0300854 break;
855 }
Hisham Muhammad556d7c02021-09-03 12:44:19 +1000856 case PERCENT_MEM: Process_printPercentage(this->percent_mem, buffer, n, &attr); break;
Christian Göttsche9f68c8d2020-12-15 19:44:52 +0100857 case PGRP: xSnprintf(buffer, n, "%*d ", Process_pidDigits, this->pgrp); break;
858 case PID: xSnprintf(buffer, n, "%*d ", Process_pidDigits, this->pid); break;
859 case PPID: xSnprintf(buffer, n, "%*d ", Process_pidDigits, this->ppid); break;
Christian Göttschefee744a2021-01-27 15:11:46 +0100860 case PRIORITY:
861 if (this->priority <= -100)
Hisham Muhammad09e241f2017-07-27 16:07:50 -0300862 xSnprintf(buffer, n, " RT ");
Hisham Muhammadbe1700c2015-03-16 01:43:04 -0300863 else
Hisham Muhammad09e241f2017-07-27 16:07:50 -0300864 xSnprintf(buffer, n, "%3ld ", this->priority);
Hisham Muhammadbe1700c2015-03-16 01:43:04 -0300865 break;
Hisham Muhammad09e241f2017-07-27 16:07:50 -0300866 case PROCESSOR: xSnprintf(buffer, n, "%3d ", Settings_cpuId(this->settings, this->processor)); break;
Christian Göttsche9f68c8d2020-12-15 19:44:52 +0100867 case SESSION: xSnprintf(buffer, n, "%*d ", Process_pidDigits, this->session); break;
Hisham Muhammad09e241f2017-07-27 16:07:50 -0300868 case STARTTIME: xSnprintf(buffer, n, "%s", this->starttime_show); break;
Christian Göttschefee744a2021-01-27 15:11:46 +0100869 case STATE:
Hisham Muhammad09e241f2017-07-27 16:07:50 -0300870 xSnprintf(buffer, n, "%c ", this->state);
Christian Göttschefee744a2021-01-27 15:11:46 +0100871 switch (this->state) {
Christian Göttsche0580dbb2021-08-30 19:20:42 +0200872#ifdef HTOP_NETBSD
873 case 'P':
874#else
Christian Göttschefee744a2021-01-27 15:11:46 +0100875 case 'R':
Christian Göttsche0580dbb2021-08-30 19:20:42 +0200876#endif
877 attr = CRT_colors[PROCESS_RUN_STATE];
Christian Göttschefee744a2021-01-27 15:11:46 +0100878 break;
879 case 'D':
880 attr = CRT_colors[PROCESS_D_STATE];
881 break;
882 case 'I':
883 case 'S':
884 attr = CRT_colors[PROCESS_SHADOW];
885 break;
Valmiky Arquissandas64e0d942014-10-14 02:30:17 +0100886 }
Hisham Muhammadd6231ba2006-03-04 18:16:49 +0000887 break;
Daniel Langec34be412018-10-07 11:16:12 +0200888 case ST_UID: xSnprintf(buffer, n, "%5d ", this->st_uid); break;
Christian Göttscheb41e4d92021-04-14 20:16:16 +0200889 case TIME: Process_printTime(str, this->time, coloring); return;
Christian Göttschefee744a2021-01-27 15:11:46 +0100890 case TGID:
891 if (this->tgid == this->pid)
892 attr = CRT_colors[PROCESS_SHADOW];
893
894 xSnprintf(buffer, n, "%*d ", Process_pidDigits, this->tgid);
895 break;
Christian Göttsche9f68c8d2020-12-15 19:44:52 +0100896 case TPGID: xSnprintf(buffer, n, "%*d ", Process_pidDigits, this->tpgid); break;
Christian Göttsche9a822152021-03-21 19:40:56 +0100897 case TTY:
898 if (!this->tty_name) {
Christian Göttschea3c82852021-01-27 15:11:42 +0100899 attr = CRT_colors[PROCESS_SHADOW];
Christian Göttsche9a822152021-03-21 19:40:56 +0100900 xSnprintf(buffer, n, "(no tty) ");
Christian Göttschea3c82852021-01-27 15:11:42 +0100901 } else {
Christian Göttsche9a822152021-03-21 19:40:56 +0100902 const char* name = String_startsWith(this->tty_name, "/dev/") ? (this->tty_name + strlen("/dev/")) : this->tty_name;
903 xSnprintf(buffer, n, "%-8s ", name);
Christian Göttschea3c82852021-01-27 15:11:42 +0100904 }
905 break;
Christian Göttschefee744a2021-01-27 15:11:46 +0100906 case USER:
Christian Göttsche42073ba2020-11-04 17:46:04 +0100907 if (Process_getuid != this->st_uid)
Hisham Muhammadd6231ba2006-03-04 18:16:49 +0000908 attr = CRT_colors[PROCESS_SHADOW];
Christian Göttsche5359eae2020-12-23 12:21:29 +0100909
Hisham Muhammadeb2803c2006-07-12 01:35:59 +0000910 if (this->user) {
Christian Göttschea5db1392021-01-10 15:57:46 +0100911 Process_printLeftAlignedField(str, attr, this->user, 9);
Christian Göttsche5359eae2020-12-23 12:21:29 +0100912 return;
Hisham Muhammadeb2803c2006-07-12 01:35:59 +0000913 }
Christian Göttsche5359eae2020-12-23 12:21:29 +0100914
915 xSnprintf(buffer, n, "%-9d ", this->st_uid);
Hisham Muhammadd6231ba2006-03-04 18:16:49 +0000916 break;
Hisham Muhammadd6231ba2006-03-04 18:16:49 +0000917 default:
Sohaib Mohamed6f2021f2021-07-11 03:11:29 +0200918 if (DynamicColumn_writeField(this, str, field))
919 return;
Christian Göttsche615fc932021-04-18 15:52:28 +0200920 assert(0 && "Process_writeField: default key reached"); /* should never be reached */
Hisham Muhammad09e241f2017-07-27 16:07:50 -0300921 xSnprintf(buffer, n, "- ");
Sohaib Mohamed6f2021f2021-07-11 03:11:29 +0200922 break;
Hisham Muhammadd6231ba2006-03-04 18:16:49 +0000923 }
Christian Göttschea2be57d2021-04-14 20:54:38 +0200924 RichString_appendAscii(str, attr, buffer);
Hisham Muhammadd6231ba2006-03-04 18:16:49 +0000925}
926
Christian Göttsche79ad39c2020-10-06 12:28:11 +0200927void Process_display(const Object* cast, RichString* out) {
928 const Process* this = (const Process*) cast;
929 const ProcessField* fields = this->settings->fields;
Hisham Muhammadda23c8c2008-03-09 08:58:38 +0000930 for (int i = 0; fields[i]; i++)
Hisham Muhammad4c24a9b2015-03-31 23:23:10 -0300931 As_Process(this)->writeField(this, out, fields[i]);
Benny Baumann45869512020-11-01 01:09:51 +0100932
Christian Göttsche42073ba2020-11-04 17:46:04 +0100933 if (this->settings->shadowOtherUsers && this->st_uid != Process_getuid) {
Hisham Muhammadda23c8c2008-03-09 08:58:38 +0000934 RichString_setAttr(out, CRT_colors[PROCESS_SHADOW]);
Benny Baumann45869512020-11-01 01:09:51 +0100935 }
936
937 if (this->tag == true) {
Hisham Muhammadda23c8c2008-03-09 08:58:38 +0000938 RichString_setAttr(out, CRT_colors[PROCESS_TAG]);
Benny Baumann45869512020-11-01 01:09:51 +0100939 }
940
Daniel Lange09510902020-11-16 12:13:47 +0100941 if (this->settings->highlightChanges) {
942 if (Process_isTomb(this)) {
943 out->highlightAttr = CRT_colors[PROCESS_TOMB];
944 } else if (Process_isNew(this)) {
945 out->highlightAttr = CRT_colors[PROCESS_NEW];
946 }
947 }
948
Christian Göttsche3f99c2d2021-03-12 16:46:04 +0100949 assert(RichString_size(out) > 0);
Hisham Muhammadda23c8c2008-03-09 08:58:38 +0000950}
951
Hisham Muhammad6f868b02015-02-20 14:52:10 -0200952void Process_done(Process* this) {
Hisham Muhammadda23c8c2008-03-09 08:58:38 +0000953 assert (this != NULL);
Benny Baumann02431c42020-12-19 16:21:08 +0100954 free(this->cmdline);
Benny Baumannd74e8b72021-01-30 15:31:59 +0100955 free(this->procComm);
956 free(this->procExe);
Benny Baumannb6ff5c82021-05-25 19:02:12 +0200957 free(this->procCwd);
Benny Baumanncdb660a2021-04-10 11:10:50 +0200958 free(this->mergedCommand.str);
Christian Göttsche9a822152021-03-21 19:40:56 +0100959 free(this->tty_name);
Hisham Muhammadda23c8c2008-03-09 08:58:38 +0000960}
961
Benny Baumannc0d02022021-04-24 12:06:49 +0200962/* This function returns the string displayed in Command column, so that sorting
963 * happens on what is displayed - whether comm, full path, basename, etc.. So
964 * this follows Process_writeField(COMM) and Process_writeCommand */
Benny Baumann976c6122021-07-14 19:24:18 +0200965const char* Process_getCommandStr(const Process* this) {
Benny Baumannc0d02022021-04-24 12:06:49 +0200966 if ((Process_isUserlandThread(this) && this->settings->showThreadNames) || !this->mergedCommand.str) {
967 return this->cmdline;
968 }
969
970 return this->mergedCommand.str;
Narendran Gopalakrishnan09fe94d2020-10-17 16:24:45 +0530971}
972
Christian Göttscheba282cf2020-10-05 13:19:50 +0200973const ProcessClass Process_class = {
Hisham Muhammad4c24a9b2015-03-31 23:23:10 -0300974 .super = {
975 .extends = Class(Object),
976 .display = Process_display,
977 .delete = Process_delete,
978 .compare = Process_compare
979 },
980 .writeField = Process_writeField,
Narendran Gopalakrishnan09fe94d2020-10-17 16:24:45 +0530981 .getCommandStr = Process_getCommandStr,
Hisham Muhammad00b324b2012-12-05 15:12:20 +0000982};
983
Christian Göttsche3035e292021-01-26 18:41:04 +0100984void Process_init(Process* this, const Settings* settings) {
Hisham Muhammad3383d8e2015-01-21 23:27:31 -0200985 this->settings = settings;
Hisham Muhammadda23c8c2008-03-09 08:58:38 +0000986 this->tag = false;
Hisham Muhammad9eb91212010-06-17 19:02:03 +0000987 this->showChildren = true;
Hisham Muhammadd8e14802010-11-22 12:40:20 +0000988 this->show = true;
Hisham Muhammadda23c8c2008-03-09 08:58:38 +0000989 this->updated = false;
Benny Baumann94a52cb2021-04-10 11:46:57 +0200990 this->cmdlineBasenameEnd = -1;
Christian Göttsche9114cf62021-06-09 11:13:39 +0200991 this->st_uid = (uid_t)-1;
Benny Baumann45869512020-11-01 01:09:51 +0100992
Christian Göttsche42073ba2020-11-04 17:46:04 +0100993 if (Process_getuid == (uid_t)-1) {
Benny Baumann45869512020-11-01 01:09:51 +0100994 Process_getuid = getuid();
995 }
Hisham Muhammadda23c8c2008-03-09 08:58:38 +0000996}
997
Hisham Muhammadda23c8c2008-03-09 08:58:38 +0000998void Process_toggleTag(Process* this) {
Christian Göttsche2d231d72020-12-08 22:37:15 +0100999 this->tag = !this->tag;
Hisham Muhammadda23c8c2008-03-09 08:58:38 +00001000}
1001
Adam Saponaradde71c62020-10-30 21:56:16 -04001002bool Process_isNew(const Process* this) {
Adam Saponaraa83f5152020-10-31 20:36:53 -04001003 assert(this->processList);
Nathan Scott356488a2021-03-30 15:55:48 +11001004 if (this->processList->monotonicMs >= this->seenStampMs) {
1005 return this->processList->monotonicMs - this->seenStampMs <= 1000 * (uint64_t)this->processList->settings->highlightDelaySecs;
Daniel Lange09510902020-11-16 12:13:47 +01001006 }
Adam Saponaradde71c62020-10-30 21:56:16 -04001007 return false;
1008}
1009
1010bool Process_isTomb(const Process* this) {
Benny Baumann458749d2021-07-14 19:15:09 +02001011 return this->tombStampMs > 0;
Adam Saponaradde71c62020-10-30 21:56:16 -04001012}
1013
Hisham Muhammadda23c8c2008-03-09 08:58:38 +00001014bool Process_setPriority(Process* this, int priority) {
Christian Göttsche36880cd2021-01-21 20:27:37 +01001015 if (Settings_isReadonly())
1016 return false;
1017
Michael Kleinab3a7c22015-12-07 20:10:09 +01001018 int old_prio = getpriority(PRIO_PROCESS, this->pid);
1019 int err = setpriority(PRIO_PROCESS, this->pid, priority);
Benny Baumann82157f52021-02-16 19:44:59 +01001020
Michael Kleinab3a7c22015-12-07 20:10:09 +01001021 if (err == 0 && old_prio != getpriority(PRIO_PROCESS, this->pid)) {
1022 this->nice = priority;
Hisham Muhammadda23c8c2008-03-09 08:58:38 +00001023 }
Michael Kleinab3a7c22015-12-07 20:10:09 +01001024 return (err == 0);
Hisham Muhammadda23c8c2008-03-09 08:58:38 +00001025}
1026
Nathan Scott500fb282020-08-20 09:35:24 +10001027bool Process_changePriorityBy(Process* this, Arg delta) {
1028 return Process_setPriority(this, this->nice + delta.i);
Hisham Muhammad47e881f2012-10-04 23:59:45 +00001029}
1030
Nathan Scott500fb282020-08-20 09:35:24 +10001031bool Process_sendSignal(Process* this, Arg sgn) {
Benny Baumann82157f52021-02-16 19:44:59 +01001032 return kill(this->pid, sgn.i) == 0;
Hisham Muhammadda23c8c2008-03-09 08:58:38 +00001033}
1034
Christian Göttsche90ea3ac2020-12-23 13:02:32 +01001035int Process_pidCompare(const void* v1, const void* v2) {
Christian Göttsche18b1e9f2020-09-23 14:15:51 +02001036 const Process* p1 = (const Process*)v1;
1037 const Process* p2 = (const Process*)v2;
Christian Göttsche2d231d72020-12-08 22:37:15 +01001038
1039 return SPACESHIP_NUMBER(p1->pid, p2->pid);
Hisham Muhammad5d48ab82006-07-11 06:13:32 +00001040}
1041
Christian Göttsche90ea3ac2020-12-23 13:02:32 +01001042int Process_compare(const void* v1, const void* v2) {
Benny Baumann976c6122021-07-14 19:24:18 +02001043 const Process* p1 = (const Process*)v1;
1044 const Process* p2 = (const Process*)v2;
Christian Göttsche397b5c42020-11-04 17:46:24 +01001045
Benny Baumann976c6122021-07-14 19:24:18 +02001046 const Settings* settings = p1->settings;
Christian Göttsche397b5c42020-11-04 17:46:24 +01001047
Hisham Muhammad23272602020-12-18 11:03:31 -03001048 ProcessField key = Settings_getActiveSortKey(settings);
Hisham Muhammade8c69942020-12-17 19:08:56 -03001049
Christian Göttsche90ea3ac2020-12-23 13:02:32 +01001050 int result = Process_compareByKey(p1, p2, key);
Benny Baumann77db2402020-12-18 22:12:26 +01001051
1052 // Implement tie-breaker (needed to make tree mode more stable)
1053 if (!result)
Daniel Lange074703b2021-01-21 20:57:34 +01001054 return SPACESHIP_NUMBER(p1->pid, p2->pid);
Benny Baumann77db2402020-12-18 22:12:26 +01001055
Christian Göttschebea7f8e2021-03-12 16:44:46 +01001056 return (Settings_getActiveDirection(settings) == 1) ? result : -result;
Benny Baumann77db2402020-12-18 22:12:26 +01001057}
1058
Christian Göttsched5de1bc2021-01-27 15:11:44 +01001059static uint8_t stateCompareValue(char state) {
1060 switch (state) {
1061
1062 case 'S':
1063 return 10;
1064
1065 case 'I':
1066 return 9;
1067
1068 case 'X':
1069 return 8;
1070
1071 case 'Z':
1072 return 7;
1073
1074 case 't':
1075 return 6;
1076
1077 case 'T':
1078 return 5;
1079
1080 case 'L':
1081 return 4;
1082
1083 case 'D':
1084 return 3;
1085
1086 case 'R':
1087 return 2;
1088
1089 case '?':
1090 return 1;
1091
1092 default:
1093 return 0;
1094 }
1095}
1096
Christian Göttsche90ea3ac2020-12-23 13:02:32 +01001097int Process_compareByKey_Base(const Process* p1, const Process* p2, ProcessField key) {
Benny Baumann77db2402020-12-18 22:12:26 +01001098 int r;
1099
Christian Göttsche89473cc2020-12-15 19:44:48 +01001100 switch (key) {
Hisham Muhammad5d48ab82006-07-11 06:13:32 +00001101 case PERCENT_CPU:
Christian Göttsche15eab202020-10-30 17:02:20 +01001102 case PERCENT_NORM_CPU:
Daniel Lange4531b312021-01-21 14:27:23 +01001103 return SPACESHIP_NUMBER(p1->percent_cpu, p2->percent_cpu);
Hisham Muhammad5d48ab82006-07-11 06:13:32 +00001104 case PERCENT_MEM:
Daniel Lange4531b312021-01-21 14:27:23 +01001105 return SPACESHIP_NUMBER(p1->m_resident, p2->m_resident);
Hisham Muhammad5d48ab82006-07-11 06:13:32 +00001106 case COMM:
Narendran Gopalakrishnan09fe94d2020-10-17 16:24:45 +05301107 return SPACESHIP_NULLSTR(Process_getCommand(p1), Process_getCommand(p2));
Benny Baumannaa8552b2021-04-18 19:25:56 +02001108 case PROC_COMM: {
Benny Baumann976c6122021-07-14 19:24:18 +02001109 const char* comm1 = p1->procComm ? p1->procComm : (Process_isKernelThread(p1) ? kthreadID : "");
1110 const char* comm2 = p2->procComm ? p2->procComm : (Process_isKernelThread(p2) ? kthreadID : "");
Benny Baumannaa8552b2021-04-18 19:25:56 +02001111 return SPACESHIP_NULLSTR(comm1, comm2);
1112 }
1113 case PROC_EXE: {
Benny Baumann976c6122021-07-14 19:24:18 +02001114 const char* exe1 = p1->procExe ? (p1->procExe + p1->procExeBasenameOffset) : (Process_isKernelThread(p1) ? kthreadID : "");
1115 const char* exe2 = p2->procExe ? (p2->procExe + p2->procExeBasenameOffset) : (Process_isKernelThread(p2) ? kthreadID : "");
Benny Baumannaa8552b2021-04-18 19:25:56 +02001116 return SPACESHIP_NULLSTR(exe1, exe2);
1117 }
Benny Baumannb6ff5c82021-05-25 19:02:12 +02001118 case CWD:
1119 return SPACESHIP_NULLSTR(p1->procCwd, p2->procCwd);
Christian Göttsche550a1412021-05-02 13:29:39 +02001120 case ELAPSED:
1121 r = -SPACESHIP_NUMBER(p1->starttime_ctime, p2->starttime_ctime);
1122 return r != 0 ? r : SPACESHIP_NUMBER(p1->pid, p2->pid);
Hisham Muhammadbe1700c2015-03-16 01:43:04 -03001123 case MAJFLT:
Daniel Lange4531b312021-01-21 14:27:23 +01001124 return SPACESHIP_NUMBER(p1->majflt, p2->majflt);
Hisham Muhammadbe1700c2015-03-16 01:43:04 -03001125 case MINFLT:
Daniel Lange4531b312021-01-21 14:27:23 +01001126 return SPACESHIP_NUMBER(p1->minflt, p2->minflt);
Hisham Muhammadbe1700c2015-03-16 01:43:04 -03001127 case M_RESIDENT:
Daniel Lange4531b312021-01-21 14:27:23 +01001128 return SPACESHIP_NUMBER(p1->m_resident, p2->m_resident);
Christian Göttschefa002c02020-11-20 17:09:34 +01001129 case M_VIRT:
Daniel Lange4531b312021-01-21 14:27:23 +01001130 return SPACESHIP_NUMBER(p1->m_virt, p2->m_virt);
Hisham Muhammadbe1700c2015-03-16 01:43:04 -03001131 case NICE:
Christian Göttsche397b5c42020-11-04 17:46:24 +01001132 return SPACESHIP_NUMBER(p1->nice, p2->nice);
Hisham Muhammadd357c672007-05-21 19:10:53 +00001133 case NLWP:
Christian Göttsche397b5c42020-11-04 17:46:24 +01001134 return SPACESHIP_NUMBER(p1->nlwp, p2->nlwp);
Hisham Muhammadbe1700c2015-03-16 01:43:04 -03001135 case PGRP:
Christian Göttsche397b5c42020-11-04 17:46:24 +01001136 return SPACESHIP_NUMBER(p1->pgrp, p2->pgrp);
Hisham Muhammadbe1700c2015-03-16 01:43:04 -03001137 case PID:
Christian Göttsche397b5c42020-11-04 17:46:24 +01001138 return SPACESHIP_NUMBER(p1->pid, p2->pid);
Hisham Muhammadbe1700c2015-03-16 01:43:04 -03001139 case PPID:
Christian Göttsche397b5c42020-11-04 17:46:24 +01001140 return SPACESHIP_NUMBER(p1->ppid, p2->ppid);
Hisham Muhammadbe1700c2015-03-16 01:43:04 -03001141 case PRIORITY:
Christian Göttsche397b5c42020-11-04 17:46:24 +01001142 return SPACESHIP_NUMBER(p1->priority, p2->priority);
Hisham Muhammad272e2d92015-03-16 23:01:48 -03001143 case PROCESSOR:
Christian Göttsche397b5c42020-11-04 17:46:24 +01001144 return SPACESHIP_NUMBER(p1->processor, p2->processor);
Hisham Muhammadbe1700c2015-03-16 01:43:04 -03001145 case SESSION:
Christian Göttsche397b5c42020-11-04 17:46:24 +01001146 return SPACESHIP_NUMBER(p1->session, p2->session);
1147 case STARTTIME:
1148 r = SPACESHIP_NUMBER(p1->starttime_ctime, p2->starttime_ctime);
1149 return r != 0 ? r : SPACESHIP_NUMBER(p1->pid, p2->pid);
Hisham Muhammadbe1700c2015-03-16 01:43:04 -03001150 case STATE:
Christian Göttsched5de1bc2021-01-27 15:11:44 +01001151 return SPACESHIP_NUMBER(stateCompareValue(p1->state), stateCompareValue(p2->state));
Hisham Muhammadbe1700c2015-03-16 01:43:04 -03001152 case ST_UID:
Christian Göttsche397b5c42020-11-04 17:46:24 +01001153 return SPACESHIP_NUMBER(p1->st_uid, p2->st_uid);
Hisham Muhammadbe1700c2015-03-16 01:43:04 -03001154 case TIME:
Daniel Lange4531b312021-01-21 14:27:23 +01001155 return SPACESHIP_NUMBER(p1->time, p2->time);
Hisham Muhammadbe1700c2015-03-16 01:43:04 -03001156 case TGID:
Christian Göttsche397b5c42020-11-04 17:46:24 +01001157 return SPACESHIP_NUMBER(p1->tgid, p2->tgid);
Hisham Muhammadbe1700c2015-03-16 01:43:04 -03001158 case TPGID:
Christian Göttsche397b5c42020-11-04 17:46:24 +01001159 return SPACESHIP_NUMBER(p1->tpgid, p2->tpgid);
Christian Göttsche9a822152021-03-21 19:40:56 +01001160 case TTY:
1161 /* Order no tty last */
1162 return SPACESHIP_DEFAULTSTR(p1->tty_name, p2->tty_name, "\x7F");
Hisham Muhammadbe1700c2015-03-16 01:43:04 -03001163 case USER:
Christian Göttsche397b5c42020-11-04 17:46:24 +01001164 return SPACESHIP_NULLSTR(p1->user, p2->user);
Hisham Muhammad5d48ab82006-07-11 06:13:32 +00001165 default:
Christian Göttsche615fc932021-04-18 15:52:28 +02001166 assert(0 && "Process_compareByKey_Base: default key reached"); /* should never be reached */
Benny Baumann77db2402020-12-18 22:12:26 +01001167 return SPACESHIP_NUMBER(p1->pid, p2->pid);
Hisham Muhammad5d48ab82006-07-11 06:13:32 +00001168 }
Hisham Muhammadd6231ba2006-03-04 18:16:49 +00001169}
Christian Göttsche05fb6812021-05-18 22:29:25 +02001170
1171void Process_updateComm(Process* this, const char* comm) {
1172 if (!this->procComm && !comm)
1173 return;
1174
1175 if (this->procComm && comm && String_eq(this->procComm, comm))
1176 return;
1177
1178 free(this->procComm);
1179 this->procComm = comm ? xStrdup(comm) : NULL;
1180 this->mergedCommand.commChanged = true;
1181}
1182
1183static int skipPotentialPath(const char* cmdline, int end) {
1184 if (cmdline[0] != '/')
1185 return 0;
1186
1187 int slash = 0;
1188 for (int i = 1; i < end; i++) {
Benny Baumann0d85af22021-07-14 19:18:27 +02001189 if (cmdline[i] == '/' && cmdline[i + 1] != '\0') {
Christian Göttsche05fb6812021-05-18 22:29:25 +02001190 slash = i + 1;
1191 continue;
1192 }
1193
Benny Baumann0d85af22021-07-14 19:18:27 +02001194 if (cmdline[i] == ' ' && cmdline[i - 1] != '\\')
Christian Göttsche05fb6812021-05-18 22:29:25 +02001195 return slash;
1196
Benny Baumann0d85af22021-07-14 19:18:27 +02001197 if (cmdline[i] == ':' && cmdline[i + 1] == ' ')
Christian Göttsche05fb6812021-05-18 22:29:25 +02001198 return slash;
1199 }
1200
1201 return slash;
1202}
1203
1204void Process_updateCmdline(Process* this, const char* cmdline, int basenameStart, int basenameEnd) {
1205 assert(basenameStart >= 0);
1206 assert((cmdline && basenameStart < (int)strlen(cmdline)) || (!cmdline && basenameStart == 0));
Christian Göttschec408add2021-05-23 15:53:23 +02001207 assert((basenameEnd > basenameStart) || (basenameEnd == 0 && basenameStart == 0));
Christian Göttsche05fb6812021-05-18 22:29:25 +02001208 assert((cmdline && basenameEnd <= (int)strlen(cmdline)) || (!cmdline && basenameEnd == 0));
1209
1210 if (!this->cmdline && !cmdline)
1211 return;
1212
1213 if (this->cmdline && cmdline && String_eq(this->cmdline, cmdline))
1214 return;
1215
1216 free(this->cmdline);
1217 this->cmdline = cmdline ? xStrdup(cmdline) : NULL;
1218 this->cmdlineBasenameStart = (basenameStart || !cmdline) ? basenameStart : skipPotentialPath(cmdline, basenameEnd);
1219 this->cmdlineBasenameEnd = basenameEnd;
1220 this->mergedCommand.cmdlineChanged = true;
1221}
1222
1223void Process_updateExe(Process* this, const char* exe) {
1224 if (!this->procExe && !exe)
1225 return;
1226
1227 if (this->procExe && exe && String_eq(this->procExe, exe))
1228 return;
1229
1230 free(this->procExe);
1231 if (exe) {
1232 this->procExe = xStrdup(exe);
1233 const char* lastSlash = strrchr(exe, '/');
1234 this->procExeBasenameOffset = (lastSlash && *(lastSlash + 1) != '\0' && lastSlash != exe) ? (lastSlash - exe + 1) : 0;
1235 } else {
1236 this->procExe = NULL;
1237 this->procExeBasenameOffset = 0;
1238 }
1239 this->mergedCommand.exeChanged = true;
1240}