mirror of
https://github.com/fastfetch-cli/fastfetch.git
synced 2026-10-30 09:33:39 +01:00
rewrote shell / terminal detection
This commit is contained in:
@@ -0,0 +1,239 @@
|
||||
#include "fastfetch.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <pthread.h>
|
||||
|
||||
static void setExeName(FFstrbuf* exe, const char** exeName)
|
||||
{
|
||||
uint32_t lastSlashIndex = ffStrbufLastIndexC(exe, '/');
|
||||
if(lastSlashIndex < exe->length)
|
||||
*exeName = exe->chars + lastSlashIndex + 1;
|
||||
}
|
||||
|
||||
static void getProcessInformation(const char* pid, FFstrbuf* processName, FFstrbuf* exe, const char** exeName)
|
||||
{
|
||||
FFstrbuf cmdlineFilePath;
|
||||
ffStrbufInit(&cmdlineFilePath);
|
||||
ffStrbufAppendS(&cmdlineFilePath, "/proc/");
|
||||
ffStrbufAppendS(&cmdlineFilePath, pid);
|
||||
ffStrbufAppendS(&cmdlineFilePath, "/cmdline");
|
||||
|
||||
ffGetFileContent(cmdlineFilePath.chars, exe);
|
||||
ffStrbufSubstrBeforeFirstC(exe, '\0'); //Trim the arguments
|
||||
|
||||
if(exe->length == 0)
|
||||
ffStrbufSet(exe, processName);
|
||||
|
||||
setExeName(exe, exeName);
|
||||
|
||||
ffStrbufDestroy(&cmdlineFilePath);
|
||||
}
|
||||
|
||||
static void getTerminalShell(FFTerminalShellResult* result, const char* pid)
|
||||
{
|
||||
if(pid == NULL || *pid == '\0')
|
||||
return;
|
||||
|
||||
FFstrbuf statFilePath;
|
||||
ffStrbufInit(&statFilePath);
|
||||
ffStrbufAppendS(&statFilePath, "/proc/");
|
||||
ffStrbufAppendS(&statFilePath, pid);
|
||||
ffStrbufAppendS(&statFilePath, "/stat");
|
||||
|
||||
FILE* stat = fopen(statFilePath.chars, "r");
|
||||
|
||||
ffStrbufDestroy(&statFilePath);
|
||||
|
||||
if(stat == NULL)
|
||||
return;
|
||||
|
||||
char name[256];
|
||||
name[0] = '\0';
|
||||
|
||||
char ppid[256];
|
||||
ppid[0] = '\0';
|
||||
|
||||
fscanf(stat, "%*s (%255[^)]) %*c %255s", name, ppid); //stat (comm) state ppid
|
||||
fclose(stat);
|
||||
|
||||
if(
|
||||
*name == '\0' ||
|
||||
*ppid == '\0' ||
|
||||
*ppid == '-' ||
|
||||
strcasecmp(ppid, "0") == 0
|
||||
) return;
|
||||
|
||||
//Common programs that are between terminal and own process, but are not the shell
|
||||
if(
|
||||
strcasecmp(name, "sudo") == 0 ||
|
||||
strcasecmp(name, "su") == 0 ||
|
||||
strcasecmp(name, "doas") == 0 ||
|
||||
strcasecmp(name, "strace") == 0 ||
|
||||
strcasecmp(name, "gdb") == 0
|
||||
) {
|
||||
getTerminalShell(result, ppid);
|
||||
return;
|
||||
}
|
||||
|
||||
//Known shells
|
||||
if(
|
||||
strcasecmp(name, "bash") == 0 ||
|
||||
strcasecmp(name, "sh") == 0 ||
|
||||
strcasecmp(name, "zsh") == 0 ||
|
||||
strcasecmp(name, "ksh") == 0 ||
|
||||
strcasecmp(name, "fish") == 0 ||
|
||||
strcasecmp(name, "dash") == 0 ||
|
||||
strcasecmp(name, "git-shell") == 0
|
||||
) {
|
||||
ffStrbufAppendS(&result->shellProcessName, name);
|
||||
getProcessInformation(pid, &result->shellProcessName, &result->shellExe, &result->shellExeName);
|
||||
|
||||
getTerminalShell(result, ppid);
|
||||
return;
|
||||
}
|
||||
|
||||
ffStrbufAppendS(&result->terminalProcessName, name);
|
||||
getProcessInformation(pid, &result->terminalProcessName, &result->terminalExe, &result->terminalExeName);
|
||||
}
|
||||
|
||||
static void getTerminalFromEnv(FFTerminalShellResult* result)
|
||||
{
|
||||
if(
|
||||
result->terminalProcessName.length != 0 &&
|
||||
ffStrbufStartsWithIgnCaseS(&result->terminalProcessName, "login") != 0 &&
|
||||
ffStrbufIgnCaseCompS(&result->terminalProcessName, "systemd") != 0 &&
|
||||
ffStrbufIgnCaseCompS(&result->terminalProcessName, "init") != 0 &&
|
||||
ffStrbufIgnCaseCompS(&result->terminalProcessName, "(init)") != 0
|
||||
) return;
|
||||
|
||||
char* term = getenv("TERM");
|
||||
|
||||
//TTY
|
||||
if(term == NULL || *term == '\0' || strcasecmp(term, "linux") == 0)
|
||||
term = ttyname(STDIN_FILENO);
|
||||
|
||||
ffStrbufAppendS(&result->terminalProcessName, term);
|
||||
ffStrbufSetS(&result->terminalExe, term);
|
||||
setExeName(&result->terminalExe, &result->terminalExeName);
|
||||
}
|
||||
|
||||
static void getUserShellFromEnv(FFTerminalShellResult* result)
|
||||
{
|
||||
ffStrbufAppendS(&result->userShellExe, getenv("SHELL"));
|
||||
setExeName(&result->userShellExe, &result->userShellExeName);
|
||||
|
||||
//If shell detection via processes failed
|
||||
if(result->shellProcessName.length == 0 && result->userShellExe.length > 0)
|
||||
{
|
||||
ffStrbufAppendS(&result->shellProcessName, result->userShellExeName);
|
||||
ffStrbufSet(&result->shellExe, &result->userShellExe);
|
||||
setExeName(&result->shellExe, &result->shellExeName);
|
||||
}
|
||||
}
|
||||
|
||||
static void getShellVersionBash(FFstrbuf* exe, FFstrbuf* version)
|
||||
{
|
||||
ffProcessAppendStdOut(version, (char* const[]) {
|
||||
"env",
|
||||
"-i",
|
||||
exe->chars,
|
||||
"--norc",
|
||||
"--noprofile",
|
||||
"-c",
|
||||
"printf \"%s\" \"$BASH_VERSION\"",
|
||||
NULL
|
||||
});
|
||||
ffStrbufSubstrBeforeFirstC(version, '(');
|
||||
}
|
||||
|
||||
static void getShellVersionZsh(FFstrbuf* exe, FFstrbuf* version)
|
||||
{
|
||||
ffProcessAppendStdOut(version, (char* const[]) {
|
||||
"env",
|
||||
"-i",
|
||||
exe->chars,
|
||||
"--no-rcs",
|
||||
"-c",
|
||||
"printf \"%s\" \"$ZSH_VERSION\"",
|
||||
NULL
|
||||
});
|
||||
}
|
||||
|
||||
static void getShellVersionGeneric(FFstrbuf* exe, const char* exeName, FFstrbuf* version)
|
||||
{
|
||||
FFstrbuf command;
|
||||
ffStrbufInit(&command);
|
||||
ffStrbufAppendS(&command, "printf \"%s\" \"$");
|
||||
ffStrbufAppendTransformS(&command, exeName, toupper);
|
||||
ffStrbufAppendS(&command, "_VERSION\"");
|
||||
|
||||
ffProcessAppendStdOut(version, (char* const[]) {
|
||||
"env",
|
||||
"-i",
|
||||
exe->chars,
|
||||
"-c",
|
||||
command.chars,
|
||||
NULL
|
||||
});
|
||||
ffStrbufSubstrBeforeFirstC(version, '(');
|
||||
ffStrbufRemoveStrings(version, 2, "-release", "release");
|
||||
|
||||
ffStrbufDestroy(&command);
|
||||
}
|
||||
|
||||
static void getShellVersion(FFstrbuf* exe, const char* exeName, FFstrbuf* version)
|
||||
{
|
||||
if(strcasecmp(exeName, "bash") == 0)
|
||||
getShellVersionBash(exe, version);
|
||||
else if(strcasecmp(exeName, "zsh") == 0)
|
||||
getShellVersionZsh(exe, version);
|
||||
else
|
||||
getShellVersionGeneric(exe, exeName, version);
|
||||
}
|
||||
|
||||
const FFTerminalShellResult* ffDetectTerminalShell(FFinstance* instance)
|
||||
{
|
||||
UNUSED(instance);
|
||||
|
||||
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
static FFTerminalShellResult result;
|
||||
static bool init = false;
|
||||
pthread_mutex_lock(&mutex);
|
||||
if(init)
|
||||
{
|
||||
pthread_mutex_unlock(&mutex);
|
||||
return &result;
|
||||
}
|
||||
init = true;
|
||||
|
||||
ffStrbufInit(&result.shellProcessName);
|
||||
ffStrbufInit(&result.shellExe);
|
||||
result.shellExeName = result.shellExe.chars;
|
||||
ffStrbufInit(&result.shellVersion);
|
||||
|
||||
ffStrbufInit(&result.terminalProcessName);
|
||||
ffStrbufInit(&result.terminalExe);
|
||||
result.terminalExeName = result.terminalExe.chars;
|
||||
|
||||
ffStrbufInit(&result.userShellExe);
|
||||
result.userShellExeName = result.userShellExe.chars;
|
||||
ffStrbufInit(&result.userShellVersion);
|
||||
|
||||
char ppid[256];
|
||||
snprintf(ppid, 255, "%i", getppid());
|
||||
getTerminalShell(&result, ppid);
|
||||
|
||||
getTerminalFromEnv(&result);
|
||||
getUserShellFromEnv(&result);
|
||||
getShellVersion(&result.shellExe, result.shellExeName, &result.shellVersion);
|
||||
|
||||
if(strcasecmp(result.shellExeName, result.userShellExeName) != 0)
|
||||
getShellVersion(&result.userShellExe, result.userShellExeName, &result.userShellVersion);
|
||||
else
|
||||
ffStrbufSet(&result.userShellVersion, &result.shellVersion);
|
||||
|
||||
pthread_mutex_unlock(&mutex);
|
||||
return &result;
|
||||
}
|
||||
@@ -323,7 +323,7 @@ static void getFromProcDir(FFinstance* instance, FFWMDEResult* result, ProtocolH
|
||||
ffStrbufAppendS(&procPath, dirent->d_name);
|
||||
ffStrbufAppendS(&procPath, "/cmdline");
|
||||
ffGetFileContent(procPath.chars, &processName);
|
||||
ffStrbufRecalculateLength(&processName); //Arguments are seperated by a \0 char. We make use of this to extract only the executable path. This is needed if arguments contain the / char
|
||||
ffStrbufSubstrBeforeFirstC(&processName, '\0'); //Trim the arguments
|
||||
ffStrbufSubstrAfterLastC(&processName, '/');
|
||||
ffStrbufSubstrBefore(&procPath, procPathLength);
|
||||
|
||||
|
||||
@@ -32,9 +32,9 @@ static inline void* detectWMDEThreadMain(void* instance)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline void* detectTerminalThreadMain(void* instance)
|
||||
static inline void* detectTerminalShellThreadMain(void* instance)
|
||||
{
|
||||
ffDetectTerminal((FFinstance*)instance);
|
||||
ffDetectTerminalShell((FFinstance*)instance);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -56,9 +56,9 @@ static inline void* startThreadsThreadMain(void* instance)
|
||||
pthread_create(>k4Thread, NULL, detectGTK4ThreadMain, instance);
|
||||
pthread_detach(gtk4Thread);
|
||||
|
||||
pthread_t terminalThread;
|
||||
pthread_create(&terminalThread, NULL, detectTerminalThreadMain, instance);
|
||||
pthread_detach(terminalThread);
|
||||
pthread_t terminalShellThread;
|
||||
pthread_create(&terminalShellThread, NULL, detectTerminalShellThreadMain, instance);
|
||||
pthread_detach(terminalShellThread);
|
||||
|
||||
pthread_t plasmaThread;
|
||||
pthread_create(&plasmaThread, NULL, detectPlasmaThreadMain, instance);
|
||||
|
||||
Reference in New Issue
Block a user