master ohmu/fastfetch-openbsd / src / detection / physicaldisk / physicaldisk_bsd.c
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