#include "disk.h" #include "common/io.h" #include "common/strutil.h" #include #include #include #include #include static bool isPhysicalDevice(const struct mnttab* device) { // Always show the root path if (ffStrEquals(device->mnt_mountp, "/")) { return true; } if (ffStrEquals(device->mnt_special, "none")) { return false; } // ZFS pool if (ffStrEquals(device->mnt_fstype, "zfs")) { return true; } // Pseudo filesystems don't have a device in /dev if (!ffStrStartsWith(device->mnt_special, "/dev/")) { return false; } struct stat deviceStat; if (stat(device->mnt_special, &deviceStat) != 0) { return false; } // Ignore all devices that are not block devices if (!S_ISBLK(deviceStat.st_mode)) { return false; } return true; } static bool isSubvolume(const FFlist* disks, FFDisk* currentDisk) { if (ffStrbufEqualS(¤tDisk->filesystem, "zfs")) { // ZFS subvolumes uint32_t index = ffStrbufFirstIndexC(¤tDisk->mountFrom, '/'); if (index == currentDisk->mountFrom.length) { return false; } FF_STRBUF_AUTO_DESTROY zpoolName = ffStrbufCreateNS(index, currentDisk->mountFrom.chars); for (uint32_t i = 0; i < disks->length - 1; i++) { const FFDisk* otherDevice = FF_LIST_GET(FFDisk, *disks, i); if (ffStrbufEqualS(&otherDevice->filesystem, "zfs") && ffStrbufStartsWith(&otherDevice->mountFrom, &zpoolName)) { return true; } } return false; } else { // Filter all disks which device was already found. This catches BTRFS subvolumes. for (uint32_t i = 0; i < disks->length - 1; i++) { const FFDisk* otherDevice = FF_LIST_GET(FFDisk, *disks, i); if (ffStrbufEqual(¤tDisk->mountFrom, &otherDevice->mountFrom)) { return true; } } } return false; } static void detectType(const FFlist* disks, FFDisk* currentDisk, struct mnttab* device) { if (hasmntopt(device, MNTOPT_NOBROWSE)) { currentDisk->type = FF_DISK_VOLUME_TYPE_HIDDEN_BIT; } else if (isSubvolume(disks, currentDisk)) { currentDisk->type = FF_DISK_VOLUME_TYPE_SUBVOLUME_BIT; } else { currentDisk->type = FF_DISK_VOLUME_TYPE_REGULAR_BIT; } if (hasmntopt(device, MNTOPT_RO)) { currentDisk->type |= FF_DISK_VOLUME_TYPE_READONLY_BIT; } } static void detectStats(FFDisk* disk) { struct statvfs fs; if (statvfs(disk->mountpoint.chars, &fs) != 0) { memset(&fs, 0, sizeof(fs)); } disk->bytesTotal = fs.f_blocks * fs.f_frsize; disk->bytesFree = fs.f_bfree * fs.f_frsize; disk->bytesAvailable = fs.f_bavail * fs.f_frsize; disk->bytesUsed = 0; // To be filled in ./disk.c disk->filesTotal = (uint32_t) fs.f_files; disk->filesUsed = (uint32_t) (disk->filesTotal - fs.f_ffree); ffStrbufSetS(&disk->name, fs.f_fstr); ffStrbufTrimRightSpace(&disk->name); disk->createTime = 0; } const char* ffDetectDisksImpl(FFDiskOptions* options, FFlist* disks) { FF_AUTO_CLOSE_FILE FILE* mountsFile = fopen(MNTTAB, "r"); if (mountsFile == NULL) { return "fopen(\"" MNTTAB "\", \"r\") == NULL"; } struct mnttab device; while (getmntent(mountsFile, &device) == 0) { if (__builtin_expect(options->folders.length, 0)) { if (!ffStrbufSeparatedContainS(&options->folders, device.mnt_mountp, FF_DISK_FOLDER_SEPARATOR)) { continue; } } else if (!isPhysicalDevice(&device)) { continue; } if (options->hideFolders.length && ffDiskMatchesFolderPatterns(&options->hideFolders, device.mnt_mountp, FF_DISK_FOLDER_SEPARATOR)) { continue; } if (options->hideFS.length && ffStrbufSeparatedContainS(&options->hideFS, device.mnt_fstype, ':')) { continue; } // We have a valid device, add it to the list FFDisk* disk = FF_LIST_ADD(FFDisk, *disks); disk->type = FF_DISK_VOLUME_TYPE_NONE; ffStrbufInitS(&disk->mountFrom, device.mnt_special); ffStrbufInitS(&disk->mountpoint, device.mnt_mountp); ffStrbufInitS(&disk->filesystem, device.mnt_fstype); ffStrbufInit(&disk->name); detectType(disks, disk, &device); detectStats(disk); } return NULL; }