Files
fastfetch/src/detection/terminalshell/terminalshell_windows.cpp
T

285 lines
9.5 KiB
C++
Raw Normal View History

2022-10-08 16:04:55 +08:00
extern "C" {
#include "terminalshell.h"
#include "common/processing.h"
2022-10-14 17:19:36 +08:00
#include "common/thread.h"
2022-10-08 16:04:55 +08:00
}
#include <inttypes.h>
#include <processthreadsapi.h>
#include <wchar.h>
2022-10-15 19:51:33 +08:00
#include <chrono>
#ifdef FF_USE_WIN_FAST_PPID_DETECTION
#include <winternl.h>
static bool getProcessInfo(uint32_t pid, uint32_t* ppid, FFstrbuf* pname, FFstrbuf* exe, const char** exeName)
2022-10-08 16:04:55 +08:00
{
2022-10-15 19:51:33 +08:00
HANDLE hProcess = pid == 0
? GetCurrentProcess()
: OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, TRUE, pid);
if(ppid)
{
PROCESS_BASIC_INFORMATION info;
ULONG size;
if(NT_SUCCESS(NtQueryInformationProcess(hProcess, ProcessBasicInformation, &info, sizeof(info), &size)))
{
assert(size == sizeof(info));
*ppid = (uint32_t)info.InheritedFromUniqueProcessId;
}
else
{
CloseHandle(hProcess);
return false;
}
}
if(exe)
{
DWORD bufSize = exe->allocated;
if(QueryFullProcessImageNameA(hProcess, 0, exe->chars, &bufSize))
exe->length = bufSize;
else
{
CloseHandle(hProcess);
return false;
}
}
if(pname && exeName)
{
*exeName = exe->chars + ffStrbufLastIndexC(exe, '\\') + 1;
ffStrbufSetS(pname, *exeName);
}
2022-10-08 16:04:55 +08:00
2022-10-15 19:51:33 +08:00
CloseHandle(hProcess);
return true;
}
#else
#include "util/windows/wmi.hpp"
static bool getProcessInfo(uint32_t pid, uint32_t* ppid, FFstrbuf* pname, FFstrbuf* exe, const char** exeName)
2022-10-08 16:04:55 +08:00
{
2022-10-15 19:51:33 +08:00
if(pid == 0)
pid = GetCurrentProcessId();
2022-10-16 23:58:13 +08:00
wchar_t sql[256] = {};
swprintf(sql, 256, L"SELECT %ls %ls ParentProcessId FROM Win32_Process WHERE ProcessId = %" PRIu32,
pname ? L"Name," : L"",
pname ? L"ExecutablePath," : L"",
pid);
2022-10-08 16:04:55 +08:00
2022-10-16 23:58:13 +08:00
FFWmiQuery query(sql);
if(!query)
2022-10-08 16:04:55 +08:00
return false;
2022-10-16 23:58:13 +08:00
if(FFWmiRecord record = query.next())
2022-10-08 16:04:55 +08:00
{
2022-10-16 23:58:13 +08:00
if(ppid)
{
uint64_t value;
record.getUnsigned(L"ParentProcessId", &value);
*ppid = (uint32_t) value;
}
2022-10-08 16:04:55 +08:00
2022-10-16 23:58:13 +08:00
if(pname)
record.getString(L"Name", pname);
2022-10-08 16:04:55 +08:00
2022-10-16 23:58:13 +08:00
if(exe)
record.getString(L"ExecutablePath", exe);
2022-10-08 16:04:55 +08:00
2022-10-16 23:58:13 +08:00
if(exeName)
*exeName = exe->chars + ffStrbufLastIndexC(exe, '\\') + 1;
2022-10-15 19:51:33 +08:00
}
2022-10-08 16:04:55 +08:00
return true;
}
2022-10-15 19:51:33 +08:00
#endif
extern "C" bool fftsGetShellVersion(FFstrbuf* exe, const char* exeName, FFstrbuf* version);
2022-10-08 16:04:55 +08:00
static uint32_t getShellInfo(FFTerminalShellResult* result, uint32_t pid)
{
uint32_t ppid;
2022-10-15 19:51:33 +08:00
if(pid == 0 || !getProcessInfo(pid, &ppid, &result->shellProcessName, &result->shellExe, &result->shellExeName))
2022-10-08 16:04:55 +08:00
return 0;
2022-10-09 16:51:53 +08:00
ffStrbufSet(&result->shellPrettyName, &result->shellProcessName);
if(ffStrbufEndsWithIgnCaseS(&result->shellPrettyName, ".exe"))
ffStrbufSubstrBefore(&result->shellPrettyName, result->shellPrettyName.length - 4);
2022-10-08 16:04:55 +08:00
//Common programs that are between terminal and own process, but are not the shell
if(
ffStrbufIgnCaseEqualS(&result->shellPrettyName, "sudo") ||
ffStrbufIgnCaseEqualS(&result->shellPrettyName, "su") ||
ffStrbufIgnCaseEqualS(&result->shellPrettyName, "doas") ||
ffStrbufIgnCaseEqualS(&result->shellPrettyName, "strace") ||
ffStrbufIgnCaseEqualS(&result->shellPrettyName, "sshd") ||
ffStrbufIgnCaseEqualS(&result->shellPrettyName, "gdb") ||
ffStrbufIgnCaseEqualS(&result->shellPrettyName, "lldb") ||
ffStrbufIgnCaseEqualS(&result->shellPrettyName, "guake-wrapped") ||
ffStrbufContainIgnCaseS(&result->shellPrettyName, "debug")
) {
ffStrbufClear(&result->shellProcessName);
ffStrbufClear(&result->shellPrettyName);
ffStrbufClear(&result->shellExe);
result->shellExeName = nullptr;
return getShellInfo(result, ppid);
}
ffStrbufClear(&result->shellVersion);
fftsGetShellVersion(&result->shellExe, result->shellPrettyName.chars, &result->shellVersion);
if(ffStrbufIgnCaseEqualS(&result->shellPrettyName, "pwsh"))
2022-10-09 16:51:53 +08:00
ffStrbufSetS(&result->shellPrettyName, "PowerShell");
else if(ffStrbufIgnCaseEqualS(&result->shellPrettyName, "powershell"))
2022-10-09 21:33:54 +08:00
ffStrbufSetS(&result->shellPrettyName, "Windows PowerShell");
else if(ffStrbufIgnCaseEqualS(&result->shellPrettyName, "powershell_ise"))
2022-10-12 00:13:49 +08:00
ffStrbufSetS(&result->shellPrettyName, "Windows PowerShell ISE");
else if(ffStrbufIgnCaseEqualS(&result->shellPrettyName, "cmd"))
2022-10-09 21:33:54 +08:00
ffStrbufSetS(&result->shellPrettyName, "Command Prompt");
else if(ffStrbufIgnCaseEqualS(&result->shellPrettyName, "nu"))
2022-10-14 18:38:18 +08:00
ffStrbufSetS(&result->shellPrettyName, "nushell");
else if(ffStrbufIgnCaseEqualS(&result->terminalPrettyName, "explorer"))
2022-10-12 00:13:49 +08:00
{
ffStrbufSetS(&result->terminalPrettyName, "Windows Explorer"); // Started without shell
return 0;
}
2022-10-08 16:04:55 +08:00
return ppid;
}
static uint32_t getTerminalInfo(FFTerminalShellResult* result, uint32_t pid)
{
uint32_t ppid;
2022-10-15 19:51:33 +08:00
if(pid == 0 || !getProcessInfo(pid, &ppid, &result->terminalProcessName, &result->terminalExe, &result->terminalExeName))
2022-10-08 16:04:55 +08:00
return 0;
2022-10-09 16:51:53 +08:00
ffStrbufSet(&result->terminalPrettyName, &result->terminalProcessName);
if(ffStrbufEndsWithIgnCaseS(&result->terminalPrettyName, ".exe"))
2022-10-09 17:47:30 +08:00
ffStrbufSubstrBefore(&result->terminalPrettyName, result->terminalPrettyName.length - 4);
2022-10-08 16:04:55 +08:00
2022-10-14 18:38:18 +08:00
if(
ffStrbufIgnCaseEqualS(&result->terminalPrettyName, "pwsh") ||
ffStrbufIgnCaseEqualS(&result->terminalPrettyName, "cmd") ||
ffStrbufIgnCaseEqualS(&result->terminalPrettyName, "bash") ||
ffStrbufIgnCaseEqualS(&result->terminalPrettyName, "zsh") ||
ffStrbufIgnCaseEqualS(&result->terminalPrettyName, "fish") ||
ffStrbufIgnCaseEqualS(&result->terminalPrettyName, "nu") ||
ffStrbufIgnCaseEqualS(&result->terminalPrettyName, "powershell") ||
ffStrbufIgnCaseEqualS(&result->terminalPrettyName, "powershell_ise")
2022-10-14 18:38:18 +08:00
) {
//We are nested shell
ffStrbufClear(&result->terminalProcessName);
ffStrbufClear(&result->terminalPrettyName);
ffStrbufClear(&result->terminalExe);
2022-10-15 19:51:33 +08:00
result->terminalExeName = "";
2022-10-14 18:38:18 +08:00
return getTerminalInfo(result, ppid);
}
if(ffStrbufIgnCaseEqualS(&result->terminalPrettyName, "WindowsTerminal"))
2022-10-09 16:51:53 +08:00
ffStrbufSetS(&result->terminalPrettyName, "Windows Terminal");
else if(ffStrbufIgnCaseEqualS(&result->terminalPrettyName, "conhost"))
2022-10-09 16:51:53 +08:00
ffStrbufSetS(&result->terminalPrettyName, "Console Window Host");
else if(ffStrbufIgnCaseEqualS(&result->terminalPrettyName, "Code"))
ffStrbufSetS(&result->terminalPrettyName, "Visual Studio Code");
else if(ffStrbufIgnCaseEqualS(&result->terminalPrettyName, "explorer"))
2022-10-12 00:13:49 +08:00
ffStrbufSetS(&result->terminalPrettyName, "Windows Explorer");
2022-11-06 14:41:44 +08:00
else if(ffStrbufStartsWithIgnCaseS(&result->terminalPrettyName, "ConEmuC"))
ffStrbufSetS(&result->terminalPrettyName, "ConEmu");
2022-10-08 16:04:55 +08:00
return ppid;
}
2022-10-14 18:38:18 +08:00
static void getTerminalFromEnv(FFTerminalShellResult* result)
{
if(
result->terminalProcessName.length > 0 &&
!ffStrbufStartsWithIgnCaseS(&result->terminalProcessName, "login") &&
ffStrbufIgnCaseCompS(&result->terminalProcessName, "(login)") != 0 &&
ffStrbufIgnCaseCompS(&result->terminalProcessName, "systemd") != 0 &&
ffStrbufIgnCaseCompS(&result->terminalProcessName, "init") != 0 &&
ffStrbufIgnCaseCompS(&result->terminalProcessName, "(init)") != 0 &&
ffStrbufIgnCaseCompS(&result->terminalProcessName, "0") != 0
) return;
const char* term = nullptr;
2022-10-14 18:38:18 +08:00
//SSH
if(getenv("SSH_CONNECTION") != nullptr)
2022-10-14 18:38:18 +08:00
term = getenv("SSH_TTY");
//Windows Terminal
if(!term && (
getenv("WT_SESSION") != nullptr ||
getenv("WT_PROFILE_ID") != nullptr
2022-10-14 18:38:18 +08:00
)) term = "Windows Terminal";
//Alacritty
if(!term && (
getenv("ALACRITTY_SOCKET") != nullptr ||
getenv("ALACRITTY_LOG") != nullptr ||
getenv("ALACRITTY_WINDOW_ID") != nullptr
2022-10-14 18:38:18 +08:00
)) term = "Alacritty";
//Normal Terminal
if(!term)
term = getenv("TERM");
if(term)
{
ffStrbufSetS(&result->terminalProcessName, term);
ffStrbufSetS(&result->terminalPrettyName, term);
ffStrbufSetS(&result->terminalExe, term);
result->terminalExeName = "";
}
}
2022-10-08 16:04:55 +08:00
const FFTerminalShellResult* ffDetectTerminalShell(const FFinstance* instance)
{
2022-10-14 17:19:36 +08:00
FF_UNUSED(instance);
static FFThreadMutex mutex = FF_THREAD_MUTEX_INITIALIZER;
2022-10-08 16:04:55 +08:00
static FFTerminalShellResult result;
static bool init = false;
2022-10-14 17:19:36 +08:00
ffThreadMutexLock(&mutex);
2022-10-08 16:04:55 +08:00
if(init)
2022-10-14 17:19:36 +08:00
{
ffThreadMutexUnlock(&mutex);
2022-10-08 16:04:55 +08:00
return &result;
2022-10-14 17:19:36 +08:00
}
2022-10-08 16:04:55 +08:00
init = true;
ffStrbufInit(&result.shellProcessName);
ffStrbufInitA(&result.shellExe, 128);
2022-10-15 19:51:33 +08:00
result.shellExeName = "";
2022-10-09 16:51:53 +08:00
ffStrbufInit(&result.shellPrettyName);
2022-10-08 16:04:55 +08:00
ffStrbufInit(&result.shellVersion);
ffStrbufInit(&result.terminalProcessName);
ffStrbufInitA(&result.terminalExe, 128);
2022-10-15 19:51:33 +08:00
result.terminalExeName = "";
2022-10-09 16:51:53 +08:00
ffStrbufInit(&result.terminalPrettyName);
2022-10-08 16:04:55 +08:00
ffStrbufInit(&result.userShellExe);
2022-10-15 19:51:33 +08:00
result.userShellExeName = "";
2022-10-08 16:04:55 +08:00
ffStrbufInit(&result.userShellVersion);
2022-10-15 19:51:33 +08:00
uint32_t ppid;
if(!getProcessInfo(0, &ppid, nullptr, nullptr, nullptr))
2022-10-14 17:19:36 +08:00
goto exit;
2022-10-08 16:04:55 +08:00
ppid = getShellInfo(&result, ppid);
2022-10-14 17:19:36 +08:00
getTerminalInfo(&result, ppid);
2022-10-14 18:38:18 +08:00
if(result.terminalProcessName.length == 0)
getTerminalFromEnv(&result);
2022-10-08 16:04:55 +08:00
2022-10-14 17:19:36 +08:00
exit:
ffThreadMutexUnlock(&mutex);
2022-10-08 16:04:55 +08:00
return &result;
}