Skip to content

Commit 3811bb1

Browse files
committed
TerminalShell: move process info query logic into common place
1 parent 1f3d18c commit 3811bb1

File tree

5 files changed

+259
-248
lines changed

5 files changed

+259
-248
lines changed

src/common/processing.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,10 @@ static inline const char* ffProcessAppendStdErr(FFstrbuf* buffer, char* const ar
1919
ffStrbufTrimRightSpace(buffer);
2020
return error;
2121
}
22+
23+
#ifdef _WIN32
24+
bool ffProcessGetInfoWindows(uint32_t pid, uint32_t* ppid, FFstrbuf* pname, FFstrbuf* exe, const char** exeName, FFstrbuf* exePath, bool* gui);
25+
#else
26+
void ffProcessGetInfoLinux(pid_t pid, FFstrbuf* processName, FFstrbuf* exe, const char** exeName, FFstrbuf* exePath);
27+
const char* ffProcessGetBasicInfoLinux(pid_t pid, char* name, pid_t* ppid, int32_t* tty);
28+
#endif

src/common/processing_linux.c

Lines changed: 196 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
#include "common/processing.h"
33
#include "common/io/io.h"
44
#include "common/time.h"
5+
#include "util/stringUtils.h"
56

67
#include <stdlib.h>
78
#include <unistd.h>
@@ -11,6 +12,12 @@
1112
#include <errno.h>
1213
#include <sys/wait.h>
1314

15+
#if defined(__FreeBSD__) || defined(__APPLE__)
16+
#include <sys/types.h>
17+
#include <sys/user.h>
18+
#include <sys/sysctl.h>
19+
#endif
20+
1421
enum { FF_PIPE_BUFSIZ = 8192 };
1522

