mirror of
https://github.com/fastfetch-cli/fastfetch.git
synced 2026-11-10 13:37:25 +01:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6a82126aa9 | ||
|
|
798e2ccc24 | ||
|
|
2978651c9d | ||
|
|
ced33a8355 | ||
|
|
6843b56f1f | ||
|
|
c018073384 |
No files matched your search
@@ -1,3 +1,11 @@
|
||||
# Unreleased
|
||||
|
||||
Changes:
|
||||
* Improved PCI GPU name resolution by checking udev's hardware database and the NVIDIA driver's procfs before falling back to pci.ids. (GPU, Linux)
|
||||
|
||||
Bugfixes:
|
||||
* Fixed libc version detection on FreeBSD without binutils installed, and on DragonFly BSD. (Libc, FreeBSD / DragonFly)
|
||||
|
||||
# 2.71.0
|
||||
|
||||
Features:
|
||||
|
||||
+10
-9
@@ -620,6 +620,7 @@ if(LINUX)
|
||||
src/detection/dns/dns_linux.c
|
||||
src/detection/physicaldisk/physicaldisk_linux.c
|
||||
src/detection/physicalmemory/physicalmemory_linux.c
|
||||
src/detection/physicalmemory/physicalmemory_shared.c
|
||||
src/detection/diskio/diskio_linux.c
|
||||
src/detection/displayserver/linux/displayserver_linux.c
|
||||
src/detection/displayserver/linux/common.c
|
||||
@@ -798,7 +799,7 @@ elseif(FreeBSD)
|
||||
src/detection/disk/disk_bsd.c
|
||||
src/detection/dns/dns_linux.c
|
||||
src/detection/physicaldisk/physicaldisk_bsd.c
|
||||
src/detection/physicalmemory/physicalmemory_linux.c
|
||||
src/detection/physicalmemory/physicalmemory_shared.c
|
||||
src/detection/diskio/diskio_bsd.c
|
||||
src/detection/displayserver/linux/displayserver_linux.c
|
||||
src/detection/displayserver/linux/common.c
|
||||
@@ -897,7 +898,7 @@ elseif(NetBSD)
|
||||
src/detection/disk/disk_bsd.c
|
||||
src/detection/dns/dns_linux.c
|
||||
src/detection/physicaldisk/physicaldisk_nbsd.c
|
||||
src/detection/physicalmemory/physicalmemory_linux.c
|
||||
src/detection/physicalmemory/physicalmemory_shared.c
|
||||
src/detection/diskio/diskio_nbsd.c
|
||||
src/detection/displayserver/linux/displayserver_linux.c
|
||||
src/detection/displayserver/linux/common.c
|
||||
@@ -983,7 +984,7 @@ elseif(OpenBSD)
|
||||
src/detection/disk/disk_bsd.c
|
||||
src/detection/dns/dns_linux.c
|
||||
src/detection/physicaldisk/physicaldisk_obsd.c
|
||||
src/detection/physicalmemory/physicalmemory_linux.c
|
||||
src/detection/physicalmemory/physicalmemory_shared.c
|
||||
src/detection/diskio/diskio_obsd.c
|
||||
src/detection/displayserver/linux/displayserver_linux.c
|
||||
src/detection/displayserver/linux/common.c
|
||||
@@ -1124,7 +1125,7 @@ elseif(APPLE)
|
||||
src/detection/board/board_windows.c
|
||||
src/detection/chassis/chassis_windows.c
|
||||
src/detection/host/host_windows.c
|
||||
src/detection/physicalmemory/physicalmemory_linux.c
|
||||
src/detection/physicalmemory/physicalmemory_shared.c
|
||||
)
|
||||
else()
|
||||
list(APPEND LIBFASTFETCH_SRC
|
||||
@@ -1188,7 +1189,7 @@ elseif(WIN32)
|
||||
src/detection/media/media_windows.cpp
|
||||
src/detection/memory/memory_windows.c
|
||||
src/detection/mouse/mouse_windows.c
|
||||
src/detection/physicalmemory/physicalmemory_linux.c
|
||||
src/detection/physicalmemory/physicalmemory_shared.c
|
||||
src/detection/netio/netio_windows.c
|
||||
src/detection/opengl/opengl_windows.c
|
||||
src/detection/os/os_windows.c
|
||||
@@ -1244,7 +1245,7 @@ elseif(SunOS)
|
||||
src/detection/disk/disk_sunos.c
|
||||
src/detection/dns/dns_linux.c
|
||||
src/detection/physicaldisk/physicaldisk_sunos.c
|
||||
src/detection/physicalmemory/physicalmemory_linux.c
|
||||
src/detection/physicalmemory/physicalmemory_shared.c
|
||||
src/detection/diskio/diskio_sunos.c
|
||||
src/detection/displayserver/linux/displayserver_linux.c
|
||||
src/detection/displayserver/linux/common.c
|
||||
@@ -1329,7 +1330,7 @@ elseif(Haiku)
|
||||
src/detection/disk/disk_haiku.cpp
|
||||
src/detection/dns/dns_linux.c
|
||||
src/detection/physicaldisk/physicaldisk_haiku.c
|
||||
src/detection/physicalmemory/physicalmemory_linux.c
|
||||
src/detection/physicalmemory/physicalmemory_shared.c
|
||||
src/detection/diskio/diskio_nosupport.c
|
||||
src/detection/displayserver/displayserver_haiku.cpp
|
||||
src/detection/font/font_haiku.cpp
|
||||
@@ -1610,14 +1611,14 @@ if(APPLE AND EXISTS "/usr/bin/otool")
|
||||
target_compile_definitions(libfastfetch PUBLIC FF_LIBSYSTEM_VERSION="${CMAKE_MATCH_1}")
|
||||
endif()
|
||||
endif()
|
||||
if(MidnightBSD AND EXISTS "/usr/bin/objdump")
|
||||
if(FreeBSD AND NOT DragonFly AND EXISTS "/usr/bin/objdump")
|
||||
execute_process(COMMAND /bin/sh -c "/usr/bin/objdump -T /lib/libc.so.* | grep 'FBSD_[0-9][0-9]*\\.[0-9][0-9]*' -o | sort -Vru | head -1"
|
||||
OUTPUT_VARIABLE OBJDUMP_T_RESULT)
|
||||
if("${OBJDUMP_T_RESULT}" MATCHES "FBSD_([0-9]+\\.[0-9]+)")
|
||||
message(STATUS "Found FBSD ${CMAKE_MATCH_1}")
|
||||
target_compile_definitions(libfastfetch PUBLIC FF_FBSD_VERSION="${CMAKE_MATCH_1}")
|
||||
endif()
|
||||
elseif(FreeBSD AND EXISTS "/usr/local/bin/objdump")
|
||||
elseif(FreeBSD AND NOT DragonFly AND EXISTS "/usr/local/bin/objdump")
|
||||
execute_process(COMMAND /bin/sh -c "/usr/local/bin/objdump -T /lib/libc.so.* | grep 'FBSD_[0-9][0-9]*\\.[0-9][0-9]*' -o | sort -Vru | head -1"
|
||||
OUTPUT_VARIABLE OBJDUMP_T_RESULT)
|
||||
if("${OBJDUMP_T_RESULT}" MATCHES "FBSD_([0-9]+\\.[0-9]+)")
|
||||
|
||||
@@ -341,7 +341,7 @@ bool ffGPUDetectTypeByVendorAndName(FFGPUResult* gpu) {
|
||||
} else if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_INTEL) {
|
||||
// 0000:00:02.0 is reserved for Intel integrated graphics
|
||||
gpu->type = gpu->deviceId == ffGPUPciAddr2Id(0, 0, 2, 0) ? FF_GPU_TYPE_INTEGRATED : FF_GPU_TYPE_DISCRETE;
|
||||
} else if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_VMWARE || gpu->vendor.chars == FF_GPU_VENDOR_NAME_PARALLELS) {
|
||||
} else if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_VMWARE || gpu->vendor.chars == FF_GPU_VENDOR_NAME_PARALLELS || gpu->vendor.chars == FF_GPU_VENDOR_NAME_REDHAT) {
|
||||
// Virtualized GPUs
|
||||
gpu->type = FF_GPU_TYPE_INTEGRATED;
|
||||
}
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
#include "detection/gpu/gpu.h"
|
||||
#include "common/debug.h"
|
||||
#include "common/io.h"
|
||||
#include "common/FFstrbuf.h"
|
||||
#include "common/properties.h"
|
||||
#include "common/strutil.h"
|
||||
#include "modules/gpu/option.h"
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdint.h>
|
||||
|
||||
static bool detectDriverFromSysfs(FFstrbuf* result, FFstrbuf* pciDir, FFstrbuf* buffer, [[maybe_unused]] const char* drmKey) {
|
||||
uint32_t pciDirLength = pciDir->length;
|
||||
@@ -337,6 +335,64 @@ static inline uint16_t pcieWidthToLanes(const FFstrbuf* buffer) {
|
||||
return FF_GPU_PCIE_SPEED_UNSET;
|
||||
}
|
||||
|
||||
static bool parseModelName(const char* data, const char* key, bool stripVendorPrefix, FFstrbuf* name) {
|
||||
ffStrbufClear(name);
|
||||
if (!ffParsePropLines(data, key, name) || !name->length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ffStrbufDecodeHexEscapeSequences(name); // udev hex-escapes characters that are not allowed in property values
|
||||
ffStrbufTrimSpace(name);
|
||||
|
||||
// hwdb names have the form `Codename [Marketing Name]`. Reduce them exactly like
|
||||
// ffGPUParsePciIdsFile() does, so displaying the name does not change with the source.
|
||||
if (name->length > 1 && name->chars[name->length - 1] == ']') {
|
||||
const char* openingBracket = memrchr(name->chars, '[', name->length - 1);
|
||||
if (openingBracket) {
|
||||
ffStrbufSubstrAfter(name, (uint32_t) (openingBracket - name->chars));
|
||||
ffStrbufSubstrBefore(name, name->length - 1);
|
||||
}
|
||||
}
|
||||
|
||||
// The driver repeats the vendor in its own model line. Dropping it keeps the pci.ids
|
||||
// shape and lets ffGPUDetectTypeByVendorAndName() see the product family prefix.
|
||||
if (stripVendorPrefix && ffStrbufStartsWithIgnCaseS(name, "NVIDIA ")) {
|
||||
ffStrbufSubstrAfter(name, (uint32_t) strlen("NVIDIA ") - 1); // excludes the index itself
|
||||
}
|
||||
|
||||
ffStrbufTrimSpace(name);
|
||||
return name->length > 0;
|
||||
}
|
||||
|
||||
static bool nameFromFile(const FFstrbuf* path, const char* key, bool stripVendorPrefix, FFstrbuf* buffer, FFstrbuf* name) {
|
||||
if (!ffReadFileBuffer(path->chars, buffer) || !parseModelName(buffer->chars, key, stripVendorPrefix, name)) {
|
||||
return false;
|
||||
}
|
||||
FF_DEBUG("GPU name resolved from %s: %s", path->chars, name->chars);
|
||||
return true;
|
||||
}
|
||||
|
||||
// The driver and udev already resolved the model name at probe / boot time. Only `Model:` is
|
||||
// consumed: the sibling `power` file goes through the RM and can wake a GPU suspended in runtime D3.
|
||||
static bool resolveNameFromFiles(const char* pciPath, bool isNvidia, FFstrbuf* buffer, FFstrbuf* name) {
|
||||
FF_STRBUF_AUTO_DESTROY path = ffStrbufCreateA(128);
|
||||
|
||||
if (isNvidia) {
|
||||
ffStrbufSetF(&path, "/proc/driver/nvidia/gpus/%s/information", pciPath);
|
||||
if (nameFromFile(&path, "Model:", true, buffer, name)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
ffStrbufSetF(&path, "/run/udev/data/+pci:%s", pciPath);
|
||||
if (nameFromFile(&path, "E:ID_MODEL_FROM_DATABASE=", false, buffer, name)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
ffStrbufClear(name);
|
||||
return false;
|
||||
}
|
||||
|
||||
static const char* detectPci(const FFGPUOptions* options, FFlist* gpus, FFstrbuf* buffer, FFstrbuf* deviceDir, const char* drmKey) {
|
||||
const uint32_t drmDirPathLength = deviceDir->length;
|
||||
uint32_t vendorId, deviceId, subVendorId, subDeviceId;
|
||||
@@ -465,8 +521,13 @@ static const char* detectPci(const FFGPUOptions* options, FFlist* gpus, FFstrbuf
|
||||
}
|
||||
|
||||
if (gpu->name.length == 0) {
|
||||
// Stop at the first hit; unknown vendors are left to pci.ids, which also fills in `vendor`.
|
||||
bool resolved = gpu->vendor.length > 0 &&
|
||||
resolveNameFromFiles(pPciPath, gpu->vendor.chars == FF_GPU_VENDOR_NAME_NVIDIA, buffer, &gpu->name);
|
||||
if (!resolved) {
|
||||
ffGPUFillVendorAndName(subclassId, (uint16_t) vendorId, (uint16_t) deviceId, gpu);
|
||||
}
|
||||
}
|
||||
|
||||
ffGPUDetectTypeByVendorAndName(gpu);
|
||||
|
||||
|
||||
@@ -1,244 +1,225 @@
|
||||
#include "physicalmemory.h"
|
||||
#include "common/debug.h"
|
||||
#include "common/endian.h"
|
||||
#include "common/io.h"
|
||||
#include "common/smbios.h"
|
||||
#include "common/strutil.h"
|
||||
|
||||
// 7.18
|
||||
typedef struct [[gnu::packed]] FFSmbiosMemoryDevice {
|
||||
FFSmbiosHeader Header;
|
||||
// systemd >= 248 decodes SMBIOS Type 16 / 17 into udev properties of the `dmi:id` device
|
||||
// (see systemd's src/udev/dmi_memory_id/dmi_memory_id.c). The database is world readable,
|
||||
// while /sys/firmware/dmi/tables/DMI and /dev/mem are root-only, so try it first.
|
||||
#define FF_UDEV_DMI_ID_DB "/run/udev/data/+dmi:id"
|
||||
#define FF_UDEV_MEMORY_DEVICE_PREFIX "E:MEMORY_DEVICE_"
|
||||
#define FF_UDEV_MAX_MEMORY_DEVICES 256
|
||||
|
||||
// 2.1+
|
||||
uint16_t PhysicalMemoryArrayHandle; // varies
|
||||
uint16_t MemoryErrorInformationHandle; // varies
|
||||
uint16_t TotalWidth; // varies
|
||||
uint16_t DataWidth; // varies
|
||||
uint16_t Size; // varies
|
||||
uint8_t FormFactor; // enum
|
||||
uint8_t DeviceSet; // varies
|
||||
uint8_t DeviceLocator; // string
|
||||
uint8_t BankLocator; // string
|
||||
uint8_t MemoryType; // enum
|
||||
uint16_t TypeDetail; // bit field
|
||||
|
||||
// 2.3+
|
||||
uint16_t Speed; // varies
|
||||
uint8_t Manufacturer; // string
|
||||
uint8_t SerialNumber; // string
|
||||
uint8_t AssetTag; // string
|
||||
uint8_t PartNumber; // string
|
||||
|
||||
// 2.6+
|
||||
uint8_t Attributes; // varies
|
||||
|
||||
// 2.7+
|
||||
uint32_t ExtendedSize; // varies
|
||||
uint16_t ConfiguredMemorySpeed; // varies
|
||||
|
||||
// 2.8+
|
||||
uint16_t MinimumVoltage; // varies
|
||||
uint16_t MaximumVoltage; // varies
|
||||
uint16_t ConfiguredVoltage; // varies
|
||||
|
||||
// 3.2+
|
||||
uint8_t MemoryTechnology; // varies
|
||||
uint16_t MemoryOperatingMode; // bit field
|
||||
uint8_t FirmwareVersion; // string
|
||||
uint16_t ModuleManufacturerID; // varies
|
||||
uint16_t ModuleProductID; // varies
|
||||
uint16_t MemorySubsystemControllerManufacturerID; // vaies
|
||||
uint16_t MemorySubsystemControllerProductID; // varies
|
||||
uint64_t NonVolatileSize; // varies
|
||||
uint64_t VolatileSize; // varies
|
||||
uint64_t CacheSize; // varies
|
||||
uint64_t LogicalSize; // varies
|
||||
|
||||
// 3.3+
|
||||
uint32_t ExtendedSpeed; // varies
|
||||
uint32_t ExtendedConfiguredSpeed; // varies
|
||||
|
||||
// 3.7+
|
||||
uint16_t Pmic0ManufacturerID; // varies
|
||||
uint16_t Pmic0RevisionNumber; // varies
|
||||
uint16_t RcdManufacturerID; // varies
|
||||
uint16_t RcdRevisionNumber; // varies
|
||||
} FFSmbiosMemoryDevice;
|
||||
|
||||
static_assert(offsetof(FFSmbiosMemoryDevice, RcdRevisionNumber) == 0x62,
|
||||
"FFSmbiosMemoryDevice: Wrong struct alignment");
|
||||
|
||||
const char* ffDetectPhysicalMemory(FFPhysicalMemoryOptions* options, FFlist* result) {
|
||||
const FFSmbiosHeaderTable* smbiosTable = ffGetSmbiosHeaderTable();
|
||||
if (!smbiosTable) {
|
||||
FF_DEBUG("Failed to get SMBIOS data");
|
||||
return "Failed to get SMBIOS data";
|
||||
}
|
||||
|
||||
const FFSmbiosMemoryDevice* data = (const FFSmbiosMemoryDevice*) (*smbiosTable)[FF_SMBIOS_TYPE_MEMORY_DEVICE];
|
||||
if (!data) {
|
||||
FF_DEBUG("Memory device is not found in SMBIOS data");
|
||||
return "Memory device is not found in SMBIOS data";
|
||||
}
|
||||
|
||||
const FFSmbiosMemoryDevice* endOfTable = (const FFSmbiosMemoryDevice*) (*smbiosTable)[FF_SMBIOS_TYPE_END_OF_TABLE];
|
||||
for (; data != endOfTable; data = (const FFSmbiosMemoryDevice*) ffSmbiosNextEntry(&data->Header)) {
|
||||
if (data->Header.Type != FF_SMBIOS_TYPE_MEMORY_DEVICE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const char* strings = (const char*) data + data->Header.Length;
|
||||
uint16_t size = FF_READ_LE(data->Size);
|
||||
bool installed = size != 0;
|
||||
|
||||
if (!installed && !options->showEmptySlots) {
|
||||
continue;
|
||||
}
|
||||
|
||||
FFPhysicalMemoryResult* device = FF_LIST_ADD(FFPhysicalMemoryResult, *result);
|
||||
ffStrbufInit(&device->type);
|
||||
ffStrbufInit(&device->formFactor);
|
||||
ffStrbufInit(&device->locator);
|
||||
ffStrbufInit(&device->vendor);
|
||||
ffStrbufInit(&device->serial);
|
||||
ffStrbufInit(&device->partNumber);
|
||||
device->size = 0;
|
||||
device->maxSpeed = 0;
|
||||
device->runningSpeed = 0;
|
||||
device->installed = installed;
|
||||
device->ecc = false;
|
||||
|
||||
uint16_t totalWidth = FF_READ_LE(data->TotalWidth);
|
||||
uint16_t dataWidth = FF_READ_LE(data->DataWidth);
|
||||
if (installed && totalWidth != 0xFFFF && dataWidth != 0xFFFF) {
|
||||
device->ecc = totalWidth > dataWidth;
|
||||
}
|
||||
|
||||
if (installed && size != 0xFFFF) {
|
||||
if (size == 0x7FFF) {
|
||||
device->size = (FF_READ_LE(data->ExtendedSize) & ~(1ULL << 31)) * 1024ULL * 1024ULL;
|
||||
} else if (size & (1 << 15)) {
|
||||
// in kB
|
||||
device->size = (size & ~(1ULL << 15)) * 1024ULL;
|
||||
} else {
|
||||
// in MB
|
||||
device->size = size * 1024ULL * 1024ULL;
|
||||
}
|
||||
}
|
||||
|
||||
// https://github.com/fastfetch-cli/fastfetch/issues/1051#issuecomment-2206687345
|
||||
const char* lbank = ffSmbiosLocateString(strings, data->BankLocator);
|
||||
const char* ldevice = ffSmbiosLocateString(strings, data->DeviceLocator);
|
||||
if (lbank && ldevice) {
|
||||
ffStrbufSetF(&device->locator, "%s/%s", lbank, ldevice);
|
||||
} else if (lbank) {
|
||||
ffStrbufSetS(&device->locator, lbank);
|
||||
} else if (ldevice) {
|
||||
ffStrbufSetS(&device->locator, ldevice);
|
||||
}
|
||||
|
||||
const char* formFactorNames[] = {
|
||||
nullptr, // 0x00 (Placeholder for indexing)
|
||||
"Other", // 0x01
|
||||
"Unknown", // 0x02
|
||||
"SIMM", // 0x03
|
||||
"SIP", // 0x04
|
||||
"Chip", // 0x05
|
||||
"DIP", // 0x06
|
||||
"ZIP", // 0x07
|
||||
"Proprietary Card", // 0x08
|
||||
"DIMM", // 0x09
|
||||
"TSOP", // 0x0A
|
||||
"Row of chips", // 0x0B
|
||||
"RIMM", // 0x0C
|
||||
"SODIMM", // 0x0D
|
||||
"SRIMM", // 0x0E
|
||||
"FBDIMM", // 0x0F
|
||||
"Die", // 0x10
|
||||
"CAMM", // 0x11
|
||||
"CUDIMM", // 0x12
|
||||
"CSODIMM", // 0x13
|
||||
static void ffUdevResultAdd(FFlist* result) {
|
||||
*FF_LIST_ADD(FFPhysicalMemoryResult, *result) = (FFPhysicalMemoryResult){
|
||||
// Doubles as parse-time state: absent PRESENT / SIZE means "present, unknown
|
||||
// size", so it starts true and is only ever cleared by PRESENT=0 or SIZE=0.
|
||||
.installed = true,
|
||||
.type = ffStrbufCreate(),
|
||||
.formFactor = ffStrbufCreate(),
|
||||
.locator = ffStrbufCreate(),
|
||||
.partNumber = ffStrbufCreate(),
|
||||
.vendor = ffStrbufCreate(),
|
||||
.serial = ffStrbufCreate(),
|
||||
};
|
||||
if (data->FormFactor > 0 && data->FormFactor < ARRAY_SIZE(formFactorNames)) {
|
||||
ffStrbufSetS(&device->formFactor, formFactorNames[data->FormFactor]);
|
||||
}
|
||||
|
||||
static void ffUdevResultDestroy(FFPhysicalMemoryResult* device) {
|
||||
ffStrbufDestroy(&device->type);
|
||||
ffStrbufDestroy(&device->formFactor);
|
||||
ffStrbufDestroy(&device->locator);
|
||||
ffStrbufDestroy(&device->partNumber);
|
||||
ffStrbufDestroy(&device->vendor);
|
||||
ffStrbufDestroy(&device->serial);
|
||||
}
|
||||
|
||||
// udev hex-escapes characters that are not allowed in property values (\xHH).
|
||||
// Also drop the placeholder strings ("Unknown", "0x0000...", "<OUT OF SPEC>", ...).
|
||||
static void ffUdevSetString(FFstrbuf* strbuf, const char* value) {
|
||||
ffStrbufSetS(strbuf, value);
|
||||
ffStrbufDecodeHexEscapeSequences(strbuf);
|
||||
// Older systemd versions print an empty value, newer ones "<OUT OF SPEC>".
|
||||
if (ffStrbufStartsWithS(strbuf, "<OUT OF SPEC>")) {
|
||||
ffStrbufClear(strbuf);
|
||||
}
|
||||
ffCleanUpSmbiosValue(strbuf);
|
||||
}
|
||||
|
||||
// `locator` is the "bank/device" join, but the two properties arrive in no guaranteed
|
||||
// order. Prepending the bank and appending the device yields the same result either way.
|
||||
// systemd emits each property at most once per device.
|
||||
static void ffUdevAppendLocator(FFPhysicalMemoryResult* device, const char* value, bool bank) {
|
||||
FF_STRBUF_AUTO_DESTROY part = ffStrbufCreate();
|
||||
ffUdevSetString(&part, value);
|
||||
if (part.length == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (device->locator.length > 0) {
|
||||
if (bank) {
|
||||
ffStrbufPrependC(&device->locator, '/');
|
||||
} else {
|
||||
ffStrbufSetF(&device->formFactor, "Unknown (%d)", (int) data->FormFactor);
|
||||
ffStrbufAppendC(&device->locator, '/');
|
||||
}
|
||||
|
||||
const char* memoryTypeNames[] = {
|
||||
nullptr, // 0x00 (Placeholder for indexing)
|
||||
"Other", // 0x01
|
||||
"Unknown", // 0x02
|
||||
"DRAM", // 0x03
|
||||
"EDRAM", // 0x04
|
||||
"VRAM", // 0x05
|
||||
"SRAM", // 0x06
|
||||
"RAM", // 0x07
|
||||
"ROM", // 0x08
|
||||
"FLASH", // 0x09
|
||||
"EEPROM", // 0x0A
|
||||
"FEPROM", // 0x0B
|
||||
"EPROM", // 0x0C
|
||||
"CDRAM", // 0x0D
|
||||
"3DRAM", // 0x0E
|
||||
"SDRAM", // 0x0F
|
||||
"SGRAM", // 0x10
|
||||
"RDRAM", // 0x11
|
||||
"DDR", // 0x12
|
||||
"DDR2", // 0x13
|
||||
"DDR2 FB-DIMM", // 0x14
|
||||
"Reserved", // 0x15
|
||||
"Reserved", // 0x16
|
||||
"Reserved", // 0x17
|
||||
"DDR3", // 0x18
|
||||
"FBD2", // 0x19
|
||||
"DDR4", // 0x1A
|
||||
"LPDDR", // 0x1B
|
||||
"LPDDR2", // 0x1C
|
||||
"LPDDR3", // 0x1D
|
||||
"LPDDR4", // 0x1E
|
||||
"Logical non-volatile device", // 0x1F
|
||||
"HBM", // 0x20
|
||||
"HBM2", // 0x21
|
||||
"DDR5", // 0x22
|
||||
"LPDDR5", // 0x23
|
||||
"HBM3", // 0x24
|
||||
"MRDIMM", // 0x25
|
||||
};
|
||||
if (!installed) {
|
||||
ffStrbufSetStatic(&device->type, "Empty");
|
||||
} else if (data->MemoryType > 0 && data->MemoryType < ARRAY_SIZE(memoryTypeNames)) {
|
||||
ffStrbufSetStatic(&device->type, memoryTypeNames[data->MemoryType]);
|
||||
}
|
||||
if (bank) {
|
||||
ffStrbufPrepend(&device->locator, &part);
|
||||
} else {
|
||||
ffStrbufSetF(&device->type, "Unknown (%d)", (int) data->MemoryType);
|
||||
}
|
||||
|
||||
if (installed && data->Header.Length > offsetof(FFSmbiosMemoryDevice, Speed)) // 2.3+
|
||||
{
|
||||
uint16_t speed = FF_READ_LE(data->Speed);
|
||||
if (speed) {
|
||||
device->maxSpeed = speed == 0xFFFF ? FF_READ_LE(data->ExtendedSpeed) : speed;
|
||||
}
|
||||
|
||||
ffStrbufSetStatic(&device->vendor, ffSmbiosLocateString(strings, data->Manufacturer));
|
||||
ffCleanUpSmbiosValue(&device->vendor);
|
||||
FFPhysicalMemoryUpdateVendorString(device);
|
||||
|
||||
ffStrbufSetStatic(&device->serial, ffSmbiosLocateString(strings, data->SerialNumber));
|
||||
ffCleanUpSmbiosValue(&device->serial);
|
||||
|
||||
ffStrbufSetStatic(&device->partNumber, ffSmbiosLocateString(strings, data->PartNumber));
|
||||
ffCleanUpSmbiosValue(&device->partNumber);
|
||||
}
|
||||
|
||||
if (installed && data->Header.Length > offsetof(FFSmbiosMemoryDevice, ConfiguredMemorySpeed)) // 2.7+
|
||||
{
|
||||
uint16_t configuredSpeed = FF_READ_LE(data->ConfiguredMemorySpeed);
|
||||
if (configuredSpeed) {
|
||||
device->runningSpeed = configuredSpeed == 0xFFFF
|
||||
? FF_READ_LE(data->ExtendedConfiguredSpeed)
|
||||
: configuredSpeed;
|
||||
}
|
||||
ffStrbufAppend(&device->locator, &part);
|
||||
}
|
||||
}
|
||||
|
||||
// Splits a line like "E:MEMORY_DEVICE_0_SIZE=4294967296" in place. Returns the field
|
||||
// name, or nullptr when the line is unrelated or has an out-of-range device index.
|
||||
// The mere presence of such a line means the udev database describes the memory devices
|
||||
// completely, whether or not its field is recognized or its value is a placeholder.
|
||||
static const char* ffUdevParseHeader(char* line, uint32_t* index, const char** value) {
|
||||
if (!ffStrStartsWith(line, FF_UDEV_MEMORY_DEVICE_PREFIX)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
char* eq = strchr(line, '=');
|
||||
if (!eq) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const char* p = line + sizeof(FF_UDEV_MEMORY_DEVICE_PREFIX) - 1;
|
||||
char* end = nullptr;
|
||||
unsigned long n = strtoul(p, &end, 10);
|
||||
if (end == p || *end != '_' || n >= FF_UDEV_MAX_MEMORY_DEVICES) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
*eq = '\0';
|
||||
*index = (uint32_t) n;
|
||||
*value = eq + 1;
|
||||
return end + 1;
|
||||
}
|
||||
|
||||
// The udev database is authoritative: as soon as it contains any MEMORY_DEVICE_*
|
||||
// property, the set of memory devices it describes is considered complete and the
|
||||
// caller must not fall back to SMBIOS -- even when every slot is empty, all values
|
||||
// are placeholders, or showEmptySlots filters everything out of `result`.
|
||||
static bool ffDetectPhysicalMemoryFromUdev(FFPhysicalMemoryOptions* options, FFlist* result) {
|
||||
FF_STRBUF_AUTO_DESTROY db = ffStrbufCreate();
|
||||
if (!ffReadFileBuffer(FF_UDEV_DMI_ID_DB, &db)) {
|
||||
FF_DEBUG("Failed to read %s", FF_UDEV_DMI_ID_DB);
|
||||
return false;
|
||||
}
|
||||
|
||||
// The udev index addresses `result` directly: MEMORY_DEVICE_n_* maps to entry
|
||||
// `base + n`. Entries are therefore naturally sorted and can be updated in place,
|
||||
// without a staging list, a comparator or any result copying. FFstrbuf holds no
|
||||
// pointer into itself, so FF_LIST_ADD may relocate existing entries freely.
|
||||
// Sparse indices leave placeholder entries behind; they are removed below.
|
||||
bool seen[FF_UDEV_MAX_MEMORY_DEVICES] = { false };
|
||||
uint16_t totalWidths[FF_UDEV_MAX_MEMORY_DEVICES] = { 0 };
|
||||
uint16_t dataWidths[FF_UDEV_MAX_MEMORY_DEVICES] = { 0 };
|
||||
const uint32_t base = result->length;
|
||||
bool found = false;
|
||||
|
||||
char* line = nullptr;
|
||||
size_t len = 0;
|
||||
while (ffStrbufGetline(&line, &len, &db)) {
|
||||
// `len` must stay intact: the next ffStrbufGetline call advances the cursor by it.
|
||||
if (len > 0 && line[len - 1] == '\r') {
|
||||
line[len - 1] = '\0';
|
||||
}
|
||||
|
||||
uint32_t index;
|
||||
const char* value;
|
||||
const char* field = ffUdevParseHeader(line, &index, &value);
|
||||
if (!field) {
|
||||
continue;
|
||||
}
|
||||
|
||||
while (base + index >= result->length) {
|
||||
ffUdevResultAdd(result);
|
||||
}
|
||||
found = true;
|
||||
seen[index] = true;
|
||||
FFPhysicalMemoryResult* device = FF_LIST_GET(FFPhysicalMemoryResult, *result, base + index);
|
||||
|
||||
if (ffStrEquals(field, "SIZE")) {
|
||||
device->size = strtoull(value, nullptr, 10);
|
||||
if (device->size == 0) {
|
||||
device->installed = false;
|
||||
}
|
||||
} else if (ffStrEquals(field, "PRESENT")) {
|
||||
if (strtoul(value, nullptr, 10) == 0) {
|
||||
device->installed = false;
|
||||
}
|
||||
} else if (ffStrEquals(field, "TOTAL_WIDTH")) {
|
||||
totalWidths[index] = (uint16_t) strtoul(value, nullptr, 10);
|
||||
} else if (ffStrEquals(field, "DATA_WIDTH")) {
|
||||
dataWidths[index] = (uint16_t) strtoul(value, nullptr, 10);
|
||||
} else if (ffStrEquals(field, "SPEED_MTS")) {
|
||||
device->maxSpeed = (uint32_t) strtoul(value, nullptr, 10);
|
||||
} else if (ffStrEquals(field, "CONFIGURED_SPEED_MTS")) {
|
||||
device->runningSpeed = (uint32_t) strtoul(value, nullptr, 10);
|
||||
} else if (ffStrEquals(field, "FORM_FACTOR")) {
|
||||
ffUdevSetString(&device->formFactor, value);
|
||||
} else if (ffStrEquals(field, "BANK_LOCATOR")) {
|
||||
ffUdevAppendLocator(device, value, true);
|
||||
} else if (ffStrEquals(field, "LOCATOR")) {
|
||||
ffUdevAppendLocator(device, value, false);
|
||||
} else if (ffStrEquals(field, "TYPE")) {
|
||||
ffUdevSetString(&device->type, value);
|
||||
} else if (ffStrEquals(field, "MANUFACTURER")) {
|
||||
ffUdevSetString(&device->vendor, value);
|
||||
} else if (ffStrEquals(field, "SERIAL_NUMBER")) {
|
||||
ffUdevSetString(&device->serial, value);
|
||||
} else if (ffStrEquals(field, "PART_NUMBER")) {
|
||||
ffUdevSetString(&device->partNumber, value);
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
FF_DEBUG("No MEMORY_DEVICE_* properties in %s", FF_UDEV_DMI_ID_DB);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Finalize and drop sparse / empty slots. `i` tracks the current list position
|
||||
// while `index` tracks the original udev index, which survives the removals.
|
||||
uint32_t i = base;
|
||||
for (uint32_t index = 0; i < result->length; ++index) {
|
||||
FFPhysicalMemoryResult* device = FF_LIST_GET(FFPhysicalMemoryResult, *result, i);
|
||||
if (!seen[index] || (!device->installed && !options->showEmptySlots)) {
|
||||
ffUdevResultDestroy(device);
|
||||
FF_LIST_REMOVE_AT(FFPhysicalMemoryResult, *result, i);
|
||||
continue;
|
||||
}
|
||||
|
||||
device->ecc = totalWidths[index] > 0 && dataWidths[index] > 0 &&
|
||||
totalWidths[index] > dataWidths[index];
|
||||
|
||||
if (!device->installed) {
|
||||
device->maxSpeed = device->runningSpeed = 0;
|
||||
ffStrbufSetStatic(&device->type, "Empty");
|
||||
ffStrbufClear(&device->vendor);
|
||||
ffStrbufClear(&device->serial);
|
||||
ffStrbufClear(&device->partNumber);
|
||||
} else {
|
||||
if (device->type.length == 0) {
|
||||
ffStrbufSetStatic(&device->type, "Unknown");
|
||||
}
|
||||
FFPhysicalMemoryUpdateVendorString(device);
|
||||
}
|
||||
++i;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
const char* ffDetectPhysicalMemory(FFPhysicalMemoryOptions* options, FFlist* result) {
|
||||
if (ffDetectPhysicalMemoryFromUdev(options, result)) {
|
||||
FF_DEBUG("Physical memory detected from %s", FF_UDEV_DMI_ID_DB);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
FF_DEBUG("Falling back to reading SMBIOS directly");
|
||||
// Implemented in physicalmemory_shared.c. On Linux it is used as a fallback when udev data
|
||||
// is unavailable; on other SMBIOS capable platforms it backs ffDetectPhysicalMemory directly.
|
||||
const char* ffDetectPhysicalMemoryFromSmbios(FFPhysicalMemoryOptions * options, FFlist * result);
|
||||
return ffDetectPhysicalMemoryFromSmbios(options, result);
|
||||
}
|
||||
@@ -0,0 +1,252 @@
|
||||
#include "physicalmemory.h"
|
||||
#include "common/debug.h"
|
||||
#include "common/endian.h"
|
||||
#include "common/smbios.h"
|
||||
|
||||
// 7.18
|
||||
typedef struct [[gnu::packed]] FFSmbiosMemoryDevice {
|
||||
FFSmbiosHeader Header;
|
||||
|
||||
// 2.1+
|
||||
uint16_t PhysicalMemoryArrayHandle; // varies
|
||||
uint16_t MemoryErrorInformationHandle; // varies
|
||||
uint16_t TotalWidth; // varies
|
||||
uint16_t DataWidth; // varies
|
||||
uint16_t Size; // varies
|
||||
uint8_t FormFactor; // enum
|
||||
uint8_t DeviceSet; // varies
|
||||
uint8_t DeviceLocator; // string
|
||||
uint8_t BankLocator; // string
|
||||
uint8_t MemoryType; // enum
|
||||
uint16_t TypeDetail; // bit field
|
||||
|
||||
// 2.3+
|
||||
uint16_t Speed; // varies
|
||||
uint8_t Manufacturer; // string
|
||||
uint8_t SerialNumber; // string
|
||||
uint8_t AssetTag; // string
|
||||
uint8_t PartNumber; // string
|
||||
|
||||
// 2.6+
|
||||
uint8_t Attributes; // varies
|
||||
|
||||
// 2.7+
|
||||
uint32_t ExtendedSize; // varies
|
||||
uint16_t ConfiguredMemorySpeed; // varies
|
||||
|
||||
// 2.8+
|
||||
uint16_t MinimumVoltage; // varies
|
||||
uint16_t MaximumVoltage; // varies
|
||||
uint16_t ConfiguredVoltage; // varies
|
||||
|
||||
// 3.2+
|
||||
uint8_t MemoryTechnology; // varies
|
||||
uint16_t MemoryOperatingMode; // bit field
|
||||
uint8_t FirmwareVersion; // string
|
||||
uint16_t ModuleManufacturerID; // varies
|
||||
uint16_t ModuleProductID; // varies
|
||||
uint16_t MemorySubsystemControllerManufacturerID; // vaies
|
||||
uint16_t MemorySubsystemControllerProductID; // varies
|
||||
uint64_t NonVolatileSize; // varies
|
||||
uint64_t VolatileSize; // varies
|
||||
uint64_t CacheSize; // varies
|
||||
uint64_t LogicalSize; // varies
|
||||
|
||||
// 3.3+
|
||||
uint32_t ExtendedSpeed; // varies
|
||||
uint32_t ExtendedConfiguredSpeed; // varies
|
||||
|
||||
// 3.7+
|
||||
uint16_t Pmic0ManufacturerID; // varies
|
||||
uint16_t Pmic0RevisionNumber; // varies
|
||||
uint16_t RcdManufacturerID; // varies
|
||||
uint16_t RcdRevisionNumber; // varies
|
||||
} FFSmbiosMemoryDevice;
|
||||
|
||||
static_assert(offsetof(FFSmbiosMemoryDevice, RcdRevisionNumber) == 0x62,
|
||||
"FFSmbiosMemoryDevice: Wrong struct alignment");
|
||||
|
||||
const char* ffDetectPhysicalMemoryFromSmbios(FFPhysicalMemoryOptions* options, FFlist* result) {
|
||||
const FFSmbiosHeaderTable* smbiosTable = ffGetSmbiosHeaderTable();
|
||||
if (!smbiosTable) {
|
||||
FF_DEBUG("Failed to get SMBIOS data");
|
||||
return "Failed to get SMBIOS data";
|
||||
}
|
||||
|
||||
const FFSmbiosMemoryDevice* data = (const FFSmbiosMemoryDevice*) (*smbiosTable)[FF_SMBIOS_TYPE_MEMORY_DEVICE];
|
||||
if (!data) {
|
||||
FF_DEBUG("Memory device is not found in SMBIOS data");
|
||||
return "Memory device is not found in SMBIOS data";
|
||||
}
|
||||
|
||||
const FFSmbiosMemoryDevice* endOfTable = (const FFSmbiosMemoryDevice*) (*smbiosTable)[FF_SMBIOS_TYPE_END_OF_TABLE];
|
||||
for (; data != endOfTable; data = (const FFSmbiosMemoryDevice*) ffSmbiosNextEntry(&data->Header)) {
|
||||
if (data->Header.Type != FF_SMBIOS_TYPE_MEMORY_DEVICE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const char* strings = (const char*) data + data->Header.Length;
|
||||
uint16_t size = FF_READ_LE(data->Size);
|
||||
bool installed = size != 0;
|
||||
|
||||
if (!installed && !options->showEmptySlots) {
|
||||
continue;
|
||||
}
|
||||
|
||||
FFPhysicalMemoryResult* device = FF_LIST_ADD(FFPhysicalMemoryResult, *result);
|
||||
*device = (FFPhysicalMemoryResult) {
|
||||
.installed = installed,
|
||||
.type = ffStrbufCreate(),
|
||||
.formFactor = ffStrbufCreate(),
|
||||
.locator = ffStrbufCreate(),
|
||||
.partNumber = ffStrbufCreate(),
|
||||
.vendor = ffStrbufCreate(),
|
||||
.serial = ffStrbufCreate(),
|
||||
};
|
||||
|
||||
uint16_t totalWidth = FF_READ_LE(data->TotalWidth);
|
||||
uint16_t dataWidth = FF_READ_LE(data->DataWidth);
|
||||
if (installed && totalWidth != 0xFFFF && dataWidth != 0xFFFF) {
|
||||
device->ecc = totalWidth > dataWidth;
|
||||
}
|
||||
|
||||
if (installed && size != 0xFFFF) {
|
||||
if (size == 0x7FFF) {
|
||||
device->size = (FF_READ_LE(data->ExtendedSize) & ~(1ULL << 31)) * 1024ULL * 1024ULL;
|
||||
} else if (size & (1 << 15)) {
|
||||
// in kB
|
||||
device->size = (size & ~(1ULL << 15)) * 1024ULL;
|
||||
} else {
|
||||
// in MB
|
||||
device->size = size * 1024ULL * 1024ULL;
|
||||
}
|
||||
}
|
||||
|
||||
// https://github.com/fastfetch-cli/fastfetch/issues/1051#issuecomment-2206687345
|
||||
const char* lbank = ffSmbiosLocateString(strings, data->BankLocator);
|
||||
const char* ldevice = ffSmbiosLocateString(strings, data->DeviceLocator);
|
||||
if (lbank) {
|
||||
ffStrbufSetS(&device->locator, lbank);
|
||||
}
|
||||
if (lbank && ldevice) {
|
||||
ffStrbufAppendC(&device->locator, '/');
|
||||
}
|
||||
if (ldevice) {
|
||||
ffStrbufAppendS(&device->locator, ldevice);
|
||||
}
|
||||
|
||||
const char* formFactorNames[] = {
|
||||
nullptr, // 0x00 (Placeholder for indexing)
|
||||
"Other", // 0x01
|
||||
"Unknown", // 0x02
|
||||
"SIMM", // 0x03
|
||||
"SIP", // 0x04
|
||||
"Chip", // 0x05
|
||||
"DIP", // 0x06
|
||||
"ZIP", // 0x07
|
||||
"Proprietary Card", // 0x08
|
||||
"DIMM", // 0x09
|
||||
"TSOP", // 0x0A
|
||||
"Row of chips", // 0x0B
|
||||
"RIMM", // 0x0C
|
||||
"SODIMM", // 0x0D
|
||||
"SRIMM", // 0x0E
|
||||
"FBDIMM", // 0x0F
|
||||
"Die", // 0x10
|
||||
"CAMM", // 0x11
|
||||
"CUDIMM", // 0x12
|
||||
"CSODIMM", // 0x13
|
||||
};
|
||||
if (data->FormFactor > 0 && data->FormFactor < ARRAY_SIZE(formFactorNames)) {
|
||||
ffStrbufSetS(&device->formFactor, formFactorNames[data->FormFactor]);
|
||||
} else {
|
||||
ffStrbufSetF(&device->formFactor, "Unknown (%d)", (int) data->FormFactor);
|
||||
}
|
||||
|
||||
const char* memoryTypeNames[] = {
|
||||
nullptr, // 0x00 (Placeholder for indexing)
|
||||
"Other", // 0x01
|
||||
"Unknown", // 0x02
|
||||
"DRAM", // 0x03
|
||||
"EDRAM", // 0x04
|
||||
"VRAM", // 0x05
|
||||
"SRAM", // 0x06
|
||||
"RAM", // 0x07
|
||||
"ROM", // 0x08
|
||||
"FLASH", // 0x09
|
||||
"EEPROM", // 0x0A
|
||||
"FEPROM", // 0x0B
|
||||
"EPROM", // 0x0C
|
||||
"CDRAM", // 0x0D
|
||||
"3DRAM", // 0x0E
|
||||
"SDRAM", // 0x0F
|
||||
"SGRAM", // 0x10
|
||||
"RDRAM", // 0x11
|
||||
"DDR", // 0x12
|
||||
"DDR2", // 0x13
|
||||
"DDR2 FB-DIMM", // 0x14
|
||||
"Reserved", // 0x15
|
||||
"Reserved", // 0x16
|
||||
"Reserved", // 0x17
|
||||
"DDR3", // 0x18
|
||||
"FBD2", // 0x19
|
||||
"DDR4", // 0x1A
|
||||
"LPDDR", // 0x1B
|
||||
"LPDDR2", // 0x1C
|
||||
"LPDDR3", // 0x1D
|
||||
"LPDDR4", // 0x1E
|
||||
"Logical non-volatile device", // 0x1F
|
||||
"HBM", // 0x20
|
||||
"HBM2", // 0x21
|
||||
"DDR5", // 0x22
|
||||
"LPDDR5", // 0x23
|
||||
"HBM3", // 0x24
|
||||
"MRDIMM", // 0x25
|
||||
};
|
||||
if (!installed) {
|
||||
ffStrbufSetStatic(&device->type, "Empty");
|
||||
} else if (data->MemoryType > 0 && data->MemoryType < ARRAY_SIZE(memoryTypeNames)) {
|
||||
ffStrbufSetStatic(&device->type, memoryTypeNames[data->MemoryType]);
|
||||
} else {
|
||||
ffStrbufSetF(&device->type, "Unknown (%d)", (int) data->MemoryType);
|
||||
}
|
||||
|
||||
if (installed && data->Header.Length > offsetof(FFSmbiosMemoryDevice, Speed)) // 2.3+
|
||||
{
|
||||
uint16_t speed = FF_READ_LE(data->Speed);
|
||||
if (speed) {
|
||||
device->maxSpeed = speed == 0xFFFF ? FF_READ_LE(data->ExtendedSpeed) : speed;
|
||||
}
|
||||
|
||||
ffStrbufSetStatic(&device->vendor, ffSmbiosLocateString(strings, data->Manufacturer));
|
||||
ffCleanUpSmbiosValue(&device->vendor);
|
||||
FFPhysicalMemoryUpdateVendorString(device);
|
||||
|
||||
ffStrbufSetStatic(&device->serial, ffSmbiosLocateString(strings, data->SerialNumber));
|
||||
ffCleanUpSmbiosValue(&device->serial);
|
||||
|
||||
ffStrbufSetStatic(&device->partNumber, ffSmbiosLocateString(strings, data->PartNumber));
|
||||
ffCleanUpSmbiosValue(&device->partNumber);
|
||||
}
|
||||
|
||||
if (installed && data->Header.Length > offsetof(FFSmbiosMemoryDevice, ConfiguredMemorySpeed)) // 2.7+
|
||||
{
|
||||
uint16_t configuredSpeed = FF_READ_LE(data->ConfiguredMemorySpeed);
|
||||
if (configuredSpeed) {
|
||||
device->runningSpeed = configuredSpeed == 0xFFFF
|
||||
? FF_READ_LE(data->ExtendedConfiguredSpeed)
|
||||
: configuredSpeed;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// On Linux ffDetectPhysicalMemory is provided by physicalmemory_linux.c, which prefers udev
|
||||
// data and only falls back to the SMBIOS parser above. Every other platform uses it directly.
|
||||
#ifndef __linux__
|
||||
const char* ffDetectPhysicalMemory(FFPhysicalMemoryOptions* options, FFlist* result) {
|
||||
return ffDetectPhysicalMemoryFromSmbios(options, result);
|
||||
}
|
||||
#endif
|
||||
@@ -414,7 +414,7 @@ bool fftsGetShellVersion(FFstrbuf* exe, const char* exeName, FFstrbuf* version)
|
||||
if (ffStrEqualsIgnCase(exeName, "fish")) {
|
||||
return getShellVersionFish(exe, version);
|
||||
}
|
||||
if (ffStrEqualsIgnCase(exeName, "pwsh")) {
|
||||
if (ffStrEqualsIgnCase(exeName, "pwsh") || ffStrEqualsIgnCase(exeName, "pwsh-preview")) {
|
||||
return getShellVersionPwsh(exe, version);
|
||||
}
|
||||
if (ffStrEqualsIgnCase(exeName, "csh") || ffStrEqualsIgnCase(exeName, "tcsh")) {
|
||||
|
||||
@@ -63,6 +63,8 @@ static uint32_t getShellInfo(FFShellResult* result, uint32_t pid) {
|
||||
static void setShellInfoDetails(FFShellResult* result) {
|
||||
if (ffStrbufIgnCaseEqualS(&result->prettyName, "pwsh")) {
|
||||
ffStrbufSetS(&result->prettyName, "PowerShell");
|
||||
} else if (ffStrbufIgnCaseEqualS(&result->prettyName, "pwsh-preview")) {
|
||||
ffStrbufSetS(&result->prettyName, "PowerShell Preview");
|
||||
} else if (ffStrbufIgnCaseEqualS(&result->prettyName, "powershell")) {
|
||||
ffStrbufSetS(&result->prettyName, "Windows PowerShell");
|
||||
} else if (ffStrbufIgnCaseEqualS(&result->prettyName, "powershell_ise")) {
|
||||
|
||||
@@ -133,18 +133,6 @@ static const FFlogo T[] = {
|
||||
.colorTitle = FF_COLOR_FG_256 "32",
|
||||
},
|
||||
#endif
|
||||
#ifdef FASTFETCH_DATATEXT_LOGO_TURKISH
|
||||
// Turkish
|
||||
{
|
||||
.names = { "Turkish", },
|
||||
.lines = FASTFETCH_DATATEXT_LOGO_TURKISH,
|
||||
.colors = {
|
||||
FF_COLOR_FG_DEFAULT,
|
||||
},
|
||||
.colorKeys = FF_COLOR_FG_BLUE,
|
||||
.colorTitle = FF_COLOR_FG_RED,
|
||||
},
|
||||
#endif
|
||||
#ifdef FASTFETCH_DATATEXT_LOGO_TUXEDO_OS
|
||||
// TuxedoOS
|
||||
{
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
@@@@@@@@@
|
||||
@@@@@@ @@
|
||||
@@@@@
|
||||
@@@@@
|
||||
@@@@@@
|
||||
@@@@@ @@@@@
|
||||
@@@@@@ @@@@@@@@@@@@@
|
||||
@@@@@@@ @@ @@@@@@ @
|
||||
@@@@@@@@@@@ @@@@@
|
||||
@@@@
|
||||
@@@@
|
||||
@@@@@@@@@@ @@@@@
|
||||
@@@@@@@ @@ @@@@@@ @
|
||||
@@@@@@ @@@@@@@@@@@@@
|
||||
@@@@@ @@@@@@@
|
||||
@@@@@@
|
||||
@@@@@
|
||||
@@@@@
|
||||
@@@@@@ @@
|
||||
@@@@@@@@@@
|
||||
Reference in new issue
Block a user