ohmu
·
2026-10-15
1#include "physicaldisk.h"
2
3#if __has_include(<libgeom.h>)
4
5 #include "common/debug.h"
6 #include "common/strutil.h"
7
8 #include <devstat.h>
9 #include <memory.h>
10 #include <fcntl.h>
11 #include <sys/ioctl.h>
12 #include <sys/disk.h>
13 #include <libgeom.h>
14
15const char* ffDetectPhysicalDisk(FFlist* result, FFPhysicalDiskOptions* options) {
16 struct gmesh geomTree;
17 if (geom_gettree(&geomTree) < 0) {
18 FF_DEBUG("geom_gettree() failed");
19 return "geom_gettree() failed";
20 }
21
22 if (geom_stats_open() < 0) {
23 FF_DEBUG("geom_stats_open() failed");
24 return "geom_stats_open() failed";
25 }
26
27 void* snap = geom_stats_snapshot_get();
28 struct devstat* snapIter;
29 while ((snapIter = geom_stats_snapshot_next(snap)) != nullptr) {
30 if (snapIter->device_type & DEVSTAT_TYPE_PASS) {
31 continue;
32 }
33 struct gident* geomId = geom_lookupid(&geomTree, snapIter->id);
34 if (geomId == nullptr) {
35 continue;
36 }
37 if (geomId->lg_what != ISPROVIDER) {
38 continue;
39 }
40 struct gprovider* provider = (struct gprovider*) geomId->lg_ptr;
41 if (provider->lg_geom->lg_rank != 1) {
42 continue;
43 }
44
45 FFPhysicalDiskType type = FF_PHYSICALDISK_TYPE_NONE;
46 if (!ffStrEquals(provider->lg_geom->lg_class->lg_name, "DISK")) {
47 if (options->hideType & FF_PHYSICALDISK_TYPE_VIRTUAL) {
48 continue;
49 }
50
51 type |= FF_PHYSICALDISK_TYPE_VIRTUAL;
52 }
53 uint64_t size = (uint64_t) provider->lg_mediasize;
54 if (size == 0) {
55 if (options->hideType & FF_PHYSICALDISK_TYPE_UNUSED) {
56 continue;
57 }
58
59 type |= FF_PHYSICALDISK_TYPE_UNUSED;
60 }
61
62 FF_STRBUF_AUTO_DESTROY name = ffStrbufCreateS(provider->lg_name);
63 FF_STRBUF_AUTO_DESTROY identifier = ffStrbufCreate();
64 for (struct gconfig* ptr = provider->lg_config.lh_first; ptr; ptr = ptr->lg_config.le_next) {
65 if (ffStrEquals(ptr->lg_name, "descr")) {
66 ffStrbufSetS(&name, ptr->lg_val);
67 } else if (ffStrEquals(ptr->lg_name, "rotationrate") && !ffStrEquals(ptr->lg_val, "unknown")) {
68 type |= ffStrEquals(ptr->lg_val, "0") ? FF_PHYSICALDISK_TYPE_SSD : FF_PHYSICALDISK_TYPE_HDD;
69 } else if (ffStrEquals(ptr->lg_name, "ident")) {
70 ffStrbufSetS(&identifier, ptr->lg_val);
71 } else if (ffStrEquals(ptr->lg_name, "access")) {
72 if (ffStrEquals(ptr->lg_val, "read-only")) {
73 type |= FF_PHYSICALDISK_TYPE_READONLY;
74 } else if (ffStrEquals(ptr->lg_val, "read-write")) {
75 type |= FF_PHYSICALDISK_TYPE_READWRITE;
76 }
77 }
78 }
79
80 if (options->namePrefix.length && !ffStrbufStartsWith(&name, &options->namePrefix)) {
81 continue;
82 }
83
84 FFPhysicalDiskResult* device = FF_LIST_ADD(FFPhysicalDiskResult, *result);
85 ffStrbufInitF(&device->devPath, "/dev/%s", provider->lg_name);
86 ffStrbufInitMove(&device->serial, &identifier);
87 ffStrbufTrimSpace(&device->serial);
88 ffStrbufInit(&device->revision);
89 ffStrbufInit(&device->interconnect);
90 ffStrbufInitMove(&device->name, &name);
91 device->size = size;
92 device->temperature = FF_PHYSICALDISK_TEMP_UNSET;
93
94 switch (snapIter->device_type & DEVSTAT_TYPE_IF_MASK) {
95 case DEVSTAT_TYPE_IF_SCSI:
96 ffStrbufSetStatic(&device->interconnect, "SCSI");
97 break;
98 case DEVSTAT_TYPE_IF_IDE:
99 ffStrbufSetStatic(&device->interconnect, "IDE");
100 break;
101 case DEVSTAT_TYPE_IF_OTHER:
102 ffStrbufSetStatic(&device->interconnect, "OTHER");
103 break;
104
105 // https://github.com/freebsd/freebsd-src/commit/d282baddb0b029ca8466d23ac51e95c918442535
106 case 0x040 /*DEVSTAT_TYPE_IF_NVME*/:
107 ffStrbufSetStatic(&device->interconnect, "NVMe");
108 break;
109 }
110
111 if (!(device->type & FF_PHYSICALDISK_TYPE_READONLY) && !(device->type & FF_PHYSICALDISK_TYPE_READWRITE)) {
112 int acr = 1, acw = 1; // Number of partitions mounted for reading or writing
113 if (sscanf(provider->lg_mode, "r%dw%de%*d", &acr, &acw) == 2 && acr) {
114 type |= acw ? FF_PHYSICALDISK_TYPE_READWRITE : FF_PHYSICALDISK_TYPE_READONLY;
115 }
116 }
117
118 device->type = type;
119 }
120
121 geom_stats_snapshot_free(snap);
122 geom_stats_close();
123
124 return nullptr;
125}
126#else
127const char* ffDetectPhysicalDisk(FFlist* result, FFPhysicalDiskOptions* options) {
128 FF_UNUSED(result, options);
129 return "Fastfetch was compiled without libgeom support";
130}
131#endif