diff options
| author | sumuel <samuel@yakubos.org> | 2026-08-17 20:44:55 +0000 |
|---|---|---|
| committer | sumuel <samuel@yakubos.org> | 2026-08-17 20:44:55 +0000 |
| commit | 76424950e373d3b04ac3dd13019151bfba3e8423 (patch) | |
| tree | 4c3cfdbda039e592b9186be3e28f8d7cfd439e8a /src/detection/physicaldisk/physicaldisk_linux.c | |
Add the files
Diffstat (limited to 'src/detection/physicaldisk/physicaldisk_linux.c')
| -rw-r--r-- | src/detection/physicaldisk/physicaldisk_linux.c | 202 |
1 files changed, 202 insertions, 0 deletions
diff --git a/src/detection/physicaldisk/physicaldisk_linux.c b/src/detection/physicaldisk/physicaldisk_linux.c new file mode 100644 index 0000000..f8126b9 --- /dev/null +++ b/src/detection/physicaldisk/physicaldisk_linux.c @@ -0,0 +1,202 @@ +#include "physicaldisk.h" +#include "common/io.h" +#include "common/properties.h" +#include "common/strutil.h" + +#include <ctype.h> +#include <limits.h> +#include <unistd.h> +#include <fcntl.h> + +static double detectNvmeTemp(int devfd) { + char pathHwmon[] = "hwmon$/temp1_input"; + + for (char c = '0'; c <= '9'; c++) // hopefully there's only one digit + { + pathHwmon[strlen("hwmon")] = c; + char buffer[64]; + ssize_t size = ffReadFileDataRelative(devfd, pathHwmon, ARRAY_SIZE(buffer), buffer); + if (size > 0) { + buffer[size] = '\0'; + double temp = strtod(buffer, NULL); + return temp > 0 && temp < 10000000 /*VMware*/ ? temp / 1000 : FF_PHYSICALDISK_TEMP_UNSET; + } + } + + return FF_PHYSICALDISK_TEMP_UNSET; +} + +static void parsePhysicalDisk(int dfd, const char* devName, FFPhysicalDiskOptions* options, FFlist* result) { + uint64_t size = 0; + + { + char blkSize[32]; + ssize_t fileSize = ffReadFileDataRelative(dfd, "size", ARRAY_SIZE(blkSize) - 1, blkSize); + if (fileSize > 0) { + blkSize[fileSize] = 0; + size = (uint64_t) strtoul(blkSize, NULL, 10) * 512; + } + } + + FFPhysicalDiskType type = FF_PHYSICALDISK_TYPE_NONE; + if (size == 0) { + if (options->hideType & FF_PHYSICALDISK_TYPE_UNUSED) { + return; + } + + type |= FF_PHYSICALDISK_TYPE_UNUSED; + } + + int devfd = openat(dfd, "device", O_RDONLY | O_CLOEXEC | O_PATH | O_DIRECTORY); + + if (devfd < 0) { + if (options->hideType & FF_PHYSICALDISK_TYPE_VIRTUAL) { + return; + } + + type |= FF_PHYSICALDISK_TYPE_VIRTUAL; + } + + FF_STRBUF_AUTO_DESTROY name = ffStrbufCreate(); + + if (devfd > 0) { + if (ffAppendFileBufferRelative(devfd, "vendor", &name)) { + ffStrbufTrimRightSpace(&name); + if (name.length > 0) { + ffStrbufAppendC(&name, ' '); + } + } + + ffAppendFileBufferRelative(devfd, "model", &name); + ffStrbufTrimRightSpace(&name); + + if (name.length == 0) { + ffStrbufSetS(&name, devName); + } + + if (ffStrStartsWith(devName, "nvme")) { + int devid, nsid; + if (sscanf(devName, "nvme%dn%d", &devid, &nsid) == 2) { + bool multiNs = nsid > 1; + if (!multiNs) { + char pathSysBlock[32]; + snprintf(pathSysBlock, ARRAY_SIZE(pathSysBlock), "/dev/nvme%dn2", devid); + multiNs = access(pathSysBlock, F_OK) == 0; + } + if (multiNs) { + // In Asahi Linux, there are multiple namespaces for the same NVMe drive. + ffStrbufAppendF(&name, " - %d", nsid); + } + } + } + + if (options->namePrefix.length && !ffStrbufStartsWith(&name, &options->namePrefix)) { + return; + } + } else { + ffStrbufSetS(&name, devName); + } + + FFPhysicalDiskResult* device = FF_LIST_ADD(FFPhysicalDiskResult, *result); + ffStrbufInitMove(&device->name, &name); + ffStrbufInitF(&device->devPath, "/dev/%s", devName); + ffStrbufInit(&device->serial); + ffStrbufInit(&device->revision); + ffStrbufInit(&device->interconnect); + device->type = type; + device->size = size; + device->temperature = FF_PHYSICALDISK_TEMP_UNSET; + + bool isVirtio = false; + if (devfd > 0) { + if (ffStrStartsWith(devName, "nvme")) { + ffStrbufSetStatic(&device->interconnect, "NVMe"); + } else if (ffStrStartsWith(devName, "mmcblk")) { + ffStrbufSetStatic(&device->interconnect, "MMC"); + } else { + char pathSysDeviceLink[64]; + snprintf(pathSysDeviceLink, ARRAY_SIZE(pathSysDeviceLink), "/sys/block/%s/device", devName); + char pathSysDeviceReal[PATH_MAX]; + if (realpath(pathSysDeviceLink, pathSysDeviceReal)) { + if (strstr(pathSysDeviceReal, "/usb") != NULL) { + ffStrbufSetStatic(&device->interconnect, "USB"); + } else if (strstr(pathSysDeviceReal, "/ata") != NULL) { + ffStrbufSetStatic(&device->interconnect, "ATA"); + } else if (strstr(pathSysDeviceReal, "/scsi") != NULL) { + ffStrbufSetStatic(&device->interconnect, "SCSI"); + } else if (strstr(pathSysDeviceReal, "/nvme") != NULL) { + ffStrbufSetStatic(&device->interconnect, "NVMe"); + } else if (strstr(pathSysDeviceReal, "/virtio") != NULL) { + ffStrbufSetStatic(&device->interconnect, "VirtIO"); + isVirtio = true; // VirtIO devices are virtual, but we still want to report it + } else { + if (ffAppendFileBufferRelative(devfd, "transport", &device->interconnect)) { + ffStrbufTrimRightSpace(&device->interconnect); + } + } + } + } + } else { + ffStrbufSetStatic(&device->interconnect, "Virtual"); + } + + if (devfd > 0 && !isVirtio) { + char isRotationalChar = '1'; + if (ffReadFileDataRelative(dfd, "queue/rotational", 1, &isRotationalChar) > 0) { + device->type |= isRotationalChar == '1' ? FF_PHYSICALDISK_TYPE_HDD : FF_PHYSICALDISK_TYPE_SSD; + } + + if (ffReadFileBufferRelative(devfd, "serial", &device->serial)) { + ffStrbufTrimSpace(&device->serial); + } + + if (ffReadFileBufferRelative(devfd, "firmware_rev", &device->revision) || + ffReadFileBufferRelative(devfd, "rev", &device->revision)) { + ffStrbufTrimRightSpace(&device->revision); + } + + if (options->temp) { + device->temperature = detectNvmeTemp(devfd); + } + } + + { + char removableChar = '0'; + if (ffReadFileDataRelative(dfd, "removable", 1, &removableChar) > 0) { + device->type |= removableChar == '1' ? FF_PHYSICALDISK_TYPE_REMOVABLE : FF_PHYSICALDISK_TYPE_FIXED; + } + } + + { + char roChar = '0'; + if (ffReadFileDataRelative(dfd, "ro", 1, &roChar) > 0) { + device->type |= roChar == '1' ? FF_PHYSICALDISK_TYPE_READONLY : FF_PHYSICALDISK_TYPE_READWRITE; + } + } +} + +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[sizeof("/sys/block/") + sizeof(sysBlockEntry->d_name)]; + snprintf(pathSysBlock, ARRAY_SIZE(pathSysBlock), "/sys/block/%s", devName); + + int dfd = openat(dirfd(sysBlockDirp), devName, O_RDONLY | O_CLOEXEC | O_PATH | O_DIRECTORY); + if (dfd > 0) { + parsePhysicalDisk(dfd, devName, options, result); + } + } + + return NULL; +} |