Skip to content

Commit

Permalink
Merge branch 'htop-dev:main' into main
Browse files Browse the repository at this point in the history
  • Loading branch information
Alex313031 authored Jan 31, 2024
2 parents 3698e08 + 32cb302 commit d05bf95
Show file tree
Hide file tree
Showing 6 changed files with 149 additions and 106 deletions.
5 changes: 2 additions & 3 deletions Header.c
Original file line number Diff line number Diff line change
Expand Up @@ -86,10 +86,9 @@ static void Header_addMeterByName(Header* this, const char* name, MeterModeId mo
unsigned int param = 0;
size_t nameLen;
if (paren) {
int ok = sscanf(paren, "(%10u)", &param); // CPUMeter
if (!ok) {
if (sscanf(paren, "(%10u)", &param) != 1) { // not CPUMeter
char dynamic[32] = {0};
if (sscanf(paren, "(%30s)", dynamic)) { // DynamicMeter
if (sscanf(paren, "(%30s)", dynamic) == 1) { // DynamicMeter
char* end;
if ((end = strrchr(dynamic, ')')) == NULL)
return; // htoprc parse failure
Expand Down
10 changes: 8 additions & 2 deletions Process.c
Original file line number Diff line number Diff line change
Expand Up @@ -1038,8 +1038,14 @@ void Process_updateCmdline(Process* this, const char* cmdline, int basenameStart

free(this->cmdline);
this->cmdline = cmdline ? xStrdup(cmdline) : NULL;
this->cmdlineBasenameStart = (basenameStart || !cmdline) ? basenameStart : skipPotentialPath(cmdline, basenameEnd);
this->cmdlineBasenameEnd = basenameEnd;
if (Process_isKernelThread(this)) {
/* kernel threads have no basename */
this->cmdlineBasenameStart = 0;
this->cmdlineBasenameEnd = 0;
} else {
this->cmdlineBasenameStart = (basenameStart || !cmdline) ? basenameStart : skipPotentialPath(cmdline, basenameEnd);
this->cmdlineBasenameEnd = basenameEnd;
}

this->mergedCommand.lastUpdate = 0;
}
Expand Down
2 changes: 1 addition & 1 deletion Settings.c
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,7 @@ static int toFieldIndex(Hashtable* columns, const char* str) {
} else {
// Dynamically-defined columns are always stored by-name.
char dynamic[32] = {0};
if (sscanf(str, "Dynamic(%30s)", dynamic)) {
if (sscanf(str, "Dynamic(%30s)", dynamic) == 1) {
char* end;
if ((end = strrchr(dynamic, ')')) != NULL) {
bool success;
Expand Down
12 changes: 6 additions & 6 deletions linux/LinuxMachine.c
Original file line number Diff line number Diff line change
Expand Up @@ -302,8 +302,8 @@ static void LinuxMachine_scanZramInfo(LinuxMachine* this) {
memory_t orig_data_size = 0;
memory_t compr_data_size = 0;

if (!fscanf(disksize_file, "%llu\n", &size) ||
!fscanf(mm_stat_file, " %llu %llu", &orig_data_size, &compr_data_size)) {
if (1 != fscanf(disksize_file, "%llu\n", &size) ||
2 != fscanf(mm_stat_file, " %llu %llu", &orig_data_size, &compr_data_size)) {
fclose(disksize_file);
fclose(mm_stat_file);
break;
Expand Down Expand Up @@ -342,10 +342,10 @@ static void LinuxMachine_scanZfsArcstats(LinuxMachine* this) {
sscanf(buffer + strlen(label), " %*2u %32llu", variable); \
break; \
} else (void) 0 /* Require a ";" after the macro use. */
#define tryReadFlag(label, variable, flag) \
if (String_startsWith(buffer, label)) { \
(flag) = sscanf(buffer + strlen(label), " %*2u %32llu", variable); \
break; \
#define tryReadFlag(label, variable, flag) \
if (String_startsWith(buffer, label)) { \
(flag) = (1 == sscanf(buffer + strlen(label), " %*2u %32llu", variable)); \
break; \
} else (void) 0 /* Require a ";" after the macro use. */

switch (buffer[0]) {
Expand Down
224 changes: 131 additions & 93 deletions linux/LinuxProcessTable.c
Original file line number Diff line number Diff line change
Expand Up @@ -426,29 +426,29 @@ static bool LinuxProcessTable_readStatusFile(Process* process, openat_arg_t proc
} else if (String_startsWith(buffer, "voluntary_ctxt_switches:")) {
unsigned long vctxt;
int ok = sscanf(buffer, "voluntary_ctxt_switches:\t%lu", &vctxt);
if (ok >= 1) {
if (ok == 1) {
ctxt += vctxt;
}

} else if (String_startsWith(buffer, "nonvoluntary_ctxt_switches:")) {
unsigned long nvctxt;
int ok = sscanf(buffer, "nonvoluntary_ctxt_switches:\t%lu", &nvctxt);
if (ok >= 1) {
if (ok == 1) {
ctxt += nvctxt;
}

#ifdef HAVE_VSERVER
} else if (String_startsWith(buffer, "VxID:")) {
int vxid;
int ok = sscanf(buffer, "VxID:\t%32d", &vxid);
if (ok >= 1) {
if (ok == 1) {
lp->vxid = vxid;
}
#ifdef HAVE_ANCIENT_VSERVER
} else if (String_startsWith(buffer, "s_context:")) {
int vxid;
int ok = sscanf(buffer, "s_context:\t%32d", &vxid);
if (ok >= 1) {
if (ok == 1) {
lp->vxid = vxid;
}
#endif /* HAVE_ANCIENT_VSERVER */
Expand Down Expand Up @@ -938,7 +938,7 @@ static void LinuxProcessTable_readOomData(LinuxProcess* process, openat_arg_t pr
if (fgets(buffer, PROC_LINE_LENGTH, file)) {
unsigned int oom;
int ok = sscanf(buffer, "%u", &oom);
if (ok >= 1) {
if (ok == 1) {
process->oom = oom;
}
}
Expand Down Expand Up @@ -1090,43 +1090,88 @@ static void LinuxProcessTable_readDelayAcctData(LinuxProcessTable* this, LinuxPr
#endif

static bool LinuxProcessTable_readCmdlineFile(Process* process, openat_arg_t procFd) {
char filename[MAX_NAME + 1];
ssize_t amtRead;

/* execve could change /proc/[pid]/exe, so procExe should be updated */
#if defined(HAVE_READLINKAT) && defined(HAVE_OPENAT)
amtRead = readlinkat(procFd, "exe", filename, sizeof(filename) - 1);
#else
amtRead = Compat_readlink(procFd, "exe", filename, sizeof(filename) - 1);
#endif
if (amtRead > 0) {
filename[amtRead] = 0;
if (!process->procExe ||
(!process->procExeDeleted && !String_eq(filename, process->procExe)) ||
process->procExeDeleted) {

const char* deletedMarker = " (deleted)";
const size_t markerLen = strlen(deletedMarker);
const size_t filenameLen = strlen(filename);

if (filenameLen > markerLen) {
bool oldExeDeleted = process->procExeDeleted;

process->procExeDeleted = String_eq(filename + filenameLen - markerLen, deletedMarker);

if (process->procExeDeleted)
filename[filenameLen - markerLen] = '\0';

if (oldExeDeleted != process->procExeDeleted)
process->mergedCommand.lastUpdate = 0;
}

Process_updateExe(process, filename);
}
} else if (process->procExe) {
Process_updateExe(process, NULL);
process->procExeDeleted = false;
}

char command[4096 + 1]; // max cmdline length on Linux
ssize_t amtRead = xReadfileat(procFd, "cmdline", command, sizeof(command));
amtRead = xReadfileat(procFd, "cmdline", command, sizeof(command));
if (amtRead <= 0)
return false;

int tokenEnd = 0;
int tokenStart = 0;
int tokenEnd = -1;
int tokenStart = -1;
int lastChar = 0;
bool argSepNUL = false;
bool argSepSpace = false;

for (int i = 0; i < amtRead; i++) {
// If this is true, there's a NUL byte in the middle of command
if (tokenEnd >= 0) {
argSepNUL = true;
}

const char argChar = command[i];

/* newline used as delimiter - when forming the mergedCommand, newline is
* converted to space by Process_makeCommandStr */
if (command[i] == '\0') {
if (argChar == '\0') {
command[i] = '\n';
} else {
/* Record some information for the argument parsing heuristic below. */
if (tokenEnd)
argSepNUL = true;
if (command[i] <= ' ')
argSepSpace = true;
}

if (command[i] == '\n') {
if (tokenEnd == 0) {
// Set tokenEnd to the NUL byte
if (tokenEnd < 0) {
tokenEnd = i;
}
} else {
/* htop considers the next character after the last / that is before
* basenameOffset, as the start of the basename in cmdline - see
* Process_writeCommand */
if (!tokenEnd && command[i] == '/') {
tokenStart = i + 1;
}
lastChar = i;

continue;
}

/* Record some information for the argument parsing heuristic below. */
if (argChar <= ' ') {
argSepSpace = true;
}

/* Detect the last / before the end of the token as
* the start of the basename in cmdline, see Process_writeCommand */
if (argChar == '/' && tokenEnd < 0) {
tokenStart = i + 1;
}

lastChar = i;
}

command[lastChar + 1] = '\0';
Expand All @@ -1145,54 +1190,78 @@ static bool LinuxProcessTable_readCmdlineFile(Process* process, openat_arg_t pro
* As path names may contain we try to cross-validate if the path we got that way exists.
*/

tokenStart = tokenEnd = 0;
tokenStart = -1;
tokenEnd = -1;

size_t exeLen = process->procExe ? strlen(process->procExe) : 0;

if (process->procExe && String_startsWith(command, process->procExe) &&
exeLen < (size_t)lastChar && command[exeLen] <= ' ') {
tokenStart = process->procExeBasenameOffset;
tokenEnd = exeLen;
}

// From initial scan we know there's at least one space.
// Check if that's part of a filename for an existing file.
if (Compat_faccessat(AT_FDCWD, command, F_OK, AT_SYMLINK_NOFOLLOW) != 0) {
else if (Compat_faccessat(AT_FDCWD, command, F_OK, AT_SYMLINK_NOFOLLOW) != 0) {
// If we reach here the path does not exist.
// Thus begin searching for the part of it that actually is.

int tokenArg0Start = 0;
// Thus begin searching for the part of it that actually does.
int tokenArg0Start = -1;

for (int i = 0; i <= lastChar; i++) {
const char cmdChar = command[i];

/* Any ASCII control or space used as delimiter */
char tmpCommandChar = command[i];
if (cmdChar <= ' ') {
if (tokenEnd >= 0) {
// Split on every further separator, regardless of path correctness
command[i] = '\n';
continue;
}

if (command[i] <= ' ') {
if (!tokenEnd) {
command[i] = '\0';
// Found our first argument
command[i] = '\0';

bool found = Compat_faccessat(AT_FDCWD, command, F_OK, AT_SYMLINK_NOFOLLOW) == 0;
bool found = Compat_faccessat(AT_FDCWD, command, F_OK, AT_SYMLINK_NOFOLLOW) == 0;

// Restore if this wasn't it
command[i] = found ? '\n' : tmpCommandChar;
// Restore if this wasn't it
command[i] = found ? '\n' : cmdChar;

if (found)
tokenEnd = i;
if (!tokenArg0Start)
tokenArg0Start = tokenStart;
} else {
// Split on every further separator, regardless of path correctness
command[i] = '\n';
}
} else if (!tokenEnd) {
if (command[i] == '/' || (command[i] == '\\' && (!tokenStart || command[tokenStart - 1] == '\\'))) {
tokenStart = i + 1;
} else if (command[i] == ':' && (command[i + 1] != '/' && command[i + 1] != '\\')) {
if (found)
tokenEnd = i;
}
if (tokenArg0Start < 0)
tokenArg0Start = tokenStart < 0 ? 0 : tokenStart;

continue;
}

if (tokenEnd >= 0) {
continue;
}

if (cmdChar == '/') {
// Normal path separator
tokenStart = i + 1;
} else if (cmdChar == '\\' && (tokenStart < 1 || command[tokenStart - 1] == '\\')) {
// Windows Path separator (WINE)
tokenStart = i + 1;
} else if (cmdChar == ':' && (command[i + 1] != '/' && command[i + 1] != '\\')) {
// Colon not part of a Windows Path
tokenEnd = i;
} else if (tokenStart < 0) {
// Relative path
tokenStart = i;
}
}

if (!tokenEnd) {
if (tokenEnd < 0) {
tokenStart = tokenArg0Start;

// No token delimiter found, forcibly split
for (int i = 0; i <= lastChar; i++) {
if (command[i] <= ' ') {
command[i] = '\n';
if (!tokenEnd) {
if (tokenEnd < 0) {
tokenEnd = i;
}
}
Expand All @@ -1204,11 +1273,17 @@ static bool LinuxProcessTable_readCmdlineFile(Process* process, openat_arg_t pro
* file.so [kdeinit5] file local:/run/user/1000/klauncherdqbouY.1.slave-socket local:/run/user/1000/kded5TwsDAx.1.slave-socket
* Reset if start is behind end.
*/
if (tokenStart >= tokenEnd)
tokenStart = tokenEnd = 0;
if (tokenStart >= tokenEnd) {
tokenStart = -1;
tokenEnd = -1;
}
}

if (tokenStart < 0) {
tokenStart = 0;
}

if (tokenEnd == 0) {
if (tokenEnd < 0) {
tokenEnd = lastChar + 1;
}

Expand All @@ -1222,43 +1297,6 @@ static bool LinuxProcessTable_readCmdlineFile(Process* process, openat_arg_t pro
Process_updateComm(process, NULL);
}

char filename[MAX_NAME + 1];

/* execve could change /proc/[pid]/exe, so procExe should be updated */
#if defined(HAVE_READLINKAT) && defined(HAVE_OPENAT)
amtRead = readlinkat(procFd, "exe", filename, sizeof(filename) - 1);
#else
amtRead = Compat_readlink(procFd, "exe", filename, sizeof(filename) - 1);
#endif
if (amtRead > 0) {
filename[amtRead] = 0;
if (!process->procExe ||
(!process->procExeDeleted && !String_eq(filename, process->procExe)) ||
process->procExeDeleted) {

const char* deletedMarker = " (deleted)";
const size_t markerLen = strlen(deletedMarker);
const size_t filenameLen = strlen(filename);

if (filenameLen > markerLen) {
bool oldExeDeleted = process->procExeDeleted;

process->procExeDeleted = String_eq(filename + filenameLen - markerLen, deletedMarker);

if (process->procExeDeleted)
filename[filenameLen - markerLen] = '\0';

if (oldExeDeleted != process->procExeDeleted)
process->mergedCommand.lastUpdate = 0;
}

Process_updateExe(process, filename);
}
} else if (process->procExe) {
Process_updateExe(process, NULL);
process->procExeDeleted = false;
}

return true;
}

Expand Down
2 changes: 1 addition & 1 deletion linux/Platform.c
Original file line number Diff line number Diff line change
Expand Up @@ -261,7 +261,7 @@ int Platform_getUptime(void) {
if (fd) {
int n = fscanf(fd, "%64lf", &uptime);
fclose(fd);
if (n <= 0) {
if (n != 1) {
return 0;
}
}
Expand Down

0 comments on commit d05bf95

Please sign in to comment.