diff --git a/CMakeLists.txt b/CMakeLists.txt index 16810ecee..710f980b2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -340,6 +340,7 @@ set(LIBFASTFETCH_SRC src/modules/opengl/opengl.c src/modules/os/os.c src/modules/packages/packages.c + src/modules/physicaldisk/physicaldisk.c src/modules/processes/processes.c src/modules/player/player.c src/modules/poweradapter/poweradapter.c @@ -394,6 +395,7 @@ if(LINUX) src/detection/cursor/cursor_linux.c src/detection/bluetooth/bluetooth_linux.c src/detection/disk/disk_linux.c + src/detection/physicaldisk/physicaldisk_linux.c src/detection/diskio/diskio_linux.c src/detection/displayserver/linux/displayserver_linux.c src/detection/displayserver/linux/drm.c @@ -453,6 +455,7 @@ elseif(ANDROID) src/detection/cursor/cursor_nosupport.c src/detection/cpuusage/cpuusage_linux.c src/detection/disk/disk_linux.c + src/detection/physicaldisk/physicaldisk_linux.c src/detection/diskio/diskio_linux.c src/detection/displayserver/displayserver_android.c src/detection/font/font_nosupport.c @@ -506,6 +509,7 @@ elseif(BSD) src/detection/cpuusage/cpuusage_bsd.c src/detection/cursor/cursor_linux.c src/detection/disk/disk_bsd.c + src/detection/physicaldisk/physicaldisk_bsd.c src/detection/diskio/diskio_bsd.c src/detection/displayserver/linux/displayserver_linux.c src/detection/displayserver/linux/drm.c @@ -566,6 +570,7 @@ elseif(APPLE) src/detection/cpuusage/cpuusage_apple.c src/detection/cursor/cursor_apple.m src/detection/disk/disk_bsd.c + src/detection/physicaldisk/physicaldisk_apple.c src/detection/diskio/diskio_apple.c src/detection/displayserver/displayserver_apple.c src/detection/font/font_apple.m @@ -619,6 +624,7 @@ elseif(WIN32) src/detection/cpuusage/cpuusage_windows.c src/detection/cursor/cursor_windows.c src/detection/disk/disk_windows.c + src/detection/physicaldisk/physicaldisk_windows.c src/detection/diskio/diskio_windows.c src/detection/displayserver/displayserver_windows.c src/detection/font/font_windows.c diff --git a/src/common/modules.c b/src/common/modules.c index a065bc625..580e946f6 100644 --- a/src/common/modules.c +++ b/src/common/modules.c @@ -96,6 +96,7 @@ static FFModuleBaseInfo* O[] = { static FFModuleBaseInfo* P[] = { (void*) &instance.config.modules.packages, + (void*) &instance.config.modules.physicalDisk, (void*) &instance.config.modules.player, (void*) &instance.config.modules.powerAdapter, (void*) &instance.config.modules.processes, diff --git a/src/detection/physicaldisk/physicaldisk.h b/src/detection/physicaldisk/physicaldisk.h new file mode 100644 index 000000000..eea569d2a --- /dev/null +++ b/src/detection/physicaldisk/physicaldisk.h @@ -0,0 +1,25 @@ +#include "fastfetch.h" + +typedef enum FFPhysicalDiskType +{ + FF_PHYSICALDISK_TYPE_NONE = 0, + + // If neither is set, it's unknown + FF_PHYSICALDISK_TYPE_HDD = 1 << 0, + FF_PHYSICALDISK_TYPE_SSD = 1 << 1, + + FF_PHYSICALDISK_TYPE_FIXED = 1 << 2, + FF_PHYSICALDISK_TYPE_REMOVABLE = 1 << 3, +} FFPhysicalDiskType; + +typedef struct FFPhysicalDiskResult +{ + FFstrbuf name; + FFstrbuf interconnect; + FFstrbuf serial; + FFstrbuf devPath; + FFPhysicalDiskType type; + uint64_t size; +} FFPhysicalDiskResult; + +const char* ffDetectPhysicalDisk(FFlist* result, FFPhysicalDiskOptions* options); diff --git a/src/detection/physicaldisk/physicaldisk_apple.c b/src/detection/physicaldisk/physicaldisk_apple.c new file mode 100644 index 000000000..bd186fab1 --- /dev/null +++ b/src/detection/physicaldisk/physicaldisk_apple.c @@ -0,0 +1,93 @@ +#include "physicaldisk.h" +#include "util/apple/cf_helpers.h" + +#include +#include +#include +#include +#include +#include + +static inline void wrapIoObjectRelease(io_service_t* service) +{ + assert(service); + if (*service) + IOObjectRelease(*service); +} +#define FF_IOOBJECT_AUTO_RELEASE __attribute__((__cleanup__(wrapIoObjectRelease))) + +const char* ffDetectPhysicalDisk(FFlist* result, FFPhysicalDiskOptions* options) +{ + FF_IOOBJECT_AUTO_RELEASE io_iterator_t iterator = 0; + if(IOServiceGetMatchingServices(MACH_PORT_NULL, IOServiceMatching(kIOMediaClass), &iterator) != KERN_SUCCESS) + return "IOServiceGetMatchingServices() failed"; + + io_registry_entry_t registryEntry; + while((registryEntry = IOIteratorNext(iterator)) != 0) + { + FF_IOOBJECT_AUTO_RELEASE io_registry_entry_t entryPartition = registryEntry; + + io_name_t deviceName; + if (IORegistryEntryGetName(registryEntry, deviceName) != KERN_SUCCESS) + continue; + + if (options->namePrefix.length && strncmp(deviceName, options->namePrefix.chars, options->namePrefix.length) != 0) + continue; + + FF_IOOBJECT_AUTO_RELEASE io_registry_entry_t entryDriver = 0; + if (IORegistryEntryGetParentEntry(entryPartition, kIOServicePlane, &entryDriver) != KERN_SUCCESS) + continue; + + if (!IOObjectConformsTo(entryDriver, kIOBlockStorageDriverClass)) // physical disk only + continue; + + FFPhysicalDiskResult* device = (FFPhysicalDiskResult*) ffListAdd(result); + ffStrbufInit(&device->serial); + ffStrbufInitS(&device->name, deviceName); + ffStrbufInit(&device->devPath); + ffStrbufInit(&device->interconnect); + device->type = FF_PHYSICALDISK_TYPE_NONE; + device->size = 0; + + FF_CFTYPE_AUTO_RELEASE CFBooleanRef removable = IORegistryEntryCreateCFProperty(entryPartition, CFSTR(kIOMediaRemovableKey), kCFAllocatorDefault, kNilOptions); + device->type |= CFBooleanGetValue(removable) ? FF_PHYSICALDISK_TYPE_REMOVABLE : FF_PHYSICALDISK_TYPE_FIXED; + + FF_CFTYPE_AUTO_RELEASE CFStringRef bsdName = IORegistryEntryCreateCFProperty(entryPartition, CFSTR(kIOBSDNameKey), kCFAllocatorDefault, kNilOptions); + if (bsdName) + { + ffCfStrGetString(bsdName, &device->devPath); + ffStrbufPrependS(&device->devPath, "/dev/"); + } + + FF_CFTYPE_AUTO_RELEASE CFNumberRef mediaSize = IORegistryEntryCreateCFProperty(entryPartition, CFSTR(kIOMediaSizeKey), kCFAllocatorDefault, kNilOptions); + if (mediaSize) + ffCfNumGetInt64(mediaSize, (int64_t*) &device->size); + else + device->size = 0; + + FF_IOOBJECT_AUTO_RELEASE io_registry_entry_t entryPhysical = 0; + if (IORegistryEntryGetParentEntry(entryDriver, kIOServicePlane, &entryPhysical) == KERN_SUCCESS) + { + FF_CFTYPE_AUTO_RELEASE CFDictionaryRef protocolCharacteristics = IORegistryEntryCreateCFProperty(entryPhysical, CFSTR(kIOPropertyProtocolCharacteristicsKey), kCFAllocatorDefault, kNilOptions); + if (protocolCharacteristics) + ffCfDictGetString(protocolCharacteristics, CFSTR(kIOPropertyPhysicalInterconnectTypeKey), &device->interconnect); + + FF_CFTYPE_AUTO_RELEASE CFDictionaryRef deviceCharacteristics = IORegistryEntryCreateCFProperty(entryPhysical, CFSTR(kIOPropertyDeviceCharacteristicsKey), kCFAllocatorDefault, kNilOptions); + if (deviceCharacteristics) + { + ffCfDictGetString(deviceCharacteristics, CFSTR(kIOPropertyProductSerialNumberKey), &device->serial); + + CFStringRef mediumType = (CFStringRef) CFDictionaryGetValue(deviceCharacteristics, CFSTR(kIOPropertyMediumTypeKey)); + if (mediumType) + { + if (CFStringCompare(mediumType, CFSTR(kIOPropertyMediumTypeSolidStateKey), 0) == 0) + device->type |= FF_PHYSICALDISK_TYPE_SSD; + else if (CFStringCompare(mediumType, CFSTR(kIOPropertyMediumTypeRotationalKey), 0) == 0) + device->type |= FF_PHYSICALDISK_TYPE_HDD; + } + } + } + } + + return NULL; +} diff --git a/src/detection/physicaldisk/physicaldisk_bsd.c b/src/detection/physicaldisk/physicaldisk_bsd.c new file mode 100644 index 000000000..c23b08aea --- /dev/null +++ b/src/detection/physicaldisk/physicaldisk_bsd.c @@ -0,0 +1,70 @@ +#include "physicaldisk.h" +#include "util/stringUtils.h" + +#include +#include +#include +#include +#include +#include + +const char* ffDetectPhysicalDisk(FFlist* result, FFPhysicalDiskOptions* options) +{ + struct gmesh geomTree; + if (geom_gettree(&geomTree) < 0) + return "geom_gettree() failed"; + + if (geom_stats_open() < 0) + return "geom_stats_open() failed"; + + void* snap = geom_stats_snapshot_get(); + struct devstat* snapIter; + while ((snapIter = geom_stats_snapshot_next(snap)) != NULL) + { + if (snapIter->device_type & DEVSTAT_TYPE_PASS) + continue; + struct gident* geomId = geom_lookupid(&geomTree, snapIter->id); + if (geomId == NULL) + continue; + if (geomId->lg_what != ISPROVIDER) + continue; + struct gprovider* provider = (struct gprovider*) geomId->lg_ptr; + if (provider->lg_geom->lg_rank != 1) + continue; + + FF_STRBUF_AUTO_DESTROY name = ffStrbufCreateS(provider->lg_name); + FF_STRBUF_AUTO_DESTROY identifier = ffStrbufCreate(); + FFPhysicalDiskType type = FF_PHYSICALDISK_TYPE_NONE; + for (struct gconfig* ptr = provider->lg_config.lh_first; ptr; ptr = ptr->lg_config.le_next) + { + if (ffStrEquals(ptr->lg_name, "descr")) + ffStrbufSetS(&name, ptr->lg_val); + else if (ffStrEquals(ptr->lg_name, "rotationrate") && !ffStrEquals(ptr->lg_val, "unknown")) + type |= ffStrEquals(ptr->lg_val, "0") ? FF_PHYSICALDISK_TYPE_SSD : FF_PHYSICALDISK_TYPE_HDD; + else if (ffStrEquals(ptr->lg_name, "ident")) + ffStrbufSetS(&identifier, ptr->lg_val); + } + + if (options->namePrefix.length && !ffStrbufStartsWith(&name, &options->namePrefix)) + continue; + + FFPhysicalDiskResult* device = (FFPhysicalDiskResult*) ffListAdd(result); + ffStrbufInitF(&device->devPath, "/dev/%s", provider->lg_name); + ffStrbufInitMove(&device->serial, &identifier); + ffStrbufInit(&device->interconnect); + switch (snapIter->device_type & DEVSTAT_TYPE_IF_MASK) + { + case DEVSTAT_TYPE_IF_SCSI: ffStrbufAppendS(&device->interconnect, "SCSI"); break; + case DEVSTAT_TYPE_IF_IDE: ffStrbufAppendS(&device->interconnect, "IDE"); break; + case DEVSTAT_TYPE_IF_OTHER: ffStrbufAppendS(&device->interconnect, "OTHER"); break; + } + device->size = (uint64_t) provider->lg_mediasize; + ffStrbufInitMove(&device->name, &name); + device->type = type; + } + + geom_stats_snapshot_free(snap); + geom_stats_close(); + + return NULL; +} diff --git a/src/detection/physicaldisk/physicaldisk_linux.c b/src/detection/physicaldisk/physicaldisk_linux.c new file mode 100644 index 000000000..ac4311e5a --- /dev/null +++ b/src/detection/physicaldisk/physicaldisk_linux.c @@ -0,0 +1,114 @@ +#include "physicaldisk.h" +#include "common/io/io.h" +#include "common/properties.h" +#include "util/stringUtils.h" + +#include +#include + +const char* ffDetectPhysicalDisk(FFlist* result, FFPhysicalDiskOptions* options) +{ + FF_AUTO_CLOSE_DIR DIR* sysBlockDirp = opendir("/sys/block/"); + if(sysBlockDirp == NULL) + return "opendir(\"/sys/block/\") == NULL"; + + struct dirent* sysBlockEntry; + while ((sysBlockEntry = readdir(sysBlockDirp)) != NULL) + { + const char* const devName = sysBlockEntry->d_name; + + if (devName[0] == '.') + continue; + + char pathSysBlock[PATH_MAX]; + snprintf(pathSysBlock, PATH_MAX, "/sys/block/%s", devName); + + char pathSysDeviceReal[PATH_MAX] = ""; + readlink(pathSysBlock, pathSysDeviceReal, sizeof(pathSysDeviceReal) - 1); + + if (strstr(pathSysDeviceReal, "/virtual/")) // virtual device + continue; + + snprintf(pathSysBlock, PATH_MAX, "/sys/block/%s/device", devName); + if (!ffPathExists(pathSysBlock, FF_PATHTYPE_DIRECTORY)) + continue; + + FFPhysicalDiskResult* device = (FFPhysicalDiskResult*) ffListAdd(result); + device->type = FF_PHYSICALDISK_TYPE_NONE; + ffStrbufInit(&device->name); + + { + snprintf(pathSysBlock, PATH_MAX, "/sys/block/%s/device/vendor", devName); + ffAppendFileBuffer(pathSysBlock, &device->name); + if (device->name.length > 0) + ffStrbufAppendC(&device->name, ' '); + + snprintf(pathSysBlock, PATH_MAX, "/sys/block/%s/device/model", devName); + ffAppendFileBuffer(pathSysBlock, &device->name); + ffStrbufTrim(&device->name, ' '); + + if (device->name.length == 0) + ffStrbufSetS(&device->name, devName); + + if (options->namePrefix.length && !ffStrbufStartsWith(&device->name, &options->namePrefix)) + { + ffStrbufDestroy(&device->name); + result->length--; + continue; + } + } + + ffStrbufInitF(&device->devPath, "/dev/%s", devName); + + { + ffStrbufInit(&device->interconnect); + if (strstr(pathSysDeviceReal, "/usb") != NULL) + ffStrbufSetS(&device->interconnect, "usb"); + else + { + snprintf(pathSysBlock, PATH_MAX, "/sys/block/%s/device/transport", devName); + if (!ffAppendFileBuffer(pathSysBlock, &device->interconnect)) + { + snprintf(pathSysBlock, PATH_MAX, "/sys/block/%s/device/uevent", devName); + if (ffParsePropFile(pathSysBlock, "DEVTYPE=", &device->interconnect)) + ffStrbufSubstrBeforeLastC(&device->interconnect, '_'); + } + } + } + + { + snprintf(pathSysBlock, PATH_MAX, "/sys/block/%s/queue/rotational", devName); + char isRotationalChar = '1'; + if (ffReadFileData(pathSysBlock, 1, &isRotationalChar) > 0) + device->type |= isRotationalChar == '1' ? FF_PHYSICALDISK_TYPE_HDD : FF_PHYSICALDISK_TYPE_SSD; + } + + { + snprintf(pathSysBlock, PATH_MAX, "/sys/block/%s/size", devName); + char blkSize[32]; + ssize_t fileSize = ffReadFileData(pathSysBlock, sizeof(blkSize) - 1, blkSize); + if (fileSize > 0) + { + blkSize[fileSize] = 0; + device->size = (uint64_t) strtoul(blkSize, NULL, 10) * 512; + } + else + device->size = 0; + } + + { + char removableChar = '0'; + snprintf(pathSysBlock, PATH_MAX, "/sys/block/%s/removable", devName); + if (ffReadFileData(pathSysBlock, 1, &removableChar) > 0) + device->type |= removableChar == '1' ? FF_PHYSICALDISK_TYPE_REMOVABLE : FF_PHYSICALDISK_TYPE_FIXED; + } + + { + ffStrbufInit(&device->serial); + snprintf(pathSysBlock, PATH_MAX, "/sys/block/%s/device/serial", devName); + ffReadFileBuffer(pathSysBlock, &device->serial); + } + } + + return NULL; +} diff --git a/src/detection/physicaldisk/physicaldisk_windows.c b/src/detection/physicaldisk/physicaldisk_windows.c new file mode 100644 index 000000000..1ad1a5779 --- /dev/null +++ b/src/detection/physicaldisk/physicaldisk_windows.c @@ -0,0 +1,131 @@ +#include "physicaldisk.h" +#include "common/io/io.h" +#include "util/windows/unicode.h" + +#include +#include + +const char* ffDetectPhysicalDisk(FFlist* result, FFPhysicalDiskOptions* options) +{ + wchar_t szDevice[32] = L"\\\\.\\PhysicalDrive"; + wchar_t* pNum = szDevice + strlen("\\\\.\\PhysicalDrive"); + for (uint32_t idev = 0; ; ++idev) + { + _ultow(idev, pNum, 10); + + FF_AUTO_CLOSE_FD HANDLE hDevice = CreateFileW(szDevice, FILE_READ_ATTRIBUTES, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); + if (hDevice == INVALID_HANDLE_VALUE) + break; + + DWORD retSize; + char sddBuffer[4096]; + if(!DeviceIoControl( + hDevice, + IOCTL_STORAGE_QUERY_PROPERTY, + &(STORAGE_PROPERTY_QUERY) { + .PropertyId = StorageDeviceProperty, + .QueryType = PropertyStandardQuery, + }, + sizeof(STORAGE_PROPERTY_QUERY), + &sddBuffer, + sizeof(sddBuffer), + &retSize, + NULL + ) || retSize == 0) + continue; + + FFPhysicalDiskResult* device = (FFPhysicalDiskResult*) ffListAdd(result); + device->type = FF_PHYSICALDISK_TYPE_NONE; + STORAGE_DEVICE_DESCRIPTOR* sdd = (STORAGE_DEVICE_DESCRIPTOR*) sddBuffer; + + ffStrbufInit(&device->name); + if (sdd->VendorIdOffset != 0) + { + ffStrbufSetS(&device->name, (const char*) sddBuffer + sdd->VendorIdOffset); + ffStrbufTrim(&device->name, ' '); + } + if (sdd->ProductIdOffset != 0) + { + if (device->name.length) + ffStrbufAppendC(&device->name, ' '); + + ffStrbufAppendS(&device->name, (const char*) sddBuffer + sdd->ProductIdOffset); + ffStrbufTrimRight(&device->name, ' '); + } + + if (options->namePrefix.length && !ffStrbufStartsWith(&device->name, &options->namePrefix)) + { + ffStrbufDestroy(&device->name); + result->length--; + continue; + } + + ffStrbufInitWS(&device->devPath, szDevice); + ffStrbufInit(&device->serial); + if (sdd->SerialNumberOffset != 0) + { + ffStrbufSetS(&device->serial, (const char*) sddBuffer + sdd->SerialNumberOffset); + ffStrbufTrim(&device->serial, ' '); + } + + device->type |= sdd->RemovableMedia ? FF_PHYSICALDISK_TYPE_REMOVABLE : FF_PHYSICALDISK_TYPE_FIXED; + + ffStrbufInit(&device->interconnect); + switch (sdd->BusType) + { + case BusTypeUnknown: ffStrbufSetStatic(&device->interconnect, "Unknown"); break; + case BusTypeScsi: ffStrbufSetStatic(&device->interconnect, "Scsi"); break; + case BusTypeAtapi: ffStrbufSetStatic(&device->interconnect, "Atapi"); break; + case BusTypeAta: ffStrbufSetStatic(&device->interconnect, "Ata"); break; + case BusType1394: ffStrbufSetStatic(&device->interconnect, "1394"); break; + case BusTypeSsa: ffStrbufSetStatic(&device->interconnect, "Ssa"); break; + case BusTypeFibre: ffStrbufSetStatic(&device->interconnect, "Fibra"); break; + case BusTypeUsb: ffStrbufSetStatic(&device->interconnect, "Usb"); break; + case BusTypeRAID: ffStrbufSetStatic(&device->interconnect, "RAID"); break; + case BusTypeiScsi: ffStrbufSetStatic(&device->interconnect, "iScsi"); break; + case BusTypeSas: ffStrbufSetStatic(&device->interconnect, "Sas"); break; + case BusTypeSata: ffStrbufSetStatic(&device->interconnect, "Sata"); break; + case BusTypeSd: ffStrbufSetStatic(&device->interconnect, "Sd"); break; + case BusTypeMmc: ffStrbufSetStatic(&device->interconnect, "Mmc"); break; + case BusTypeVirtual: ffStrbufSetStatic(&device->interconnect, "Virtual"); break; + case BusTypeFileBackedVirtual: ffStrbufSetStatic(&device->interconnect, "FileBackedVirtual"); break; + case BusTypeSpaces: ffStrbufSetStatic(&device->interconnect, "Spaces"); break; + case BusTypeNvme: ffStrbufSetStatic(&device->interconnect, "Nvme"); break; + case BusTypeSCM: ffStrbufSetStatic(&device->interconnect, "SCM"); break; + case BusTypeUfs: ffStrbufSetStatic(&device->interconnect, "Ufs"); break; + default: ffStrbufSetF(&device->interconnect, "Unknown (%d)", (int) sdd->BusType); break; + } + + DEVICE_SEEK_PENALTY_DESCRIPTOR dspd = {}; + if(DeviceIoControl( + hDevice, + IOCTL_STORAGE_QUERY_PROPERTY, + &(STORAGE_PROPERTY_QUERY) { + .PropertyId = StorageDeviceSeekPenaltyProperty, + .QueryType = PropertyStandardQuery, + }, + sizeof(STORAGE_PROPERTY_QUERY), + &dspd, + sizeof(dspd), + &retSize, + NULL + ) && retSize == sizeof(dspd)) + device->type |= dspd.IncursSeekPenalty ? FF_PHYSICALDISK_TYPE_HDD : FF_PHYSICALDISK_TYPE_SSD; + + DISK_GEOMETRY_EX dge = {}; + if(DeviceIoControl( + hDevice, + IOCTL_DISK_GET_DRIVE_GEOMETRY_EX, + NULL, + 0, + &dge, + sizeof(dge), + &retSize, + NULL)) + device->size = (uint64_t) dge.DiskSize.QuadPart; + else + device->size = 0; + } + + return NULL; +} diff --git a/src/modules/modules.h b/src/modules/modules.h index 57632fb7d..35d6523c4 100644 --- a/src/modules/modules.h +++ b/src/modules/modules.h @@ -37,6 +37,7 @@ #include "modules/opencl/opencl.h" #include "modules/os/os.h" #include "modules/packages/packages.h" +#include "modules/physicaldisk/physicaldisk.h" #include "modules/player/player.h" #include "modules/poweradapter/poweradapter.h" #include "modules/processes/processes.h" diff --git a/src/modules/options.h b/src/modules/options.h index 191767c77..aa124c24a 100644 --- a/src/modules/options.h +++ b/src/modules/options.h @@ -37,6 +37,7 @@ #include "modules/opencl/option.h" #include "modules/os/option.h" #include "modules/packages/option.h" +#include "modules/physicaldisk/option.h" #include "modules/player/option.h" #include "modules/poweradapter/option.h" #include "modules/processes/option.h" diff --git a/src/modules/physicaldisk/option.h b/src/modules/physicaldisk/option.h new file mode 100644 index 000000000..243a98a6a --- /dev/null +++ b/src/modules/physicaldisk/option.h @@ -0,0 +1,13 @@ +#pragma once + +// This file will be included in "fastfetch.h", do NOT put unnecessary things here + +#include "common/option.h" + +typedef struct FFPhysicalDiskOptions +{ + FFModuleBaseInfo moduleInfo; + FFModuleArgs moduleArgs; + + FFstrbuf namePrefix; +} FFPhysicalDiskOptions; diff --git a/src/modules/physicaldisk/physicaldisk.c b/src/modules/physicaldisk/physicaldisk.c new file mode 100644 index 000000000..05911eb64 --- /dev/null +++ b/src/modules/physicaldisk/physicaldisk.c @@ -0,0 +1,241 @@ +#include "common/printing.h" +#include "common/jsonconfig.h" +#include "common/parsing.h" +#include "detection/physicaldisk/physicaldisk.h" +#include "modules/physicaldisk/physicaldisk.h" +#include "util/stringUtils.h" + +#define FF_PHYSICALDISK_DISPLAY_NAME "Physical Disk" +#define FF_PHYSICALDISK_NUM_FORMAT_ARGS 7 + +static int sortDevices(const FFPhysicalDiskResult* left, const FFPhysicalDiskResult* right) +{ + return ffStrbufComp(&left->name, &right->name); +} + +static void formatKey(const FFPhysicalDiskOptions* options, FFPhysicalDiskResult* dev, uint32_t index, FFstrbuf* key) +{ + if(options->moduleArgs.key.length == 0) + { + ffStrbufSetF(key, FF_PHYSICALDISK_DISPLAY_NAME " (%s)", dev->name.length ? dev->name.chars : dev->devPath.chars); + } + else + { + ffStrbufClear(key); + ffParseFormatString(key, &options->moduleArgs.key, 2, (FFformatarg[]){ + {FF_FORMAT_ARG_TYPE_UINT, &index}, + {FF_FORMAT_ARG_TYPE_STRBUF, &dev->name}, + {FF_FORMAT_ARG_TYPE_STRBUF, &dev->devPath}, + }); + } +} + +void ffPrintPhysicalDisk(FFPhysicalDiskOptions* options) +{ + FF_LIST_AUTO_DESTROY result = ffListCreate(sizeof(FFPhysicalDiskResult)); + const char* error = ffDetectPhysicalDisk(&result, options); + + if(error) + { + ffPrintError(FF_PHYSICALDISK_DISPLAY_NAME, 0, &options->moduleArgs, "%s", error); + return; + } + + ffListSort(&result, (const void*) sortDevices); + + uint32_t index = 0; + FF_STRBUF_AUTO_DESTROY key = ffStrbufCreate(); + FF_STRBUF_AUTO_DESTROY buffer = ffStrbufCreate(); + + FF_LIST_FOR_EACH(FFPhysicalDiskResult, dev, result) + { + formatKey(options, dev, result.length == 1 ? 0 : index + 1, &key); + ffStrbufClear(&buffer); + ffParseSize(dev->size, &buffer); + + const char* physicalType = dev->type & FF_PHYSICALDISK_TYPE_HDD + ? "HDD" + : dev->type & FF_PHYSICALDISK_TYPE_SSD + ? "SSD" + : ""; + const char* removableType = dev->type & FF_PHYSICALDISK_TYPE_REMOVABLE + ? "Removable" + : dev->type & FF_PHYSICALDISK_TYPE_FIXED + ? "Fixed" + : ""; + + if(options->moduleArgs.outputFormat.length == 0) + { + ffPrintLogoAndKey(key.chars, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT); + + if (physicalType[0] || removableType[0]) + { + ffStrbufAppendS(&buffer, " ["); + if (physicalType[0]) + ffStrbufAppendS(&buffer, physicalType); + if (removableType[0]) + { + if (physicalType[0]) + ffStrbufAppendS(&buffer, ", "); + ffStrbufAppendS(&buffer, removableType); + } + ffStrbufAppendC(&buffer, ']'); + } + ffStrbufPutTo(&buffer, stdout); + } + else + { + ffParseSize(dev->size, &buffer); + ffPrintFormatString(key.chars, 0, &options->moduleArgs, FF_PRINT_TYPE_NO_CUSTOM_KEY, FF_PHYSICALDISK_NUM_FORMAT_ARGS, (FFformatarg[]){ + {FF_FORMAT_ARG_TYPE_STRBUF, &buffer}, + {FF_FORMAT_ARG_TYPE_STRBUF, &dev->name}, + {FF_FORMAT_ARG_TYPE_STRBUF, &dev->interconnect}, + {FF_FORMAT_ARG_TYPE_STRING, physicalType}, + {FF_FORMAT_ARG_TYPE_STRBUF, &dev->devPath}, + {FF_FORMAT_ARG_TYPE_STRBUF, &dev->serial}, + {FF_FORMAT_ARG_TYPE_STRING, removableType}, + }); + } + ++index; + } + + FF_LIST_FOR_EACH(FFPhysicalDiskResult, dev, result) + { + ffStrbufDestroy(&dev->name); + ffStrbufDestroy(&dev->interconnect); + ffStrbufDestroy(&dev->devPath); + ffStrbufDestroy(&dev->serial); + } +} + +bool ffParsePhysicalDiskCommandOptions(FFPhysicalDiskOptions* options, const char* key, const char* value) +{ + const char* subKey = ffOptionTestPrefix(key, FF_PHYSICALDISK_MODULE_NAME); + if (!subKey) return false; + if (ffOptionParseModuleArgs(key, subKey, value, &options->moduleArgs)) + return true; + + if (ffStrEqualsIgnCase(subKey, "name-prefix")) + { + ffOptionParseString(key, value, &options->namePrefix); + return true; + } + + return false; +} + +void ffParsePhysicalDiskJsonObject(FFPhysicalDiskOptions* options, yyjson_val* module) +{ + yyjson_val *key_, *val; + size_t idx, max; + yyjson_obj_foreach(module, idx, max, key_, val) + { + const char* key = yyjson_get_str(key_); + if(ffStrEqualsIgnCase(key, "type")) + continue; + + if (ffJsonConfigParseModuleArgs(key, val, &options->moduleArgs)) + continue; + + if (ffStrEqualsIgnCase(key, "namePrefix")) + { + ffStrbufSetS(&options->namePrefix, yyjson_get_str(val)); + continue; + } + + ffPrintError(FF_PHYSICALDISK_MODULE_NAME, 0, &options->moduleArgs, "Unknown JSON key %s", key); + } +} + +void ffGeneratePhysicalDiskJsonConfig(FFPhysicalDiskOptions* options, yyjson_mut_doc* doc, yyjson_mut_val* module) +{ + __attribute__((__cleanup__(ffDestroyPhysicalDiskOptions))) FFPhysicalDiskOptions defaultOptions; + ffInitPhysicalDiskOptions(&defaultOptions); + + ffJsonConfigGenerateModuleArgsConfig(doc, module, &defaultOptions.moduleArgs, &options->moduleArgs); + + if (!ffStrbufEqual(&options->namePrefix, &defaultOptions.namePrefix)) + yyjson_mut_obj_add_strbuf(doc, module, "namePrefix", &options->namePrefix); +} + +void ffGeneratePhysicalDiskJsonResult(FFPhysicalDiskOptions* options, yyjson_mut_doc* doc, yyjson_mut_val* module) +{ + FF_LIST_AUTO_DESTROY result = ffListCreate(sizeof(FFPhysicalDiskResult)); + const char* error = ffDetectPhysicalDisk(&result, options); + + if(error) + { + yyjson_mut_obj_add_str(doc, module, "error", error); + return; + } + + yyjson_mut_val* arr = yyjson_mut_obj_add_arr(doc, module, "result"); + FF_LIST_FOR_EACH(FFPhysicalDiskResult, dev, result) + { + yyjson_mut_val* obj = yyjson_mut_arr_add_obj(doc, arr); + yyjson_mut_obj_add_strbuf(doc, obj, "name", &dev->name); + yyjson_mut_obj_add_strbuf(doc, obj, "devPath", &dev->devPath); + yyjson_mut_obj_add_strbuf(doc, obj, "interconnect", &dev->interconnect); + + if (dev->type & FF_PHYSICALDISK_TYPE_HDD) + yyjson_mut_obj_add_str(doc, obj, "kind", "HDD"); + else if (dev->type & FF_PHYSICALDISK_TYPE_SSD) + yyjson_mut_obj_add_str(doc, obj, "kind", "SSD"); + else + yyjson_mut_obj_add_null(doc, obj, "kind"); + + yyjson_mut_obj_add_uint(doc, obj, "size", dev->size); + yyjson_mut_obj_add_strbuf(doc, obj, "serial", &dev->serial); + + if (dev->type & FF_PHYSICALDISK_TYPE_REMOVABLE) + yyjson_mut_obj_add_bool(doc, obj, "removable", true); + else if (dev->type & FF_PHYSICALDISK_TYPE_FIXED) + yyjson_mut_obj_add_bool(doc, obj, "removable", false); + else + yyjson_mut_obj_add_null(doc, obj, "removable"); + } + + FF_LIST_FOR_EACH(FFPhysicalDiskResult, dev, result) + { + ffStrbufDestroy(&dev->name); + ffStrbufDestroy(&dev->interconnect); + ffStrbufDestroy(&dev->devPath); + } +} + +void ffPrintPhysicalDiskHelpFormat(void) +{ + ffPrintModuleFormatHelp(FF_PHYSICALDISK_MODULE_NAME, "{1}", FF_PHYSICALDISK_NUM_FORMAT_ARGS, (const char* []) { + "Device size (formatted)", + "Device name", + "Device interconnect type", + "Device raw file path", + "Serial number", + "Device kind (SSD or HDD)", + "Device kind (Removable or Fixed)", + }); +} + +void ffInitPhysicalDiskOptions(FFPhysicalDiskOptions* options) +{ + ffOptionInitModuleBaseInfo( + &options->moduleInfo, + FF_PHYSICALDISK_MODULE_NAME, + "Print physical disk information", + ffParsePhysicalDiskCommandOptions, + ffParsePhysicalDiskJsonObject, + ffPrintPhysicalDisk, + ffGeneratePhysicalDiskJsonResult, + ffPrintPhysicalDiskHelpFormat, + ffGeneratePhysicalDiskJsonConfig + ); + ffOptionInitModuleArg(&options->moduleArgs); + + ffStrbufInit(&options->namePrefix); +} + +void ffDestroyPhysicalDiskOptions(FFPhysicalDiskOptions* options) +{ + ffOptionDestroyModuleArg(&options->moduleArgs); + ffStrbufDestroy(&options->namePrefix); +} diff --git a/src/modules/physicaldisk/physicaldisk.h b/src/modules/physicaldisk/physicaldisk.h new file mode 100644 index 000000000..d8216c140 --- /dev/null +++ b/src/modules/physicaldisk/physicaldisk.h @@ -0,0 +1,9 @@ +#pragma once + +#include "fastfetch.h" + +#define FF_PHYSICALDISK_MODULE_NAME "PhysicalDisk" + +void ffPrintPhysicalDisk(FFPhysicalDiskOptions* options); +void ffInitPhysicalDiskOptions(FFPhysicalDiskOptions* options); +void ffDestroyPhysicalDiskOptions(FFPhysicalDiskOptions* options); diff --git a/src/options/modules.c b/src/options/modules.c index 2047abdde..68b835d82 100644 --- a/src/options/modules.c +++ b/src/options/modules.c @@ -38,6 +38,7 @@ void ffOptionsInitModules(FFOptionsModules* options) ffInitOpenCLOptions(&options->openCL); ffInitOpenGLOptions(&options->openGL); ffInitPackagesOptions(&options->packages); + ffInitPhysicalDiskOptions(&options->physicalDisk); ffInitPlayerOptions(&options->player); ffInitPowerAdapterOptions(&options->powerAdapter); ffInitProcessesOptions(&options->processes); @@ -98,6 +99,7 @@ void ffOptionsDestroyModules(FFOptionsModules* options) ffDestroyOSOptions(&options->os); ffDestroyOpenCLOptions(&options->openCL); ffDestroyOpenGLOptions(&options->openGL); + ffDestroyPhysicalDiskOptions(&options->physicalDisk); ffDestroyPackagesOptions(&options->packages); ffDestroyPlayerOptions(&options->player); ffDestroyPowerAdapterOptions(&options->powerAdapter); diff --git a/src/options/modules.h b/src/options/modules.h index 66b4203c6..e9836e140 100644 --- a/src/options/modules.h +++ b/src/options/modules.h @@ -39,6 +39,7 @@ typedef struct FFOptionsModules FFOpenCLOptions openCL; FFOpenGLOptions openGL; FFPackagesOptions packages; + FFPhysicalDiskOptions physicalDisk; FFPlayerOptions player; FFPowerAdapterOptions powerAdapter; FFProcessesOptions processes;