#include "FFPlatform_private.h" #include "util/stringUtils.h" #include "fastfetch_config.h" #include "common/io/io.h" #include #include #include #include #include #ifdef __APPLE__ #include #include #elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) #include #elif defined(__HAIKU__) #include #include #endif static void getExePath(FFPlatform* platform) { char exePath[PATH_MAX + 1]; #ifdef __linux__ ssize_t exePathLen = readlink("/proc/self/exe", exePath, sizeof(exePath) - 1); if (exePathLen >= 0) exePath[exePathLen] = '\0'; #elif defined(__APPLE__) int exePathLen = proc_pidpath((int) getpid(), exePath, sizeof(exePath)); #elif defined(__FreeBSD__) || defined(__NetBSD__) size_t exePathLen = sizeof(exePath); if(sysctl( (int[]){CTL_KERN, #ifdef __FreeBSD__ KERN_PROC, KERN_PROC_PATHNAME, (int) getpid() #else KERN_PROC_ARGS, (int) getpid(), KERN_PROC_PATHNAME #endif }, 4, exePath, &exePathLen, NULL, 0 ) < 0) exePathLen = 0; else exePathLen--; // remove terminating NUL #elif defined(__OpenBSD__) size_t exePathLen = 0; #elif defined(__sun) ssize_t exePathLen = readlink("/proc/self/path/a.out", exePath, sizeof(exePath) - 1); if (exePathLen >= 0) exePath[exePathLen] = '\0'; #elif defined(__HAIKU__) size_t exePathLen = 0; image_info info; int32 cookie = 0; while (get_next_image_info(B_CURRENT_TEAM, &cookie, &info) == B_OK) { if (info.type == B_APP_IMAGE) { exePathLen = strlcpy(exePath, info.name, PATH_MAX); break; } } #endif if (exePathLen > 0) { ffStrbufEnsureFree(&platform->exePath, PATH_MAX); if (realpath(exePath, platform->exePath.chars)) ffStrbufRecalculateLength(&platform->exePath); else ffStrbufSetNS(&platform->exePath, (uint32_t) exePathLen, exePath); } } static void platformPathAddEnv(FFlist* dirs, const char* env) { const char* envValue = getenv(env); if(!ffStrSet(envValue)) return; FF_STRBUF_AUTO_DESTROY value = ffStrbufCreateA(64); ffStrbufAppendS(&value, envValue); uint32_t startIndex = 0; while (startIndex < value.length) { uint32_t colonIndex = ffStrbufNextIndexC(&value, startIndex, ':'); value.chars[colonIndex] = '\0'; if(!ffStrSet(value.chars + startIndex)) { startIndex = colonIndex + 1; continue; } ffPlatformPathAddAbsolute(dirs, value.chars + startIndex); startIndex = colonIndex + 1; } } static void getHomeDir(FFPlatform* platform, const struct passwd* pwd) { const char* home = pwd ? pwd->pw_dir : getenv("HOME"); ffStrbufAppendS(&platform->homeDir, home); ffStrbufEnsureEndsWithC(&platform->homeDir, '/'); } static void getCacheDir(FFPlatform* platform) { const char* cache = getenv("XDG_CACHE_HOME"); if(ffStrSet(cache)) { ffStrbufAppendS(&platform->cacheDir, cache); ffStrbufEnsureEndsWithC(&platform->cacheDir, '/'); } else { ffStrbufAppend(&platform->cacheDir, &platform->homeDir); ffStrbufAppendS(&platform->cacheDir, ".cache/"); } } static void getConfigDirs(FFPlatform* platform) { // Always make sure `${XDG_CONFIG_HOME:-$HOME/.config}` is the first entry platformPathAddEnv(&platform->configDirs, "XDG_CONFIG_HOME"); ffPlatformPathAddHome(&platform->configDirs, platform, ".config/"); #if defined(__APPLE__) ffPlatformPathAddHome(&platform->configDirs, platform, "Library/Preferences/"); ffPlatformPathAddHome(&platform->configDirs, platform, "Library/Application Support/"); #endif #if defined(__HAIKU__) ffPlatformPathAddHome(&platform->configDirs, platform, "config/settings/"); #endif ffPlatformPathAddHome(&platform->configDirs, platform, ""); platformPathAddEnv(&platform->configDirs, "XDG_CONFIG_DIRS"); #if !defined(__APPLE__) ffPlatformPathAddAbsolute(&platform->configDirs, FASTFETCH_TARGET_DIR_ETC "/xdg/"); #endif ffPlatformPathAddAbsolute(&platform->configDirs, FASTFETCH_TARGET_DIR_ETC "/"); ffPlatformPathAddAbsolute(&platform->configDirs, FASTFETCH_TARGET_DIR_INSTALL_SYSCONF "/"); } static void getDataDirs(FFPlatform* platform) { platformPathAddEnv(&platform->dataDirs, "XDG_DATA_HOME"); ffPlatformPathAddHome(&platform->dataDirs, platform, ".local/share/"); // Add ${currentExePath}/../share if (platform->exePath.length > 0) { FF_STRBUF_AUTO_DESTROY path = ffStrbufCreateCopy(&platform->exePath); ffStrbufSubstrBeforeLastC(&path, '/'); ffStrbufSubstrBeforeLastC(&path, '/'); ffStrbufAppendS(&path, "/share"); ffPlatformPathAddAbsolute(&platform->dataDirs, path.chars); } #ifdef __APPLE__ ffPlatformPathAddHome(&platform->dataDirs, platform, "Library/Application Support/"); #endif ffPlatformPathAddHome(&platform->dataDirs, platform, ""); platformPathAddEnv(&platform->dataDirs, "XDG_DATA_DIRS"); #ifdef _PATH_LOCALBASE ffPlatformPathAddAbsolute(&platform->dataDirs, _PATH_LOCALBASE "/share/"); #endif ffPlatformPathAddAbsolute(&platform->dataDirs, FASTFETCH_TARGET_DIR_USR "/local/share/"); ffPlatformPathAddAbsolute(&platform->dataDirs, FASTFETCH_TARGET_DIR_USR "/share/"); } static void getUserName(FFPlatform* platform, const struct passwd* pwd) { const char* user = getenv("USER"); if(!ffStrSet(user) && pwd) user = pwd->pw_name; ffStrbufAppendS(&platform->userName, user); if (pwd) ffStrbufAppendS(&platform->fullUserName, pwd->pw_gecos); } static void getHostName(FFPlatform* platform, const struct utsname* uts) { ffStrbufAppendS(&platform->hostName, uts->nodename); } static void getUserShell(FFPlatform* platform, const struct passwd* pwd) { const char* shell = getenv("SHELL"); if(!ffStrSet(shell) && pwd) shell = pwd->pw_shell; ffStrbufAppendS(&platform->userShell, shell); } static void getSysinfo(FFPlatformSysinfo* info, const struct utsname* uts) { ffStrbufAppendS(&info->name, uts->sysname); ffStrbufAppendS(&info->release, uts->release); ffStrbufAppendS(&info->version, uts->version); #ifdef __HAIKU__ /* historical reason */ if (ffStrEquals(uts->machine, "BePC")) ffStrbufSetStatic(&info->architecture, "i386"); else #endif ffStrbufAppendS(&info->architecture, uts->machine); ffStrbufInit(&info->displayVersion); #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__OpenBSD__) || defined(__NetBSD__) size_t length = sizeof(info->pageSize); sysctl((int[]){ CTL_HW, HW_PAGESIZE }, 2, &info->pageSize, &length, NULL, 0); #else info->pageSize = (uint32_t) sysconf(_SC_PAGESIZE); #endif } void ffPlatformInitImpl(FFPlatform* platform) { struct passwd* pwd = getpwuid(getuid()); struct utsname uts; if(uname(&uts) < 0) memset(&uts, 0, sizeof(uts)); getExePath(platform); getHomeDir(platform, pwd); getCacheDir(platform); getConfigDirs(platform); getDataDirs(platform); getUserName(platform, pwd); getHostName(platform, &uts); getUserShell(platform, pwd); getSysinfo(&platform->sysinfo, &uts); }