1623
static inline int ffPipe2(int *fds, int flags)
@@ -101,3 +108,192 @@ const char* ffProcessAppendOutput(FFstrbuf* buffer, char* const argv[], bool use
101108

102109
return "read(childPipeFd, str, FF_PIPE_BUFSIZ) failed";
103110
}
111+
112+
void ffProcessGetInfoLinux(pid_t pid, FFstrbuf* processName, FFstrbuf* exe, const char** exeName, FFstrbuf* exePath)
113+
{
114+
assert(processName->length > 0);
115+
ffStrbufClear(exe);
116+
117+
#ifdef __linux__
118+
119+
char filePath[64];
120+
snprintf(filePath, sizeof(filePath), "/proc/%d/cmdline", (int)pid);
121+
122+
if(ffAppendFileBuffer(filePath, exe))
123+
{
124+
ffStrbufTrimRightSpace(exe);
125+
ffStrbufRecalculateLength(exe); //Trim the arguments
126+
ffStrbufTrimLeft(exe, '-'); //Login shells start with a dash
127+
}
128+
129+
snprintf(filePath, sizeof(filePath), "/proc/%d/exe", (int)pid);
130+
ffStrbufEnsureFixedLengthFree(exePath, PATH_MAX);
131+
ssize_t length = readlink(filePath, exePath->chars, exePath->allocated - 1);
132+
if (length > 0) // doesn't contain trailing NUL
133+
{
134+
exePath->chars[length] = '\0';
135+
exePath->length = (uint32_t) length;
136+
}
137+
138+
#elif defined(__APPLE__)
139+
140+
size_t len = 0;
141+
int mibs[] = { CTL_KERN, KERN_PROCARGS2, pid };
142+
if (sysctl(mibs, sizeof(mibs) / sizeof(*mibs), NULL, &len, NULL, 0) == 0)
143+
{
144+
#ifndef MAC_OS_X_VERSION_10_15
145+
//don't know why if don't let len longer, proArgs2 and len will change during the following sysctl() in old MacOS version.
146+
len++;
147+
#endif
148+
FF_AUTO_FREE char* const procArgs2 = malloc(len);
149+
if (sysctl(mibs, sizeof(mibs) / sizeof(*mibs), procArgs2, &len, NULL, 0) == 0)
150+
{
151+
// https://gist.github.com/nonowarn/770696#file-getargv-c-L46
152+
uint32_t argc = *(uint32_t*) procArgs2;
153+
const char* realExePath = procArgs2 + sizeof(argc);
154+
155+
const char* arg0 = memchr(realExePath, '\0', len - (size_t) (realExePath - procArgs2));
156+
ffStrbufSetNS(exePath, (uint32_t) (arg0 - realExePath), realExePath);
157+
158+
do arg0++; while (*arg0 == '\0');
159+
assert(arg0 < procArgs2 + len);
160+
if (*arg0 == '-') arg0++; // Login shells
161+
162+
ffStrbufSetS(exe, arg0);
163+
}
164+
}
165+
166+
#elif defined(__FreeBSD__)
167+
168+
size_t size = ARG_MAX;
169+
FF_AUTO_FREE char* args = malloc(size);
170+
171+
static_assert(ARG_MAX > PATH_MAX, "");
172+
173+
if(sysctl(
174+
(int[]){CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, pid}, 4,
175+
args, &size,
176+
NULL, 0
177+
) == 0)
178+
ffStrbufSetNS(exePath, (uint32_t) (size - 1), args);
179+
180+
size = ARG_MAX;
181+
if(sysctl(
182+
(int[]){CTL_KERN, KERN_PROC, KERN_PROC_ARGS, pid}, 4,
183+
args, &size,
184+
NULL, 0
185+
) == 0)
186+
{
187+
char* arg0 = args;
188+
size_t arg0Len = strlen(args);
189+
if (size > arg0Len + 1)
190+
{
191+
char* p = (char*) memrchr(args, '/', arg0Len);
192+
if (p)
193+
{
194+
p++;
195+
if (ffStrStartsWith(p, "python")) // /usr/local/bin/python3.9 /home/carter/.local/bin/xonsh
196+
{
197+
arg0 += arg0Len + 1;
198+
}
199+
}
200+
}
201+
if (arg0[0] == '-') arg0++;
202+
ffStrbufSetS(exe, arg0);
203+
}
204+
205+
#endif
206+
207+
if(exe->length == 0)
208+
ffStrbufSet(exe, processName);
209+
210+
assert(exe->length > 0);
211+
uint32_t lastSlashIndex = ffStrbufLastIndexC(exe, '/');
212+
if(lastSlashIndex < exe->length)
213+
*exeName = exe->chars + lastSlashIndex + 1;
214+
}
215+
216+
const char* ffProcessGetBasicInfoLinux(pid_t pid, char* name, pid_t* ppid, int32_t* tty)
217+
{
218+
if (pid <= 0)
219+
return "Invalid pid";
220+
221+
#ifdef __linux__
222+
223+
char statFilePath[64];
224+
snprintf(statFilePath, sizeof(statFilePath), "/proc/%d/stat", (int)pid);
225+
char buf[PROC_FILE_BUFFSIZ];
226+
ssize_t nRead = ffReadFileData(statFilePath, sizeof(buf) - 1, buf);
227+
if(nRead < 0)
228+
return "ffReadFileData(statFilePath, sizeof(buf)-1, buf) failed";
229+
buf[nRead] = '\0';
230+
231+
*ppid = 0;
232+
static_assert(sizeof(*ppid) == sizeof(int), "");
233+
234+
int tty_;
235+
if(
236+
sscanf(buf, "%*s (%255[^)]) %*c %d %*d %*d %d", name, ppid, &tty_) < 2 || //stat (comm) state ppid pgrp session tty
237+
!ffStrSet(name) ||
238+
*ppid == 0
239+
)
240+
return "sscanf(stat) failed";
241+
242+
if (tty)
243+
*tty = tty_ & 0xFF;
244+
245+
#elif defined(__APPLE__)
246+
247+
struct kinfo_proc proc;
248+
size_t size = sizeof(proc);
249+
if(sysctl(
250+
(int[]){CTL_KERN, KERN_PROC, KERN_PROC_PID, pid}, 4,
251+
&proc, &size,
252+
NULL, 0
253+
))
254+
return "sysctl(KERN_PROC_PID) failed";
255+
256+
*ppid = (pid_t)proc.kp_eproc.e_ppid;
257+
strcpy(name, proc.kp_proc.p_comm); //trancated to 16 chars
258+
if (tty)
259+
{
260+
*tty = ((proc.kp_eproc.e_tdev >> 24) & 0xFF) == 0x10
261+
? proc.kp_eproc.e_tdev & 0xFFFFFF
262+
: -1;
263+
}
264+
265+
#elif defined(__FreeBSD__)
266+
267+
struct kinfo_proc proc;
268+
size_t size = sizeof(proc);
269+
if(sysctl(
270+
(int[]){CTL_KERN, KERN_PROC, KERN_PROC_PID, pid}, 4,
271+
&proc, &size,
272+
NULL, 0
273+
))
274+
return "sysctl(KERN_PROC_PID) failed";
275+
276+
*ppid = (pid_t)proc.ki_ppid;
277+
strcpy(name, proc.ki_comm);
278+
if (tty)
279+
{
280+
if (proc.ki_tdev != NODEV && proc.ki_flag & P_CONTROLT)
281+
{
282+
const char* ttyName = devname(proc.ki_tdev, S_IFCHR);
283+
if (ffStrStartsWith(ttyName, "pts/"))
284+
*tty = (int32_t) strtol(ttyName + strlen("pts/"), NULL, 10);
285+
else
286+
*tty = -1;
287+
}
288+
else
289+
*tty = -1;
290+
}
291+
292+
#else
293+
294+
return "Unsupported platform";
295+
296+
#endif
297+
298+
return NULL;
299+
}

