TerminalShell: move process info query logic into common place

This commit is contained in:
李通洲
2024-05-28 22:34:41 +08:00
committed by 李通洲
parent 1f3d18cdbc
commit 3811bb1be4
5 changed files with 259 additions and 248 deletions
@@ -10,12 +10,6 @@
#include <stdlib.h>
#include <unistd.h>
#if defined(__FreeBSD__) || defined(__APPLE__)
#include <sys/types.h>
#include <sys/user.h>
#include <sys/sysctl.h>
#endif
static void setExeName(FFstrbuf* exe, const char** exeName)
{
assert(exe->length > 0);
@@ -24,192 +18,6 @@ static void setExeName(FFstrbuf* exe, const char** exeName)
*exeName = exe->chars + lastSlashIndex + 1;
}
static void getProcessInformation(pid_t pid, FFstrbuf* processName, FFstrbuf* exe, const char** exeName, FFstrbuf* exePath)
{
assert(processName->length > 0);
ffStrbufClear(exe);
#ifdef __linux__
char filePath[64];
snprintf(filePath, sizeof(filePath), "/proc/%d/cmdline", (int)pid);
if(ffAppendFileBuffer(filePath, exe))
{
ffStrbufTrimRightSpace(exe);
ffStrbufRecalculateLength(exe); //Trim the arguments
ffStrbufTrimLeft(exe, '-'); //Login shells start with a dash
}
snprintf(filePath, sizeof(filePath), "/proc/%d/exe", (int)pid);
ffStrbufEnsureFixedLengthFree(exePath, PATH_MAX);
ssize_t length = readlink(filePath, exePath->chars, exePath->allocated - 1);
if (length > 0) // doesn't contain trailing NUL
{
exePath->chars[length] = '\0';
exePath->length = (uint32_t) length;
}
#elif defined(__APPLE__)
size_t len = 0;
int mibs[] = { CTL_KERN, KERN_PROCARGS2, pid };
if (sysctl(mibs, sizeof(mibs) / sizeof(*mibs), NULL, &len, NULL, 0) == 0)
{
#ifndef MAC_OS_X_VERSION_10_15
//don't know why if don't let len longer, proArgs2 and len will change during the following sysctl() in old MacOS version.
len++;
#endif
FF_AUTO_FREE char* const procArgs2 = malloc(len);
if (sysctl(mibs, sizeof(mibs) / sizeof(*mibs), procArgs2, &len, NULL, 0) == 0)
{
// https://gist.github.com/nonowarn/770696#file-getargv-c-L46
uint32_t argc = *(uint32_t*) procArgs2;
const char* realExePath = procArgs2 + sizeof(argc);
const char* arg0 = memchr(realExePath, '\0', len - (size_t) (realExePath - procArgs2));
ffStrbufSetNS(exePath, (uint32_t) (arg0 - realExePath), realExePath);
do arg0++; while (*arg0 == '\0');
assert(arg0 < procArgs2 + len);
if (*arg0 == '-') arg0++; // Login shells
ffStrbufSetS(exe, arg0);
}
}
#elif defined(__FreeBSD__)
size_t size = ARG_MAX;
FF_AUTO_FREE char* args = malloc(size);
static_assert(ARG_MAX > PATH_MAX, "");
if(sysctl(
(int[]){CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, pid}, 4,
args, &size,
NULL, 0
) == 0)
ffStrbufSetNS(exePath, (uint32_t) (size - 1), args);
size = ARG_MAX;
if(sysctl(
(int[]){CTL_KERN, KERN_PROC, KERN_PROC_ARGS, pid}, 4,
args, &size,
NULL, 0
) == 0)
{
char* arg0 = args;
size_t arg0Len = strlen(args);
if (size > arg0Len + 1)
{
char* p = (char*) memrchr(args, '/', arg0Len);
if (p)
{
p++;
if (ffStrStartsWith(p, "python")) // /usr/local/bin/python3.9 /home/carter/.local/bin/xonsh
{
arg0 += arg0Len + 1;
}
}
}
if (arg0[0] == '-') arg0++;
ffStrbufSetS(exe, arg0);
}
#endif
if(exe->length == 0)
ffStrbufSet(exe, processName);
setExeName(exe, exeName);
}
static const char* getProcessNameAndPpid(pid_t pid, char* name, pid_t* ppid, int32_t* tty)
{
if (pid <= 0)
return "Invalid pid";
#ifdef __linux__
char statFilePath[64];
snprintf(statFilePath, sizeof(statFilePath), "/proc/%d/stat", (int)pid);
char buf[PROC_FILE_BUFFSIZ];
ssize_t nRead = ffReadFileData(statFilePath, sizeof(buf) - 1, buf);
if(nRead < 0)
return "ffReadFileData(statFilePath, sizeof(buf)-1, buf) failed";
buf[nRead] = '\0';
*ppid = 0;
static_assert(sizeof(*ppid) == sizeof(int), "");
int tty_;
if(
sscanf(buf, "%*s (%255[^)]) %*c %d %*d %*d %d", name, ppid, &tty_) < 2 || //stat (comm) state ppid pgrp session tty
!ffStrSet(name) ||
*ppid == 0
)
return "sscanf(stat) failed";
if (tty)
*tty = tty_ & 0xFF;
#elif defined(__APPLE__)
struct kinfo_proc proc;
size_t size = sizeof(proc);
if(sysctl(
(int[]){CTL_KERN, KERN_PROC, KERN_PROC_PID, pid}, 4,
&proc, &size,
NULL, 0
))
return "sysctl(KERN_PROC_PID) failed";
*ppid = (pid_t)proc.kp_eproc.e_ppid;
strcpy(name, proc.kp_proc.p_comm); //trancated to 16 chars
if (tty)
{
*tty = ((proc.kp_eproc.e_tdev >> 24) & 0xFF) == 0x10
? proc.kp_eproc.e_tdev & 0xFFFFFF
: -1;
}
#elif defined(__FreeBSD__)
struct kinfo_proc proc;
size_t size = sizeof(proc);
if(sysctl(
(int[]){CTL_KERN, KERN_PROC, KERN_PROC_PID, pid}, 4,
&proc, &size,
NULL, 0
))
return "sysctl(KERN_PROC_PID) failed";
*ppid = (pid_t)proc.ki_ppid;
strcpy(name, proc.ki_comm);
if (tty)
{
if (proc.ki_tdev != NODEV && proc.ki_flag & P_CONTROLT)
{
const char* ttyName = devname(proc.ki_tdev, S_IFCHR);
if (ffStrStartsWith(ttyName, "pts/"))
*tty = (int32_t) strtol(ttyName + strlen("pts/"), NULL, 10);
else
*tty = -1;
}
else
*tty = -1;
}
#else
return "Unsupported platform";
#endif
return NULL;
}
static pid_t getShellInfo(FFShellResult* result, pid_t pid)
{
char name[256];
@@ -227,7 +35,7 @@ static pid_t getShellInfo(FFShellResult* result, pid_t pid)
userShellName = instance.state.platform.userShell.chars + index + 1;
}
while (getProcessNameAndPpid(pid, name, &ppid, &tty) == NULL)
while (ffProcessGetBasicInfoLinux(pid, name, &ppid, &tty) == NULL)
{
if (!ffStrEquals(userShellName, name))
{
@@ -264,7 +72,7 @@ static pid_t getShellInfo(FFShellResult* result, pid_t pid)
result->ppid = (uint32_t) ppid;
result->tty = tty;
ffStrbufSetS(&result->processName, name);
getProcessInformation(pid, &result->processName, &result->exe, &result->exeName, &result->exePath);
ffProcessGetInfoLinux(pid, &result->processName, &result->exe, &result->exeName, &result->exePath);
break;
}
return ppid;
@@ -277,7 +85,7 @@ static pid_t getTerminalInfo(FFTerminalResult* result, pid_t pid)
pid_t ppid = 0;
while (getProcessNameAndPpid(pid, name, &ppid, NULL) == NULL)
while (ffProcessGetBasicInfoLinux(pid, name, &ppid, NULL) == NULL)
{
//Known shells
if (
@@ -324,7 +132,7 @@ static pid_t getTerminalInfo(FFTerminalResult* result, pid_t pid)
for (; pLeft < pRight; ++pLeft)
if (*pLeft < 'a' || *pLeft > 'z')
break;
if (pLeft == pRight && getProcessNameAndPpid(ppid, name, &ppid, NULL) != NULL)
if (pLeft == pRight && ffProcessGetBasicInfoLinux(ppid, name, &ppid, NULL) != NULL)
return 0;
}
}
@@ -333,7 +141,7 @@ static pid_t getTerminalInfo(FFTerminalResult* result, pid_t pid)
result->pid = (uint32_t) pid;
result->ppid = (uint32_t) ppid;
ffStrbufSetS(&result->processName, name);
getProcessInformation(pid, &result->processName, &result->exe, &result->exeName, &result->exePath);
ffProcessGetInfoLinux(pid, &result->processName, &result->exe, &result->exeName, &result->exePath);
break;
}
return ppid;
@@ -348,10 +156,10 @@ static bool getTerminalInfoByPidEnv(FFTerminalResult* result, const char* pidEnv
pid_t pid = (pid_t) strtol(envStr, NULL, 10);
result->pid = (uint32_t) pid;
char name[256];
if (getProcessNameAndPpid(pid, name, (pid_t*) &result->ppid, NULL) == NULL)
if (ffProcessGetBasicInfoLinux(pid, name, (pid_t*) &result->ppid, NULL) == NULL)
{
ffStrbufSetS(&result->processName, name);
getProcessInformation(pid, &result->processName, &result->exe, &result->exeName, &result->exePath);
ffProcessGetInfoLinux(pid, &result->processName, &result->exe, &result->exeName, &result->exePath);
return true;
}