ohmu
·
2026-10-15
1#include "disk.h"
2#include "common/io.h"
3#include "common/strutil.h"
4
5#include <sys/mntent.h>
6#include <sys/stat.h>
7#include <sys/statvfs.h>
8#include <sys/mount.h>
9#include <sys/mnttab.h>
10
11static bool isPhysicalDevice(const struct mnttab* device) {
12 // Always show the root path
13 if (ffStrEquals(device->mnt_mountp, "/")) {
14 return true;
15 }
16
17 if (ffStrEquals(device->mnt_special, "none")) {
18 return false;
19 }
20
21 // ZFS pool
22 if (ffStrEquals(device->mnt_fstype, "zfs")) {
23 return true;
24 }
25
26 // Pseudo filesystems don't have a device in /dev
27 if (!ffStrStartsWith(device->mnt_special, "/dev/")) {
28 return false;
29 }
30
31 struct stat deviceStat;
32 if (stat(device->mnt_special, &deviceStat) != 0) {
33 return false;
34 }
35
36 // Ignore all devices that are not block devices
37 if (!S_ISBLK(deviceStat.st_mode)) {
38 return false;
39 }
40
41 return true;
42}
43
44static bool isSubvolume(const FFlist* disks, FFDisk* currentDisk) {
45 if (ffStrbufEqualS(¤tDisk->filesystem, "zfs")) {
46 // ZFS subvolumes
47 uint32_t index = ffStrbufFirstIndexC(¤tDisk->mountFrom, '/');
48 if (index == currentDisk->mountFrom.length) {
49 return false;
50 }
51
52 FF_STRBUF_AUTO_DESTROY zpoolName = ffStrbufCreateNS(index, currentDisk->mountFrom.chars);
53 for (uint32_t i = 0; i < disks->length - 1; i++) {
54 const FFDisk* otherDevice = FF_LIST_GET(FFDisk, *disks, i);
55 if (ffStrbufEqualS(&otherDevice->filesystem, "zfs") && ffStrbufStartsWith(&otherDevice->mountFrom, &zpoolName)) {
56 return true;
57 }
58 }
59
60 return false;
61 } else {
62 // Filter all disks which device was already found. This catches BTRFS subvolumes.
63 for (uint32_t i = 0; i < disks->length - 1; i++) {
64 const FFDisk* otherDevice = FF_LIST_GET(FFDisk, *disks, i);
65
66 if (ffStrbufEqual(¤tDisk->mountFrom, &otherDevice->mountFrom)) {
67 return true;
68 }
69 }
70 }
71
72 return false;
73}
74
75static void detectType(const FFlist* disks, FFDisk* currentDisk, struct mnttab* device) {
76 if (hasmntopt(device, MNTOPT_NOBROWSE)) {
77 currentDisk->type = FF_DISK_VOLUME_TYPE_HIDDEN_BIT;
78 } else if (isSubvolume(disks, currentDisk)) {
79 currentDisk->type = FF_DISK_VOLUME_TYPE_SUBVOLUME_BIT;
80 } else {
81 currentDisk->type = FF_DISK_VOLUME_TYPE_REGULAR_BIT;
82 }
83 if (hasmntopt(device, MNTOPT_RO)) {
84 currentDisk->type |= FF_DISK_VOLUME_TYPE_READONLY_BIT;
85 }
86}
87
88static void detectStats(FFDiskOptions* options, FFDisk* disk) {
89 struct statvfs fs;
90 if (statvfs(disk->mountpoint.chars, &fs) != 0) {
91 memset(&fs, 0, sizeof(fs));
92 }
93
94 disk->bytesTotal = fs.f_blocks * fs.f_frsize;
95 disk->bytesFree = (options->calcType == FF_DISK_CALC_TYPE_FREE ? fs.f_bfree : fs.f_bavail) * fs.f_frsize;
96
97 disk->filesTotal = (uint32_t) fs.f_files;
98 disk->filesUsed = (uint32_t) (disk->filesTotal - fs.f_ffree);
99
100 ffStrbufSetS(&disk->name, fs.f_fstr);
101 ffStrbufTrimRightSpace(&disk->name);
102
103 disk->createTime = 0;
104}
105
106const char* ffDetectDisksImpl(FFDiskOptions* options, FFlist* disks) {
107 FF_AUTO_CLOSE_FILE FILE* mountsFile = fopen(MNTTAB, "r");
108 if (mountsFile == nullptr) {
109 return "fopen(\"" MNTTAB "\", \"r\") == nullptr";
110 }
111
112 struct mnttab device;
113
114 while (getmntent(mountsFile, &device) == 0) {
115 if (__builtin_expect(options->folders.length, 0)) {
116 if (!ffStrbufSeparatedContainS(&options->folders, device.mnt_mountp, FF_DISK_FOLDER_SEPARATOR)) {
117 continue;
118 }
119 } else if (!isPhysicalDevice(&device)) {
120 continue;
121 }
122
123 if (options->hideFolders.length && ffDiskMatchesFolderPatterns(&options->hideFolders, device.mnt_mountp, FF_DISK_FOLDER_SEPARATOR)) {
124 continue;
125 }
126
127 if (options->hideFS.length && ffStrbufSeparatedContainS(&options->hideFS, device.mnt_fstype, ':')) {
128 continue;
129 }
130
131 // We have a valid device, add it to the list
132 FFDisk* disk = FF_LIST_ADD(FFDisk, *disks);
133 disk->type = FF_DISK_VOLUME_TYPE_NONE;
134 ffStrbufInitS(&disk->mountFrom, device.mnt_special);
135 ffStrbufInitS(&disk->mountpoint, device.mnt_mountp);
136 ffStrbufInitS(&disk->filesystem, device.mnt_fstype);
137 ffStrbufInit(&disk->name);
138 detectType(disks, disk, &device);
139 detectStats(options, disk);
140 }
141
142 return nullptr;
143}