|
| 1 | +#include "physicaldisk.h" |
| 2 | +#include "common/io.h" |
| 3 | +#include "common/sysctl.h" |
| 4 | + |
| 5 | +#include <util.h> |
| 6 | +#include <sys/ioctl.h> |
| 7 | +#include <sys/disklabel.h> |
| 8 | +#include <sys/dkio.h> |
| 9 | +#include <sys/scsiio.h> |
| 10 | +#include <scsi/scsi_all.h> |
| 11 | +#include <fcntl.h> |
| 12 | +#include <errno.h> |
| 13 | + |
| 14 | +const char* ffDetectPhysicalDisk(FFlist* result, FFPhysicalDiskOptions* options) { |
| 15 | + FF_STRBUF_AUTO_DESTROY diskNames = ffStrbufCreate(); |
| 16 | + const char* error = ffSysctlGetString(CTL_HW, HW_DISKNAMES, &diskNames); |
| 17 | + if (error) { |
| 18 | + return error; |
| 19 | + } |
| 20 | + |
| 21 | + char* diskName = NULL; |
| 22 | + size_t len = 0; |
| 23 | + while (ffStrbufGetdelim(&diskName, &len, ',', &diskNames)) { |
| 24 | + char* colon = strchr(diskName, ':'); |
| 25 | + if (colon) { |
| 26 | + *colon = '\0'; |
| 27 | + } |
| 28 | + |
| 29 | + char* devPath = NULL; |
| 30 | + bool readOnly = false; |
| 31 | + FF_AUTO_CLOSE_FD int f = opendev(diskName, O_RDWR, OPENDEV_PART, &devPath); |
| 32 | + if (f < 0) { |
| 33 | + if (errno == EACCES) { |
| 34 | + return "Permission denied; root required"; |
| 35 | + } else if (errno == EBUSY) { |
| 36 | + readOnly = true; |
| 37 | + f = opendev(diskName, O_RDONLY, OPENDEV_PART, &devPath); |
| 38 | + } |
| 39 | + } |
| 40 | + if (f < 0) continue; // Unknown error |
| 41 | + |
| 42 | + struct disklabel dl; |
| 43 | + if (ioctl(f, DIOCGPDINFO, &dl) < 0) { |
| 44 | + continue; |
| 45 | + } |
| 46 | + |
| 47 | + bool isVirtual = dl.d_type == DTYPE_VND || dl.d_type == DTYPE_RDROOT; |
| 48 | + bool isUnknown = dl.d_ncylinders == 0; |
| 49 | + FFPhysicalDiskResult* device = (FFPhysicalDiskResult*) ffListAdd(result); |
| 50 | + ffStrbufInitS(&device->name, dl.d_packname); |
| 51 | + ffStrbufInitS(&device->devPath, devPath); |
| 52 | + ffStrbufInit(&device->serial); |
| 53 | + ffStrbufInit(&device->revision); |
| 54 | + ffStrbufInitS(&device->interconnect, dl.d_typename); |
| 55 | + device->type = (!isVirtual ? FF_PHYSICALDISK_TYPE_NONE : FF_PHYSICALDISK_TYPE_VIRTUAL) | |
| 56 | + (!isUnknown ? FF_PHYSICALDISK_TYPE_NONE : FF_PHYSICALDISK_TYPE_UNKNOWN) | |
| 57 | + (!readOnly ? FF_PHYSICALDISK_TYPE_READWRITE : FF_PHYSICALDISK_TYPE_READONLY); |
| 58 | + device->size = DL_GETDSIZE(&dl) * dl.d_secsize; |
| 59 | + device->temperature = FF_PHYSICALDISK_TEMP_UNSET; |
| 60 | + |
| 61 | + struct scsi_inquiry_data inquiry; |
| 62 | + if (ioctl(f, SCIOCCOMMAND, &(struct scsireq) { |
| 63 | + .cmd = { [0] = INQUIRY, [4] = sizeof(inquiry) }, |
| 64 | + .cmdlen = 6, |
| 65 | + .databuf = (caddr_t) &inquiry, |
| 66 | + .datalen = sizeof(inquiry), |
| 67 | + .timeout = 1000, |
| 68 | + .flags = SCCMD_READ, |
| 69 | + }) == 0) { |
| 70 | + ffStrbufClear(&device->name); |
| 71 | + ffStrbufAppendNS(&device->name, (uint32_t) ARRAY_SIZE(inquiry.vendor), inquiry.vendor); |
| 72 | + ffStrbufTrimRight(&device->name, ' '); |
| 73 | + ffStrbufAppendC(&device->name, ' '); |
| 74 | + ffStrbufAppendNS(&device->name, (uint32_t) ARRAY_SIZE(inquiry.product), inquiry.product); |
| 75 | + ffStrbufTrimRight(&device->name, ' '); |
| 76 | + ffStrbufSetS(&device->revision, inquiry.revision); |
| 77 | + ffStrbufTrimRight(&device->revision, ' '); |
| 78 | + device->type |= inquiry.dev_qual2 & SID_REMOVABLE ? FF_PHYSICALDISK_TYPE_REMOVABLE : FF_PHYSICALDISK_TYPE_FIXED; |
| 79 | + } |
| 80 | + |
| 81 | + struct scsi_vpd_serial vpdSerial; |
| 82 | + if (ioctl(f, SCIOCCOMMAND, &(struct scsireq) { |
| 83 | + .cmd = { [0] = INQUIRY, [1] = SI_EVPD, [2] = SI_PG_SERIAL, [4] = sizeof(vpdSerial) }, |
| 84 | + .cmdlen = 6, |
| 85 | + .databuf = (caddr_t) &vpdSerial, |
| 86 | + .datalen = sizeof(vpdSerial), |
| 87 | + .timeout = 1000, |
| 88 | + .flags = SCCMD_READ, |
| 89 | + }) == 0 && vpdSerial.hdr.page_code == SI_PG_SERIAL) { |
| 90 | + ffStrbufSetNS(&device->serial, vpdSerial.hdr.page_length[1], vpdSerial.serial); |
| 91 | + ffStrbufTrimSpace(&device->serial); |
| 92 | + } |
| 93 | + } |
| 94 | + |
| 95 | + return NULL; |
| 96 | +} |
0 commit comments