ohmu
·
2026-10-15
1#include "physicaldisk.h"
2
3#include "common/debug.h"
4#include "common/io.h"
5#include "common/strutil.h"
6
7#include <OS.h>
8#include <StorageDefs.h>
9#include <Drivers.h>
10#include <sys/ioctl.h>
11
12static const char* searchRawDeviceFile(FFstrbuf* path, const char* diskType, FFlist* result, FFPhysicalDiskOptions* options) {
13 FF_AUTO_CLOSE_DIR DIR* dir = opendir(path->chars);
14 if (!dir) {
15 FF_DEBUG("opendir(\"%s\") failed: %s", path->chars, strerror(errno));
16 return "detectDiskType: opendir() failed";
17 }
18 uint32_t baseLen = path->length;
19
20 struct dirent* entry;
21 while ((entry = readdir(dir))) {
22 if (entry->d_name[0] == '.') {
23 continue;
24 }
25 ffStrbufAppendC(path, '/');
26 ffStrbufAppendS(path, entry->d_name);
27
28 struct stat st;
29 if (stat(path->chars, &st) != 0) {
30 ffStrbufSubstrBefore(path, baseLen);
31 continue;
32 }
33
34 if (S_ISDIR(st.st_mode)) {
35 searchRawDeviceFile(path, diskType, result, options);
36 } else if (ffStrEquals(entry->d_name, "raw")) {
37 FF_AUTO_CLOSE_FD int rawfd = open(path->chars, O_RDONLY | O_CLOEXEC);
38 if (rawfd < 0) {
39 continue;
40 }
41
42 device_geometry geometry;
43 if (ioctl(rawfd, B_GET_GEOMETRY, &geometry, sizeof(geometry)) < 0) {
44 continue;
45 }
46
47 char name[B_OS_NAME_LENGTH];
48 if (ioctl(rawfd, B_GET_DEVICE_NAME, name, sizeof(name)) != 0) {
49 // ioctl reports `not a tty` for NVME drives for some reason
50 snprintf(name, sizeof(name), "Unknown %s drive", diskType);
51 }
52
53 if (options->namePrefix.length && strncmp(name, options->namePrefix.chars, options->namePrefix.length) != 0) {
54 continue;
55 }
56
57 FFPhysicalDiskType type = FF_PHYSICALDISK_TYPE_NONE;
58 uint64_t size = (uint64_t) geometry.cylinder_count * geometry.head_count * geometry.sectors_per_track * geometry.bytes_per_sector;
59 if (size == 0) {
60 if (options->hideType & FF_PHYSICALDISK_TYPE_UNUSED) {
61 continue;
62 }
63
64 type |= FF_PHYSICALDISK_TYPE_UNUSED;
65 }
66
67 FFPhysicalDiskResult* device = FF_LIST_ADD(FFPhysicalDiskResult, *result);
68 ffStrbufInitS(&device->name, name);
69 ffStrbufInitCopy(&device->devPath, path);
70 ffStrbufInit(&device->serial);
71 ffStrbufInit(&device->revision);
72 ffStrbufInitS(&device->interconnect, diskType);
73 device->temperature = FF_PHYSICALDISK_TEMP_UNSET;
74 device->type = type |
75 (geometry.read_only ? FF_PHYSICALDISK_TYPE_READONLY : FF_PHYSICALDISK_TYPE_READWRITE) |
76 (geometry.removable ? FF_PHYSICALDISK_TYPE_REMOVABLE : FF_PHYSICALDISK_TYPE_FIXED);
77 device->size = size;
78 }
79
80 ffStrbufSubstrBefore(path, baseLen);
81 }
82 return nullptr;
83}
84
85const char* ffDetectPhysicalDisk(FFlist* result, FFPhysicalDiskOptions* options) {
86 FF_AUTO_CLOSE_DIR DIR* dir = opendir("/dev/disk");
87 if (!dir) {
88 FF_DEBUG("opendir(\"/dev/disk\") failed: %s", strerror(errno));
89 return "opendir(/dev/disk) failed";
90 }
91
92 FF_STRBUF_AUTO_DESTROY path = ffStrbufCreateA(64);
93 ffStrbufAppendS(&path, "/dev/disk/");
94 uint32_t baseLen = path.length;
95
96 struct dirent* entry;
97 while ((entry = readdir(dir))) {
98 if (entry->d_name[0] == '.' || ffStrEquals(entry->d_name, "virtual")) {
99 continue;
100 }
101 ffStrbufAppendS(&path, entry->d_name);
102 searchRawDeviceFile(&path, entry->d_name, result, options);
103 ffStrbufSubstrBefore(&path, baseLen);
104 }
105
106 return nullptr;
107}