diff --git a/CMakeLists.txt b/CMakeLists.txt index e95f33ddd..cbe462dc2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -793,7 +793,7 @@ elseif(NetBSD) src/detection/cursor/cursor_linux.c src/detection/disk/disk_bsd.c src/detection/dns/dns_linux.c - src/detection/physicaldisk/physicaldisk_nosupport.c + src/detection/physicaldisk/physicaldisk_nbsd.c src/detection/physicalmemory/physicalmemory_linux.c src/detection/diskio/diskio_nbsd.c src/detection/displayserver/linux/displayserver_linux.c @@ -1774,6 +1774,7 @@ elseif(NetBSD) PRIVATE "bluetooth" PRIVATE "m" PRIVATE "prop" + PRIVATE "util" ) elseif(SunOS) target_link_libraries(libfastfetch diff --git a/src/detection/physicaldisk/physicaldisk_nbsd.c b/src/detection/physicaldisk/physicaldisk_nbsd.c new file mode 100644 index 000000000..4d6d0b2c8 --- /dev/null +++ b/src/detection/physicaldisk/physicaldisk_nbsd.c @@ -0,0 +1,154 @@ +#define DKTYPENAMES +#include "physicaldisk.h" +#include "common/io.h" +#include "common/sysctl.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +const char* ffDetectPhysicalDisk(FFlist* result, FFPhysicalDiskOptions* options) { + FF_STRBUF_AUTO_DESTROY diskNames = ffStrbufCreate(); + const char* error = ffSysctlGetString("hw.disknames", &diskNames); + if (error) { + return error; + } + + char* diskName = NULL; + size_t len = 0; + while (ffStrbufGetdelim(&diskName, &len, ' ', &diskNames)) { + char devPath[256]; + FF_AUTO_CLOSE_FD int f = opendisk(diskName, O_RDONLY, devPath, ARRAY_SIZE(devPath), 0); + if (f < 0) { + if (errno == EACCES) { + return "Permission denied; root required"; + } else { + continue; + } + } + + struct disklabel dl; + if (ioctl(f, DIOCGDINFO, &dl) < 0) { + continue; + } + + unsigned long sectorsPerUnit, sectorSize; + + const char* devType = NULL; + + prop_dictionary_t dict = NULL; + if (prop_dictionary_recv_ioctl(f, DIOCGDISKINFO, &dict) == 0) { + prop_dictionary_get_string(dict, "type", &devType); + + prop_dictionary_t geometry; + if (prop_dictionary_get_dict(dict, "geometry", &geometry)) { + prop_dictionary_get_ulong(geometry, "sectors-per-unit", §orsPerUnit); + prop_dictionary_get_ulong(geometry, "sector-size", §orSize); + } else { + sectorsPerUnit = dl.d_secperunit; + sectorSize = dl.d_secsize; + } + } else { + sectorsPerUnit = dl.d_secperunit; + sectorSize = dl.d_secsize; + } + + bool isVirtual = false; + switch (dl.d_type) { + case DKTYPE_VND: + case DKTYPE_LD: + case DKTYPE_RAID: + case DKTYPE_CGD: + case DKTYPE_VINUM: + case DKTYPE_DM: + case DKTYPE_RUMPD: + case DKTYPE_MD: + isVirtual = true; + } + + bool isUnknown = sectorsPerUnit == 0; + FFPhysicalDiskResult* device = (FFPhysicalDiskResult*) ffListAdd(result); + ffStrbufInitS(&device->name, devType ?: dl.d_packname); + ffStrbufInitS(&device->devPath, devPath); + ffStrbufInit(&device->serial); + ffStrbufInit(&device->revision); + ffStrbufInitS(&device->interconnect, dktypenames[dl.d_type]); + device->type = (!isVirtual ? FF_PHYSICALDISK_TYPE_NONE : FF_PHYSICALDISK_TYPE_VIRTUAL) | + (!isUnknown ? FF_PHYSICALDISK_TYPE_NONE : FF_PHYSICALDISK_TYPE_UNKNOWN) | + (dl.d_flags & D_REMOVABLE ? FF_PHYSICALDISK_TYPE_REMOVABLE : FF_PHYSICALDISK_TYPE_FIXED); + device->size = sectorsPerUnit * sectorSize; + device->temperature = FF_PHYSICALDISK_TEMP_UNSET; + + if (dict) { + prop_object_release(dict); + dict = NULL; + } + + struct scsipi_inquiry_data inquiry = {}; + scsireq_t req = { + .cmd = { [0] = INQUIRY, [4] = sizeof(inquiry) }, + .cmdlen = 6, + .databuf = (caddr_t) &inquiry, + .datalen = sizeof(inquiry), + .timeout = 1000, + .flags = SCCMD_READ, + }; + if (ioctl(f, SCIOCCOMMAND, &req) == 0 && req.retsts == SCCMD_OK) { + ffStrbufClear(&device->name); + ffStrbufAppendNS(&device->name, (uint32_t) ARRAY_SIZE(inquiry.vendor), inquiry.vendor); + ffStrbufTrimRight(&device->name, '\0'); + ffStrbufTrimRight(&device->name, ' '); + ffStrbufAppendC(&device->name, ' '); + ffStrbufAppendNS(&device->name, (uint32_t) ARRAY_SIZE(inquiry.product), inquiry.product); + ffStrbufTrimRight(&device->name, '\0'); + ffStrbufTrimRight(&device->name, ' '); + + ffStrbufSetNS(&device->revision, (uint32_t) ARRAY_SIZE(inquiry.revision), inquiry.revision); + ffStrbufTrimRight(&device->name, '\0'); + ffStrbufTrimRight(&device->revision, ' '); + } else { + continue; + } + + struct { + struct scsipi_inquiry_evpd_header header; + struct scsipi_inquiry_evpd_serial body; + } evpd = {}; + req = (scsireq_t) { + .cmd = { [0] = INQUIRY, [1] = SINQ_EVPD, [2] = SINQ_VPD_UNIT_SERIAL, [4] = sizeof(evpd) }, + .cmdlen = 6, + .databuf = (caddr_t) &evpd, + .datalen = sizeof(evpd), + .timeout = 1000, + .flags = SCCMD_READ, + }; + if (ioctl(f, SCIOCCOMMAND, &req) == 0 && req.retsts == SCCMD_OK && evpd.header.pagecode == SINQ_VPD_UNIT_SERIAL) { + for (uint8_t i = 0; i < evpd.header.length[1]; ++i) { + ffStrbufAppendF(&device->serial, "%02X", evpd.body.serial_number[i]); + } + ffStrbufTrimRight(&device->serial, ' '); + } + + struct scsi_mode_parameter_header_6 mode = {}; + req = (scsireq_t) { + .cmd = { [0] = SCSI_MODE_SENSE_6, [2] = SMS_PAGE_MASK, [4] = sizeof(mode) }, + .cmdlen = 6, + .databuf = (caddr_t) &mode, + .datalen = sizeof(mode), + .timeout = 1000, + .flags = SCCMD_READ, + }; + if (ioctl(f, SCIOCCOMMAND, &req) == 0 && req.retsts == SCCMD_OK && mode.data_length > 0) { + device->type |= mode.dev_spec & 0x80 ? FF_PHYSICALDISK_TYPE_READONLY : FF_PHYSICALDISK_TYPE_READWRITE; + } + } + + return NULL; +}