From 6da57d64c3875465c26999cf31ea07258a1f1561 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Fri, 12 Jan 2024 16:40:21 +0800 Subject: [PATCH] TerminalShell: split terminal detection and shell detection --- .../terminalshell/terminalshell_linux.c | 192 ++++++++++-------- .../terminalshell/terminalshell_windows.c | 36 +++- 2 files changed, 130 insertions(+), 98 deletions(-) diff --git a/src/detection/terminalshell/terminalshell_linux.c b/src/detection/terminalshell/terminalshell_linux.c index 327ba9772..cea214ca7 100644 --- a/src/detection/terminalshell/terminalshell_linux.c +++ b/src/detection/terminalshell/terminalshell_linux.c @@ -118,7 +118,7 @@ static const char* getProcessNameAndPpid(pid_t pid, char* name, pid_t* ppid) return NULL; } -static void getTerminalShell(FFTerminalShellResult* result, pid_t pid) +static pid_t getShellInfo(FFTerminalShellResult* result, pid_t pid) { char name[256]; name[0] = '\0'; @@ -126,7 +126,7 @@ static void getTerminalShell(FFTerminalShellResult* result, pid_t pid) pid_t ppid = 0; if(getProcessNameAndPpid(pid, name, &ppid)) - return; + return 0; //Common programs that are between terminal and own process, but are not the shell if( @@ -137,6 +137,7 @@ static void getTerminalShell(FFTerminalShellResult* result, pid_t pid) strcasecmp(name, "sshd") == 0 || strcasecmp(name, "gdb") == 0 || strcasecmp(name, "lldb") == 0 || + strcasecmp(name, "lldb-mi") == 0 || strcasecmp(name, "login") == 0 || strcasecmp(name, "ltrace") == 0 || strcasecmp(name, "perf") == 0 || @@ -144,10 +145,24 @@ static void getTerminalShell(FFTerminalShellResult* result, pid_t pid) strcasestr(name, "debug") != NULL || strcasestr(name, "command-not-found") != NULL || ffStrEndsWith(name, ".sh") - ) { - getTerminalShell(result, ppid); - return; - } + ) + return getShellInfo(result, ppid); + + result->shellPid = (uint32_t) pid; + ffStrbufSetS(&result->shellProcessName, name); + getProcessInformation(pid, &result->shellProcessName, &result->shellExe, &result->shellExeName); + return ppid; +} + +static pid_t getTerminalInfo(FFTerminalShellResult* result, pid_t pid) +{ + char name[256]; + name[0] = '\0'; + + pid_t ppid = 0; + + if(getProcessNameAndPpid(pid, name, &ppid)) + return 0; //Known shells if ( @@ -167,17 +182,8 @@ static void getTerminalShell(FFTerminalShellResult* result, pid_t pid) strcasecmp(name, "elvish") == 0 || strcasecmp(name, "oil.ovm") == 0 || (strcasecmp(name, "python") == 0 && getenv("XONSH_VERSION")) - ) { - if (result->shellProcessName.length == 0) - { - result->shellPid = (uint32_t) pid; - ffStrbufSetS(&result->shellProcessName, name); - getProcessInformation(pid, &result->shellProcessName, &result->shellExe, &result->shellExeName); - } - - getTerminalShell(result, ppid); - return; - } + ) + return getTerminalInfo(result, ppid); #ifdef __APPLE__ // https://github.com/fastfetch-cli/fastfetch/discussions/501 @@ -188,6 +194,7 @@ static void getTerminalShell(FFTerminalShellResult* result, pid_t pid) result->terminalPid = (uint32_t) pid; ffStrbufSetS(&result->terminalProcessName, name); getProcessInformation(pid, &result->terminalProcessName, &result->terminalExe, &result->terminalExeName); + return ppid; } static void getTerminalFromEnv(FFTerminalShellResult* result) @@ -288,6 +295,80 @@ bool fftsGetShellVersion(FFstrbuf* exe, const char* exeName, FFstrbuf* version); bool fftsGetTerminalVersion(FFstrbuf* processName, FFstrbuf* exe, FFstrbuf* version); +static void setShellInfoDetails(FFTerminalShellResult* result) +{ + ffStrbufClear(&result->shellVersion); + fftsGetShellVersion(&result->shellExe, result->shellExeName, &result->shellVersion); + + if(ffStrbufEqualS(&result->shellProcessName, "pwsh")) + ffStrbufInitStatic(&result->shellPrettyName, "PowerShell"); + else if(ffStrbufEqualS(&result->shellProcessName, "nu")) + ffStrbufInitStatic(&result->shellPrettyName, "nushell"); + else if(ffStrbufIgnCaseEqualS(&result->shellProcessName, "python") && getenv("XONSH_VERSION")) + ffStrbufInitStatic(&result->shellPrettyName, "xonsh"); + else if(ffStrbufIgnCaseEqualS(&result->shellProcessName, "oil.ovm")) + ffStrbufInitStatic(&result->shellPrettyName, "Oils"); + else + { + // https://github.com/fastfetch-cli/fastfetch/discussions/280#discussioncomment-3831734 + ffStrbufInitS(&result->shellPrettyName, result->shellExeName); + } +} + +static void setTerminalInfoDetails(FFTerminalShellResult* result) +{ + if(result->terminalExeName[0] == '.' && ffStrEndsWith(result->terminalExeName, "-wrapped")) + { + // For NixOS. Ref: #510 and https://github.com/NixOS/nixpkgs/pull/249428 + // We use terminalProcessName when detecting version and font, overriding it for simplification + ffStrbufSetNS( + &result->terminalProcessName, + (uint32_t) (strlen(result->terminalExeName) - strlen(".-wrapped")), + result->terminalExeName + 1); + } + + if(ffStrbufEqualS(&result->terminalProcessName, "wezterm-gui")) + ffStrbufInitStatic(&result->terminalPrettyName, "WezTerm"); + if(ffStrbufStartsWithS(&result->terminalProcessName, "tmux:")) + ffStrbufInitStatic(&result->terminalPrettyName, "tmux"); + + #if defined(__ANDROID__) + + else if(ffStrbufEqualS(&result->terminalProcessName, "com.termux")) + ffStrbufInitStatic(&result->terminalPrettyName, "Termux"); + + #elif defined(__linux__) || defined(__FreeBSD__) + + else if(ffStrbufStartsWithS(&result->terminalProcessName, "gnome-terminal-")) + ffStrbufInitStatic(&result->terminalPrettyName, "GNOME Terminal"); + else if(ffStrbufStartsWithS(&result->terminalProcessName, "kgx")) + ffStrbufInitStatic(&result->terminalPrettyName, "GNOME Console"); + else if(ffStrbufEqualS(&result->terminalProcessName, "urxvt") || + ffStrbufEqualS(&result->terminalProcessName, "urxvtd") || + ffStrbufEqualS(&result->terminalProcessName, "rxvt") + ) + ffStrbufInitStatic(&result->terminalPrettyName, "rxvt-unicode"); + + #elif defined(__APPLE__) + + else if(ffStrbufEqualS(&result->terminalProcessName, "iTerm.app") || ffStrbufStartsWithS(&result->terminalProcessName, "iTermServer-")) + ffStrbufInitStatic(&result->terminalPrettyName, "iTerm"); + else if(ffStrbufEqualS(&result->terminalProcessName, "Apple_Terminal")) + ffStrbufInitStatic(&result->terminalPrettyName, "Apple Terminal"); + else if(ffStrbufEqualS(&result->terminalProcessName, "WarpTerminal")) + ffStrbufInitStatic(&result->terminalPrettyName, "Warp"); + + #endif + + else if(strncmp(result->terminalExeName, result->terminalProcessName.chars, result->terminalProcessName.length) == 0) // if exeName starts with processName, print it. Otherwise print processName + ffStrbufInitS(&result->terminalPrettyName, result->terminalExeName); + else + ffStrbufInitCopy(&result->terminalPrettyName, &result->terminalProcessName); + + ffStrbufInit(&result->terminalVersion); + fftsGetTerminalVersion(&result->terminalProcessName, &result->terminalExe, &result->terminalVersion); +} + const FFTerminalShellResult* ffDetectTerminalShell() { static FFTerminalShellResult result; @@ -317,78 +398,15 @@ const FFTerminalShellResult* ffDetectTerminalShell() result.terminalExeName = result.terminalExe.chars; result.terminalPid = 0; - getTerminalShell(&result, getppid()); - - getTerminalFromEnv(&result); + pid_t ppid = getppid(); + ppid = getShellInfo(&result, ppid); getUserShellFromEnv(&result); + setShellInfoDetails(&result); - ffStrbufClear(&result.shellVersion); - fftsGetShellVersion(&result.shellExe, result.shellExeName, &result.shellVersion); - - if(ffStrbufEqualS(&result.shellProcessName, "pwsh")) - ffStrbufInitStatic(&result.shellPrettyName, "PowerShell"); - else if(ffStrbufEqualS(&result.shellProcessName, "nu")) - ffStrbufInitStatic(&result.shellPrettyName, "nushell"); - else if(ffStrbufIgnCaseEqualS(&result.shellProcessName, "python") && getenv("XONSH_VERSION")) - ffStrbufInitStatic(&result.shellPrettyName, "xonsh"); - else if(ffStrbufIgnCaseEqualS(&result.shellProcessName, "oil.ovm")) - ffStrbufInitStatic(&result.shellPrettyName, "Oils"); - else - { - // https://github.com/fastfetch-cli/fastfetch/discussions/280#discussioncomment-3831734 - ffStrbufInitS(&result.shellPrettyName, result.shellExeName); - } - - if(result.terminalExeName[0] == '.' && ffStrEndsWith(result.terminalExeName, "-wrapped")) - { - // For NixOS. Ref: #510 and https://github.com/NixOS/nixpkgs/pull/249428 - // We use terminalProcessName when detecting version and font, overriding it for simplification - ffStrbufSetNS( - &result.terminalProcessName, - (uint32_t) (strlen(result.terminalExeName) - strlen(".-wrapped")), - result.terminalExeName + 1); - } - - if(ffStrbufEqualS(&result.terminalProcessName, "wezterm-gui")) - ffStrbufInitStatic(&result.terminalPrettyName, "WezTerm"); - if(ffStrbufStartsWithS(&result.terminalProcessName, "tmux:")) - ffStrbufInitStatic(&result.terminalPrettyName, "tmux"); - - #if defined(__ANDROID__) - - else if(ffStrbufEqualS(&result.terminalProcessName, "com.termux")) - ffStrbufInitStatic(&result.terminalPrettyName, "Termux"); - - #elif defined(__linux__) || defined(__FreeBSD__) - - else if(ffStrbufStartsWithS(&result.terminalProcessName, "gnome-terminal-")) - ffStrbufInitStatic(&result.terminalPrettyName, "GNOME Terminal"); - else if(ffStrbufStartsWithS(&result.terminalProcessName, "kgx")) - ffStrbufInitStatic(&result.terminalPrettyName, "GNOME Console"); - else if(ffStrbufEqualS(&result.terminalProcessName, "urxvt") || - ffStrbufEqualS(&result.terminalProcessName, "urxvtd") || - ffStrbufEqualS(&result.terminalProcessName, "rxvt") - ) - ffStrbufInitStatic(&result.terminalPrettyName, "rxvt-unicode"); - - #elif defined(__APPLE__) - - else if(ffStrbufEqualS(&result.terminalProcessName, "iTerm.app") || ffStrbufStartsWithS(&result.terminalProcessName, "iTermServer-")) - ffStrbufInitStatic(&result.terminalPrettyName, "iTerm"); - else if(ffStrbufEqualS(&result.terminalProcessName, "Apple_Terminal")) - ffStrbufInitStatic(&result.terminalPrettyName, "Apple Terminal"); - else if(ffStrbufEqualS(&result.terminalProcessName, "WarpTerminal")) - ffStrbufInitStatic(&result.terminalPrettyName, "Warp"); - - #endif - - else if(strncmp(result.terminalExeName, result.terminalProcessName.chars, result.terminalProcessName.length) == 0) // if exeName starts with processName, print it. Otherwise print processName - ffStrbufInitS(&result.terminalPrettyName, result.terminalExeName); - else - ffStrbufInitCopy(&result.terminalPrettyName, &result.terminalProcessName); - - ffStrbufInit(&result.terminalVersion); - fftsGetTerminalVersion(&result.terminalProcessName, &result.terminalExe, &result.terminalVersion); + if (ppid) + ppid = getTerminalInfo(&result, ppid); + getTerminalFromEnv(&result); + setTerminalInfoDetails(&result); return &result; } diff --git a/src/detection/terminalshell/terminalshell_windows.c b/src/detection/terminalshell/terminalshell_windows.c index 0f2f23c81..ac5ad1872 100644 --- a/src/detection/terminalshell/terminalshell_windows.c +++ b/src/detection/terminalshell/terminalshell_windows.c @@ -120,6 +120,19 @@ static uint32_t getShellInfo(FFTerminalShellResult* result, uint32_t pid) fftsGetShellVersion(&result->shellExe, result->shellPrettyName.chars, &result->shellVersion); result->shellPid = pid; + + if(ffStrbufIgnCaseEqualS(&result->shellPrettyName, "explorer")) + { + ffStrbufSetS(&result->shellPrettyName, "Windows Explorer"); // Started without shell + // In this case, terminal process will be created by fastfetch itself. + ppid = 0; + } + + return ppid; +} + +static void setShellInfoDetails(FFTerminalShellResult* result) +{ if(ffStrbufIgnCaseEqualS(&result->shellPrettyName, "pwsh")) ffStrbufSetS(&result->shellPrettyName, "PowerShell"); else if(ffStrbufIgnCaseEqualS(&result->shellPrettyName, "powershell")) @@ -131,7 +144,7 @@ static uint32_t getShellInfo(FFTerminalShellResult* result, uint32_t pid) ffStrbufClear(&result->shellPrettyName); FF_AUTO_CLOSE_FD HANDLE snapshot = NULL; - while(!(snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, pid)) && GetLastError() == ERROR_BAD_LENGTH) {} + while(!(snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, result->shellPid)) && GetLastError() == ERROR_BAD_LENGTH) {} if(snapshot) { @@ -154,13 +167,7 @@ static uint32_t getShellInfo(FFTerminalShellResult* result, uint32_t pid) else if(ffStrbufIgnCaseEqualS(&result->shellPrettyName, "nu")) ffStrbufSetS(&result->shellPrettyName, "nushell"); else if(ffStrbufIgnCaseEqualS(&result->shellPrettyName, "explorer")) - { - ffStrbufSetS(&result->shellPrettyName, "Windows Explorer"); // Started without shell - // In this case, terminal process will be created by fastfetch itself. - return 0; - } - - return ppid; + ffStrbufSetS(&result->shellPrettyName, "Windows Explorer"); } static bool getTerminalFromEnv(FFTerminalShellResult* result) @@ -198,7 +205,7 @@ static bool getTerminalFromEnv(FFTerminalShellResult* result) if(!term && ( getenv("WT_SESSION") != NULL || getenv("WT_PROFILE_ID") != NULL - )) term = "Windows Terminal"; + )) term = "WindowsTerminal"; //Alacritty if(!term && ( @@ -334,6 +341,11 @@ static uint32_t getTerminalInfo(FFTerminalShellResult* result, uint32_t pid) else result->terminalPid = pid; + return ppid; +} + +static void setTerminalInfoDetails(FFTerminalShellResult* result) +{ if(ffStrbufIgnCaseEqualS(&result->terminalPrettyName, "WindowsTerminal")) ffStrbufSetStatic(&result->terminalPrettyName, ffStrbufContainIgnCaseS(&result->terminalExe, ".WindowsTerminalPreview_") ? "Windows Terminal Preview" @@ -347,8 +359,6 @@ static uint32_t getTerminalInfo(FFTerminalShellResult* result, uint32_t pid) ffStrbufSetStatic(&result->terminalPrettyName, "Windows Explorer"); else if(ffStrbufEqualS(&result->terminalPrettyName, "wezterm-gui")) ffStrbufSetStatic(&result->terminalPrettyName, "WezTerm"); - - return ppid; } bool fftsGetTerminalVersion(FFstrbuf* processName, FFstrbuf* exe, FFstrbuf* version); @@ -379,12 +389,16 @@ const FFTerminalShellResult* ffDetectTerminalShell(void) return &result; ppid = getShellInfo(&result, ppid); + setShellInfoDetails(&result); + if(ppid) getTerminalInfo(&result, ppid); if(result.terminalProcessName.length == 0) getTerminalFromEnv(&result); + setTerminalInfoDetails(&result); + ffStrbufInit(&result.terminalVersion); fftsGetTerminalVersion(&result.terminalProcessName, &result.terminalExe, &result.terminalVersion);