diff --git a/CMakeLists.txt b/CMakeLists.txt index 1687f162c..1d0cf1b4d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -64,6 +64,7 @@ cmake_dependent_option(ENABLE_OPENCL "Enable opencl" ON "LINUX OR BSD OR WIN32" cmake_dependent_option(ENABLE_LIBCJSON "Enable libcjson" ON "LINUX OR WIN32" OFF) cmake_dependent_option(ENABLE_FREETYPE "Enable freetype" ON "ANDROID" OFF) cmake_dependent_option(ENABLE_THREADS "Enable multithreading" ON "Threads_FOUND AND NOT ANDROID" OFF) +cmake_dependent_option(USE_WIN_FAST_PPID_DETECTION "Use internal NTAPI instead of querying WMI to get PPID" ON "WIN32" OFF) option(BUILD_TESTS "Build tests" OFF) # Also create test executables option(SET_TWEAK "Add tweak to project version" ON) # This is set to off by github actions for release builds @@ -523,7 +524,12 @@ elseif(WIN32) PRIVATE "opengl32" PRIVATE "wbemuuid" PRIVATE "ws2_32" + PRIVATE "ntdll" + PRIVATE "version" ) + if(USE_WIN_FAST_PPID_DETECTION) + target_compile_definitions(libfastfetch PRIVATE FF_USE_WIN_FAST_PPID_DETECTION) + endif() endif() target_include_directories(libfastfetch diff --git a/src/common/processing_windows.c b/src/common/processing_windows.c index 9ec6da811..cd091ac6c 100644 --- a/src/common/processing_windows.c +++ b/src/common/processing_windows.c @@ -28,7 +28,7 @@ const char* ffProcessAppendStdOut(FFstrbuf* buffer, char* const argv[]) }; FFstrbuf cmdline; - ffStrbufInitS(&cmdline, argv[0]); + ffStrbufInitF(&cmdline, "\"%s\"", argv[0]); for(char* const* parg = &argv[1]; *parg; ++parg) { ffStrbufAppendC(&cmdline, ' '); diff --git a/src/detection/localip/localip_windows.c b/src/detection/localip/localip_windows.c index 275987f10..e23a32fe8 100644 --- a/src/detection/localip/localip_windows.c +++ b/src/detection/localip/localip_windows.c @@ -5,24 +5,10 @@ #include "localip.h" -static void addNewIp(FFlist* list, const wchar_t* name, const char* addr, bool ipv6) +static void addNewIp(FFlist* list, const char* name, const char* addr, bool ipv6) { FFLocalIpResult* ip = (FFLocalIpResult*) ffListAdd(list); - - int len = (int)wcslen(name); - if(len > 0) - { - int size_needed = WideCharToMultiByte(CP_UTF8, 0, name, len, NULL, 0, NULL, NULL); - ffStrbufInitA(&ip->name, (uint32_t)size_needed + 1); - WideCharToMultiByte(CP_UTF8, 0, name, len, ip->name.chars, size_needed, NULL, NULL); - ip->name.length = (uint32_t)size_needed; - ip->name.chars[size_needed] = '\0'; - } - else - { - ffStrbufInitS(&ip->name, "*"); - } - + ffStrbufInitS(&ip->name, name); ffStrbufInitS(&ip->addr, addr); ip->ipv6 = ipv6; } @@ -64,6 +50,11 @@ const char* ffDetectLocalIps(const FFinstance* instance, FFlist* results) if (adapter->IfType == IF_TYPE_SOFTWARE_LOOPBACK && !instance->config.localIpShowLoop) continue; + char name[128]; + WideCharToMultiByte(CP_UTF8, 0, adapter->FriendlyName, -1, name, sizeof(name), NULL, NULL); + if (instance->config.localIpNamePrefix.length && strncmp(name, instance->config.localIpNamePrefix.chars, instance->config.localIpNamePrefix.length) != 0) + continue; + for (IP_ADAPTER_UNICAST_ADDRESS* ifa = adapter->FirstUnicastAddress; ifa; ifa = ifa->Next) { if (ifa->Address.lpSockaddr->sa_family == AF_INET) @@ -75,7 +66,7 @@ const char* ffDetectLocalIps(const FFinstance* instance, FFlist* results) SOCKADDR_IN* ipv4 = (SOCKADDR_IN*) ifa->Address.lpSockaddr; char addressBuffer[INET_ADDRSTRLEN]; inet_ntop(AF_INET, &ipv4->sin_addr, addressBuffer, INET_ADDRSTRLEN); - addNewIp(results, adapter->FriendlyName, addressBuffer, false); + addNewIp(results, name, addressBuffer, false); } else if (ifa->Address.lpSockaddr->sa_family == AF_INET6) { @@ -86,7 +77,7 @@ const char* ffDetectLocalIps(const FFinstance* instance, FFlist* results) SOCKADDR_IN6* ipv6 = (SOCKADDR_IN6*) ifa->Address.lpSockaddr; char addressBuffer[INET6_ADDRSTRLEN]; inet_ntop(AF_INET6, &ipv6->sin6_addr, addressBuffer, INET6_ADDRSTRLEN); - addNewIp(results, adapter->FriendlyName, addressBuffer, false); + addNewIp(results, name, addressBuffer, false); } } } diff --git a/src/detection/os/os_windows.cpp b/src/detection/os/os_windows.cpp index aa04bb976..c6dd9977e 100644 --- a/src/detection/os/os_windows.cpp +++ b/src/detection/os/os_windows.cpp @@ -51,6 +51,18 @@ void ffDetectOSImpl(FFOSResult* os, const FFinstance* instance) uint32_t index = ffStrbufFirstIndexC(&os->variant, ' '); ffStrbufAppendNS(&os->version, index, os->variant.chars); ffStrbufSubstrAfter(&os->variant, index); + + // Windows Server 20xx Rx + if(ffStrbufEndsWithC(&os->prettyName, 'r')) + { + if(os->variant.chars[0] == 'R' && + isdigit(os->variant.chars[1]) && + (os->variant.chars[2] == '\0' || os->variant.chars[2] == ' ')) + { + ffStrbufAppendF(&os->version, " R%c", os->variant.chars[1]); + ffStrbufSubstrAfter(&os->variant, strlen("Rx ") - 1); + } + } } else { @@ -59,7 +71,7 @@ void ffDetectOSImpl(FFOSResult* os, const FFinstance* instance) ffStrbufClear(&os->variant); } - ffStrbufAppendF(&os->id, "Windows %*s", os->version.length, os->version.chars); + ffStrbufAppendF(&os->id, "%*s %*s", os->prettyName.length, os->prettyName.chars, os->version.length, os->version.chars); ffGetWmiObjString(pclsObj, L"BuildNumber", &os->buildID); ffGetWmiObjString(pclsObj, L"OSArchitecture", &os->architecture); diff --git a/src/detection/terminalshell/terminalshell.c b/src/detection/terminalshell/terminalshell.c index e48b919a3..f4141a6b2 100644 --- a/src/detection/terminalshell/terminalshell.c +++ b/src/detection/terminalshell/terminalshell.c @@ -1,6 +1,41 @@ #include "fastfetch.h" #include "common/processing.h" +#ifdef _WIN32 + +#include + +static bool getFileVersion(const char* exePath, FFstrbuf* version) +{ + DWORD handle; + DWORD size = GetFileVersionInfoSizeA(exePath, &handle); + if(size > 0) + { + void* versionData = malloc(size); + if(GetFileVersionInfoA(exePath, handle, size, versionData)) + { + VS_FIXEDFILEINFO* verInfo; + UINT len; + if(VerQueryValueW(versionData, L"\\", (void**)&verInfo, &len) && len && verInfo->dwSignature == 0xFEEF04BD) + { + ffStrbufAppendF(version, "%u.%u.%u.%u", + (unsigned)(( verInfo->dwFileVersionMS >> 16 ) & 0xffff), + (unsigned)(( verInfo->dwFileVersionMS >> 0 ) & 0xffff), + (unsigned)(( verInfo->dwFileVersionLS >> 16 ) & 0xffff), + (unsigned)(( verInfo->dwFileVersionLS >> 0 ) & 0xffff) + ); + free(versionData); + return true; + } + } + free(versionData); + } + + return false; +} + +#endif + static void getShellVersionBash(FFstrbuf* exe, FFstrbuf* version) { ffProcessAppendStdOut(version, (char* const[]) { @@ -25,7 +60,7 @@ static void getShellVersionZsh(FFstrbuf* exe, FFstrbuf* version) ffStrbufSubstrAfterFirstC(version, ' '); } -static void getShellVersionFishPwsh(FFstrbuf* exe, FFstrbuf* version) +static void getShellVersionFish(FFstrbuf* exe, FFstrbuf* version) { ffProcessAppendStdOut(version, (char* const[]) { exe->chars, @@ -36,6 +71,43 @@ static void getShellVersionFishPwsh(FFstrbuf* exe, FFstrbuf* version) ffStrbufSubstrAfterLastC(version, ' '); } +static void getShellVersionPwsh(FFstrbuf* exe, FFstrbuf* version) +{ + #ifdef _WIN32 + if(getFileVersion(exe->chars, version)) + return; + #endif + + ffProcessAppendStdOut(version, (char* const[]) { + exe->chars, + "--version", + NULL + }); + ffStrbufTrimRight(version, '\n'); + ffStrbufSubstrAfterLastC(version, ' '); +} + +#ifdef _WIN32 +static void getShellVersionWinPowerShell(FFstrbuf* exe, FFstrbuf* version) +{ + ffProcessAppendStdOut(version, (char* const[]) { + exe->chars, + "-NoLogo", + "-NoProfile", + "-Command", + "$PSVersionTable.PSVersion.ToString()", + NULL + }); + ffStrbufTrimRight(version, '\n'); + ffStrbufSubstrAfterLastC(version, ' '); +} + +static void getShellVersionCmd(FFstrbuf* exe, FFstrbuf* version) +{ + getFileVersion(exe->chars, version); +} +#endif + static void getShellVersionNu(FFstrbuf* exe, FFstrbuf* version) { ffProcessAppendStdOut(version, (char* const[]) { @@ -52,10 +124,20 @@ bool fftsGetShellVersion(FFstrbuf* exe, const char* exeName, FFstrbuf* version) getShellVersionBash(exe, version); else if(strcasecmp(exeName, "zsh") == 0) getShellVersionZsh(exe, version); - else if(strcasecmp(exeName, "fish") == 0 || strcasecmp(exeName, "pwsh") == 0) - getShellVersionFishPwsh(exe, version); + else if(strcasecmp(exeName, "fish") == 0) + getShellVersionFish(exe, version); + else if(strcasecmp(exeName, "pwsh") == 0) + getShellVersionPwsh(exe, version); else if(strcasecmp(exeName, "nu") == 0) getShellVersionNu(exe, version); + + #ifdef _WIN32 + else if(strcasecmp(exeName, "powershell") == 0 || strcasecmp(exeName, "powershell_ise") == 0) + getShellVersionWinPowerShell(exe, version); + else if(strcasecmp(exeName, "cmd") == 0) + getShellVersionCmd(exe, version); + #endif + else ok = false; return ok; diff --git a/src/detection/terminalshell/terminalshell_windows.cpp b/src/detection/terminalshell/terminalshell_windows.cpp index cd904f97e..71a34c6ea 100644 --- a/src/detection/terminalshell/terminalshell_windows.cpp +++ b/src/detection/terminalshell/terminalshell_windows.cpp @@ -3,20 +3,68 @@ extern "C" { #include "common/processing.h" #include "common/thread.h" } -#include "util/windows/wmi.hpp" #include #include #include -struct ProcessInfo -{ - uint32_t pid; - FFstrbuf psName; -}; +#include -static bool getProcessInfo(uint32_t pid, uint32_t* ppid, FFstrbuf* pname, FFstrbuf* exe) +#ifdef FF_USE_WIN_FAST_PPID_DETECTION + +#include + +static bool getProcessInfo(uint32_t pid, uint32_t* ppid, FFstrbuf* pname, FFstrbuf* exe, const char** exeName) { + 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); + } + + 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) +{ + if(pid == 0) + pid = GetCurrentProcessId(); + wchar_t query[256] = {}; swprintf(query, 256, L"SELECT %ls %ls ParentProcessId FROM Win32_Process WHERE ProcessId = %" PRIu32, pname ? L"Name," : L"", @@ -49,20 +97,26 @@ static bool getProcessInfo(uint32_t pid, uint32_t* ppid, FFstrbuf* pname, FFstrb if(exe) ffGetWmiObjString(pclsObj, L"ExecutablePath", exe); + if(exeName) + { + *exeName = exe->chars + ffStrbufLastIndexC(exe, '\\') + 1; + } + pclsObj->Release(); pEnumerator->Release(); return true; } +#endif + extern "C" bool fftsGetShellVersion(FFstrbuf* exe, const char* exeName, FFstrbuf* version); static uint32_t getShellInfo(FFTerminalShellResult* result, uint32_t pid) { uint32_t ppid; - if(pid == 0 || !getProcessInfo(pid, &ppid, &result->shellProcessName, &result->shellExe)) + if(pid == 0 || !getProcessInfo(pid, &ppid, &result->shellProcessName, &result->shellExe, &result->shellExeName)) return 0; - result->shellExeName = result->shellExe.chars + ffStrbufLastIndexC(&result->shellExe, '\\') + 1; ffStrbufSet(&result->shellPrettyName, &result->shellProcessName); if(ffStrbufEndsWithIgnCaseS(&result->shellPrettyName, ".exe")) @@ -113,9 +167,8 @@ static uint32_t getTerminalInfo(FFTerminalShellResult* result, uint32_t pid) { uint32_t ppid; - if(pid == 0 || !getProcessInfo(pid, &ppid, &result->terminalProcessName, &result->terminalExe)) + if(pid == 0 || !getProcessInfo(pid, &ppid, &result->terminalProcessName, &result->terminalExe, &result->terminalExeName)) return 0; - result->terminalExeName = result->terminalExe.chars + ffStrbufLastIndexC(&result->terminalExe, '\\'); ffStrbufSet(&result->terminalPrettyName, &result->terminalProcessName); if(ffStrbufEndsWithIgnCaseS(&result->terminalPrettyName, ".exe")) @@ -135,7 +188,7 @@ static uint32_t getTerminalInfo(FFTerminalShellResult* result, uint32_t pid) ffStrbufClear(&result->terminalProcessName); ffStrbufClear(&result->terminalPrettyName); ffStrbufClear(&result->terminalExe); - result->terminalExeName = nullptr; + result->terminalExeName = ""; return getTerminalInfo(result, ppid); } @@ -212,21 +265,21 @@ const FFTerminalShellResult* ffDetectTerminalShell(const FFinstance* instance) ffStrbufInit(&result.shellProcessName); ffStrbufInitA(&result.shellExe, 128); - result.shellExeName = result.shellExe.chars; + result.shellExeName = ""; ffStrbufInit(&result.shellPrettyName); ffStrbufInit(&result.shellVersion); ffStrbufInit(&result.terminalProcessName); ffStrbufInitA(&result.terminalExe, 128); - result.terminalExeName = result.terminalExe.chars; + result.terminalExeName = ""; ffStrbufInit(&result.terminalPrettyName); ffStrbufInit(&result.userShellExe); - result.userShellExeName = result.userShellExe.chars; + result.userShellExeName = ""; ffStrbufInit(&result.userShellVersion); - uint32_t ppid = GetCurrentProcessId(); - if(!getProcessInfo(ppid, &ppid, nullptr, nullptr)) + uint32_t ppid; + if(!getProcessInfo(0, &ppid, nullptr, nullptr, nullptr)) goto exit; ppid = getShellInfo(&result, ppid); diff --git a/src/logo/builtin.c b/src/logo/builtin.c index 86376c7fa..e11dc0954 100644 --- a/src/logo/builtin.c +++ b/src/logo/builtin.c @@ -1280,7 +1280,7 @@ static const FFlogo* getLogoMsys2() static const FFlogo* getLogoWindows11() { FF_LOGO_INIT - FF_LOGO_NAMES("Windows 11") + FF_LOGO_NAMES("Windows 11", "Windows Server 2022") FF_LOGO_LINES( "$1\n" "################ ################\n" @@ -1310,7 +1310,7 @@ static const FFlogo* getLogoWindows11() static const FFlogo* getLogoWindows8() { FF_LOGO_INIT - FF_LOGO_NAMES("Windows 8", "Windows 8.1", "Windows 10") + FF_LOGO_NAMES("Windows 8", "Windows 8.1", "Windows 10", "Windows Server 2012", "Windows Server 2012 R2", "Windows Server 2016", "Windows Server 2019") FF_LOGO_LINES( "$1 ..,\n" " ....,,:;+ccllll\n" @@ -1343,7 +1343,7 @@ static const FFlogo* getLogoWindows8() static const FFlogo* getLogoWindows() { FF_LOGO_INIT - FF_LOGO_NAMES("Windows") + FF_LOGO_NAMES("Windows", "Windows 7", "Windows Server 2008", "Windows Server 2008 R2") FF_LOGO_LINES( "$1 ,.=:!!t3Z3z.,\n" " :tt:::tt333EE3\n" diff --git a/src/modules/localip.c b/src/modules/localip.c index 07508f3bd..89df09962 100644 --- a/src/modules/localip.c +++ b/src/modules/localip.c @@ -33,7 +33,10 @@ void ffPrintLocalIp(FFinstance* instance) if(instance->config.localIP.key.length == 0) { - ffStrbufSetF(&key, FF_LOCALIP_MODULE_NAME " (%*s)", ip->name.length, ip->name.chars); + if(ip->name.length) + ffStrbufSetF(&key, FF_LOCALIP_MODULE_NAME " (%*s)", ip->name.length, ip->name.chars); + else + ffStrbufSetS(&key, FF_LOCALIP_MODULE_NAME); } else {