blob: 600659c9bce7968956fc19cf1f2ae2f80b224e64 [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
Silke Hofstra696f79f2021-08-16 22:50:36 +020044int Process_pidDigits = PROCESS_MIN_PID_DIGITS;
45int Process_uidDigits = PROCESS_MIN_UID_DIGITS;
Hisham Muhammad94280102015-08-20 00:32:47 -030046
47void Process_setupColumnWidths() {
48 int maxPid = Platform_getMaxPid();
Benny Baumann45869512020-11-01 01:09:51 +010049 if (maxPid == -1)
50 return;
51
Silke Hofstra696f79f2021-08-16 22:50:36 +020052 if (maxPid < (int)pow(10, PROCESS_MIN_PID_DIGITS)) {
53 Process_pidDigits = PROCESS_MIN_PID_DIGITS;
54 return;
55 }
56
Explorer09ee1bf2f2022-04-18 11:17:21 +080057 Process_pidDigits = (int)log10(maxPid) + 1;
Christian Göttsche9f68c8d2020-12-15 19:44:52 +010058 assert(Process_pidDigits <= PROCESS_MAX_PID_DIGITS);
Hisham Muhammad94280102015-08-20 00:32:47 -030059}
60
Silke Hofstra696f79f2021-08-16 22:50:36 +020061void Process_setUidColumnWidth(uid_t maxUid) {
62 if (maxUid < (uid_t)pow(10, PROCESS_MIN_UID_DIGITS)) {
63 Process_uidDigits = PROCESS_MIN_UID_DIGITS;
64 return;
65 }
66
Explorer09ee1bf2f2022-04-18 11:17:21 +080067 Process_uidDigits = (int)log10(maxUid) + 1;
Silke Hofstra696f79f2021-08-16 22:50:36 +020068 assert(Process_uidDigits <= PROCESS_MAX_UID_DIGITS);
69}
70
Christian Göttscheb41e4d92021-04-14 20:16:16 +020071void Process_printBytes(RichString* str, unsigned long long number, bool coloring) {
72 char buffer[16];
Hisham Muhammadd6231ba2006-03-04 18:16:49 +000073 int len;
Daniel Flanagandd334442019-10-31 11:39:12 -050074
Christian Göttschefdaa15b2021-01-27 15:11:48 +010075 int largeNumberColor = coloring ? CRT_colors[LARGE_NUMBER] : CRT_colors[PROCESS];
76 int processMegabytesColor = coloring ? CRT_colors[PROCESS_MEGABYTES] : CRT_colors[PROCESS];
77 int processGigabytesColor = coloring ? CRT_colors[PROCESS_GIGABYTES] : CRT_colors[PROCESS];
78 int shadowColor = coloring ? CRT_colors[PROCESS_SHADOW] : CRT_colors[PROCESS];
Hisham Muhammada939cdf2014-04-24 15:00:09 -030079 int processColor = CRT_colors[PROCESS];
Daniel Flanagandd334442019-10-31 11:39:12 -050080
Christian Göttschefdaa15b2021-01-27 15:11:48 +010081 if (number == ULLONG_MAX) {
82 //Invalid number
83 RichString_appendAscii(str, shadowColor, " N/A ");
Christian Göttscheb41e4d92021-04-14 20:16:16 +020084 return;
85 }
86
87 number /= ONE_K;
88
89 if (number < 1000) {
Benny Baumann40441dc2020-09-13 23:50:24 +020090 //Plain number, no markings
Daniel Lange7899ae22020-11-28 17:57:51 +010091 len = xSnprintf(buffer, sizeof(buffer), "%5llu ", number);
Christian Göttsche157086e2020-12-04 14:44:57 +010092 RichString_appendnAscii(str, processColor, buffer, len);
Benny Baumann40441dc2020-09-13 23:50:24 +020093 } else if (number < 100000) {
94 //2 digit MB, 3 digit KB
Benny Baumann0d85af22021-07-14 19:18:27 +020095 len = xSnprintf(buffer, sizeof(buffer), "%2llu", number / 1000);
Christian Göttsche157086e2020-12-04 14:44:57 +010096 RichString_appendnAscii(str, processMegabytesColor, buffer, len);
Hisham Muhammadd6231ba2006-03-04 18:16:49 +000097 number %= 1000;
Daniel Lange7899ae22020-11-28 17:57:51 +010098 len = xSnprintf(buffer, sizeof(buffer), "%03llu ", number);
Christian Göttsche157086e2020-12-04 14:44:57 +010099 RichString_appendnAscii(str, processColor, buffer, len);
Benny Baumann40441dc2020-09-13 23:50:24 +0200100 } else if (number < 1000 * ONE_K) {
101 //3 digit MB
102 number /= ONE_K;
Daniel Lange7899ae22020-11-28 17:57:51 +0100103 len = xSnprintf(buffer, sizeof(buffer), "%4lluM ", number);
Christian Göttsche157086e2020-12-04 14:44:57 +0100104 RichString_appendnAscii(str, processMegabytesColor, buffer, len);
Benny Baumann40441dc2020-09-13 23:50:24 +0200105 } else if (number < 10000 * ONE_K) {
106 //1 digit GB, 3 digit MB
107 number /= ONE_K;
Benny Baumann0d85af22021-07-14 19:18:27 +0200108 len = xSnprintf(buffer, sizeof(buffer), "%1llu", number / 1000);
Christian Göttsche157086e2020-12-04 14:44:57 +0100109 RichString_appendnAscii(str, processGigabytesColor, buffer, len);
Benny Baumann40441dc2020-09-13 23:50:24 +0200110 number %= 1000;
Daniel Lange7899ae22020-11-28 17:57:51 +0100111 len = xSnprintf(buffer, sizeof(buffer), "%03lluM ", number);
Christian Göttsche157086e2020-12-04 14:44:57 +0100112 RichString_appendnAscii(str, processMegabytesColor, buffer, len);
Benny Baumanne0e59972020-09-20 19:54:53 +0200113 } else if (number < 100000 * ONE_K) {
Benny Baumann40441dc2020-09-13 23:50:24 +0200114 //2 digit GB, 1 digit MB
115 number /= 100 * ONE_K;
Benny Baumann0d85af22021-07-14 19:18:27 +0200116 len = xSnprintf(buffer, sizeof(buffer), "%2llu", number / 10);
Christian Göttsche157086e2020-12-04 14:44:57 +0100117 RichString_appendnAscii(str, processGigabytesColor, buffer, len);
Benny Baumann40441dc2020-09-13 23:50:24 +0200118 number %= 10;
Christian Göttschecd305b42020-11-29 14:14:46 +0100119 len = xSnprintf(buffer, sizeof(buffer), ".%1llu", number);
Christian Göttsche157086e2020-12-04 14:44:57 +0100120 RichString_appendnAscii(str, processMegabytesColor, buffer, len);
121 RichString_appendAscii(str, processGigabytesColor, "G ");
Benny Baumann40441dc2020-09-13 23:50:24 +0200122 } else if (number < 1000 * ONE_M) {
123 //3 digit GB
124 number /= ONE_M;
Daniel Lange7899ae22020-11-28 17:57:51 +0100125 len = xSnprintf(buffer, sizeof(buffer), "%4lluG ", number);
Christian Göttsche157086e2020-12-04 14:44:57 +0100126 RichString_appendnAscii(str, processGigabytesColor, buffer, len);
Michael Wittenab3171d2020-09-29 14:04:22 +0000127 } else if (number < 10000ULL * ONE_M) {
Benny Baumann40441dc2020-09-13 23:50:24 +0200128 //1 digit TB, 3 digit GB
129 number /= ONE_M;
Benny Baumann0d85af22021-07-14 19:18:27 +0200130 len = xSnprintf(buffer, sizeof(buffer), "%1llu", number / 1000);
Christian Göttsche157086e2020-12-04 14:44:57 +0100131 RichString_appendnAscii(str, largeNumberColor, buffer, len);
Benny Baumann40441dc2020-09-13 23:50:24 +0200132 number %= 1000;
Daniel Lange7899ae22020-11-28 17:57:51 +0100133 len = xSnprintf(buffer, sizeof(buffer), "%03lluG ", number);
Christian Göttsche157086e2020-12-04 14:44:57 +0100134 RichString_appendnAscii(str, processGigabytesColor, buffer, len);
Christian Göttscheb41e4d92021-04-14 20:16:16 +0200135 } else if (number < 100000 * ONE_M) {
136 //2 digit TB, 1 digit GB
137 number /= 100 * ONE_M;
Benny Baumann0d85af22021-07-14 19:18:27 +0200138 len = xSnprintf(buffer, sizeof(buffer), "%2llu", number / 10);
Christian Göttscheb41e4d92021-04-14 20:16:16 +0200139 RichString_appendnAscii(str, largeNumberColor, buffer, len);
140 number %= 10;
141 len = xSnprintf(buffer, sizeof(buffer), ".%1llu", number);
142 RichString_appendnAscii(str, processGigabytesColor, buffer, len);
143 RichString_appendAscii(str, largeNumberColor, "T ");
144 } else if (number < 10000ULL * ONE_G) {
145 //3 digit TB or 1 digit PB, 3 digit TB
146 number /= ONE_G;
147 len = xSnprintf(buffer, sizeof(buffer), "%4lluT ", number);
148 RichString_appendnAscii(str, largeNumberColor, buffer, len);
Benny Baumann40441dc2020-09-13 23:50:24 +0200149 } else {
Christian Göttscheb41e4d92021-04-14 20:16:16 +0200150 //2 digit PB and above
Benny Baumann0d85af22021-07-14 19:18:27 +0200151 len = xSnprintf(buffer, sizeof(buffer), "%4.1lfP ", (double)number / ONE_T);
Christian Göttsche157086e2020-12-04 14:44:57 +0100152 RichString_appendnAscii(str, largeNumberColor, buffer, len);
Hisham Muhammadd6231ba2006-03-04 18:16:49 +0000153 }
154}
155
Christian Göttscheb41e4d92021-04-14 20:16:16 +0200156void Process_printKBytes(RichString* str, unsigned long long number, bool coloring) {
157 if (number == ULLONG_MAX)
158 Process_printBytes(str, ULLONG_MAX, coloring);
159 else
160 Process_printBytes(str, number * ONE_K, coloring);
161}
162
163void Process_printCount(RichString* str, unsigned long long number, bool coloring) {
Daniel Lange7899ae22020-11-28 17:57:51 +0100164 char buffer[13];
Hisham Muhammada939cdf2014-04-24 15:00:09 -0300165
Christian Göttschefee744a2021-01-27 15:11:46 +0100166 int largeNumberColor = coloring ? CRT_colors[LARGE_NUMBER] : CRT_colors[PROCESS];
167 int processMegabytesColor = coloring ? CRT_colors[PROCESS_MEGABYTES] : CRT_colors[PROCESS];
Hisham Muhammada939cdf2014-04-24 15:00:09 -0300168 int processColor = CRT_colors[PROCESS];
Christian Göttschefee744a2021-01-27 15:11:46 +0100169 int processShadowColor = coloring ? CRT_colors[PROCESS_SHADOW] : CRT_colors[PROCESS];
Hisham Muhammada939cdf2014-04-24 15:00:09 -0300170
Michael Wittenab3171d2020-09-29 14:04:22 +0000171 if (number == ULLONG_MAX) {
Christian Göttsche157086e2020-12-04 14:44:57 +0100172 RichString_appendAscii(str, CRT_colors[PROCESS_SHADOW], " N/A ");
adrien1018536941f2018-12-30 20:18:35 +0800173 } else if (number >= 100000LL * ONE_DECIMAL_T) {
Benny Baumann0b29e502020-11-28 17:42:02 +0100174 xSnprintf(buffer, sizeof(buffer), "%11llu ", number / ONE_DECIMAL_G);
Christian Göttsche157086e2020-12-04 14:44:57 +0100175 RichString_appendnAscii(str, largeNumberColor, buffer, 12);
adrien1018536941f2018-12-30 20:18:35 +0800176 } else if (number >= 100LL * ONE_DECIMAL_T) {
Benny Baumann0b29e502020-11-28 17:42:02 +0100177 xSnprintf(buffer, sizeof(buffer), "%11llu ", number / ONE_DECIMAL_M);
Christian Göttsche157086e2020-12-04 14:44:57 +0100178 RichString_appendnAscii(str, largeNumberColor, buffer, 8);
Benny Baumann0d85af22021-07-14 19:18:27 +0200179 RichString_appendnAscii(str, processMegabytesColor, buffer + 8, 4);
adrien1018536941f2018-12-30 20:18:35 +0800180 } else if (number >= 10LL * ONE_DECIMAL_G) {
Benny Baumann0b29e502020-11-28 17:42:02 +0100181 xSnprintf(buffer, sizeof(buffer), "%11llu ", number / ONE_DECIMAL_K);
Christian Göttsche157086e2020-12-04 14:44:57 +0100182 RichString_appendnAscii(str, largeNumberColor, buffer, 5);
Benny Baumann0d85af22021-07-14 19:18:27 +0200183 RichString_appendnAscii(str, processMegabytesColor, buffer + 5, 3);
184 RichString_appendnAscii(str, processColor, buffer + 8, 4);
Hisham Muhammad9b351402011-05-26 16:31:18 +0000185 } else {
Benny Baumann0b29e502020-11-28 17:42:02 +0100186 xSnprintf(buffer, sizeof(buffer), "%11llu ", number);
Christian Göttsche157086e2020-12-04 14:44:57 +0100187 RichString_appendnAscii(str, largeNumberColor, buffer, 2);
Benny Baumann0d85af22021-07-14 19:18:27 +0200188 RichString_appendnAscii(str, processMegabytesColor, buffer + 2, 3);
189 RichString_appendnAscii(str, processColor, buffer + 5, 3);
190 RichString_appendnAscii(str, processShadowColor, buffer + 8, 4);
Hisham Muhammad9b351402011-05-26 16:31:18 +0000191 }
192}
193
Christian Göttscheb41e4d92021-04-14 20:16:16 +0200194void Process_printTime(RichString* str, unsigned long long totalHundredths, bool coloring) {
195 char buffer[10];
196 int len;
Hisham Muhammadd6231ba2006-03-04 18:16:49 +0000197
Christian Göttscheb41e4d92021-04-14 20:16:16 +0200198 unsigned long long totalSeconds = totalHundredths / 100;
Hisham Muhammad272e2d92015-03-16 23:01:48 -0300199 unsigned long long hours = totalSeconds / 3600;
David Zarzyckif3d9eca2021-04-10 08:02:59 -0400200 unsigned long long days = totalSeconds / 86400;
Hisham Muhammad272e2d92015-03-16 23:01:48 -0300201 int minutes = (totalSeconds / 60) % 60;
202 int seconds = totalSeconds % 60;
203 int hundredths = totalHundredths - (totalSeconds * 100);
Christian Göttscheb41e4d92021-04-14 20:16:16 +0200204
205 int yearColor = coloring ? CRT_colors[LARGE_NUMBER] : CRT_colors[PROCESS];
206 int dayColor = coloring ? CRT_colors[PROCESS_GIGABYTES] : CRT_colors[PROCESS];
207 int hourColor = coloring ? CRT_colors[PROCESS_MEGABYTES] : CRT_colors[PROCESS];
208 int defColor = CRT_colors[PROCESS];
209
210 if (days >= /* Ignore leapyears */365) {
211 int years = days / 365;
212 int daysLeft = days - 365 * years;
213
Benny Baumannec809b72022-04-13 07:25:09 +0200214 if (years >= 10000000) {
215 RichString_appendnAscii(str, yearColor, "eternity ", 9);
216 } else if (years >= 1000) {
217 len = xSnprintf(buffer, sizeof(buffer), "%7dy ", years);
218 RichString_appendnAscii(str, yearColor, buffer, len);
219 } else if (daysLeft >= 100) {
Christian Göttscheb41e4d92021-04-14 20:16:16 +0200220 len = xSnprintf(buffer, sizeof(buffer), "%3dy", years);
221 RichString_appendnAscii(str, yearColor, buffer, len);
222 len = xSnprintf(buffer, sizeof(buffer), "%3dd ", daysLeft);
223 RichString_appendnAscii(str, dayColor, buffer, len);
224 } else if (daysLeft >= 10) {
225 len = xSnprintf(buffer, sizeof(buffer), "%4dy", years);
226 RichString_appendnAscii(str, yearColor, buffer, len);
227 len = xSnprintf(buffer, sizeof(buffer), "%2dd ", daysLeft);
228 RichString_appendnAscii(str, dayColor, buffer, len);
Hisham Muhammad9c44f582011-12-14 23:29:07 +0000229 } else {
Christian Göttscheb41e4d92021-04-14 20:16:16 +0200230 len = xSnprintf(buffer, sizeof(buffer), "%5dy", years);
231 RichString_appendnAscii(str, yearColor, buffer, len);
232 len = xSnprintf(buffer, sizeof(buffer), "%1dd ", daysLeft);
233 RichString_appendnAscii(str, dayColor, buffer, len);
Hisham Muhammad9c44f582011-12-14 23:29:07 +0000234 }
Christian Göttscheb41e4d92021-04-14 20:16:16 +0200235 } else if (days >= 100) {
236 int hoursLeft = hours - days * 24;
237
238 if (hoursLeft >= 10) {
239 len = xSnprintf(buffer, sizeof(buffer), "%4llud", days);
240 RichString_appendnAscii(str, dayColor, buffer, len);
241 len = xSnprintf(buffer, sizeof(buffer), "%2dh ", hoursLeft);
242 RichString_appendnAscii(str, hourColor, buffer, len);
243 } else {
244 len = xSnprintf(buffer, sizeof(buffer), "%5llud", days);
245 RichString_appendnAscii(str, dayColor, buffer, len);
246 len = xSnprintf(buffer, sizeof(buffer), "%1dh ", hoursLeft);
247 RichString_appendnAscii(str, hourColor, buffer, len);
248 }
249 } else if (hours >= 100) {
250 int minutesLeft = totalSeconds / 60 - hours * 60;
251
252 if (minutesLeft >= 10) {
253 len = xSnprintf(buffer, sizeof(buffer), "%4lluh", hours);
254 RichString_appendnAscii(str, hourColor, buffer, len);
255 len = xSnprintf(buffer, sizeof(buffer), "%2dm ", minutesLeft);
256 RichString_appendnAscii(str, defColor, buffer, len);
257 } else {
258 len = xSnprintf(buffer, sizeof(buffer), "%5lluh", hours);
259 RichString_appendnAscii(str, hourColor, buffer, len);
260 len = xSnprintf(buffer, sizeof(buffer), "%1dm ", minutesLeft);
261 RichString_appendnAscii(str, defColor, buffer, len);
262 }
263 } else if (hours > 0) {
264 len = xSnprintf(buffer, sizeof(buffer), "%2lluh", hours);
265 RichString_appendnAscii(str, hourColor, buffer, len);
266 len = xSnprintf(buffer, sizeof(buffer), "%02d:%02d ", minutes, seconds);
267 RichString_appendnAscii(str, defColor, buffer, len);
268 } else {
269 len = xSnprintf(buffer, sizeof(buffer), "%2d:%02d.%02d ", minutes, seconds, hundredths);
270 RichString_appendnAscii(str, defColor, buffer, len);
Hisham Muhammadd6231ba2006-03-04 18:16:49 +0000271 }
Hisham Muhammadd6231ba2006-03-04 18:16:49 +0000272}
273
Christian Göttschea63cfc82020-10-13 14:26:40 +0200274void Process_fillStarttimeBuffer(Process* this) {
275 struct tm date;
276 (void) localtime_r(&this->starttime_ctime, &date);
277 strftime(this->starttime_show, sizeof(this->starttime_show) - 1, (this->starttime_ctime > (time(NULL) - 86400)) ? "%R " : "%b%d ", &date);
278}
279
Benny Baumannbcb18ef2021-04-10 13:31:39 +0200280/*
281 * TASK_COMM_LEN is defined to be 16 for /proc/[pid]/comm in man proc(5), but it is
282 * not available in an userspace header - so define it.
283 *
284 * Note: This is taken from LINUX headers, but implicitly taken for other platforms
285 * for sake of brevity.
286 *
287 * Note: when colorizing a basename with the comm prefix, the entire basename
288 * (not just the comm prefix) is colorized for better readability, and it is
289 * implicit that only upto (TASK_COMM_LEN - 1) could be comm.
290 */
291#define TASK_COMM_LEN 16
Tobias Geerinckx-Rice293eec42015-07-29 21:14:29 +0200292
Benny Baumann976c6122021-07-14 19:24:18 +0200293static bool findCommInCmdline(const char* comm, const char* cmdline, int cmdlineBasenameStart, int* pCommStart, int* pCommEnd) {
Benny Baumannbcb18ef2021-04-10 13:31:39 +0200294 /* Try to find procComm in tokenized cmdline - this might in rare cases
295 * mis-identify a string or fail, if comm or cmdline had been unsuitably
296 * modified by the process */
Benny Baumann976c6122021-07-14 19:24:18 +0200297 const char* tokenBase;
Benny Baumannbcb18ef2021-04-10 13:31:39 +0200298 size_t tokenLen;
299 const size_t commLen = strlen(comm);
300
301 if (cmdlineBasenameStart < 0)
302 return false;
303
Benny Baumann976c6122021-07-14 19:24:18 +0200304 for (const char* token = cmdline + cmdlineBasenameStart; *token;) {
Benny Baumannbcb18ef2021-04-10 13:31:39 +0200305 for (tokenBase = token; *token && *token != '\n'; ++token) {
306 if (*token == '/') {
307 tokenBase = token + 1;
Hisham Muhammadf2a190b2014-02-27 17:11:23 -0300308 }
Hisham Muhammadd6231ba2006-03-04 18:16:49 +0000309 }
Benny Baumannbcb18ef2021-04-10 13:31:39 +0200310 tokenLen = token - tokenBase;
311
312 if ((tokenLen == commLen || (tokenLen > commLen && commLen == (TASK_COMM_LEN - 1))) &&
313 strncmp(tokenBase, comm, commLen) == 0) {
314 *pCommStart = tokenBase - cmdline;
315 *pCommEnd = token - cmdline;
316 return true;
317 }
318
319 if (*token) {
320 do {
321 ++token;
322 } while (*token && '\n' == *token);
Tobias Geerinckx-Rice293eec42015-07-29 21:14:29 +0200323 }
Hisham Muhammadd6231ba2006-03-04 18:16:49 +0000324 }
Benny Baumannbcb18ef2021-04-10 13:31:39 +0200325 return false;
326}
Tobias Geerinckx-Rice293eec42015-07-29 21:14:29 +0200327
Benny Baumann976c6122021-07-14 19:24:18 +0200328static int matchCmdlinePrefixWithExeSuffix(const char* cmdline, int cmdlineBaseOffset, const char* exe, int exeBaseOffset, int exeBaseLen) {
Benny Baumannbcb18ef2021-04-10 13:31:39 +0200329 int matchLen; /* matching length to be returned */
330 char delim; /* delimiter following basename */
Tobias Geerinckx-Rice293eec42015-07-29 21:14:29 +0200331
Benny Baumannbcb18ef2021-04-10 13:31:39 +0200332 /* cmdline prefix is an absolute path: it must match whole exe. */
333 if (cmdline[0] == '/') {
334 matchLen = exeBaseLen + exeBaseOffset;
335 if (strncmp(cmdline, exe, matchLen) == 0) {
336 delim = cmdline[matchLen];
337 if (delim == 0 || delim == '\n' || delim == ' ') {
338 return matchLen;
339 }
340 }
341 return 0;
342 }
343
344 /* cmdline prefix is a relative path: We need to first match the basename at
345 * cmdlineBaseOffset and then reverse match the cmdline prefix with the exe
346 * suffix. But there is a catch: Some processes modify their cmdline in ways
347 * that make htop's identification of the basename in cmdline unreliable.
348 * For e.g. /usr/libexec/gdm-session-worker modifies its cmdline to
349 * "gdm-session-worker [pam/gdm-autologin]" and htop ends up with
350 * proccmdlineBasenameEnd at "gdm-autologin]". This issue could arise with
351 * chrome as well as it stores in cmdline its concatenated argument vector,
352 * without NUL delimiter between the arguments (which may contain a '/')
353 *
354 * So if needed, we adjust cmdlineBaseOffset to the previous (if any)
355 * component of the cmdline relative path, and retry the procedure. */
356 bool delimFound; /* if valid basename delimiter found */
357 do {
358 /* match basename */
359 matchLen = exeBaseLen + cmdlineBaseOffset;
360 if (cmdlineBaseOffset < exeBaseOffset &&
361 strncmp(cmdline + cmdlineBaseOffset, exe + exeBaseOffset, exeBaseLen) == 0) {
362 delim = cmdline[matchLen];
363 if (delim == 0 || delim == '\n' || delim == ' ') {
364 int i, j;
365 /* reverse match the cmdline prefix and exe suffix */
366 for (i = cmdlineBaseOffset - 1, j = exeBaseOffset - 1;
367 i >= 0 && j >= 0 && cmdline[i] == exe[j]; --i, --j)
368 ;
369
370 /* full match, with exe suffix being a valid relative path */
371 if (i < 0 && j >= 0 && exe[j] == '/')
372 return matchLen;
373 }
374 }
375
376 /* Try to find the previous potential cmdlineBaseOffset - it would be
377 * preceded by '/' or nothing, and delimited by ' ' or '\n' */
378 for (delimFound = false, cmdlineBaseOffset -= 2; cmdlineBaseOffset > 0; --cmdlineBaseOffset) {
379 if (delimFound) {
380 if (cmdline[cmdlineBaseOffset - 1] == '/') {
381 break;
382 }
383 } else if (cmdline[cmdlineBaseOffset] == ' ' || cmdline[cmdlineBaseOffset] == '\n') {
384 delimFound = true;
385 }
386 }
387 } while (delimFound);
388
389 return 0;
390}
391
392/* stpcpy, but also converts newlines to spaces */
Benny Baumann976c6122021-07-14 19:24:18 +0200393static inline char* stpcpyWithNewlineConversion(char* dstStr, const char* srcStr) {
Benny Baumannbcb18ef2021-04-10 13:31:39 +0200394 for (; *srcStr; ++srcStr) {
395 *dstStr++ = (*srcStr == '\n') ? ' ' : *srcStr;
396 }
397 *dstStr = 0;
398 return dstStr;
399}
400
401/*
402 * This function makes the merged Command string. It also stores the offsets of the
403 * basename, comm w.r.t the merged Command string - these offsets will be used by
404 * Process_writeCommand() for coloring. The merged Command string is also
Christian Göttsche1ef8c0e2021-12-16 15:57:37 +0100405 * returned by Process_getCommand() for searching, sorting and filtering.
Benny Baumannbcb18ef2021-04-10 13:31:39 +0200406 */
Benny Baumann976c6122021-07-14 19:24:18 +0200407void Process_makeCommandStr(Process* this) {
408 ProcessMergedCommand* mc = &this->mergedCommand;
409 const Settings* settings = this->settings;
Benny Baumannbcb18ef2021-04-10 13:31:39 +0200410
411 bool showMergedCommand = settings->showMergedCommand;
412 bool showProgramPath = settings->showProgramPath;
413 bool searchCommInCmdline = settings->findCommInCmdline;
414 bool stripExeFromCmdline = settings->stripExeFromCmdline;
Benny Baumann7bfd62b2021-07-17 20:59:50 +0200415 bool showThreadNames = settings->showThreadNames;
Benny Baumannbcb18ef2021-04-10 13:31:39 +0200416
Benny Baumanna61a2e62021-04-18 18:10:04 +0200417 /* Nothing to do to (Re)Generate the Command string, if the process is:
418 * - a kernel thread, or
419 * - a zombie from before being under htop's watch, or
420 * - a user thread and showThreadNames is not set */
421 if (Process_isKernelThread(this))
422 return;
marcluqued8dfbbd2021-10-12 00:45:09 +0200423 if (this->state == ZOMBIE && !this->mergedCommand.str)
Benny Baumanna61a2e62021-04-18 18:10:04 +0200424 return;
Jan Kończak8c996832022-01-05 14:27:51 +0100425 if (Process_isUserlandThread(this) && settings->showThreadNames && (showThreadNames == mc->prevShowThreadNames) && (mc->prevMergeSet == showMergedCommand))
Benny Baumanna61a2e62021-04-18 18:10:04 +0200426 return;
427
Benny Baumannbcb18ef2021-04-10 13:31:39 +0200428 /* this->mergedCommand.str needs updating only if its state or contents changed.
429 * Its content is based on the fields cmdline, comm, and exe. */
430 if (
Benny Baumann458749d2021-07-14 19:15:09 +0200431 mc->prevMergeSet == showMergedCommand &&
432 mc->prevPathSet == showProgramPath &&
433 mc->prevCommSet == searchCommInCmdline &&
434 mc->prevCmdlineSet == stripExeFromCmdline &&
Benny Baumann7bfd62b2021-07-17 20:59:50 +0200435 mc->prevShowThreadNames == showThreadNames &&
Benny Baumann458749d2021-07-14 19:15:09 +0200436 !mc->cmdlineChanged &&
437 !mc->commChanged &&
438 !mc->exeChanged
Benny Baumannbcb18ef2021-04-10 13:31:39 +0200439 ) {
440 return;
441 }
442
443 /* The field separtor "│" has been chosen such that it will not match any
444 * valid string used for searching or filtering */
Benny Baumann976c6122021-07-14 19:24:18 +0200445 const char* SEPARATOR = CRT_treeStr[TREE_STR_VERT];
Benny Baumannbcb18ef2021-04-10 13:31:39 +0200446 const int SEPARATOR_LEN = strlen(SEPARATOR);
447
448 /* Check for any changed fields since we last built this string */
449 if (mc->cmdlineChanged || mc->commChanged || mc->exeChanged) {
450 free(mc->str);
451 /* Accommodate the column text, two field separators and terminating NUL */
Benny Baumann7ef58f22021-05-17 23:15:24 +0200452 size_t maxLen = 2 * SEPARATOR_LEN + 1;
453 maxLen += this->cmdline ? strlen(this->cmdline) : strlen("(zombie)");
454 maxLen += this->procComm ? strlen(this->procComm) : 0;
455 maxLen += this->procExe ? strlen(this->procExe) : 0;
456
457 mc->str = xCalloc(1, maxLen);
Benny Baumannbcb18ef2021-04-10 13:31:39 +0200458 }
459
460 /* Preserve the settings used in this run */
461 mc->prevMergeSet = showMergedCommand;
462 mc->prevPathSet = showProgramPath;
463 mc->prevCommSet = searchCommInCmdline;
464 mc->prevCmdlineSet = stripExeFromCmdline;
Benny Baumann7bfd62b2021-07-17 20:59:50 +0200465 mc->prevShowThreadNames = showThreadNames;
Benny Baumannbcb18ef2021-04-10 13:31:39 +0200466
467 /* Mark everything as unchanged */
468 mc->cmdlineChanged = false;
469 mc->commChanged = false;
470 mc->exeChanged = false;
471
472 /* Reset all locations that need extra handling when actually displaying */
473 mc->highlightCount = 0;
474 memset(mc->highlights, 0, sizeof(mc->highlights));
475
476 size_t mbMismatch = 0;
Benny Baumann9a781552021-05-15 21:54:46 +0200477 #define WRITE_HIGHLIGHT(_offset, _length, _attr, _flags) \
478 do { \
479 /* Check if we still have capacity */ \
480 assert(mc->highlightCount < ARRAYSIZE(mc->highlights)); \
481 if (mc->highlightCount >= ARRAYSIZE(mc->highlights)) \
Christian Göttsche5dec9472021-08-22 17:14:36 +0200482 break; \
Benny Baumann9a781552021-05-15 21:54:46 +0200483 \
484 mc->highlights[mc->highlightCount].offset = str - strStart + (_offset) - mbMismatch; \
485 mc->highlights[mc->highlightCount].length = _length; \
486 mc->highlights[mc->highlightCount].attr = _attr; \
487 mc->highlights[mc->highlightCount].flags = _flags; \
488 mc->highlightCount++; \
Benny Baumannbcb18ef2021-04-10 13:31:39 +0200489 } while (0)
490
Benny Baumann9a781552021-05-15 21:54:46 +0200491 #define WRITE_SEPARATOR \
492 do { \
493 WRITE_HIGHLIGHT(0, 1, CRT_colors[FAILED_READ], CMDLINE_HIGHLIGHT_FLAG_SEPARATOR); \
494 mbMismatch += SEPARATOR_LEN - 1; \
495 str = stpcpy(str, SEPARATOR); \
Benny Baumannbcb18ef2021-04-10 13:31:39 +0200496 } while (0)
497
498 const int baseAttr = Process_isThread(this) ? CRT_colors[PROCESS_THREAD_BASENAME] : CRT_colors[PROCESS_BASENAME];
499 const int commAttr = Process_isThread(this) ? CRT_colors[PROCESS_THREAD_COMM] : CRT_colors[PROCESS_COMM];
Christian Göttsche81541252021-04-04 18:07:26 +0200500 const int delExeAttr = CRT_colors[FAILED_READ];
501 const int delLibAttr = CRT_colors[PROCESS_TAG];
Benny Baumannbcb18ef2021-04-10 13:31:39 +0200502
503 /* Establish some shortcuts to data we need */
Benny Baumann976c6122021-07-14 19:24:18 +0200504 const char* cmdline = this->cmdline;
505 const char* procComm = this->procComm;
506 const char* procExe = this->procExe;
Benny Baumannbcb18ef2021-04-10 13:31:39 +0200507
Benny Baumann976c6122021-07-14 19:24:18 +0200508 char* strStart = mc->str;
509 char* str = strStart;
Benny Baumannbcb18ef2021-04-10 13:31:39 +0200510
511 int cmdlineBasenameStart = this->cmdlineBasenameStart;
512 int cmdlineBasenameEnd = this->cmdlineBasenameEnd;
513
514 if (!cmdline) {
515 cmdlineBasenameStart = 0;
516 cmdlineBasenameEnd = 0;
517 cmdline = "(zombie)";
518 }
519
520 assert(cmdlineBasenameStart >= 0);
521 assert(cmdlineBasenameStart <= (int)strlen(cmdline));
522
523 if (!showMergedCommand || !procExe || !procComm) { /* fall back to cmdline */
Jan Kończak8c996832022-01-05 14:27:51 +0100524 if ((showMergedCommand || (Process_isUserlandThread(this) && showThreadNames)) && procComm && strlen(procComm)) { /* set column to or prefix it with comm */
Benny Baumannbcb18ef2021-04-10 13:31:39 +0200525 if (strncmp(cmdline + cmdlineBasenameStart, procComm, MINIMUM(TASK_COMM_LEN - 1, strlen(procComm))) != 0) {
526 WRITE_HIGHLIGHT(0, strlen(procComm), commAttr, CMDLINE_HIGHLIGHT_FLAG_COMM);
527 str = stpcpy(str, procComm);
528
Jan Kończak8c996832022-01-05 14:27:51 +0100529 if(!showMergedCommand)
530 return;
531
Benny Baumannbcb18ef2021-04-10 13:31:39 +0200532 WRITE_SEPARATOR;
533 }
534 }
535
Benny Baumann2824e292021-05-15 21:55:14 +0200536 if (cmdlineBasenameEnd > cmdlineBasenameStart)
537 WRITE_HIGHLIGHT(showProgramPath ? cmdlineBasenameStart : 0, cmdlineBasenameEnd - cmdlineBasenameStart, baseAttr, CMDLINE_HIGHLIGHT_FLAG_BASENAME);
Benny Baumannb7248f62021-10-06 16:38:45 +0200538
539 if (this->procExeDeleted)
540 WRITE_HIGHLIGHT(showProgramPath ? cmdlineBasenameStart : 0, cmdlineBasenameEnd - cmdlineBasenameStart, delExeAttr, CMDLINE_HIGHLIGHT_FLAG_DELETED);
541 else if (this->usesDeletedLib)
542 WRITE_HIGHLIGHT(showProgramPath ? cmdlineBasenameStart : 0, cmdlineBasenameEnd - cmdlineBasenameStart, delLibAttr, CMDLINE_HIGHLIGHT_FLAG_DELETED);
543
Benny Baumann2824e292021-05-15 21:55:14 +0200544 (void)stpcpyWithNewlineConversion(str, cmdline + (showProgramPath ? 0 : cmdlineBasenameStart));
Benny Baumannbcb18ef2021-04-10 13:31:39 +0200545
546 return;
547 }
548
549 int exeLen = strlen(this->procExe);
550 int exeBasenameOffset = this->procExeBasenameOffset;
551 int exeBasenameLen = exeLen - exeBasenameOffset;
552
553 assert(exeBasenameOffset >= 0);
554 assert(exeBasenameOffset <= (int)strlen(procExe));
555
556 bool haveCommInExe = false;
Christian Göttschece27f832021-08-08 16:04:26 +0200557 if (procExe && procComm && (!Process_isUserlandThread(this) || showThreadNames)) {
Benny Baumannbcb18ef2021-04-10 13:31:39 +0200558 haveCommInExe = strncmp(procExe + exeBasenameOffset, procComm, TASK_COMM_LEN - 1) == 0;
559 }
560
561 /* Start with copying exe */
562 if (showProgramPath) {
563 if (haveCommInExe)
564 WRITE_HIGHLIGHT(exeBasenameOffset, exeBasenameLen, commAttr, CMDLINE_HIGHLIGHT_FLAG_COMM);
565 WRITE_HIGHLIGHT(exeBasenameOffset, exeBasenameLen, baseAttr, CMDLINE_HIGHLIGHT_FLAG_BASENAME);
566 if (this->procExeDeleted)
Christian Göttsche81541252021-04-04 18:07:26 +0200567 WRITE_HIGHLIGHT(exeBasenameOffset, exeBasenameLen, delExeAttr, CMDLINE_HIGHLIGHT_FLAG_DELETED);
568 else if (this->usesDeletedLib)
569 WRITE_HIGHLIGHT(exeBasenameOffset, exeBasenameLen, delLibAttr, CMDLINE_HIGHLIGHT_FLAG_DELETED);
Benny Baumannbcb18ef2021-04-10 13:31:39 +0200570 str = stpcpy(str, procExe);
571 } else {
572 if (haveCommInExe)
573 WRITE_HIGHLIGHT(0, exeBasenameLen, commAttr, CMDLINE_HIGHLIGHT_FLAG_COMM);
574 WRITE_HIGHLIGHT(0, exeBasenameLen, baseAttr, CMDLINE_HIGHLIGHT_FLAG_BASENAME);
575 if (this->procExeDeleted)
Christian Göttsche81541252021-04-04 18:07:26 +0200576 WRITE_HIGHLIGHT(0, exeBasenameLen, delExeAttr, CMDLINE_HIGHLIGHT_FLAG_DELETED);
577 else if (this->usesDeletedLib)
578 WRITE_HIGHLIGHT(0, exeBasenameLen, delLibAttr, CMDLINE_HIGHLIGHT_FLAG_DELETED);
Benny Baumannbcb18ef2021-04-10 13:31:39 +0200579 str = stpcpy(str, procExe + exeBasenameOffset);
580 }
581
582 bool haveCommInCmdline = false;
583 int commStart = 0;
584 int commEnd = 0;
585
586 /* Try to match procComm with procExe's basename: This is reliable (predictable) */
587 if (searchCommInCmdline) {
588 /* commStart/commEnd will be adjusted later along with cmdline */
Christian Göttschece27f832021-08-08 16:04:26 +0200589 haveCommInCmdline = (!Process_isUserlandThread(this) || showThreadNames) && findCommInCmdline(procComm, cmdline, cmdlineBasenameStart, &commStart, &commEnd);
Benny Baumannbcb18ef2021-04-10 13:31:39 +0200590 }
591
592 int matchLen = matchCmdlinePrefixWithExeSuffix(cmdline, cmdlineBasenameStart, procExe, exeBasenameOffset, exeBasenameLen);
593
594 bool haveCommField = false;
595
Christian Göttschece27f832021-08-08 16:04:26 +0200596 if (!haveCommInExe && !haveCommInCmdline && procComm && (!Process_isUserlandThread(this) || showThreadNames)) {
Benny Baumannbcb18ef2021-04-10 13:31:39 +0200597 WRITE_SEPARATOR;
598 WRITE_HIGHLIGHT(0, strlen(procComm), commAttr, CMDLINE_HIGHLIGHT_FLAG_COMM);
599 str = stpcpy(str, procComm);
600 haveCommField = true;
601 }
602
603 if (matchLen) {
604 /* strip the matched exe prefix */
605 cmdline += matchLen;
606
607 commStart -= matchLen;
608 commEnd -= matchLen;
609 }
610
611 if (!matchLen || (haveCommField && *cmdline)) {
612 /* cmdline will be a separate field */
613 WRITE_SEPARATOR;
614 }
615
Christian Göttschece27f832021-08-08 16:04:26 +0200616 if (!haveCommInExe && haveCommInCmdline && !haveCommField && (!Process_isUserlandThread(this) || showThreadNames))
Benny Baumannbcb18ef2021-04-10 13:31:39 +0200617 WRITE_HIGHLIGHT(commStart, commEnd - commStart, commAttr, CMDLINE_HIGHLIGHT_FLAG_COMM);
618
619 /* Display cmdline if it hasn't been consumed by procExe */
620 if (*cmdline)
621 (void)stpcpyWithNewlineConversion(str, cmdline);
622
623 #undef WRITE_SEPARATOR
624 #undef WRITE_HIGHLIGHT
625}
626
627void Process_writeCommand(const Process* this, int attr, int baseAttr, RichString* str) {
628 (void)baseAttr;
629
Benny Baumann976c6122021-07-14 19:24:18 +0200630 const ProcessMergedCommand* mc = &this->mergedCommand;
Benny Baumannbcb18ef2021-04-10 13:31:39 +0200631
632 int strStart = RichString_size(str);
633
634 const bool highlightBaseName = this->settings->highlightBaseName;
635 const bool highlightSeparator = true;
Benny Baumannbf07c712020-12-19 16:46:00 +0100636 const bool highlightDeleted = this->settings->highlightDeletedExe;
Benny Baumannbcb18ef2021-04-10 13:31:39 +0200637
638 if (!this->mergedCommand.str) {
639 int len = 0;
640 const char* cmdline = this->cmdline;
641
642 if (highlightBaseName || !this->settings->showProgramPath) {
643 int basename = 0;
644 for (int i = 0; i < this->cmdlineBasenameEnd; i++) {
645 if (cmdline[i] == '/') {
646 basename = i + 1;
647 } else if (cmdline[i] == ':') {
648 len = i + 1;
649 break;
650 }
651 }
652 if (len == 0) {
653 if (this->settings->showProgramPath) {
654 strStart += basename;
655 } else {
656 cmdline += basename;
657 }
658 len = this->cmdlineBasenameEnd - basename;
659 }
660 }
661
662 RichString_appendWide(str, attr, cmdline);
663
664 if (this->settings->highlightBaseName) {
665 RichString_setAttrn(str, baseAttr, strStart, len);
666 }
667
668 return;
669 }
670
671 RichString_appendWide(str, attr, this->mergedCommand.str);
672
673 for (size_t i = 0, hlCount = CLAMP(mc->highlightCount, 0, ARRAYSIZE(mc->highlights)); i < hlCount; i++) {
Benny Baumann976c6122021-07-14 19:24:18 +0200674 const ProcessCmdlineHighlight* hl = &mc->highlights[i];
Benny Baumannbcb18ef2021-04-10 13:31:39 +0200675
676 if (!hl->length)
677 continue;
678
679 if (hl->flags & CMDLINE_HIGHLIGHT_FLAG_SEPARATOR)
680 if (!highlightSeparator)
681 continue;
682
683 if (hl->flags & CMDLINE_HIGHLIGHT_FLAG_BASENAME)
684 if (!highlightBaseName)
685 continue;
686
687 if (hl->flags & CMDLINE_HIGHLIGHT_FLAG_DELETED)
688 if (!highlightDeleted)
689 continue;
690
691 RichString_setAttrn(str, hl->attr, strStart + hl->offset, hl->length);
Benny Baumann45869512020-11-01 01:09:51 +0100692 }
Hisham Muhammadd6231ba2006-03-04 18:16:49 +0000693}
694
Christian Göttscheb41e4d92021-04-14 20:16:16 +0200695void Process_printRate(RichString* str, double rate, bool coloring) {
696 char buffer[16];
697
Hisham Muhammad3383d8e2015-01-21 23:27:31 -0200698 int largeNumberColor = CRT_colors[LARGE_NUMBER];
699 int processMegabytesColor = CRT_colors[PROCESS_MEGABYTES];
700 int processColor = CRT_colors[PROCESS];
Christian Göttscheb41e4d92021-04-14 20:16:16 +0200701 int shadowColor = CRT_colors[PROCESS_SHADOW];
Benny Baumann0b29e502020-11-28 17:42:02 +0100702
Hisham Muhammad3383d8e2015-01-21 23:27:31 -0200703 if (!coloring) {
704 largeNumberColor = CRT_colors[PROCESS];
705 processMegabytesColor = CRT_colors[PROCESS];
Hisham Muhammad2338ad52008-03-14 18:50:49 +0000706 }
Benny Baumann0b29e502020-11-28 17:42:02 +0100707
Benny Baumann29ec1152020-09-07 11:53:58 +0200708 if (isnan(rate)) {
Christian Göttscheb41e4d92021-04-14 20:16:16 +0200709 RichString_appendAscii(str, shadowColor, " N/A ");
710 } else if (rate < 0.005) {
711 int len = snprintf(buffer, sizeof(buffer), "%7.2f B/s ", rate);
712 RichString_appendnAscii(str, shadowColor, buffer, len);
Hisham797bcd02016-02-20 02:22:57 -0200713 } else if (rate < ONE_K) {
Christian Göttscheb41e4d92021-04-14 20:16:16 +0200714 int len = snprintf(buffer, sizeof(buffer), "%7.2f B/s ", rate);
Christian Göttsche157086e2020-12-04 14:44:57 +0100715 RichString_appendnAscii(str, processColor, buffer, len);
adrien1018536941f2018-12-30 20:18:35 +0800716 } else if (rate < ONE_M) {
Christian Göttscheb41e4d92021-04-14 20:16:16 +0200717 int len = snprintf(buffer, sizeof(buffer), "%7.2f K/s ", rate / ONE_K);
Christian Göttsche157086e2020-12-04 14:44:57 +0100718 RichString_appendnAscii(str, processColor, buffer, len);
adrien1018536941f2018-12-30 20:18:35 +0800719 } else if (rate < ONE_G) {
Christian Göttscheb41e4d92021-04-14 20:16:16 +0200720 int len = snprintf(buffer, sizeof(buffer), "%7.2f M/s ", rate / ONE_M);
Christian Göttsche157086e2020-12-04 14:44:57 +0100721 RichString_appendnAscii(str, processMegabytesColor, buffer, len);
adrien1018536941f2018-12-30 20:18:35 +0800722 } else if (rate < ONE_T) {
Christian Göttscheb41e4d92021-04-14 20:16:16 +0200723 int len = snprintf(buffer, sizeof(buffer), "%7.2f G/s ", rate / ONE_G);
724 RichString_appendnAscii(str, largeNumberColor, buffer, len);
725 } else if (rate < ONE_P) {
726 int len = snprintf(buffer, sizeof(buffer), "%7.2f T/s ", rate / ONE_T);
Christian Göttsche157086e2020-12-04 14:44:57 +0100727 RichString_appendnAscii(str, largeNumberColor, buffer, len);
Hisham Muhammad3383d8e2015-01-21 23:27:31 -0200728 } else {
Christian Göttscheb41e4d92021-04-14 20:16:16 +0200729 int len = snprintf(buffer, sizeof(buffer), "%7.2f P/s ", rate / ONE_P);
Christian Göttsche157086e2020-12-04 14:44:57 +0100730 RichString_appendnAscii(str, largeNumberColor, buffer, len);
Hisham Muhammad3383d8e2015-01-21 23:27:31 -0200731 }
Hisham Muhammad2338ad52008-03-14 18:50:49 +0000732}
733
Christian Göttschea5db1392021-01-10 15:57:46 +0100734void Process_printLeftAlignedField(RichString* str, int attr, const char* content, unsigned int width) {
Christian Göttsche08ac22d2021-01-14 09:59:11 +0100735 int columns = width;
736 RichString_appendnWideColumns(str, attr, content, strlen(content), &columns);
737 RichString_appendChr(str, attr, ' ', width + 1 - columns);
Christian Göttschea5db1392021-01-10 15:57:46 +0100738}
739
Benny Baumannedf319e2022-02-27 20:29:40 +0100740void Process_printPercentage(float val, char* buffer, int n, uint8_t width, int* attr) {
Hisham Muhammad556d7c02021-09-03 12:44:19 +1000741 if (val >= 0) {
742 if (val < 99.9F) {
743 if (val < 0.05F) {
744 *attr = CRT_colors[PROCESS_SHADOW];
745 }
Benny Baumannedf319e2022-02-27 20:29:40 +0100746 xSnprintf(buffer, n, "%*.1f ", width, val);
Hisham Muhammad556d7c02021-09-03 12:44:19 +1000747 } else {
Nathan Scottbe824482021-09-14 11:16:34 +1000748 *attr = CRT_colors[PROCESS_MEGABYTES];
Kumar6133cac2022-02-19 07:35:04 +0530749 if (val < 100.0F)
750 val = 100.0F; // Don't round down and display "val" as "99".
Benny Baumannedf319e2022-02-27 20:29:40 +0100751 xSnprintf(buffer, n, "%*.0f ", width, val);
Hisham Muhammad556d7c02021-09-03 12:44:19 +1000752 }
753 } else {
754 *attr = CRT_colors[PROCESS_SHADOW];
Benny Baumannedf319e2022-02-27 20:29:40 +0100755 xSnprintf(buffer, n, "%*.*s ", width, width, "N/A");
Hisham Muhammad556d7c02021-09-03 12:44:19 +1000756 }
757}
758
marcluqued8dfbbd2021-10-12 00:45:09 +0200759static inline char processStateChar(ProcessState state) {
760 switch (state) {
761 case UNKNOWN: return '?';
762 case RUNNABLE: return 'U';
763 case RUNNING: return 'R';
764 case QUEUED: return 'Q';
765 case WAITING: return 'W';
766 case UNINTERRUPTIBLE_WAIT: return 'D';
767 case BLOCKED: return 'B';
768 case PAGING: return 'P';
769 case STOPPED: return 'T';
770 case TRACED: return 't';
771 case ZOMBIE: return 'Z';
772 case DEFUNCT: return 'X';
773 case IDLE: return 'I';
774 case SLEEPING: return 'S';
775 default:
776 assert(0);
777 return '!';
778 }
779}
780
Christian Göttsche79ad39c2020-10-06 12:28:11 +0200781void Process_writeField(const Process* this, RichString* str, ProcessField field) {
Christian Göttschefee744a2021-01-27 15:11:46 +0100782 char buffer[256];
783 size_t n = sizeof(buffer);
Hisham Muhammadd6231ba2006-03-04 18:16:49 +0000784 int attr = CRT_colors[DEFAULT_COLOR];
Hisham Muhammad3383d8e2015-01-21 23:27:31 -0200785 bool coloring = this->settings->highlightMegabytes;
Hisham Muhammadd6231ba2006-03-04 18:16:49 +0000786
787 switch (field) {
Hisham Muhammadd6231ba2006-03-04 18:16:49 +0000788 case COMM: {
Christian Göttschefee744a2021-01-27 15:11:46 +0100789 int baseattr = CRT_colors[PROCESS_BASENAME];
Hisham Muhammad3383d8e2015-01-21 23:27:31 -0200790 if (this->settings->highlightThreads && Process_isThread(this)) {
Hisham Muhammad93f091c2008-03-08 23:39:48 +0000791 attr = CRT_colors[PROCESS_THREAD];
792 baseattr = CRT_colors[PROCESS_THREAD_BASENAME];
793 }
Hisham Muhammad72ba20f2021-08-31 15:38:52 +1000794 const ScreenSettings* ss = this->settings->ss;
795 if (!ss->treeView || this->indent == 0) {
Hisham Muhammad93f091c2008-03-08 23:39:48 +0000796 Process_writeCommand(this, attr, baseattr, str);
Hisham Muhammadd6231ba2006-03-04 18:16:49 +0000797 return;
Hisham Muhammadd6231ba2006-03-04 18:16:49 +0000798 }
Christian Göttschefee744a2021-01-27 15:11:46 +0100799
800 char* buf = buffer;
801 int maxIndent = 0;
802 bool lastItem = (this->indent < 0);
803 int indent = (this->indent < 0 ? -this->indent : this->indent);
804
805 for (int i = 0; i < 32; i++) {
806 if (indent & (1U << i)) {
Benny Baumann0d85af22021-07-14 19:18:27 +0200807 maxIndent = i + 1;
Christian Göttschefee744a2021-01-27 15:11:46 +0100808 }
809 }
810
811 for (int i = 0; i < maxIndent - 1; i++) {
812 int written, ret;
813 if (indent & (1 << i)) {
814 ret = xSnprintf(buf, n, "%s ", CRT_treeStr[TREE_STR_VERT]);
815 } else {
816 ret = xSnprintf(buf, n, " ");
817 }
818 if (ret < 0 || (size_t)ret >= n) {
819 written = n;
820 } else {
821 written = ret;
822 }
823 buf += written;
824 n -= written;
825 }
826
827 const char* draw = CRT_treeStr[lastItem ? TREE_STR_BEND : TREE_STR_RTEE];
828 xSnprintf(buf, n, "%s%s ", draw, this->showChildren ? CRT_treeStr[TREE_STR_SHUT] : CRT_treeStr[TREE_STR_OPEN] );
829 RichString_appendWide(str, CRT_colors[PROCESS_TREE], buffer);
830 Process_writeCommand(this, attr, baseattr, str);
831 return;
Hisham Muhammadd6231ba2006-03-04 18:16:49 +0000832 }
Benny Baumannaa8552b2021-04-18 19:25:56 +0200833 case PROC_COMM: {
834 const char* procComm;
835 if (this->procComm) {
836 attr = CRT_colors[Process_isUserlandThread(this) ? PROCESS_THREAD_COMM : PROCESS_COMM];
837 procComm = this->procComm;
838 } else {
839 attr = CRT_colors[PROCESS_SHADOW];
840 procComm = Process_isKernelThread(this) ? kthreadID : "N/A";
841 }
842
843 Process_printLeftAlignedField(str, attr, procComm, TASK_COMM_LEN - 1);
844 return;
845 }
846 case PROC_EXE: {
847 const char* procExe;
848 if (this->procExe) {
849 attr = CRT_colors[Process_isUserlandThread(this) ? PROCESS_THREAD_BASENAME : PROCESS_BASENAME];
Benny Baumannde1d0632021-06-10 23:23:03 +0200850 if (this->settings->highlightDeletedExe) {
851 if (this->procExeDeleted)
852 attr = CRT_colors[FAILED_READ];
853 else if (this->usesDeletedLib)
854 attr = CRT_colors[PROCESS_TAG];
855 }
Benny Baumannaa8552b2021-04-18 19:25:56 +0200856 procExe = this->procExe + this->procExeBasenameOffset;
857 } else {
858 attr = CRT_colors[PROCESS_SHADOW];
859 procExe = Process_isKernelThread(this) ? kthreadID : "N/A";
860 }
861
862 Process_printLeftAlignedField(str, attr, procExe, TASK_COMM_LEN - 1);
863 return;
864 }
Benny Baumannb6ff5c82021-05-25 19:02:12 +0200865 case CWD: {
866 const char* cwd;
867 if (!this->procCwd) {
868 attr = CRT_colors[PROCESS_SHADOW];
869 cwd = "N/A";
870 } else if (String_startsWith(this->procCwd, "/proc/") && strstr(this->procCwd, " (deleted)") != NULL) {
871 attr = CRT_colors[PROCESS_SHADOW];
872 cwd = "main thread terminated";
873 } else {
874 cwd = this->procCwd;
875 }
876 Process_printLeftAlignedField(str, attr, cwd, 25);
877 return;
878 }
Benny Baumannb83ce852022-04-03 12:57:23 +0200879 case ELAPSED: {
880 const uint64_t rt = this->processList->realtimeMs;
881 const uint64_t st = this->starttime_ctime * 1000;
882 const uint64_t dt =
883 rt < st ? 0 :
884 rt - st;
885 Process_printTime(str, /* convert to hundreds of a second */ dt / 10, coloring);
886 return;
887 }
Christian Göttscheb41e4d92021-04-14 20:16:16 +0200888 case MAJFLT: Process_printCount(str, this->majflt, coloring); return;
889 case MINFLT: Process_printCount(str, this->minflt, coloring); return;
890 case M_RESIDENT: Process_printKBytes(str, this->m_resident, coloring); return;
891 case M_VIRT: Process_printKBytes(str, this->m_virt, coloring); return;
Christian Göttschefee744a2021-01-27 15:11:46 +0100892 case NICE:
Hisham Muhammad09e241f2017-07-27 16:07:50 -0300893 xSnprintf(buffer, n, "%3ld ", this->nice);
Hisham Muhammadbe1700c2015-03-16 01:43:04 -0300894 attr = this->nice < 0 ? CRT_colors[PROCESS_HIGH_PRIORITY]
895 : this->nice > 0 ? CRT_colors[PROCESS_LOW_PRIORITY]
Christian Göttschefee744a2021-01-27 15:11:46 +0100896 : CRT_colors[PROCESS_SHADOW];
897 break;
898 case NLWP:
899 if (this->nlwp == 1)
900 attr = CRT_colors[PROCESS_SHADOW];
901
902 xSnprintf(buffer, n, "%4ld ", this->nlwp);
903 break;
Benny Baumannedf319e2022-02-27 20:29:40 +0100904 case PERCENT_CPU: Process_printPercentage(this->percent_cpu, buffer, n, Process_fieldWidths[PERCENT_CPU], &attr); break;
Christian Göttschefee744a2021-01-27 15:11:46 +0100905 case PERCENT_NORM_CPU: {
Hisham Muhammad556d7c02021-09-03 12:44:19 +1000906 float cpuPercentage = this->percent_cpu / this->processList->activeCPUs;
Benny Baumannedf319e2022-02-27 20:29:40 +0100907 Process_printPercentage(cpuPercentage, buffer, n, Process_fieldWidths[PERCENT_CPU], &attr);
Hisham Muhammadbe1700c2015-03-16 01:43:04 -0300908 break;
909 }
Benny Baumannedf319e2022-02-27 20:29:40 +0100910 case PERCENT_MEM: Process_printPercentage(this->percent_mem, buffer, n, 4, &attr); break;
Christian Göttsche9f68c8d2020-12-15 19:44:52 +0100911 case PGRP: xSnprintf(buffer, n, "%*d ", Process_pidDigits, this->pgrp); break;
912 case PID: xSnprintf(buffer, n, "%*d ", Process_pidDigits, this->pid); break;
913 case PPID: xSnprintf(buffer, n, "%*d ", Process_pidDigits, this->ppid); break;
Christian Göttschefee744a2021-01-27 15:11:46 +0100914 case PRIORITY:
915 if (this->priority <= -100)
Hisham Muhammad09e241f2017-07-27 16:07:50 -0300916 xSnprintf(buffer, n, " RT ");
Hisham Muhammadbe1700c2015-03-16 01:43:04 -0300917 else
Hisham Muhammad09e241f2017-07-27 16:07:50 -0300918 xSnprintf(buffer, n, "%3ld ", this->priority);
Hisham Muhammadbe1700c2015-03-16 01:43:04 -0300919 break;
Hisham Muhammad09e241f2017-07-27 16:07:50 -0300920 case PROCESSOR: xSnprintf(buffer, n, "%3d ", Settings_cpuId(this->settings, this->processor)); break;
Christian Göttsche9f68c8d2020-12-15 19:44:52 +0100921 case SESSION: xSnprintf(buffer, n, "%*d ", Process_pidDigits, this->session); break;
Hisham Muhammad09e241f2017-07-27 16:07:50 -0300922 case STARTTIME: xSnprintf(buffer, n, "%s", this->starttime_show); break;
Christian Göttschefee744a2021-01-27 15:11:46 +0100923 case STATE:
marcluqued8dfbbd2021-10-12 00:45:09 +0200924 xSnprintf(buffer, n, "%c ", processStateChar(this->state));
Christian Göttschefee744a2021-01-27 15:11:46 +0100925 switch (this->state) {
marcluqued8dfbbd2021-10-12 00:45:09 +0200926 case RUNNABLE:
927 case RUNNING:
928 case TRACED:
Christian Göttsche0580dbb2021-08-30 19:20:42 +0200929 attr = CRT_colors[PROCESS_RUN_STATE];
Christian Göttschefee744a2021-01-27 15:11:46 +0100930 break;
marcluqued8dfbbd2021-10-12 00:45:09 +0200931
932 case BLOCKED:
933 case DEFUNCT:
934 case STOPPED:
Christian Göttschea38f4842021-12-04 18:12:36 +0100935 case UNINTERRUPTIBLE_WAIT:
marcluqued8dfbbd2021-10-12 00:45:09 +0200936 case ZOMBIE:
Christian Göttschefee744a2021-01-27 15:11:46 +0100937 attr = CRT_colors[PROCESS_D_STATE];
938 break;
marcluqued8dfbbd2021-10-12 00:45:09 +0200939
940 case QUEUED:
941 case WAITING:
marcluqued8dfbbd2021-10-12 00:45:09 +0200942 case IDLE:
943 case SLEEPING:
Christian Göttschefee744a2021-01-27 15:11:46 +0100944 attr = CRT_colors[PROCESS_SHADOW];
945 break;
marcluqued8dfbbd2021-10-12 00:45:09 +0200946
947 case UNKNOWN:
948 case PAGING:
949 break;
Valmiky Arquissandas64e0d942014-10-14 02:30:17 +0100950 }
Hisham Muhammadd6231ba2006-03-04 18:16:49 +0000951 break;
Silke Hofstra696f79f2021-08-16 22:50:36 +0200952 case ST_UID: xSnprintf(buffer, n, "%*d ", Process_uidDigits, this->st_uid); break;
Christian Göttscheb41e4d92021-04-14 20:16:16 +0200953 case TIME: Process_printTime(str, this->time, coloring); return;
Christian Göttschefee744a2021-01-27 15:11:46 +0100954 case TGID:
955 if (this->tgid == this->pid)
956 attr = CRT_colors[PROCESS_SHADOW];
957
958 xSnprintf(buffer, n, "%*d ", Process_pidDigits, this->tgid);
959 break;
Christian Göttsche9f68c8d2020-12-15 19:44:52 +0100960 case TPGID: xSnprintf(buffer, n, "%*d ", Process_pidDigits, this->tpgid); break;
Christian Göttsche9a822152021-03-21 19:40:56 +0100961 case TTY:
962 if (!this->tty_name) {
Christian Göttschea3c82852021-01-27 15:11:42 +0100963 attr = CRT_colors[PROCESS_SHADOW];
Christian Göttsche9a822152021-03-21 19:40:56 +0100964 xSnprintf(buffer, n, "(no tty) ");
Christian Göttschea3c82852021-01-27 15:11:42 +0100965 } else {
Christian Göttsche9a822152021-03-21 19:40:56 +0100966 const char* name = String_startsWith(this->tty_name, "/dev/") ? (this->tty_name + strlen("/dev/")) : this->tty_name;
967 xSnprintf(buffer, n, "%-8s ", name);
Christian Göttschea3c82852021-01-27 15:11:42 +0100968 }
969 break;
Christian Göttschefee744a2021-01-27 15:11:46 +0100970 case USER:
Christian Göttsche42073ba2020-11-04 17:46:04 +0100971 if (Process_getuid != this->st_uid)
Hisham Muhammadd6231ba2006-03-04 18:16:49 +0000972 attr = CRT_colors[PROCESS_SHADOW];
Christian Göttsche5359eae2020-12-23 12:21:29 +0100973
Hisham Muhammadeb2803c2006-07-12 01:35:59 +0000974 if (this->user) {
Silke Hofstra696f79f2021-08-16 22:50:36 +0200975 Process_printLeftAlignedField(str, attr, this->user, 10);
Christian Göttsche5359eae2020-12-23 12:21:29 +0100976 return;
Hisham Muhammadeb2803c2006-07-12 01:35:59 +0000977 }
Christian Göttsche5359eae2020-12-23 12:21:29 +0100978
Silke Hofstra696f79f2021-08-16 22:50:36 +0200979 xSnprintf(buffer, n, "%-10d ", this->st_uid);
Hisham Muhammadd6231ba2006-03-04 18:16:49 +0000980 break;
Hisham Muhammadd6231ba2006-03-04 18:16:49 +0000981 default:
Sohaib Mohamed6f2021f2021-07-11 03:11:29 +0200982 if (DynamicColumn_writeField(this, str, field))
983 return;
Christian Göttsche615fc932021-04-18 15:52:28 +0200984 assert(0 && "Process_writeField: default key reached"); /* should never be reached */
Hisham Muhammad09e241f2017-07-27 16:07:50 -0300985 xSnprintf(buffer, n, "- ");
Sohaib Mohamed6f2021f2021-07-11 03:11:29 +0200986 break;
Hisham Muhammadd6231ba2006-03-04 18:16:49 +0000987 }
Christian Göttschea2be57d2021-04-14 20:54:38 +0200988 RichString_appendAscii(str, attr, buffer);
Hisham Muhammadd6231ba2006-03-04 18:16:49 +0000989}
990
Christian Göttsche79ad39c2020-10-06 12:28:11 +0200991void Process_display(const Object* cast, RichString* out) {
992 const Process* this = (const Process*) cast;
Hisham Muhammad72ba20f2021-08-31 15:38:52 +1000993 const ProcessField* fields = this->settings->ss->fields;
Hisham Muhammadda23c8c2008-03-09 08:58:38 +0000994 for (int i = 0; fields[i]; i++)
Hisham Muhammad4c24a9b2015-03-31 23:23:10 -0300995 As_Process(this)->writeField(this, out, fields[i]);
Benny Baumann45869512020-11-01 01:09:51 +0100996
Christian Göttsche42073ba2020-11-04 17:46:04 +0100997 if (this->settings->shadowOtherUsers && this->st_uid != Process_getuid) {
Hisham Muhammadda23c8c2008-03-09 08:58:38 +0000998 RichString_setAttr(out, CRT_colors[PROCESS_SHADOW]);
Benny Baumann45869512020-11-01 01:09:51 +0100999 }
1000
1001 if (this->tag == true) {
Hisham Muhammadda23c8c2008-03-09 08:58:38 +00001002 RichString_setAttr(out, CRT_colors[PROCESS_TAG]);
Benny Baumann45869512020-11-01 01:09:51 +01001003 }
1004
Daniel Lange09510902020-11-16 12:13:47 +01001005 if (this->settings->highlightChanges) {
1006 if (Process_isTomb(this)) {
1007 out->highlightAttr = CRT_colors[PROCESS_TOMB];
1008 } else if (Process_isNew(this)) {
1009 out->highlightAttr = CRT_colors[PROCESS_NEW];
1010 }
1011 }
1012
Christian Göttsche3f99c2d2021-03-12 16:46:04 +01001013 assert(RichString_size(out) > 0);
Hisham Muhammadda23c8c2008-03-09 08:58:38 +00001014}
1015
Hisham Muhammad6f868b02015-02-20 14:52:10 -02001016void Process_done(Process* this) {
Hisham Muhammadda23c8c2008-03-09 08:58:38 +00001017 assert (this != NULL);
Benny Baumann02431c42020-12-19 16:21:08 +01001018 free(this->cmdline);
Benny Baumannd74e8b72021-01-30 15:31:59 +01001019 free(this->procComm);
1020 free(this->procExe);
Benny Baumannb6ff5c82021-05-25 19:02:12 +02001021 free(this->procCwd);
Benny Baumanncdb660a2021-04-10 11:10:50 +02001022 free(this->mergedCommand.str);
Christian Göttsche9a822152021-03-21 19:40:56 +01001023 free(this->tty_name);
Hisham Muhammadda23c8c2008-03-09 08:58:38 +00001024}
1025
Benny Baumannc0d02022021-04-24 12:06:49 +02001026/* This function returns the string displayed in Command column, so that sorting
1027 * happens on what is displayed - whether comm, full path, basename, etc.. So
1028 * this follows Process_writeField(COMM) and Process_writeCommand */
Christian Göttsche1ef8c0e2021-12-16 15:57:37 +01001029const char* Process_getCommand(const Process* this) {
Benny Baumannc0d02022021-04-24 12:06:49 +02001030 if ((Process_isUserlandThread(this) && this->settings->showThreadNames) || !this->mergedCommand.str) {
1031 return this->cmdline;
1032 }
1033
1034 return this->mergedCommand.str;
Narendran Gopalakrishnan09fe94d2020-10-17 16:24:45 +05301035}
1036
Christian Göttscheba282cf2020-10-05 13:19:50 +02001037const ProcessClass Process_class = {
Hisham Muhammad4c24a9b2015-03-31 23:23:10 -03001038 .super = {
1039 .extends = Class(Object),
1040 .display = Process_display,
1041 .delete = Process_delete,
1042 .compare = Process_compare
1043 },
1044 .writeField = Process_writeField,
Hisham Muhammad00b324b2012-12-05 15:12:20 +00001045};
1046
Christian Göttsche3035e292021-01-26 18:41:04 +01001047void Process_init(Process* this, const Settings* settings) {
Hisham Muhammad3383d8e2015-01-21 23:27:31 -02001048 this->settings = settings;
Hisham Muhammadda23c8c2008-03-09 08:58:38 +00001049 this->tag = false;
Hisham Muhammad9eb91212010-06-17 19:02:03 +00001050 this->showChildren = true;
Hisham Muhammadd8e14802010-11-22 12:40:20 +00001051 this->show = true;
Hisham Muhammadda23c8c2008-03-09 08:58:38 +00001052 this->updated = false;
Benny Baumann94a52cb2021-04-10 11:46:57 +02001053 this->cmdlineBasenameEnd = -1;
Christian Göttsche9114cf62021-06-09 11:13:39 +02001054 this->st_uid = (uid_t)-1;
Benny Baumann45869512020-11-01 01:09:51 +01001055
Christian Göttsche42073ba2020-11-04 17:46:04 +01001056 if (Process_getuid == (uid_t)-1) {
Benny Baumann45869512020-11-01 01:09:51 +01001057 Process_getuid = getuid();
1058 }
Hisham Muhammadda23c8c2008-03-09 08:58:38 +00001059}
1060
Hisham Muhammadda23c8c2008-03-09 08:58:38 +00001061void Process_toggleTag(Process* this) {
Christian Göttsche2d231d72020-12-08 22:37:15 +01001062 this->tag = !this->tag;
Hisham Muhammadda23c8c2008-03-09 08:58:38 +00001063}
1064
Adam Saponaradde71c62020-10-30 21:56:16 -04001065bool Process_isNew(const Process* this) {
Adam Saponaraa83f5152020-10-31 20:36:53 -04001066 assert(this->processList);
Nathan Scott356488a2021-03-30 15:55:48 +11001067 if (this->processList->monotonicMs >= this->seenStampMs) {
1068 return this->processList->monotonicMs - this->seenStampMs <= 1000 * (uint64_t)this->processList->settings->highlightDelaySecs;
Daniel Lange09510902020-11-16 12:13:47 +01001069 }
Adam Saponaradde71c62020-10-30 21:56:16 -04001070 return false;
1071}
1072
1073bool Process_isTomb(const Process* this) {
Benny Baumann458749d2021-07-14 19:15:09 +02001074 return this->tombStampMs > 0;
Adam Saponaradde71c62020-10-30 21:56:16 -04001075}
1076
Hisham Muhammadda23c8c2008-03-09 08:58:38 +00001077bool Process_setPriority(Process* this, int priority) {
Christian Göttsche36880cd2021-01-21 20:27:37 +01001078 if (Settings_isReadonly())
1079 return false;
1080
Michael Kleinab3a7c22015-12-07 20:10:09 +01001081 int old_prio = getpriority(PRIO_PROCESS, this->pid);
1082 int err = setpriority(PRIO_PROCESS, this->pid, priority);
Benny Baumann82157f52021-02-16 19:44:59 +01001083
Michael Kleinab3a7c22015-12-07 20:10:09 +01001084 if (err == 0 && old_prio != getpriority(PRIO_PROCESS, this->pid)) {
1085 this->nice = priority;
Hisham Muhammadda23c8c2008-03-09 08:58:38 +00001086 }
Michael Kleinab3a7c22015-12-07 20:10:09 +01001087 return (err == 0);
Hisham Muhammadda23c8c2008-03-09 08:58:38 +00001088}
1089
Nathan Scott500fb282020-08-20 09:35:24 +10001090bool Process_changePriorityBy(Process* this, Arg delta) {
1091 return Process_setPriority(this, this->nice + delta.i);
Hisham Muhammad47e881f2012-10-04 23:59:45 +00001092}
1093
Nathan Scott500fb282020-08-20 09:35:24 +10001094bool Process_sendSignal(Process* this, Arg sgn) {
Benny Baumann82157f52021-02-16 19:44:59 +01001095 return kill(this->pid, sgn.i) == 0;
Hisham Muhammadda23c8c2008-03-09 08:58:38 +00001096}
1097
Christian Göttsche90ea3ac2020-12-23 13:02:32 +01001098int Process_compare(const void* v1, const void* v2) {
Benny Baumann976c6122021-07-14 19:24:18 +02001099 const Process* p1 = (const Process*)v1;
1100 const Process* p2 = (const Process*)v2;
Christian Göttsche397b5c42020-11-04 17:46:24 +01001101
Benny Baumann976c6122021-07-14 19:24:18 +02001102 const Settings* settings = p1->settings;
Hisham Muhammad72ba20f2021-08-31 15:38:52 +10001103 const ScreenSettings* ss = settings->ss;
Christian Göttsche397b5c42020-11-04 17:46:24 +01001104
Hisham Muhammad72ba20f2021-08-31 15:38:52 +10001105 ProcessField key = ScreenSettings_getActiveSortKey(ss);
Hisham Muhammade8c69942020-12-17 19:08:56 -03001106
Christian Göttsche90ea3ac2020-12-23 13:02:32 +01001107 int result = Process_compareByKey(p1, p2, key);
Benny Baumann77db2402020-12-18 22:12:26 +01001108
1109 // Implement tie-breaker (needed to make tree mode more stable)
1110 if (!result)
Daniel Lange074703b2021-01-21 20:57:34 +01001111 return SPACESHIP_NUMBER(p1->pid, p2->pid);
Benny Baumann77db2402020-12-18 22:12:26 +01001112
Hisham Muhammad72ba20f2021-08-31 15:38:52 +10001113 return (ScreenSettings_getActiveDirection(ss) == 1) ? result : -result;
Benny Baumann77db2402020-12-18 22:12:26 +01001114}
1115
Christian Göttsche90ea3ac2020-12-23 13:02:32 +01001116int Process_compareByKey_Base(const Process* p1, const Process* p2, ProcessField key) {
Benny Baumann77db2402020-12-18 22:12:26 +01001117 int r;
1118
Christian Göttsche89473cc2020-12-15 19:44:48 +01001119 switch (key) {
Hisham Muhammad5d48ab82006-07-11 06:13:32 +00001120 case PERCENT_CPU:
Christian Göttsche15eab202020-10-30 17:02:20 +01001121 case PERCENT_NORM_CPU:
Daniel Lange4531b312021-01-21 14:27:23 +01001122 return SPACESHIP_NUMBER(p1->percent_cpu, p2->percent_cpu);
Hisham Muhammad5d48ab82006-07-11 06:13:32 +00001123 case PERCENT_MEM:
Daniel Lange4531b312021-01-21 14:27:23 +01001124 return SPACESHIP_NUMBER(p1->m_resident, p2->m_resident);
Hisham Muhammad5d48ab82006-07-11 06:13:32 +00001125 case COMM:
Narendran Gopalakrishnan09fe94d2020-10-17 16:24:45 +05301126 return SPACESHIP_NULLSTR(Process_getCommand(p1), Process_getCommand(p2));
Benny Baumannaa8552b2021-04-18 19:25:56 +02001127 case PROC_COMM: {
Benny Baumann976c6122021-07-14 19:24:18 +02001128 const char* comm1 = p1->procComm ? p1->procComm : (Process_isKernelThread(p1) ? kthreadID : "");
1129 const char* comm2 = p2->procComm ? p2->procComm : (Process_isKernelThread(p2) ? kthreadID : "");
Benny Baumannaa8552b2021-04-18 19:25:56 +02001130 return SPACESHIP_NULLSTR(comm1, comm2);
1131 }
1132 case PROC_EXE: {
Benny Baumann976c6122021-07-14 19:24:18 +02001133 const char* exe1 = p1->procExe ? (p1->procExe + p1->procExeBasenameOffset) : (Process_isKernelThread(p1) ? kthreadID : "");
1134 const char* exe2 = p2->procExe ? (p2->procExe + p2->procExeBasenameOffset) : (Process_isKernelThread(p2) ? kthreadID : "");
Benny Baumannaa8552b2021-04-18 19:25:56 +02001135 return SPACESHIP_NULLSTR(exe1, exe2);
1136 }
Benny Baumannb6ff5c82021-05-25 19:02:12 +02001137 case CWD:
1138 return SPACESHIP_NULLSTR(p1->procCwd, p2->procCwd);
Christian Göttsche550a1412021-05-02 13:29:39 +02001139 case ELAPSED:
1140 r = -SPACESHIP_NUMBER(p1->starttime_ctime, p2->starttime_ctime);
1141 return r != 0 ? r : SPACESHIP_NUMBER(p1->pid, p2->pid);
Hisham Muhammadbe1700c2015-03-16 01:43:04 -03001142 case MAJFLT:
Daniel Lange4531b312021-01-21 14:27:23 +01001143 return SPACESHIP_NUMBER(p1->majflt, p2->majflt);
Hisham Muhammadbe1700c2015-03-16 01:43:04 -03001144 case MINFLT:
Daniel Lange4531b312021-01-21 14:27:23 +01001145 return SPACESHIP_NUMBER(p1->minflt, p2->minflt);
Hisham Muhammadbe1700c2015-03-16 01:43:04 -03001146 case M_RESIDENT:
Daniel Lange4531b312021-01-21 14:27:23 +01001147 return SPACESHIP_NUMBER(p1->m_resident, p2->m_resident);
Christian Göttschefa002c02020-11-20 17:09:34 +01001148 case M_VIRT:
Daniel Lange4531b312021-01-21 14:27:23 +01001149 return SPACESHIP_NUMBER(p1->m_virt, p2->m_virt);
Hisham Muhammadbe1700c2015-03-16 01:43:04 -03001150 case NICE:
Christian Göttsche397b5c42020-11-04 17:46:24 +01001151 return SPACESHIP_NUMBER(p1->nice, p2->nice);
Hisham Muhammadd357c672007-05-21 19:10:53 +00001152 case NLWP:
Christian Göttsche397b5c42020-11-04 17:46:24 +01001153 return SPACESHIP_NUMBER(p1->nlwp, p2->nlwp);
Hisham Muhammadbe1700c2015-03-16 01:43:04 -03001154 case PGRP:
Christian Göttsche397b5c42020-11-04 17:46:24 +01001155 return SPACESHIP_NUMBER(p1->pgrp, p2->pgrp);
Hisham Muhammadbe1700c2015-03-16 01:43:04 -03001156 case PID:
Christian Göttsche397b5c42020-11-04 17:46:24 +01001157 return SPACESHIP_NUMBER(p1->pid, p2->pid);
Hisham Muhammadbe1700c2015-03-16 01:43:04 -03001158 case PPID:
Christian Göttsche397b5c42020-11-04 17:46:24 +01001159 return SPACESHIP_NUMBER(p1->ppid, p2->ppid);
Hisham Muhammadbe1700c2015-03-16 01:43:04 -03001160 case PRIORITY:
Christian Göttsche397b5c42020-11-04 17:46:24 +01001161 return SPACESHIP_NUMBER(p1->priority, p2->priority);
Hisham Muhammad272e2d92015-03-16 23:01:48 -03001162 case PROCESSOR:
Christian Göttsche397b5c42020-11-04 17:46:24 +01001163 return SPACESHIP_NUMBER(p1->processor, p2->processor);
Hisham Muhammadbe1700c2015-03-16 01:43:04 -03001164 case SESSION:
Christian Göttsche397b5c42020-11-04 17:46:24 +01001165 return SPACESHIP_NUMBER(p1->session, p2->session);
1166 case STARTTIME:
1167 r = SPACESHIP_NUMBER(p1->starttime_ctime, p2->starttime_ctime);
1168 return r != 0 ? r : SPACESHIP_NUMBER(p1->pid, p2->pid);
Hisham Muhammadbe1700c2015-03-16 01:43:04 -03001169 case STATE:
marcluqued8dfbbd2021-10-12 00:45:09 +02001170 return SPACESHIP_NUMBER(p1->state, p2->state);
Hisham Muhammadbe1700c2015-03-16 01:43:04 -03001171 case ST_UID:
Christian Göttsche397b5c42020-11-04 17:46:24 +01001172 return SPACESHIP_NUMBER(p1->st_uid, p2->st_uid);
Hisham Muhammadbe1700c2015-03-16 01:43:04 -03001173 case TIME:
Daniel Lange4531b312021-01-21 14:27:23 +01001174 return SPACESHIP_NUMBER(p1->time, p2->time);
Hisham Muhammadbe1700c2015-03-16 01:43:04 -03001175 case TGID:
Christian Göttsche397b5c42020-11-04 17:46:24 +01001176 return SPACESHIP_NUMBER(p1->tgid, p2->tgid);
Hisham Muhammadbe1700c2015-03-16 01:43:04 -03001177 case TPGID:
Christian Göttsche397b5c42020-11-04 17:46:24 +01001178 return SPACESHIP_NUMBER(p1->tpgid, p2->tpgid);
Christian Göttsche9a822152021-03-21 19:40:56 +01001179 case TTY:
1180 /* Order no tty last */
1181 return SPACESHIP_DEFAULTSTR(p1->tty_name, p2->tty_name, "\x7F");
Hisham Muhammadbe1700c2015-03-16 01:43:04 -03001182 case USER:
Christian Göttsche397b5c42020-11-04 17:46:24 +01001183 return SPACESHIP_NULLSTR(p1->user, p2->user);
Hisham Muhammad5d48ab82006-07-11 06:13:32 +00001184 default:
Christian Göttschefa9f2602021-12-08 13:02:18 +01001185 CRT_debug("Process_compareByKey_Base() called with key %d", key);
Christian Göttsche615fc932021-04-18 15:52:28 +02001186 assert(0 && "Process_compareByKey_Base: default key reached"); /* should never be reached */
Benny Baumann77db2402020-12-18 22:12:26 +01001187 return SPACESHIP_NUMBER(p1->pid, p2->pid);
Hisham Muhammad5d48ab82006-07-11 06:13:32 +00001188 }
Hisham Muhammadd6231ba2006-03-04 18:16:49 +00001189}
Christian Göttsche05fb6812021-05-18 22:29:25 +02001190
1191void Process_updateComm(Process* this, const char* comm) {
1192 if (!this->procComm && !comm)
1193 return;
1194
1195 if (this->procComm && comm && String_eq(this->procComm, comm))
1196 return;
1197
1198 free(this->procComm);
1199 this->procComm = comm ? xStrdup(comm) : NULL;
1200 this->mergedCommand.commChanged = true;
1201}
1202
1203static int skipPotentialPath(const char* cmdline, int end) {
1204 if (cmdline[0] != '/')
1205 return 0;
1206
1207 int slash = 0;
1208 for (int i = 1; i < end; i++) {
Benny Baumann0d85af22021-07-14 19:18:27 +02001209 if (cmdline[i] == '/' && cmdline[i + 1] != '\0') {
Christian Göttsche05fb6812021-05-18 22:29:25 +02001210 slash = i + 1;
1211 continue;
1212 }
1213
Benny Baumann0d85af22021-07-14 19:18:27 +02001214 if (cmdline[i] == ' ' && cmdline[i - 1] != '\\')
Christian Göttsche05fb6812021-05-18 22:29:25 +02001215 return slash;
1216
Benny Baumann0d85af22021-07-14 19:18:27 +02001217 if (cmdline[i] == ':' && cmdline[i + 1] == ' ')
Christian Göttsche05fb6812021-05-18 22:29:25 +02001218 return slash;
1219 }
1220
1221 return slash;
1222}
1223
1224void Process_updateCmdline(Process* this, const char* cmdline, int basenameStart, int basenameEnd) {
1225 assert(basenameStart >= 0);
1226 assert((cmdline && basenameStart < (int)strlen(cmdline)) || (!cmdline && basenameStart == 0));
Christian Göttschec408add2021-05-23 15:53:23 +02001227 assert((basenameEnd > basenameStart) || (basenameEnd == 0 && basenameStart == 0));
Christian Göttsche05fb6812021-05-18 22:29:25 +02001228 assert((cmdline && basenameEnd <= (int)strlen(cmdline)) || (!cmdline && basenameEnd == 0));
1229
1230 if (!this->cmdline && !cmdline)
1231 return;
1232
1233 if (this->cmdline && cmdline && String_eq(this->cmdline, cmdline))
1234 return;
1235
1236 free(this->cmdline);
1237 this->cmdline = cmdline ? xStrdup(cmdline) : NULL;
1238 this->cmdlineBasenameStart = (basenameStart || !cmdline) ? basenameStart : skipPotentialPath(cmdline, basenameEnd);
1239 this->cmdlineBasenameEnd = basenameEnd;
1240 this->mergedCommand.cmdlineChanged = true;
1241}
1242
1243void Process_updateExe(Process* this, const char* exe) {
1244 if (!this->procExe && !exe)
1245 return;
1246
1247 if (this->procExe && exe && String_eq(this->procExe, exe))
1248 return;
1249
1250 free(this->procExe);
1251 if (exe) {
1252 this->procExe = xStrdup(exe);
1253 const char* lastSlash = strrchr(exe, '/');
1254 this->procExeBasenameOffset = (lastSlash && *(lastSlash + 1) != '\0' && lastSlash != exe) ? (lastSlash - exe + 1) : 0;
1255 } else {
1256 this->procExe = NULL;
1257 this->procExeBasenameOffset = 0;
1258 }
1259 this->mergedCommand.exeChanged = true;
1260}
Christian Göttsche3ba69522021-12-04 19:57:47 +01001261
1262uint8_t Process_fieldWidths[LAST_PROCESSFIELD] = { 0 };
1263
1264void Process_resetFieldWidths() {
1265 for (size_t i = 0; i < LAST_PROCESSFIELD; i++) {
1266 if (!Process_fields[i].autoWidth)
1267 continue;
1268
1269 size_t len = strlen(Process_fields[i].title);
1270 assert(len <= UINT8_MAX);
1271 Process_fieldWidths[i] = (uint8_t)len;
1272 }
1273}
1274
1275void Process_updateFieldWidth(ProcessField key, size_t width) {
1276 if (width > UINT8_MAX)
1277 Process_fieldWidths[key] = UINT8_MAX;
1278 else if (width > Process_fieldWidths[key])
1279 Process_fieldWidths[key] = (uint8_t)width;
1280}
Benny Baumannedf319e2022-02-27 20:29:40 +01001281
1282void Process_updateCPUFieldWidths(float percentage) {
1283 if (percentage < 99.9) {
1284 Process_updateFieldWidth(PERCENT_CPU, 4);
1285 Process_updateFieldWidth(PERCENT_NORM_CPU, 4);
1286 return;
1287 }
1288
1289 uint8_t width = ceil(log10(percentage + .2));
1290
1291 Process_updateFieldWidth(PERCENT_CPU, width);
1292 Process_updateFieldWidth(PERCENT_NORM_CPU, width);
1293}