src/common/processing_windows.c

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
#include "common/io/io.h"
44

55
#include <Windows.h>
6+
#include <ntstatus.h>
7+
#include <winternl.h>
68

79
enum { FF_PIPE_BUFSIZ = 8192 };
810

@@ -124,3 +126,46 @@ const char* ffProcessAppendOutput(FFstrbuf* buffer, char* const argv[], bool use
124126

125127
return NULL;
126128
}
129+
130+
bool ffProcessGetInfoWindows(uint32_t pid, uint32_t* ppid, FFstrbuf* pname, FFstrbuf* exe, const char** exeName, FFstrbuf* exePath, bool* gui)
131+
{
132+
FF_AUTO_CLOSE_FD HANDLE hProcess = pid == 0
133+
? GetCurrentProcess()
134+
: OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pid);
135+
136+
if (gui)
137+
*gui = GetGuiResources(hProcess, GR_GDIOBJECTS) > 0;
138+
139+
if(ppid)
140+
{
141+
PROCESS_BASIC_INFORMATION info = {};
142+
ULONG size;
143+
if(NT_SUCCESS(NtQueryInformationProcess(hProcess, ProcessBasicInformation, &info, sizeof(info), &size)))
144+
{
145+
assert(size == sizeof(info));
146+
*ppid = (uint32_t)info.InheritedFromUniqueProcessId;
147+
}
148+
else
149+
return false;
150+
}
151+
if(exe)
152+
{
153+
DWORD bufSize = exe->allocated;
154+
if(QueryFullProcessImageNameA(hProcess, 0, exe->chars, &bufSize))
155+
{
156+
// We use full path here
157+
// Querying command line of remote processes in Windows requires either WMI or ReadProcessMemory
158+
exe->length = bufSize;
159+
if (exePath) ffStrbufSet(exePath, exe);
160+
}
161+
else
162+
return false;
163+
}
164+
if(pname && exeName)
165+
{
166+
*exeName = exe->chars + ffStrbufLastIndexC(exe, '\\') + 1;
167+
ffStrbufSetS(pname, *exeName);
168+
}
169+
170+
return true;
171+
}

0 commit comments

Comments
 (0)