htop/Process.c

574 lines
19 KiB
C
Raw Normal View History

2006-03-04 18:16:49 +00:00
/*
htop - Process.c
2015-03-21 19:52:54 +00:00
(C) 2004-2015 Hisham H. Muhammad
(C) 2020 Red Hat, Inc. All Rights Reserved.
Released under the GNU GPLv2, see the COPYING file
2006-03-04 18:16:49 +00:00
in the source distribution for its full text.
*/
#include "config.h" // IWYU pragma: keep
2011-12-26 21:35:57 +00:00
#include "Process.h"
2015-03-17 02:01:48 +00:00
#include <assert.h>
#include <limits.h>
#include <math.h>
#include <signal.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
#include <sys/resource.h>
2006-03-04 18:16:49 +00:00
#include "CRT.h"
2020-11-18 13:26:30 +00:00
#include "Macros.h"
#include "Platform.h"
2020-11-18 13:26:30 +00:00
#include "ProcessList.h"
#include "RichString.h"
#include "Settings.h"
2020-10-14 18:21:09 +00:00
#include "XUtils.h"
2006-03-04 18:16:49 +00:00
#if defined(MAJOR_IN_MKDEV)
#include <sys/mkdev.h>
#elif defined(MAJOR_IN_SYSMACROS)
#include <sys/sysmacros.h>
#endif
2006-03-04 18:16:49 +00:00
2020-11-04 16:46:04 +00:00
static uid_t Process_getuid = (uid_t)-1;
2006-07-12 01:35:59 +00:00
2016-02-10 20:48:04 +00:00
char Process_pidFormat[20] = "%7d ";
static char Process_titleBuffer[20][20];
void Process_setupColumnWidths() {
int maxPid = Platform_getMaxPid();
2020-11-01 00:09:51 +00:00
if (maxPid == -1)
return;
int digits = ceil(log10(maxPid));
assert(digits < 20);
for (int i = 0; Process_pidColumns[i].label; i++) {
assert(i < 20);
xSnprintf(Process_titleBuffer[i], 20, "%*s ", digits, Process_pidColumns[i].label);
Process_fields[Process_pidColumns[i].id].title = Process_titleBuffer[i];
}
xSnprintf(Process_pidFormat, sizeof(Process_pidFormat), "%%%dd ", digits);
}
Process.{h,c}: Use integer types that are more portable When building on a 32-bit system, the compiler warned that the following line uses a constant whose value is the overflow result of a compile-time computation: Process.c (line 109): } else if (number < 10000 * ONE_M) { Namely, this constant expression: 10000 * ONE_M was intended to produce the following value: 10485760000 However, the result overflowed to produce: 1895825408 The reason for this overflow is as follows: o The macros are expanded: 10000 * (ONE_K * ONE_K) 10000 * (1024L * 1024L) o The untyped constant expression "10000" is typed: 10000U * (1024L * 1024L) o The parenthesized expression is evaluated: 10000U * (1048576L) o The left operand ("10000U") is converted: 10000L * (1048576L) Unbound by integer sizes, that last multiplication would produce the following value: 10485760000 However, on a 32-bit machine, where a long is 32 bits (really 31 bits when talking about positive numbers), the maximum value that can be computed is 2**31-1: 2147483647 Consequently, the computation overflows. o The compiler produces a long int value that is the the result of overflow (10485760000 % 2**31): 1895825408L Actually, I think this overflow is implementation-defined, so it's not even a portable description of what happens. The solution is to use a long long int (or, even better, an unsigned long long int) type for the constant expression; the C standard mandates a sufficiently large maximum value for such types. Hence, the following change is made to the bad line: - } else if (number < 10000 * ONE_M) { + } else if (number < 10000ULL * ONE_M) { However, the whole line is now patently silly, because the variable "number" is typed "unsigned long", and so it will always be less than the constant expression (the compiler will warn about this, too). Hence, "number" must be typed "unsigned long long"; however, this necessitates changing all of the string formats from something like "%lu" to something like "%llu". Et voila! This commit is born. Then, for the sake of completeness, the declared types of the constant-expression macros are updated: o ONE_K is made unsigned (a "UL" instead of "L") o ONE_T is computed by introducing "1ULL *" o Similar changes are made for ONE_DECIMAL_{K,T} Also, a non-portable overflow-conversion to a signed value has been replaced with a portable comparison: - if ((long long) number == -1LL) { + if (number == ULLONG_MAX) { It might be worth reviewing the rest of the code for other cases where overflows are not handled correctly; even at runtime, it's often necessary to check for overflow unless such behavior is expected (especially for signed integer values, for which overflow has implementation-defined behavior).
2020-09-29 14:04:22 +00:00
void Process_humanNumber(RichString* str, unsigned long long number, bool coloring) {
char buffer[10];
2006-03-04 18:16:49 +00:00
int len;
2019-10-31 16:39:12 +00:00
int largeNumberColor = CRT_colors[LARGE_NUMBER];
int processMegabytesColor = CRT_colors[PROCESS_MEGABYTES];
int processGigabytesColor = CRT_colors[PROCESS_GIGABYTES];
int processColor = CRT_colors[PROCESS];
if (!coloring) {
largeNumberColor = CRT_colors[PROCESS];
processMegabytesColor = CRT_colors[PROCESS];
processGigabytesColor = CRT_colors[PROCESS];
}
2019-10-31 16:39:12 +00:00
if (number < 1000) {
//Plain number, no markings
len = xSnprintf(buffer, sizeof(buffer), "%5llu ", number);
RichString_appendnAscii(str, processColor, buffer, len);
} else if (number < 100000) {
//2 digit MB, 3 digit KB
len = xSnprintf(buffer, sizeof(buffer), "%2llu", number/1000);
RichString_appendnAscii(str, processMegabytesColor, buffer, len);
2006-03-04 18:16:49 +00:00
number %= 1000;
len = xSnprintf(buffer, sizeof(buffer), "%03llu ", number);
RichString_appendnAscii(str, processColor, buffer, len);
} else if (number < 1000 * ONE_K) {
//3 digit MB
number /= ONE_K;
len = xSnprintf(buffer, sizeof(buffer), "%4lluM ", number);
RichString_appendnAscii(str, processMegabytesColor, buffer, len);
} else if (number < 10000 * ONE_K) {
//1 digit GB, 3 digit MB
number /= ONE_K;
len = xSnprintf(buffer, sizeof(buffer), "%1llu", number/1000);
RichString_appendnAscii(str, processGigabytesColor, buffer, len);
number %= 1000;
len = xSnprintf(buffer, sizeof(buffer), "%03lluM ", number);
RichString_appendnAscii(str, processMegabytesColor, buffer, len);
} else if (number < 100000 * ONE_K) {
//2 digit GB, 1 digit MB
number /= 100 * ONE_K;
len = xSnprintf(buffer, sizeof(buffer), "%2llu", number/10);
RichString_appendnAscii(str, processGigabytesColor, buffer, len);
number %= 10;
len = xSnprintf(buffer, sizeof(buffer), ".%1llu", number);
RichString_appendnAscii(str, processMegabytesColor, buffer, len);
RichString_appendAscii(str, processGigabytesColor, "G ");
} else if (number < 1000 * ONE_M) {
//3 digit GB
number /= ONE_M;
len = xSnprintf(buffer, sizeof(buffer), "%4lluG ", number);
RichString_appendnAscii(str, processGigabytesColor, buffer, len);
Process.{h,c}: Use integer types that are more portable When building on a 32-bit system, the compiler warned that the following line uses a constant whose value is the overflow result of a compile-time computation: Process.c (line 109): } else if (number < 10000 * ONE_M) { Namely, this constant expression: 10000 * ONE_M was intended to produce the following value: 10485760000 However, the result overflowed to produce: 1895825408 The reason for this overflow is as follows: o The macros are expanded: 10000 * (ONE_K * ONE_K) 10000 * (1024L * 1024L) o The untyped constant expression "10000" is typed: 10000U * (1024L * 1024L) o The parenthesized expression is evaluated: 10000U * (1048576L) o The left operand ("10000U") is converted: 10000L * (1048576L) Unbound by integer sizes, that last multiplication would produce the following value: 10485760000 However, on a 32-bit machine, where a long is 32 bits (really 31 bits when talking about positive numbers), the maximum value that can be computed is 2**31-1: 2147483647 Consequently, the computation overflows. o The compiler produces a long int value that is the the result of overflow (10485760000 % 2**31): 1895825408L Actually, I think this overflow is implementation-defined, so it's not even a portable description of what happens. The solution is to use a long long int (or, even better, an unsigned long long int) type for the constant expression; the C standard mandates a sufficiently large maximum value for such types. Hence, the following change is made to the bad line: - } else if (number < 10000 * ONE_M) { + } else if (number < 10000ULL * ONE_M) { However, the whole line is now patently silly, because the variable "number" is typed "unsigned long", and so it will always be less than the constant expression (the compiler will warn about this, too). Hence, "number" must be typed "unsigned long long"; however, this necessitates changing all of the string formats from something like "%lu" to something like "%llu". Et voila! This commit is born. Then, for the sake of completeness, the declared types of the constant-expression macros are updated: o ONE_K is made unsigned (a "UL" instead of "L") o ONE_T is computed by introducing "1ULL *" o Similar changes are made for ONE_DECIMAL_{K,T} Also, a non-portable overflow-conversion to a signed value has been replaced with a portable comparison: - if ((long long) number == -1LL) { + if (number == ULLONG_MAX) { It might be worth reviewing the rest of the code for other cases where overflows are not handled correctly; even at runtime, it's often necessary to check for overflow unless such behavior is expected (especially for signed integer values, for which overflow has implementation-defined behavior).
2020-09-29 14:04:22 +00:00
} else if (number < 10000ULL * ONE_M) {
//1 digit TB, 3 digit GB
number /= ONE_M;
len = xSnprintf(buffer, sizeof(buffer), "%1llu", number/1000);
RichString_appendnAscii(str, largeNumberColor, buffer, len);
number %= 1000;
len = xSnprintf(buffer, sizeof(buffer), "%03lluG ", number);
RichString_appendnAscii(str, processGigabytesColor, buffer, len);
} else {
//2 digit TB and above
len = xSnprintf(buffer, sizeof(buffer), "%4.1lfT ", (double)number/ONE_G);
RichString_appendnAscii(str, largeNumberColor, buffer, len);
2006-03-04 18:16:49 +00:00
}
}
void Process_colorNumber(RichString* str, unsigned long long number, bool coloring) {
char buffer[13];
int largeNumberColor = CRT_colors[LARGE_NUMBER];
int processMegabytesColor = CRT_colors[PROCESS_MEGABYTES];
int processColor = CRT_colors[PROCESS];
int processShadowColor = CRT_colors[PROCESS_SHADOW];
if (!coloring) {
largeNumberColor = CRT_colors[PROCESS];
processMegabytesColor = CRT_colors[PROCESS];
processShadowColor = CRT_colors[PROCESS];
}
Process.{h,c}: Use integer types that are more portable When building on a 32-bit system, the compiler warned that the following line uses a constant whose value is the overflow result of a compile-time computation: Process.c (line 109): } else if (number < 10000 * ONE_M) { Namely, this constant expression: 10000 * ONE_M was intended to produce the following value: 10485760000 However, the result overflowed to produce: 1895825408 The reason for this overflow is as follows: o The macros are expanded: 10000 * (ONE_K * ONE_K) 10000 * (1024L * 1024L) o The untyped constant expression "10000" is typed: 10000U * (1024L * 1024L) o The parenthesized expression is evaluated: 10000U * (1048576L) o The left operand ("10000U") is converted: 10000L * (1048576L) Unbound by integer sizes, that last multiplication would produce the following value: 10485760000 However, on a 32-bit machine, where a long is 32 bits (really 31 bits when talking about positive numbers), the maximum value that can be computed is 2**31-1: 2147483647 Consequently, the computation overflows. o The compiler produces a long int value that is the the result of overflow (10485760000 % 2**31): 1895825408L Actually, I think this overflow is implementation-defined, so it's not even a portable description of what happens. The solution is to use a long long int (or, even better, an unsigned long long int) type for the constant expression; the C standard mandates a sufficiently large maximum value for such types. Hence, the following change is made to the bad line: - } else if (number < 10000 * ONE_M) { + } else if (number < 10000ULL * ONE_M) { However, the whole line is now patently silly, because the variable "number" is typed "unsigned long", and so it will always be less than the constant expression (the compiler will warn about this, too). Hence, "number" must be typed "unsigned long long"; however, this necessitates changing all of the string formats from something like "%lu" to something like "%llu". Et voila! This commit is born. Then, for the sake of completeness, the declared types of the constant-expression macros are updated: o ONE_K is made unsigned (a "UL" instead of "L") o ONE_T is computed by introducing "1ULL *" o Similar changes are made for ONE_DECIMAL_{K,T} Also, a non-portable overflow-conversion to a signed value has been replaced with a portable comparison: - if ((long long) number == -1LL) { + if (number == ULLONG_MAX) { It might be worth reviewing the rest of the code for other cases where overflows are not handled correctly; even at runtime, it's often necessary to check for overflow unless such behavior is expected (especially for signed integer values, for which overflow has implementation-defined behavior).
2020-09-29 14:04:22 +00:00
if (number == ULLONG_MAX) {
RichString_appendAscii(str, CRT_colors[PROCESS_SHADOW], " N/A ");
} else if (number >= 100000LL * ONE_DECIMAL_T) {
xSnprintf(buffer, sizeof(buffer), "%11llu ", number / ONE_DECIMAL_G);
RichString_appendnAscii(str, largeNumberColor, buffer, 12);
} else if (number >= 100LL * ONE_DECIMAL_T) {
xSnprintf(buffer, sizeof(buffer), "%11llu ", number / ONE_DECIMAL_M);
RichString_appendnAscii(str, largeNumberColor, buffer, 8);
RichString_appendnAscii(str, processMegabytesColor, buffer+8, 4);
} else if (number >= 10LL * ONE_DECIMAL_G) {
xSnprintf(buffer, sizeof(buffer), "%11llu ", number / ONE_DECIMAL_K);
RichString_appendnAscii(str, largeNumberColor, buffer, 5);
RichString_appendnAscii(str, processMegabytesColor, buffer+5, 3);
RichString_appendnAscii(str, processColor, buffer+8, 4);
2011-05-26 16:31:18 +00:00
} else {
xSnprintf(buffer, sizeof(buffer), "%11llu ", number);
RichString_appendnAscii(str, largeNumberColor, buffer, 2);
RichString_appendnAscii(str, processMegabytesColor, buffer+2, 3);
RichString_appendnAscii(str, processColor, buffer+5, 3);
RichString_appendnAscii(str, processShadowColor, buffer+8, 4);
2011-05-26 16:31:18 +00:00
}
}
2015-03-17 02:01:48 +00:00
void Process_printTime(RichString* str, unsigned long long totalHundredths) {
unsigned long long totalSeconds = totalHundredths / 100;
2006-03-04 18:16:49 +00:00
2015-03-17 02:01:48 +00:00
unsigned long long hours = totalSeconds / 3600;
int minutes = (totalSeconds / 60) % 60;
int seconds = totalSeconds % 60;
int hundredths = totalHundredths - (totalSeconds * 100);
char buffer[10];
if (hours >= 100) {
xSnprintf(buffer, sizeof(buffer), "%7lluh ", hours);
RichString_appendAscii(str, CRT_colors[LARGE_NUMBER], buffer);
2006-03-04 18:16:49 +00:00
} else {
if (hours) {
xSnprintf(buffer, sizeof(buffer), "%2lluh", hours);
RichString_appendAscii(str, CRT_colors[LARGE_NUMBER], buffer);
xSnprintf(buffer, sizeof(buffer), "%02d:%02d ", minutes, seconds);
} else {
xSnprintf(buffer, sizeof(buffer), "%2d:%02d.%02d ", minutes, seconds, hundredths);
}
RichString_appendAscii(str, CRT_colors[DEFAULT_COLOR], buffer);
2006-03-04 18:16:49 +00:00
}
}
void Process_fillStarttimeBuffer(Process* this) {
struct tm date;
(void) localtime_r(&this->starttime_ctime, &date);
strftime(this->starttime_show, sizeof(this->starttime_show) - 1, (this->starttime_ctime > (time(NULL) - 86400)) ? "%R " : "%b%d ", &date);
}
static inline void Process_writeCommand(const Process* this, int attr, int baseattr, RichString* str) {
int start = RichString_size(str), finish = 0;
const char* comm = this->comm;
if (this->settings->highlightBaseName || !this->settings->showProgramPath) {
int i, basename = 0;
for (i = 0; i < this->basenameOffset; i++) {
if (comm[i] == '/') {
basename = i + 1;
} else if (comm[i] == ':') {
finish = i + 1;
break;
}
2006-03-04 18:16:49 +00:00
}
if (!finish) {
2020-11-01 00:09:51 +00:00
if (this->settings->showProgramPath) {
start += basename;
2020-11-01 00:09:51 +00:00
} else {
comm += basename;
2020-11-01 00:09:51 +00:00
}
finish = this->basenameOffset - basename;
}
finish += start - 1;
2006-03-04 18:16:49 +00:00
}
RichString_appendWide(str, attr, comm);
2020-11-01 00:09:51 +00:00
if (this->settings->highlightBaseName) {
RichString_setAttrn(str, baseattr, start, finish);
2020-11-01 00:09:51 +00:00
}
2006-03-04 18:16:49 +00:00
}
void Process_outputRate(RichString* str, char* buffer, size_t n, double rate, int coloring) {
int largeNumberColor = CRT_colors[LARGE_NUMBER];
int processMegabytesColor = CRT_colors[PROCESS_MEGABYTES];
int processColor = CRT_colors[PROCESS];
if (!coloring) {
largeNumberColor = CRT_colors[PROCESS];
processMegabytesColor = CRT_colors[PROCESS];
}
if (isnan(rate)) {
RichString_appendAscii(str, CRT_colors[PROCESS_SHADOW], " N/A ");
} else if (rate < ONE_K) {
int len = snprintf(buffer, n, "%7.2f B/s ", rate);
RichString_appendnAscii(str, processColor, buffer, len);
} else if (rate < ONE_M) {
int len = snprintf(buffer, n, "%7.2f K/s ", rate / ONE_K);
RichString_appendnAscii(str, processColor, buffer, len);
} else if (rate < ONE_G) {
int len = snprintf(buffer, n, "%7.2f M/s ", rate / ONE_M);
RichString_appendnAscii(str, processMegabytesColor, buffer, len);
} else if (rate < ONE_T) {
int len = snprintf(buffer, n, "%7.2f G/s ", rate / ONE_G);
RichString_appendnAscii(str, largeNumberColor, buffer, len);
} else {
int len = snprintf(buffer, n, "%7.2f T/s ", rate / ONE_T);
RichString_appendnAscii(str, largeNumberColor, buffer, len);
}
}
void Process_writeField(const Process* this, RichString* str, ProcessField field) {
char buffer[256]; buffer[255] = '\0';
2006-03-04 18:16:49 +00:00
int attr = CRT_colors[DEFAULT_COLOR];
int baseattr = CRT_colors[PROCESS_BASENAME];
size_t n = sizeof(buffer) - 1;
bool coloring = this->settings->highlightMegabytes;
2006-03-04 18:16:49 +00:00
switch (field) {
case PERCENT_CPU:
case PERCENT_NORM_CPU: {
float cpuPercentage = this->percent_cpu;
if (field == PERCENT_NORM_CPU) {
cpuPercentage /= this->processList->cpuCount;
}
if (cpuPercentage > 999.9) {
xSnprintf(buffer, n, "%4u ", (unsigned int)cpuPercentage);
} else if (cpuPercentage > 99.9) {
xSnprintf(buffer, n, "%3u. ", (unsigned int)cpuPercentage);
} else {
xSnprintf(buffer, n, "%4.1f ", cpuPercentage);
}
break;
}
case PERCENT_MEM: {
if (this->percent_mem > 99.9) {
2019-10-31 16:39:12 +00:00
xSnprintf(buffer, n, "100. ");
} else {
xSnprintf(buffer, n, "%4.1f ", this->percent_mem);
}
break;
}
2006-03-04 18:16:49 +00:00
case COMM: {
if (this->settings->highlightThreads && Process_isThread(this)) {
attr = CRT_colors[PROCESS_THREAD];
baseattr = CRT_colors[PROCESS_THREAD_BASENAME];
}
if (!this->settings->treeView || this->indent == 0) {
Process_writeCommand(this, attr, baseattr, str);
2006-03-04 18:16:49 +00:00
return;
} else {
char* buf = buffer;
int maxIndent = 0;
bool lastItem = (this->indent < 0);
int indent = (this->indent < 0 ? -this->indent : this->indent);
2020-11-01 00:09:51 +00:00
for (int i = 0; i < 32; i++) {
if (indent & (1U << i)) {
2006-03-04 18:16:49 +00:00
maxIndent = i+1;
2020-11-01 00:09:51 +00:00
}
}
2020-11-20 07:07:56 +00:00
for (int i = 0; i < maxIndent - 1; i++) {
int written, ret;
2020-11-01 00:09:51 +00:00
if (indent & (1 << i)) {
ret = snprintf(buf, n, "%s ", CRT_treeStr[TREE_STR_VERT]);
2020-11-01 00:09:51 +00:00
} else {
ret = snprintf(buf, n, " ");
2020-11-01 00:09:51 +00:00
}
if (ret < 0 || (size_t)ret >= n) {
written = n;
} else {
written = ret;
}
buf += written;
n -= written;
}
const char* draw = CRT_treeStr[lastItem ? TREE_STR_BEND : TREE_STR_RTEE];
xSnprintf(buf, n, "%s%s ", draw, this->showChildren ? CRT_treeStr[TREE_STR_SHUT] : CRT_treeStr[TREE_STR_OPEN] );
RichString_appendWide(str, CRT_colors[PROCESS_TREE], buffer);
Process_writeCommand(this, attr, baseattr, str);
return;
2006-03-04 18:16:49 +00:00
}
}
case MAJFLT: Process_colorNumber(str, this->majflt, coloring); return;
case MINFLT: Process_colorNumber(str, this->minflt, coloring); return;
case M_RESIDENT: Process_humanNumber(str, this->m_resident, coloring); return;
case M_VIRT: Process_humanNumber(str, this->m_virt, coloring); return;
case NICE: {
xSnprintf(buffer, n, "%3ld ", this->nice);
attr = this->nice < 0 ? CRT_colors[PROCESS_HIGH_PRIORITY]
: this->nice > 0 ? CRT_colors[PROCESS_LOW_PRIORITY]
: attr;
break;
}
case NLWP: xSnprintf(buffer, n, "%4ld ", this->nlwp); break;
case PGRP: xSnprintf(buffer, n, Process_pidFormat, this->pgrp); break;
case PID: xSnprintf(buffer, n, Process_pidFormat, this->pid); break;
case PPID: xSnprintf(buffer, n, Process_pidFormat, this->ppid); break;
case PRIORITY: {
if(this->priority <= -100)
xSnprintf(buffer, n, " RT ");
else
xSnprintf(buffer, n, "%3ld ", this->priority);
break;
}
case PROCESSOR: xSnprintf(buffer, n, "%3d ", Settings_cpuId(this->settings, this->processor)); break;
case SESSION: xSnprintf(buffer, n, Process_pidFormat, this->session); break;
case STARTTIME: xSnprintf(buffer, n, "%s", this->starttime_show); break;
2006-03-04 18:16:49 +00:00
case STATE: {
xSnprintf(buffer, n, "%c ", this->state);
2014-10-14 01:30:17 +00:00
switch(this->state) {
case 'R':
attr = CRT_colors[PROCESS_R_STATE];
break;
case 'D':
attr = CRT_colors[PROCESS_D_STATE];
break;
}
2006-03-04 18:16:49 +00:00
break;
}
case ST_UID: xSnprintf(buffer, n, "%5d ", this->st_uid); break;
case TIME: Process_printTime(str, this->time); return;
case TGID: xSnprintf(buffer, n, Process_pidFormat, this->tgid); break;
case TPGID: xSnprintf(buffer, n, Process_pidFormat, this->tpgid); break;
case TTY_NR: xSnprintf(buffer, n, "%3u:%3u ", major(this->tty_nr), minor(this->tty_nr)); break;
2006-03-04 18:16:49 +00:00
case USER: {
2020-11-04 16:46:04 +00:00
if (Process_getuid != this->st_uid)
2006-03-04 18:16:49 +00:00
attr = CRT_colors[PROCESS_SHADOW];
2006-07-12 01:35:59 +00:00
if (this->user) {
xSnprintf(buffer, n, "%-9s ", this->user);
2006-07-12 01:35:59 +00:00
} else {
xSnprintf(buffer, n, "%-9d ", this->st_uid);
2006-07-12 01:35:59 +00:00
}
2011-05-26 16:31:18 +00:00
if (buffer[9] != '\0') {
buffer[9] = ' ';
buffer[10] = '\0';
2006-03-04 18:16:49 +00:00
}
break;
}
default:
xSnprintf(buffer, n, "- ");
2006-03-04 18:16:49 +00:00
}
RichString_appendWide(str, attr, buffer);
2006-03-04 18:16:49 +00:00
}
void Process_display(const Object* cast, RichString* out) {
const Process* this = (const Process*) cast;
const ProcessField* fields = this->settings->fields;
RichString_prune(out);
for (int i = 0; fields[i]; i++)
2015-04-01 02:23:10 +00:00
As_Process(this)->writeField(this, out, fields[i]);
2020-11-01 00:09:51 +00:00
2020-11-04 16:46:04 +00:00
if (this->settings->shadowOtherUsers && this->st_uid != Process_getuid) {
RichString_setAttr(out, CRT_colors[PROCESS_SHADOW]);
2020-11-01 00:09:51 +00:00
}
if (this->tag == true) {
RichString_setAttr(out, CRT_colors[PROCESS_TAG]);
2020-11-01 00:09:51 +00:00
}
2020-10-31 01:56:16 +00:00
if (this->settings->highlightChanges) {
if (Process_isTomb(this)) {
2020-10-31 01:56:16 +00:00
out->highlightAttr = CRT_colors[PROCESS_TOMB];
} else if (Process_isNew(this)) {
2020-11-01 00:36:53 +00:00
out->highlightAttr = CRT_colors[PROCESS_NEW];
}
2020-10-31 01:56:16 +00:00
}
assert(out->chlen > 0);
}
void Process_done(Process* this) {
assert (this != NULL);
free(this->comm);
}
2020-10-17 10:54:45 +00:00
static const char* Process_getCommandStr(const Process* p) {
return p->comm ? p->comm : "";
}
2020-10-05 11:19:50 +00:00
const ProcessClass Process_class = {
2015-04-01 02:23:10 +00:00
.super = {
.extends = Class(Object),
.display = Process_display,
.delete = Process_delete,
.compare = Process_compare
},
.writeField = Process_writeField,
2020-10-17 10:54:45 +00:00
.getCommandStr = Process_getCommandStr,
};
void Process_init(Process* this, const struct Settings_* settings) {
this->settings = settings;
this->tag = false;
2010-06-17 19:02:03 +00:00
this->showChildren = true;
this->show = true;
this->updated = false;
this->basenameOffset = -1;
2020-11-01 00:09:51 +00:00
2020-11-04 16:46:04 +00:00
if (Process_getuid == (uid_t)-1) {
2020-11-01 00:09:51 +00:00
Process_getuid = getuid();
}
}
void Process_toggleTag(Process* this) {
2020-12-08 21:37:15 +00:00
this->tag = !this->tag;
}
2020-10-31 01:56:16 +00:00
bool Process_isNew(const Process* this) {
2020-11-01 00:36:53 +00:00
assert(this->processList);
if (this->processList->scanTs >= this->seenTs) {
return this->processList->scanTs - this->seenTs <= 1000 * this->processList->settings->highlightDelaySecs;
}
2020-10-31 01:56:16 +00:00
return false;
}
bool Process_isTomb(const Process* this) {
2020-11-01 00:36:53 +00:00
return this->tombTs > 0;
2020-10-31 01:56:16 +00:00
}
bool Process_setPriority(Process* this, int priority) {
CRT_dropPrivileges();
int old_prio = getpriority(PRIO_PROCESS, this->pid);
int err = setpriority(PRIO_PROCESS, this->pid, priority);
CRT_restorePrivileges();
if (err == 0 && old_prio != getpriority(PRIO_PROCESS, this->pid)) {
this->nice = priority;
}
return (err == 0);
}
bool Process_changePriorityBy(Process* this, Arg delta) {
return Process_setPriority(this, this->nice + delta.i);
2012-10-04 23:59:45 +00:00
}
bool Process_sendSignal(Process* this, Arg sgn) {
CRT_dropPrivileges();
bool ok = (kill(this->pid, sgn.i) == 0);
CRT_restorePrivileges();
return ok;
}
2014-04-25 22:41:23 +00:00
long Process_pidCompare(const void* v1, const void* v2) {
Do not drop qualifier in cast ListItem.c:73:33: warning: cast from 'const void *' to 'struct ListItem_ *' drops const qualifier [-Wcast-qual] ListItem* obj1 = (ListItem*) cast1; ^ ListItem.c:74:33: warning: cast from 'const void *' to 'struct ListItem_ *' drops const qualifier [-Wcast-qual] ListItem* obj2 = (ListItem*) cast2; ^ Process.c:434:28: warning: cast from 'const void *' to 'struct Process_ *' drops const qualifier [-Wcast-qual] Process* p1 = (Process*)v1; ^ Process.c:435:28: warning: cast from 'const void *' to 'struct Process_ *' drops const qualifier [-Wcast-qual] Process* p2 = (Process*)v2; ^ Process.c:441:36: warning: cast from 'const void *' to 'struct Process_ *' drops const qualifier [-Wcast-qual] Settings *settings = ((Process*)v1)->settings; ^ Process.c:443:22: warning: cast from 'const void *' to 'struct Process_ *' drops const qualifier [-Wcast-qual] p1 = (Process*)v1; ^ Process.c:444:22: warning: cast from 'const void *' to 'struct Process_ *' drops const qualifier [-Wcast-qual] p2 = (Process*)v2; ^ Process.c:446:22: warning: cast from 'const void *' to 'struct Process_ *' drops const qualifier [-Wcast-qual] p2 = (Process*)v1; ^ Process.c:447:22: warning: cast from 'const void *' to 'struct Process_ *' drops const qualifier [-Wcast-qual] p1 = (Process*)v2; ^ AffinityPanel.c:37:16: warning: cast from 'const char *' to 'void *' drops const qualifier [-Wcast-qual] free((void*)this->text); ^ AffinityPanel.c:39:19: warning: cast from 'const char *' to 'void *' drops const qualifier [-Wcast-qual] free((void*)this->indent); ^ linux/LinuxProcess.c:294:36: warning: cast from 'const void *' to 'struct Process_ *' drops const qualifier [-Wcast-qual] Settings *settings = ((Process*)v1)->settings; ^ linux/LinuxProcess.c:296:27: warning: cast from 'const void *' to 'struct LinuxProcess_ *' drops const qualifier [-Wcast-qual] p1 = (LinuxProcess*)v1; ^ linux/LinuxProcess.c:297:27: warning: cast from 'const void *' to 'struct LinuxProcess_ *' drops const qualifier [-Wcast-qual] p2 = (LinuxProcess*)v2; ^ linux/LinuxProcess.c:299:27: warning: cast from 'const void *' to 'struct LinuxProcess_ *' drops const qualifier [-Wcast-qual] p2 = (LinuxProcess*)v1; ^ linux/LinuxProcess.c:300:27: warning: cast from 'const void *' to 'struct LinuxProcess_ *' drops const qualifier [-Wcast-qual] p1 = (LinuxProcess*)v2; ^ linux/LinuxProcessList.c:62:32: warning: cast from 'const void *' to 'struct TtyDriver_ *' drops const qualifier [-Wcast-qual] TtyDriver* a = (TtyDriver*) va; ^ linux/LinuxProcessList.c:63:32: warning: cast from 'const void *' to 'struct TtyDriver_ *' drops const qualifier [-Wcast-qual] TtyDriver* b = (TtyDriver*) vb; ^ linux/Battery.c:130:21: warning: cast from 'const char *' to 'char *' drops const qualifier [-Wcast-qual] free((char *) isOnline); ^ linux/Battery.c:197:26: warning: cast from 'const char *' to 'char *' drops const qualifier [-Wcast-qual] xSnprintf((char *) filePath, sizeof filePath, SYS_POWERSUPPLY_DIR "/%s/type", entryName); ^ linux/Battery.c:209:29: warning: cast from 'const char *' to 'char *' drops const qualifier [-Wcast-qual] xSnprintf((char *) filePath, sizeof filePath, SYS_POWERSUPPLY_DIR "/%s/uevent", entryName); ^ linux/Battery.c:262:29: warning: cast from 'const char *' to 'char *' drops const qualifier [-Wcast-qual] xSnprintf((char *) filePath, sizeof filePath, SYS_POWERSUPPLY_DIR "/%s/online", entryName); ^
2020-09-23 12:15:51 +00:00
const Process* p1 = (const Process*)v1;
const Process* p2 = (const Process*)v2;
2020-12-08 21:37:15 +00:00
return SPACESHIP_NUMBER(p1->pid, p2->pid);
}
2014-04-25 22:41:23 +00:00
long Process_compare(const void* v1, const void* v2) {
Do not drop qualifier in cast ListItem.c:73:33: warning: cast from 'const void *' to 'struct ListItem_ *' drops const qualifier [-Wcast-qual] ListItem* obj1 = (ListItem*) cast1; ^ ListItem.c:74:33: warning: cast from 'const void *' to 'struct ListItem_ *' drops const qualifier [-Wcast-qual] ListItem* obj2 = (ListItem*) cast2; ^ Process.c:434:28: warning: cast from 'const void *' to 'struct Process_ *' drops const qualifier [-Wcast-qual] Process* p1 = (Process*)v1; ^ Process.c:435:28: warning: cast from 'const void *' to 'struct Process_ *' drops const qualifier [-Wcast-qual] Process* p2 = (Process*)v2; ^ Process.c:441:36: warning: cast from 'const void *' to 'struct Process_ *' drops const qualifier [-Wcast-qual] Settings *settings = ((Process*)v1)->settings; ^ Process.c:443:22: warning: cast from 'const void *' to 'struct Process_ *' drops const qualifier [-Wcast-qual] p1 = (Process*)v1; ^ Process.c:444:22: warning: cast from 'const void *' to 'struct Process_ *' drops const qualifier [-Wcast-qual] p2 = (Process*)v2; ^ Process.c:446:22: warning: cast from 'const void *' to 'struct Process_ *' drops const qualifier [-Wcast-qual] p2 = (Process*)v1; ^ Process.c:447:22: warning: cast from 'const void *' to 'struct Process_ *' drops const qualifier [-Wcast-qual] p1 = (Process*)v2; ^ AffinityPanel.c:37:16: warning: cast from 'const char *' to 'void *' drops const qualifier [-Wcast-qual] free((void*)this->text); ^ AffinityPanel.c:39:19: warning: cast from 'const char *' to 'void *' drops const qualifier [-Wcast-qual] free((void*)this->indent); ^ linux/LinuxProcess.c:294:36: warning: cast from 'const void *' to 'struct Process_ *' drops const qualifier [-Wcast-qual] Settings *settings = ((Process*)v1)->settings; ^ linux/LinuxProcess.c:296:27: warning: cast from 'const void *' to 'struct LinuxProcess_ *' drops const qualifier [-Wcast-qual] p1 = (LinuxProcess*)v1; ^ linux/LinuxProcess.c:297:27: warning: cast from 'const void *' to 'struct LinuxProcess_ *' drops const qualifier [-Wcast-qual] p2 = (LinuxProcess*)v2; ^ linux/LinuxProcess.c:299:27: warning: cast from 'const void *' to 'struct LinuxProcess_ *' drops const qualifier [-Wcast-qual] p2 = (LinuxProcess*)v1; ^ linux/LinuxProcess.c:300:27: warning: cast from 'const void *' to 'struct LinuxProcess_ *' drops const qualifier [-Wcast-qual] p1 = (LinuxProcess*)v2; ^ linux/LinuxProcessList.c:62:32: warning: cast from 'const void *' to 'struct TtyDriver_ *' drops const qualifier [-Wcast-qual] TtyDriver* a = (TtyDriver*) va; ^ linux/LinuxProcessList.c:63:32: warning: cast from 'const void *' to 'struct TtyDriver_ *' drops const qualifier [-Wcast-qual] TtyDriver* b = (TtyDriver*) vb; ^ linux/Battery.c:130:21: warning: cast from 'const char *' to 'char *' drops const qualifier [-Wcast-qual] free((char *) isOnline); ^ linux/Battery.c:197:26: warning: cast from 'const char *' to 'char *' drops const qualifier [-Wcast-qual] xSnprintf((char *) filePath, sizeof filePath, SYS_POWERSUPPLY_DIR "/%s/type", entryName); ^ linux/Battery.c:209:29: warning: cast from 'const char *' to 'char *' drops const qualifier [-Wcast-qual] xSnprintf((char *) filePath, sizeof filePath, SYS_POWERSUPPLY_DIR "/%s/uevent", entryName); ^ linux/Battery.c:262:29: warning: cast from 'const char *' to 'char *' drops const qualifier [-Wcast-qual] xSnprintf((char *) filePath, sizeof filePath, SYS_POWERSUPPLY_DIR "/%s/online", entryName); ^
2020-09-23 12:15:51 +00:00
const Process *p1, *p2;
const Settings *settings = ((const Process*)v1)->settings;
if (Settings_getActiveDirection(settings) == 1) {
Do not drop qualifier in cast ListItem.c:73:33: warning: cast from 'const void *' to 'struct ListItem_ *' drops const qualifier [-Wcast-qual] ListItem* obj1 = (ListItem*) cast1; ^ ListItem.c:74:33: warning: cast from 'const void *' to 'struct ListItem_ *' drops const qualifier [-Wcast-qual] ListItem* obj2 = (ListItem*) cast2; ^ Process.c:434:28: warning: cast from 'const void *' to 'struct Process_ *' drops const qualifier [-Wcast-qual] Process* p1 = (Process*)v1; ^ Process.c:435:28: warning: cast from 'const void *' to 'struct Process_ *' drops const qualifier [-Wcast-qual] Process* p2 = (Process*)v2; ^ Process.c:441:36: warning: cast from 'const void *' to 'struct Process_ *' drops const qualifier [-Wcast-qual] Settings *settings = ((Process*)v1)->settings; ^ Process.c:443:22: warning: cast from 'const void *' to 'struct Process_ *' drops const qualifier [-Wcast-qual] p1 = (Process*)v1; ^ Process.c:444:22: warning: cast from 'const void *' to 'struct Process_ *' drops const qualifier [-Wcast-qual] p2 = (Process*)v2; ^ Process.c:446:22: warning: cast from 'const void *' to 'struct Process_ *' drops const qualifier [-Wcast-qual] p2 = (Process*)v1; ^ Process.c:447:22: warning: cast from 'const void *' to 'struct Process_ *' drops const qualifier [-Wcast-qual] p1 = (Process*)v2; ^ AffinityPanel.c:37:16: warning: cast from 'const char *' to 'void *' drops const qualifier [-Wcast-qual] free((void*)this->text); ^ AffinityPanel.c:39:19: warning: cast from 'const char *' to 'void *' drops const qualifier [-Wcast-qual] free((void*)this->indent); ^ linux/LinuxProcess.c:294:36: warning: cast from 'const void *' to 'struct Process_ *' drops const qualifier [-Wcast-qual] Settings *settings = ((Process*)v1)->settings; ^ linux/LinuxProcess.c:296:27: warning: cast from 'const void *' to 'struct LinuxProcess_ *' drops const qualifier [-Wcast-qual] p1 = (LinuxProcess*)v1; ^ linux/LinuxProcess.c:297:27: warning: cast from 'const void *' to 'struct LinuxProcess_ *' drops const qualifier [-Wcast-qual] p2 = (LinuxProcess*)v2; ^ linux/LinuxProcess.c:299:27: warning: cast from 'const void *' to 'struct LinuxProcess_ *' drops const qualifier [-Wcast-qual] p2 = (LinuxProcess*)v1; ^ linux/LinuxProcess.c:300:27: warning: cast from 'const void *' to 'struct LinuxProcess_ *' drops const qualifier [-Wcast-qual] p1 = (LinuxProcess*)v2; ^ linux/LinuxProcessList.c:62:32: warning: cast from 'const void *' to 'struct TtyDriver_ *' drops const qualifier [-Wcast-qual] TtyDriver* a = (TtyDriver*) va; ^ linux/LinuxProcessList.c:63:32: warning: cast from 'const void *' to 'struct TtyDriver_ *' drops const qualifier [-Wcast-qual] TtyDriver* b = (TtyDriver*) vb; ^ linux/Battery.c:130:21: warning: cast from 'const char *' to 'char *' drops const qualifier [-Wcast-qual] free((char *) isOnline); ^ linux/Battery.c:197:26: warning: cast from 'const char *' to 'char *' drops const qualifier [-Wcast-qual] xSnprintf((char *) filePath, sizeof filePath, SYS_POWERSUPPLY_DIR "/%s/type", entryName); ^ linux/Battery.c:209:29: warning: cast from 'const char *' to 'char *' drops const qualifier [-Wcast-qual] xSnprintf((char *) filePath, sizeof filePath, SYS_POWERSUPPLY_DIR "/%s/uevent", entryName); ^ linux/Battery.c:262:29: warning: cast from 'const char *' to 'char *' drops const qualifier [-Wcast-qual] xSnprintf((char *) filePath, sizeof filePath, SYS_POWERSUPPLY_DIR "/%s/online", entryName); ^
2020-09-23 12:15:51 +00:00
p1 = (const Process*)v1;
p2 = (const Process*)v2;
} else {
Do not drop qualifier in cast ListItem.c:73:33: warning: cast from 'const void *' to 'struct ListItem_ *' drops const qualifier [-Wcast-qual] ListItem* obj1 = (ListItem*) cast1; ^ ListItem.c:74:33: warning: cast from 'const void *' to 'struct ListItem_ *' drops const qualifier [-Wcast-qual] ListItem* obj2 = (ListItem*) cast2; ^ Process.c:434:28: warning: cast from 'const void *' to 'struct Process_ *' drops const qualifier [-Wcast-qual] Process* p1 = (Process*)v1; ^ Process.c:435:28: warning: cast from 'const void *' to 'struct Process_ *' drops const qualifier [-Wcast-qual] Process* p2 = (Process*)v2; ^ Process.c:441:36: warning: cast from 'const void *' to 'struct Process_ *' drops const qualifier [-Wcast-qual] Settings *settings = ((Process*)v1)->settings; ^ Process.c:443:22: warning: cast from 'const void *' to 'struct Process_ *' drops const qualifier [-Wcast-qual] p1 = (Process*)v1; ^ Process.c:444:22: warning: cast from 'const void *' to 'struct Process_ *' drops const qualifier [-Wcast-qual] p2 = (Process*)v2; ^ Process.c:446:22: warning: cast from 'const void *' to 'struct Process_ *' drops const qualifier [-Wcast-qual] p2 = (Process*)v1; ^ Process.c:447:22: warning: cast from 'const void *' to 'struct Process_ *' drops const qualifier [-Wcast-qual] p1 = (Process*)v2; ^ AffinityPanel.c:37:16: warning: cast from 'const char *' to 'void *' drops const qualifier [-Wcast-qual] free((void*)this->text); ^ AffinityPanel.c:39:19: warning: cast from 'const char *' to 'void *' drops const qualifier [-Wcast-qual] free((void*)this->indent); ^ linux/LinuxProcess.c:294:36: warning: cast from 'const void *' to 'struct Process_ *' drops const qualifier [-Wcast-qual] Settings *settings = ((Process*)v1)->settings; ^ linux/LinuxProcess.c:296:27: warning: cast from 'const void *' to 'struct LinuxProcess_ *' drops const qualifier [-Wcast-qual] p1 = (LinuxProcess*)v1; ^ linux/LinuxProcess.c:297:27: warning: cast from 'const void *' to 'struct LinuxProcess_ *' drops const qualifier [-Wcast-qual] p2 = (LinuxProcess*)v2; ^ linux/LinuxProcess.c:299:27: warning: cast from 'const void *' to 'struct LinuxProcess_ *' drops const qualifier [-Wcast-qual] p2 = (LinuxProcess*)v1; ^ linux/LinuxProcess.c:300:27: warning: cast from 'const void *' to 'struct LinuxProcess_ *' drops const qualifier [-Wcast-qual] p1 = (LinuxProcess*)v2; ^ linux/LinuxProcessList.c:62:32: warning: cast from 'const void *' to 'struct TtyDriver_ *' drops const qualifier [-Wcast-qual] TtyDriver* a = (TtyDriver*) va; ^ linux/LinuxProcessList.c:63:32: warning: cast from 'const void *' to 'struct TtyDriver_ *' drops const qualifier [-Wcast-qual] TtyDriver* b = (TtyDriver*) vb; ^ linux/Battery.c:130:21: warning: cast from 'const char *' to 'char *' drops const qualifier [-Wcast-qual] free((char *) isOnline); ^ linux/Battery.c:197:26: warning: cast from 'const char *' to 'char *' drops const qualifier [-Wcast-qual] xSnprintf((char *) filePath, sizeof filePath, SYS_POWERSUPPLY_DIR "/%s/type", entryName); ^ linux/Battery.c:209:29: warning: cast from 'const char *' to 'char *' drops const qualifier [-Wcast-qual] xSnprintf((char *) filePath, sizeof filePath, SYS_POWERSUPPLY_DIR "/%s/uevent", entryName); ^ linux/Battery.c:262:29: warning: cast from 'const char *' to 'char *' drops const qualifier [-Wcast-qual] xSnprintf((char *) filePath, sizeof filePath, SYS_POWERSUPPLY_DIR "/%s/online", entryName); ^
2020-09-23 12:15:51 +00:00
p2 = (const Process*)v1;
p1 = (const Process*)v2;
}
ProcessField key = Settings_getActiveSortKey(settings);
long result = Process_compareByKey(p1, p2, key);
// Implement tie-breaker (needed to make tree mode more stable)
if (!result)
result = SPACESHIP_NUMBER(p1->pid, p2->pid);
return result;
}
long Process_compareByKey_Base(const Process* p1, const Process* p2, ProcessField key) {
int r;
switch ((int) key) {
2006-03-04 18:16:49 +00:00
case PERCENT_CPU:
case PERCENT_NORM_CPU:
return SPACESHIP_NUMBER(p2->percent_cpu, p1->percent_cpu);
2006-03-04 18:16:49 +00:00
case PERCENT_MEM:
return SPACESHIP_NUMBER(p2->m_resident, p1->m_resident);
2006-03-04 18:16:49 +00:00
case COMM:
2020-10-17 10:54:45 +00:00
return SPACESHIP_NULLSTR(Process_getCommand(p1), Process_getCommand(p2));
case MAJFLT:
return SPACESHIP_NUMBER(p2->majflt, p1->majflt);
case MINFLT:
return SPACESHIP_NUMBER(p2->minflt, p1->minflt);
case M_RESIDENT:
return SPACESHIP_NUMBER(p2->m_resident, p1->m_resident);
case M_VIRT:
return SPACESHIP_NUMBER(p2->m_virt, p1->m_virt);
case NICE:
return SPACESHIP_NUMBER(p1->nice, p2->nice);
case NLWP:
return SPACESHIP_NUMBER(p1->nlwp, p2->nlwp);
case PGRP:
return SPACESHIP_NUMBER(p1->pgrp, p2->pgrp);
case PID:
return SPACESHIP_NUMBER(p1->pid, p2->pid);
case PPID:
return SPACESHIP_NUMBER(p1->ppid, p2->ppid);
case PRIORITY:
return SPACESHIP_NUMBER(p1->priority, p2->priority);
2015-03-17 02:01:48 +00:00
case PROCESSOR:
return SPACESHIP_NUMBER(p1->processor, p2->processor);
case SESSION:
return SPACESHIP_NUMBER(p1->session, p2->session);
case STARTTIME:
r = SPACESHIP_NUMBER(p1->starttime_ctime, p2->starttime_ctime);
return r != 0 ? r : SPACESHIP_NUMBER(p1->pid, p2->pid);
case STATE:
return SPACESHIP_NUMBER(Process_sortState(p1->state), Process_sortState(p2->state));
case ST_UID:
return SPACESHIP_NUMBER(p1->st_uid, p2->st_uid);
case TIME:
return SPACESHIP_NUMBER(p2->time, p1->time);
case TGID:
return SPACESHIP_NUMBER(p1->tgid, p2->tgid);
case TPGID:
return SPACESHIP_NUMBER(p1->tpgid, p2->tpgid);
case TTY_NR:
return SPACESHIP_NUMBER(p1->tty_nr, p2->tty_nr);
case USER:
return SPACESHIP_NULLSTR(p1->user, p2->user);
2006-03-04 18:16:49 +00:00
default:
return SPACESHIP_NUMBER(p1->pid, p2->pid);
2006-03-04 18:16:49 +00:00
}
}