|
| 1 | +#define DKTYPENAMES |
| 2 | +#include "physicaldisk.h" |
| 3 | +#include "common/io.h" |
| 4 | +#include "common/sysctl.h" |
| 5 | + |
| 6 | +#include <util.h> |
| 7 | +#include <prop/proplib.h> |
| 8 | +#include <sys/ioctl.h> |
| 9 | +#include <sys/disklabel.h> |
| 10 | +#include <sys/dkio.h> |
| 11 | +#include <sys/scsiio.h> |
| 12 | +#include <dev/scsipi/scsipi_all.h> |
| 13 | +#include <dev/scsipi/scsi_spc.h> |
| 14 | +#include <fcntl.h> |
| 15 | +#include <errno.h> |
| 16 | + |
| 17 | +const char* ffDetectPhysicalDisk(FFlist* result, FFPhysicalDiskOptions* options) { |
| 18 | + FF_STRBUF_AUTO_DESTROY diskNames = ffStrbufCreate(); |
| 19 | + const char* error = ffSysctlGetString("hw.disknames", &diskNames); |
| 20 | + if (error) { |
| 21 | + return error; |
| 22 | + } |
| 23 | + |
| 24 | + char* diskName = NULL; |
| 25 | + size_t len = 0; |
| 26 | + while (ffStrbufGetdelim(&diskName, &len, ' ', &diskNames)) { |
| 27 | + char devPath[256]; |
| 28 | + FF_AUTO_CLOSE_FD int f = opendisk(diskName, O_RDONLY, devPath, ARRAY_SIZE(devPath), 0); |
| 29 | + if (f < 0) { |
| 30 | + if (errno == EACCES) { |
| 31 | + return "Permission denied; root required"; |
| 32 | + } else { |
| 33 | + continue; |
| 34 | + } |
| 35 | + } |
| 36 | + |
| 37 | + struct disklabel dl; |
| 38 | + if (ioctl(f, DIOCGDINFO, &dl) < 0) { |
| 39 | + continue; |
| 40 | + } |
| 41 | + |
| 42 | + unsigned long sectorsPerUnit, sectorSize; |
| 43 | + |
| 44 | + const char* devType = NULL; |
| 45 | + |
| 46 | + prop_dictionary_t dict = NULL; |
| 47 | + if (prop_dictionary_recv_ioctl(f, DIOCGDISKINFO, &dict) == 0) { |
| 48 | + prop_dictionary_get_string(dict, "type", &devType); |
| 49 | + |
| 50 | + prop_dictionary_t geometry; |
| 51 | + if (prop_dictionary_get_dict(dict, "geometry", &geometry)) { |
| 52 | + prop_dictionary_get_ulong(geometry, "sectors-per-unit", §orsPerUnit); |
| 53 | + prop_dictionary_get_ulong(geometry, "sector-size", §orSize); |
| 54 | + } else { |
| 55 | + sectorsPerUnit = dl.d_secperunit; |
| 56 | + sectorSize = dl.d_secsize; |
| 57 | + } |
| 58 | + } else { |
| 59 | + sectorsPerUnit = dl.d_secperunit; |
| 60 | + sectorSize = dl.d_secsize; |
| 61 | + } |
| 62 | + |
| 63 | + bool isVirtual = false; |
| 64 | + switch (dl.d_type) { |
| 65 | + case DKTYPE_VND: |
| 66 | + case DKTYPE_LD: |
| 67 | + case DKTYPE_RAID: |
| 68 | + case DKTYPE_CGD: |
| 69 | + case DKTYPE_VINUM: |
| 70 | + case DKTYPE_DM: |
| 71 | + case DKTYPE_RUMPD: |
| 72 | + case DKTYPE_MD: |
| 73 | + isVirtual = true; |
| 74 | + } |
| 75 | + |
| 76 | + bool isUnknown = sectorsPerUnit == 0; |
| 77 | + FFPhysicalDiskResult* device = (FFPhysicalDiskResult*) ffListAdd(result); |
| 78 | + ffStrbufInitS(&device->name, devType ?: dl.d_packname); |
| 79 | + ffStrbufInitS(&device->devPath, devPath); |
| 80 | + ffStrbufInit(&device->serial); |
| 81 | + ffStrbufInit(&device->revision); |
| 82 | + ffStrbufInitS(&device->interconnect, dktypenames[dl.d_type]); |
| 83 | + device->type = (!isVirtual ? FF_PHYSICALDISK_TYPE_NONE : FF_PHYSICALDISK_TYPE_VIRTUAL) | |
| 84 | + (!isUnknown ? FF_PHYSICALDISK_TYPE_NONE : FF_PHYSICALDISK_TYPE_UNKNOWN) | |
| 85 | + (dl.d_flags & D_REMOVABLE ? FF_PHYSICALDISK_TYPE_REMOVABLE : FF_PHYSICALDISK_TYPE_FIXED); |
| 86 | + device->size = sectorsPerUnit * sectorSize; |
| 87 | + device->temperature = FF_PHYSICALDISK_TEMP_UNSET; |
| 88 | + |
| 89 | + if (dict) { |
| 90 | + prop_object_release(dict); |
| 91 | + dict = NULL; |
| 92 | + } |
| 93 | + |
| 94 | + struct scsipi_inquiry_data inquiry = {}; |
| 95 | + scsireq_t req = { |
| 96 | + .cmd = { [0] = INQUIRY, [4] = sizeof(inquiry) }, |
| 97 | + .cmdlen = 6, |
| 98 | + .databuf = (caddr_t) &inquiry, |
| 99 | + .datalen = sizeof(inquiry), |
| 100 | + .timeout = 1000, |
| 101 | + .flags = SCCMD_READ, |
| 102 | + }; |
| 103 | + if (ioctl(f, SCIOCCOMMAND, &req) == 0 && req.retsts == SCCMD_OK) { |
| 104 | + ffStrbufClear(&device->name); |
| 105 | + ffStrbufAppendNS(&device->name, (uint32_t) ARRAY_SIZE(inquiry.vendor), inquiry.vendor); |
| 106 | + ffStrbufTrimRight(&device->name, '\0'); |
| 107 | + ffStrbufTrimRight(&device->name, ' '); |
| 108 | + ffStrbufAppendC(&device->name, ' '); |
| 109 | + ffStrbufAppendNS(&device->name, (uint32_t) ARRAY_SIZE(inquiry.product), inquiry.product); |
| 110 | + ffStrbufTrimRight(&device->name, '\0'); |
| 111 | + ffStrbufTrimRight(&device->name, ' '); |
| 112 | + |
| 113 | + ffStrbufSetNS(&device->revision, (uint32_t) ARRAY_SIZE(inquiry.revision), inquiry.revision); |
| 114 | + ffStrbufTrimRight(&device->name, '\0'); |
| 115 | + ffStrbufTrimRight(&device->revision, ' '); |
| 116 | + } else { |
| 117 | + continue; |
| 118 | + } |
| 119 | + |
| 120 | + struct { |
| 121 | + struct scsipi_inquiry_evpd_header header; |
| 122 | + struct scsipi_inquiry_evpd_serial body; |
| 123 | + } evpd = {}; |
| 124 | + req = (scsireq_t) { |
| 125 | + .cmd = { [0] = INQUIRY, [1] = SINQ_EVPD, [2] = SINQ_VPD_UNIT_SERIAL, [4] = sizeof(evpd) }, |
| 126 | + .cmdlen = 6, |
| 127 | + .databuf = (caddr_t) &evpd, |
| 128 | + .datalen = sizeof(evpd), |
| 129 | + .timeout = 1000, |
| 130 | + .flags = SCCMD_READ, |
| 131 | + }; |
| 132 | + if (ioctl(f, SCIOCCOMMAND, &req) == 0 && req.retsts == SCCMD_OK && evpd.header.pagecode == SINQ_VPD_UNIT_SERIAL) { |
| 133 | + for (uint8_t i = 0; i < evpd.header.length[1]; ++i) { |
| 134 | + ffStrbufAppendF(&device->serial, "%02X", evpd.body.serial_number[i]); |
| 135 | + } |
| 136 | + ffStrbufTrimRight(&device->serial, ' '); |
| 137 | + } |
| 138 | + |
| 139 | + struct scsi_mode_parameter_header_6 mode = {}; |
| 140 | + req = (scsireq_t) { |
| 141 | + .cmd = { [0] = SCSI_MODE_SENSE_6, [2] = SMS_PAGE_MASK, [4] = sizeof(mode) }, |
| 142 | + .cmdlen = 6, |
| 143 | + .databuf = (caddr_t) &mode, |
| 144 | + .datalen = sizeof(mode), |
| 145 | + .timeout = 1000, |
| 146 | + .flags = SCCMD_READ, |
| 147 | + }; |
| 148 | + if (ioctl(f, SCIOCCOMMAND, &req) == 0 && req.retsts == SCCMD_OK && mode.data_length > 0) { |
| 149 | + device->type |= mode.dev_spec & 0x80 ? FF_PHYSICALDISK_TYPE_READONLY : FF_PHYSICALDISK_TYPE_READWRITE; |
| 150 | + } |
| 151 | + } |
| 152 | + |
| 153 | + return NULL; |
| 154 | +} |
0 commit comments