From fe89e712008d97277478bc03168df9a14385297c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Sun, 17 Sep 2023 20:08:46 +0800 Subject: [PATCH] Disk (Linux): try fixing zpool detection Ref: #559 --- src/detection/disk/disk.h | 1 + src/detection/disk/disk_bsd.c | 1 + src/detection/disk/disk_linux.c | 150 +++++++++++++------------------- src/modules/disk/disk.c | 24 +++-- 4 files changed, 78 insertions(+), 98 deletions(-) diff --git a/src/detection/disk/disk.h b/src/detection/disk/disk.h index fced34a92..3ccab52c4 100644 --- a/src/detection/disk/disk.h +++ b/src/detection/disk/disk.h @@ -7,6 +7,7 @@ typedef struct FFDisk { + FFstrbuf mountFrom; FFstrbuf mountpoint; FFstrbuf filesystem; FFstrbuf name; diff --git a/src/detection/disk/disk_bsd.c b/src/detection/disk/disk_bsd.c index efe98db9b..827ec32c2 100644 --- a/src/detection/disk/disk_bsd.c +++ b/src/detection/disk/disk_bsd.c @@ -78,6 +78,7 @@ const char* ffDetectDisksImpl(FFlist* disks) disk->filesTotal = (uint32_t) fs->f_files; disk->filesUsed = (uint32_t) (disk->filesTotal - (uint64_t)fs->f_ffree); + ffStrbufInitS(&disk->mountFrom, fs->f_mntfromname); ffStrbufInitS(&disk->mountpoint, fs->f_mntonname); ffStrbufInitS(&disk->filesystem, fs->f_fstypename); ffStrbufInit(&disk->name); diff --git a/src/detection/disk/disk_linux.c b/src/detection/disk/disk_linux.c index fb5597baa..0460cdfd1 100644 --- a/src/detection/disk/disk_linux.c +++ b/src/detection/disk/disk_linux.c @@ -7,6 +7,8 @@ #include #include #include +#include +#include #ifdef __USE_LARGEFILE64 #define stat stat64 @@ -15,74 +17,45 @@ #define readdir readdir64 #endif -static bool isPhysicalDevice(FFstrbuf* device) +static bool isPhysicalDevice(const struct mntent* device) { #ifndef __ANDROID__ //On Android, `/dev` is not accessable, so that the following checks always fail - //https://askubuntu.com/a/1289123 - if(ffStrbufEqualS(device, "/cow")) + //Always show the root path + if(ffStrEquals(device->mnt_dir, "/")) return true; //DrvFs is a filesystem plugin to WSL that was designed to support interop between WSL and the Windows filesystem. - if(ffStrbufEqualS(device, "drvfs")) + if(ffStrEquals(device->mnt_fsname, "drvfs")) return true; - //ZFS root pool. The format is rpool/// - if(ffStrbufStartsWithS(device, "rpool/")) + //ZFS pool + if(ffStrEquals(device->mnt_type, "zfs")) return true; + //Pseudo filesystems don't have a device in /dev + if(!ffStrStartsWith(device->mnt_fsname, "/dev/")) + return false; + + if( + ffStrStartsWith(device->mnt_fsname + 5, "loop") || //Ignore loop devices + ffStrStartsWith(device->mnt_fsname + 5, "ram") || //Ignore ram devices + ffStrStartsWith(device->mnt_fsname + 5, "fd") //Ignore fd devices + ) return false; + struct stat deviceStat; - if(stat(device->chars, &deviceStat) != 0) + if(stat(device->mnt_fsname, &deviceStat) != 0) return false; //Ignore all devices that are not block devices if(!S_ISBLK(deviceStat.st_mode)) return false; - //Pseudo filesystems don't have a device in /dev - if(!ffStrbufStartsWithS(device, "/dev/")) - return false; - #endif // __ANDROID__ - if( - ffStrbufStartsWithS(device, "/dev/loop") || //Ignore loop devices - ffStrbufStartsWithS(device, "/dev/ram") || //Ignore ram devices - ffStrbufStartsWithS(device, "/dev/fd") //Ignore fd devices - ) return false; - return true; } -static void appendNextEntry(FFstrbuf* buffer, char** source) -{ - //Read the current entry into the buffer - while(**source != '\0' && !isspace(**source)) - { - //After a backslash the next 3 characters are octal ascii codes - if(**source == '\\' && strnlen(*source, 4) == 4) - { - char octal[4] = {0}; - strncpy(octal, *source + 1, 3); - - long value = strtol(octal, NULL, 8); //Returns 0 on error, so no need to check endptr - if(value > 0 && value < CHAR_MAX) - { - ffStrbufAppendC(buffer, (char) value); - *source += 4; - continue; - } - } - - ffStrbufAppendC(buffer, **source); - ++*source; - } - - //Skip whitespace - while(isspace(**source)) - ++*source; -} - static void detectNameFromPath(FFDisk* disk, const struct stat* deviceStat, FFstrbuf* basePath) { DIR* dir = opendir(basePath->chars); @@ -114,10 +87,10 @@ static void detectNameFromPath(FFDisk* disk, const struct stat* deviceStat, FFst closedir(dir); } -static void detectName(FFDisk* disk, const FFstrbuf* device) +static void detectName(FFDisk* disk, const struct mntent* device) { struct stat deviceStat; - if(stat(device->chars, &deviceStat) != 0) + if(stat(device->mnt_fsname, &deviceStat) != 0) return; FF_STRBUF_AUTO_DESTROY basePath = ffStrbufCreate(); @@ -133,6 +106,8 @@ static void detectName(FFDisk* disk, const FFstrbuf* device) detectNameFromPath(disk, &deviceStat, &basePath); } + if (disk->name.length == 0) return; + // Basic\x20data\x20partition for (uint32_t i = ffStrbufFirstIndexS(&disk->name, "\\x"); i != disk->name.length; @@ -164,35 +139,46 @@ static void detectType(FF_MAYBE_UNUSED const FFlist* devices, FFDisk* currentDis #else -static bool isSubvolume(const FFlist* devices) +static bool isSubvolume(const FFlist* disks, FFDisk* currentDisk) { - const FFstrbuf* current = ffListGet(devices, devices->length - 1); - - if(ffStrbufEqualS(current, "drvfs")) // WSL Windows drives + if(ffStrbufEqualS(¤tDisk->mountFrom, "drvfs")) // WSL Windows drives return false; //Filter all disks which device was already found. This catches BTRFS subvolumes. - for(uint32_t i = 0; i < devices->length - 1; i++) + for(uint32_t i = 0; i < disks->length - 1; i++) { - const FFstrbuf* otherDevice = ffListGet(devices, i); + const FFDisk* otherDevice = ffListGet(disks, i); - if(ffStrbufEqual(current, otherDevice)) + if(ffStrbufEqual(¤tDisk->mountFrom, &otherDevice->mountFrom)) return true; } - //ZFS subvolumes: rpool///. - //Test if the third slash is present. - if(ffStrbufStartsWithS(current, "rpool/") && ffStrHasNChars(current->chars, '/', 3)) - return true; + if(ffStrbufEqualS(¤tDisk->filesystem, "zfs")) + { + //ZFS subvolumes + uint32_t index = ffStrbufFirstIndexC(¤tDisk->filesystem, '/'); + if (index == currentDisk->filesystem.length) + return false; + + FF_STRBUF_AUTO_DESTROY zpoolName = ffStrbufCreateNS(index, currentDisk->filesystem.chars); + for(uint32_t i = 0; i < disks->length - 1; i++) + { + const FFDisk* otherDevice = ffListGet(disks, i); + if(ffStrbufEqualS(&otherDevice->filesystem, "zfs") && ffStrbufStartsWith(&otherDevice->mountFrom, &zpoolName)) + return true; + } + + return false; + } return false; } -static void detectType(const FFlist* devices, FFDisk* currentDisk, const char* options) +static void detectType(const FFlist* disks, FFDisk* currentDisk, const struct mntent* options) { - if(isSubvolume(devices)) + if(isSubvolume(disks, currentDisk)) currentDisk->type = FF_DISK_VOLUME_TYPE_SUBVOLUME_BIT; - else if(strstr(options, "nosuid") != NULL || strstr(options, "nodev") != NULL) + else if(strstr(options->mnt_opts, MNTOPT_NOSUID) != NULL || strstr(options->mnt_opts, "nodev") != NULL) currentDisk->type = FF_DISK_VOLUME_TYPE_EXTERNAL_BIT; else if(ffStrbufStartsWithS(¤tDisk->mountpoint, "/boot") || ffStrbufStartsWithS(¤tDisk->mountpoint, "/efi")) currentDisk->type = FF_DISK_VOLUME_TYPE_HIDDEN_BIT; @@ -222,61 +208,43 @@ static void detectStats(FFDisk* disk) const char* ffDetectDisksImpl(FFlist* disks) { - FILE* mountsFile = fopen("/proc/mounts", "r"); + FILE* mountsFile = setmntent("/proc/mounts", "r"); if(mountsFile == NULL) - return "fopen(\"/proc/mounts\", \"r\") == NULL"; + return "setmntent(\"/proc/mounts\", \"r\") == NULL"; FF_LIST_AUTO_DESTROY devices = ffListCreate(sizeof(FFstrbuf)); - char* line = NULL; - size_t len = 0; + struct mntent* device; - while(getline(&line, &len, mountsFile) != EOF) + while((device = getmntent(mountsFile))) { - //Format of the file: " ..." (Same as fstab) - char* currentPos = line; - - //detect device - FFstrbuf* device = ffListAdd(&devices); - ffStrbufInit(device); - appendNextEntry(device, ¤tPos); - if(!isPhysicalDevice(device)) - { - ffStrbufDestroy(device); - devices.length--; continue; - } //We have a valid device, add it to the list FFDisk* disk = ffListAdd(disks); + //detect mountFrom + ffStrbufInitS(&disk->mountFrom, device->mnt_fsname); + //detect mountpoint - ffStrbufInit(&disk->mountpoint); - appendNextEntry(&disk->mountpoint, ¤tPos); + ffStrbufInitS(&disk->mountpoint, device->mnt_dir); //detect filesystem - ffStrbufInit(&disk->filesystem); - appendNextEntry(&disk->filesystem, ¤tPos); + ffStrbufInitS(&disk->filesystem, device->mnt_type); //detect name ffStrbufInit(&disk->name); detectName(disk, device); //detect type - detectType(&devices, disk, currentPos); + detectType(disks, disk, device); //Detects stats detectStats(disk); } - if(line != NULL) - free(line); - - FF_LIST_FOR_EACH(FFstrbuf, device, devices) - ffStrbufDestroy(device); - - fclose(mountsFile); + endmntent(mountsFile); return NULL; } diff --git a/src/modules/disk/disk.c b/src/modules/disk/disk.c index 4f74a380a..0dcd6d97c 100644 --- a/src/modules/disk/disk.c +++ b/src/modules/disk/disk.c @@ -194,6 +194,7 @@ void ffPrintDisk(FFDiskOptions* options) FF_LIST_FOR_EACH(FFDisk, disk, disks) { + ffStrbufDestroy(&disk->mountFrom); ffStrbufDestroy(&disk->mountpoint); ffStrbufDestroy(&disk->filesystem); ffStrbufDestroy(&disk->name); @@ -387,16 +388,24 @@ void ffGenerateDiskJson(FFDiskOptions* options, yyjson_mut_doc* doc, yyjson_mut_ FF_LIST_FOR_EACH(FFDisk, item, disks) { yyjson_mut_val* obj = yyjson_mut_arr_add_obj(doc, arr); - yyjson_mut_obj_add_uint(doc, obj, "bytesAvailable", item->bytesAvailable); - yyjson_mut_obj_add_uint(doc, obj, "bytesFree", item->bytesFree); - yyjson_mut_obj_add_uint(doc, obj, "bytesTotal", item->bytesTotal); - yyjson_mut_obj_add_uint(doc, obj, "bytesUsed", item->bytesUsed); - yyjson_mut_obj_add_uint(doc, obj, "filesTotal", item->filesTotal); - yyjson_mut_obj_add_uint(doc, obj, "filesUsed", item->filesUsed); - yyjson_mut_obj_add_strbuf(doc, obj, "filesystem", &item->filesystem); + + yyjson_mut_val* bytes = yyjson_mut_obj_add_obj(doc, obj, "bytes"); + yyjson_mut_obj_add_uint(doc, bytes, "available", item->bytesAvailable); + yyjson_mut_obj_add_uint(doc, bytes, "free", item->bytesFree); + yyjson_mut_obj_add_uint(doc, bytes, "total", item->bytesTotal); + yyjson_mut_obj_add_uint(doc, bytes, "used", item->bytesUsed); + + yyjson_mut_val* files = yyjson_mut_obj_add_obj(doc, obj, "files"); + yyjson_mut_obj_add_uint(doc, files, "total", item->filesTotal); + yyjson_mut_obj_add_uint(doc, files, "used", item->filesUsed); + + yyjson_mut_obj_add_strbuf(doc, files, "filesystem", &item->filesystem); yyjson_mut_obj_add_strbuf(doc, obj, "mountpoint", &item->mountpoint); + yyjson_mut_obj_add_strbuf(doc, obj, "mountFrom", &item->mountFrom); yyjson_mut_obj_add_strbuf(doc, obj, "name", &item->name); yyjson_mut_val* typeArr = yyjson_mut_obj_add_arr(doc, obj, "type"); + if(item->type & FF_DISK_VOLUME_TYPE_REGULAR_BIT) + yyjson_mut_arr_add_str(doc, typeArr, "Regular"); if(item->type & FF_DISK_VOLUME_TYPE_EXTERNAL_BIT) yyjson_mut_arr_add_str(doc, typeArr, "External"); if(item->type & FF_DISK_VOLUME_TYPE_SUBVOLUME_BIT) @@ -410,6 +419,7 @@ void ffGenerateDiskJson(FFDiskOptions* options, yyjson_mut_doc* doc, yyjson_mut_ FF_LIST_FOR_EACH(FFDisk, item, disks) { ffStrbufDestroy(&item->mountpoint); + ffStrbufDestroy(&item->mountFrom); ffStrbufDestroy(&item->filesystem); ffStrbufDestroy(&item->name); }