mirror of
https://github.com/fastfetch-cli/fastfetch.git
synced 2026-09-13 10:52:08 +02:00
Merge pull request #305 from LinusDierheimer/work/disk_refactor
Work/disk refactor
This commit is contained in:
+1
-1
@@ -241,6 +241,7 @@ set(LIBFASTFETCH_SRC
|
||||
src/detection/terminalshell/terminalshell.c
|
||||
src/detection/media/media.c
|
||||
src/detection/packages/packages.c
|
||||
src/detection/disk/disk.c
|
||||
src/modules/break.c
|
||||
src/modules/custom.c
|
||||
src/modules/title.c
|
||||
@@ -291,7 +292,6 @@ if(LINUX OR APPLE OR ANDROID OR BSD)
|
||||
list(APPEND LIBFASTFETCH_SRC
|
||||
src/common/processing_linux.c
|
||||
src/detection/users/users_linux.c
|
||||
src/detection/disk/disk.c
|
||||
src/detection/terminalshell/terminalshell_linux.c
|
||||
src/detection/localip/localip_linux.c
|
||||
)
|
||||
|
||||
@@ -188,6 +188,8 @@ __fastfetch_completion()
|
||||
"--pipe"
|
||||
"--title-fqdn"
|
||||
"--escape-bedrock"
|
||||
"--disk-show-removable"
|
||||
"--disk-show-hidden"
|
||||
)
|
||||
|
||||
local FF_OPTIONS_STRING=(
|
||||
|
||||
+1
-1
@@ -19,7 +19,7 @@
|
||||
--cpu-usage-format Percentage: {}
|
||||
--gpu-format Vendor: {}; Name: {}; Driver: {}; Temperature: {}; CoreCount: {}
|
||||
--memory-format Used: {}; Total: {}; Percentage: {}
|
||||
--disk-format Used: {}; Total: {}; Files: {}; Percentage: {}
|
||||
--disk-format SizeUsed: {}; SizeTotal: {}; SizePercentage: {}; FilesUsed: {}; FilesTotal: {}; FilesPercentage: {}; Removable: {}; Hidden: {}; Filesystem: {}
|
||||
--battery-format Manufactor: {}; Model: {}; Technology: {}; Capacity: {}; Status: {}
|
||||
--poweradapter-format Watts: {}; Name: {}; Manufactor: {}; Model: {}; Description: {}
|
||||
--player-format Pretty: {}; Name: {}; Bus: {}; Url: {}
|
||||
|
||||
+4
-1
@@ -20,6 +20,8 @@ void ffFormatAppendFormatArg(FFstrbuf* buffer, const FFformatarg* formatarg)
|
||||
ffStrbufAppend(buffer, (FFstrbuf*)formatarg->value);
|
||||
else if(formatarg->type == FF_FORMAT_ARG_TYPE_DOUBLE)
|
||||
ffStrbufAppendF(buffer, "%g", *(double*)formatarg->value);
|
||||
else if(formatarg->type == FF_FORMAT_ARG_TYPE_BOOL)
|
||||
ffStrbufAppendS(buffer, formatarg->value != NULL ? "true" : "false");
|
||||
else if(formatarg->type == FF_FORMAT_ARG_TYPE_LIST)
|
||||
{
|
||||
const FFlist* list = formatarg->value;
|
||||
@@ -74,7 +76,8 @@ static inline bool formatArgSet(const FFformatarg* arg)
|
||||
(arg->type == FF_FORMAT_ARG_TYPE_STRING && ffStrSet(arg->value)) ||
|
||||
(arg->type == FF_FORMAT_ARG_TYPE_UINT8 && *(uint8_t*)arg->value > 0) ||
|
||||
(arg->type == FF_FORMAT_ARG_TYPE_UINT16 && *(uint16_t*)arg->value > 0) ||
|
||||
(arg->type == FF_FORMAT_ARG_TYPE_UINT && *(uint32_t*)arg->value > 0)
|
||||
(arg->type == FF_FORMAT_ARG_TYPE_UINT && *(uint32_t*)arg->value > 0) ||
|
||||
(arg->type == FF_FORMAT_ARG_TYPE_BOOL && arg->value != NULL)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
+4
-1
@@ -13,7 +13,8 @@ typedef enum FFformatargtype
|
||||
FF_FORMAT_ARG_TYPE_STRING,
|
||||
FF_FORMAT_ARG_TYPE_STRBUF,
|
||||
FF_FORMAT_ARG_TYPE_DOUBLE,
|
||||
FF_FORMAT_ARG_TYPE_LIST
|
||||
FF_FORMAT_ARG_TYPE_LIST,
|
||||
FF_FORMAT_ARG_TYPE_BOOL
|
||||
} FFformatargtype;
|
||||
|
||||
typedef struct FFformatarg
|
||||
@@ -25,4 +26,6 @@ typedef struct FFformatarg
|
||||
void ffFormatAppendFormatArg(FFstrbuf* buffer, const FFformatarg* formatarg);
|
||||
void ffParseFormatString(FFstrbuf* buffer, const FFstrbuf* formatstr, uint32_t numArgs, const FFformatarg* arguments);
|
||||
|
||||
#define FF_FORMAT_ARG_VALUE_BOOL(xpr) ((xpr) ? (const void*) 1 : NULL)
|
||||
|
||||
#endif
|
||||
|
||||
+2
-1
@@ -253,7 +253,8 @@ static void defaultConfig(FFinstance* instance)
|
||||
instance->config.titleFQDN = false;
|
||||
|
||||
ffStrbufInitA(&instance->config.diskFolders, 0);
|
||||
instance->config.diskRemovable = false;
|
||||
instance->config.diskShowRemovable = true;
|
||||
instance->config.diskShowHidden = false;
|
||||
|
||||
ffStrbufInitA(&instance->config.batteryDir, 0);
|
||||
|
||||
|
||||
@@ -93,7 +93,9 @@ static void printError(FFinstance* instance, const char* moduleName, uint8_t mod
|
||||
vprintf(message, arguments);
|
||||
|
||||
if(!instance->config.pipe)
|
||||
puts(FASTFETCH_TEXT_MODIFIER_RESET);
|
||||
fputs(FASTFETCH_TEXT_MODIFIER_RESET, stdout);
|
||||
|
||||
putchar('\n');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+20
-19
@@ -87,25 +87,26 @@ Library options: Set the path of a library to load
|
||||
--lib-cjson <path>
|
||||
|
||||
Module specific options:
|
||||
--title-fqdn <?value>: Sets if the title should use fully qualified domain name. Default is false.
|
||||
--separator-string <str>: Set the string printed by the separator module
|
||||
--os-file <path>: Set the path to the file containing OS informations
|
||||
--disk-folders <folders>: A colon (semicolon on Windows) separated list of folder paths for the disk output. Default is "/:/home" ("C:\\;D:\\ ..." on Windows)
|
||||
--disk-removable <?value>: Sets if removable volume should be printed. Default is false
|
||||
--battery-dir <folder>: The directory where the battery folders are. Standard: /sys/class/power_supply/
|
||||
--cpu-temp <?value>: Detect and display CPU temperature if supported. Default is false
|
||||
--gpu-temp <?value>: Detect and display GPU temperature if supported. Default is false
|
||||
--battery-temp <?value>: Detect and display Battery temperature if supported. Default is false
|
||||
--localip-show-ipv4 <?value>: Show ipv4 addresses in local ip module. Default is true
|
||||
--localip-show-ipv6 <?value>: Show ipv6 addresses in local ip module. Default is false
|
||||
--localip-show-loop <?value>: Show loop back addresses (127.0.0.1) in local ip module. Default is false
|
||||
--localip-name-prefix <str>: Show ips with given name prefix only. Default is empty
|
||||
--public-ip-timeout: Time in milliseconds to wait for the public ip server to respond. Default is disabled (0)
|
||||
--public-ip-url: The URL of public IP detection server to be used.
|
||||
--weather-timeout: Time in milliseconds to wait for the weather server to respond. Default is disabled (0)
|
||||
--weather-output-format: The output weather format to be used. It must be URI encoded.
|
||||
--player-name: The name of the player to use
|
||||
--gl <value>: Sets the opengl context creation library to use. Must be auto, egl, glx or osmesa. Default is auto
|
||||
--title-fqdn <?value>: Sets if the title should use fully qualified domain name. Default is false.
|
||||
--separator-string <str>: Set the string printed by the separator module
|
||||
--os-file <path>: Set the path to the file containing OS informations
|
||||
--disk-folders <folders>: A colon (semicolon on Windows) separated list of folder paths for the disk output. Default is "/:/home" ("C:\\;D:\\ ..." on Windows)
|
||||
--disk-show-removable <?value>: Sets if removable volume should be printed. Default is true.
|
||||
--disk-show-hidden <?value>: Sets if hidden volumes should be printed. Default is false
|
||||
--battery-dir <folder>: The directory where the battery folders are. Standard: /sys/class/power_supply/
|
||||
--cpu-temp <?value>: Detect and display CPU temperature if supported. Default is false
|
||||
--gpu-temp <?value>: Detect and display GPU temperature if supported. Default is false
|
||||
--battery-temp <?value>: Detect and display Battery temperature if supported. Default is false
|
||||
--localip-show-ipv4 <?value>: Show ipv4 addresses in local ip module. Default is true
|
||||
--localip-show-ipv6 <?value>: Show ipv6 addresses in local ip module. Default is false
|
||||
--localip-show-loop <?value>: Show loop back addresses (127.0.0.1) in local ip module. Default is false
|
||||
--localip-name-prefix <str>: Show ips with given name prefix only. Default is empty
|
||||
--public-ip-timeout: Time in milliseconds to wait for the public ip server to respond. Default is disabled (0)
|
||||
--public-ip-url: The URL of public IP detection server to be used.
|
||||
--weather-timeout: Time in milliseconds to wait for the weather server to respond. Default is disabled (0)
|
||||
--weather-output-format: The output weather format to be used. It must be URI encoded.
|
||||
--player-name: The name of the player to use
|
||||
--gl <value>: Sets the opengl context creation library to use. Must be auto, egl, glx or osmesa. Default is auto
|
||||
|
||||
Parsing is not case sensitive. E.g. "--lib-PCI" is equal to "--Lib-Pci"
|
||||
If a value starts with a ?, it is optional. "true" will be used if not set.
|
||||
|
||||
+25
-46
@@ -1,56 +1,35 @@
|
||||
#include "fastfetch.h"
|
||||
#include "disk.h"
|
||||
#include "detection/internal.h"
|
||||
|
||||
#include <sys/statvfs.h>
|
||||
void ffDetectDisksImpl(FFDiskResult* disks);
|
||||
|
||||
void ffDetectDiskWithStatvfs(const char* folderPath, struct statvfs* fs, FFDiskResult* result)
|
||||
static int compareDisks(const void* disk1, const void* disk2)
|
||||
{
|
||||
ffStrbufInitS(&result->path, folderPath);
|
||||
result->used = result->total = 0;
|
||||
ffStrbufInit(&result->error);
|
||||
return ffStrbufCompAlphabetically(&((const FFDisk*) disk1)->mountpoint, &((const FFDisk*) disk2)->mountpoint);
|
||||
}
|
||||
|
||||
struct statvfs newFs;
|
||||
const FFDiskResult* ffDetectDisks()
|
||||
{
|
||||
FF_DETECTION_INTERNAL_GUARD(FFDiskResult,
|
||||
ffStrbufInit(&result.error);
|
||||
ffListInitA(&result.disks, sizeof(FFDisk), 4);
|
||||
|
||||
if(fs == NULL)
|
||||
{
|
||||
fs = &newFs;
|
||||
int ret = statvfs(folderPath, fs);
|
||||
if(ret != 0)
|
||||
ffDetectDisksImpl(&result);
|
||||
|
||||
if(result.disks.length == 0 && result.error.length == 0)
|
||||
ffStrbufAppendS(&result.error, "No disks found");
|
||||
|
||||
for(uint32_t i = 0; i < result.disks.length; ++i)
|
||||
{
|
||||
ffStrbufAppendF(&result->error, "statvfs(\"%s\", &fs) != 0 (%i)", folderPath, ret);
|
||||
return;
|
||||
FFDisk* disk = ffListGet(&result.disks, i);
|
||||
disk->bytesPercentage = (uint8_t) (((long double) disk->bytesUsed / (long double) disk->bytesTotal) * 100.0);
|
||||
disk->filesPercentage = (uint8_t) (((long double) disk->filesUsed / (long double) disk->filesTotal) * 100.0);
|
||||
}
|
||||
}
|
||||
|
||||
result->total = fs->f_blocks * fs->f_frsize;
|
||||
|
||||
if(result->total == 0)
|
||||
{
|
||||
ffStrbufAppendF(&result->error, "statvfs for %s returned size 0", folderPath);
|
||||
return;
|
||||
}
|
||||
|
||||
result->used = result->total - (fs->f_bavail * fs->f_frsize);
|
||||
result->files = (uint32_t) (fs->f_files - fs->f_ffree);
|
||||
result->removable = false; //To be set at other place
|
||||
}
|
||||
|
||||
bool ffDiskDetectDiskFolders(FFinstance* instance, FFlist* folders)
|
||||
{
|
||||
ffStrbufTrim(&instance->config.diskFolders, ':');
|
||||
if(instance->config.diskFolders.length == 0)
|
||||
return false;
|
||||
|
||||
uint32_t startIndex = 0;
|
||||
while(startIndex < instance->config.diskFolders.length)
|
||||
{
|
||||
uint32_t colonIndex = ffStrbufNextIndexC(&instance->config.diskFolders, startIndex, ':');
|
||||
instance->config.diskFolders.chars[colonIndex] = '\0';
|
||||
|
||||
ffDetectDiskWithStatvfs(instance->config.diskFolders.chars + startIndex, NULL, (FFDiskResult*)ffListAdd(folders));
|
||||
|
||||
startIndex = colonIndex + 1;
|
||||
}
|
||||
|
||||
return true;
|
||||
//We need to sort the disks, so that we can detect, which disk a path resides on
|
||||
// For example for /boot/efi/bootmgr we need to check /boot/efi before /boot
|
||||
//Note that we sort alphabetically here for a better ordering when printing the list,
|
||||
// so the check must be done in reverse order
|
||||
ffListSort(&result.disks, compareDisks);
|
||||
);
|
||||
}
|
||||
|
||||
@@ -5,17 +5,40 @@
|
||||
|
||||
#include "fastfetch.h"
|
||||
|
||||
typedef enum FFDiskType
|
||||
{
|
||||
FF_DISK_TYPE_REGULAR,
|
||||
FF_DISK_TYPE_HIDDEN,
|
||||
FF_DISK_TYPE_EXTERNAL
|
||||
} FFDiskType;
|
||||
|
||||
typedef struct FFDisk
|
||||
{
|
||||
FFstrbuf mountpoint;
|
||||
FFstrbuf filesystem;
|
||||
FFDiskType type;
|
||||
|
||||
uint64_t bytesUsed;
|
||||
uint64_t bytesTotal;
|
||||
uint8_t bytesPercentage;
|
||||
|
||||
uint32_t filesUsed;
|
||||
uint32_t filesTotal;
|
||||
uint8_t filesPercentage;
|
||||
} FFDisk;
|
||||
|
||||
typedef struct FFDiskResult
|
||||
{
|
||||
FFstrbuf path;
|
||||
uint64_t used;
|
||||
uint64_t total;
|
||||
uint32_t files;
|
||||
bool removable;
|
||||
FFstrbuf error;
|
||||
FFlist disks; //List of FFDisk
|
||||
} FFDiskResult;
|
||||
|
||||
const char* ffDiskAutodetectFolders(FFinstance* instance, FFlist* folders);
|
||||
bool ffDiskDetectDiskFolders(FFinstance* instance, FFlist* folders);
|
||||
/**
|
||||
* Returns a List of FFDisk, sorted alphabetically by mountpoint.
|
||||
* If error is not set, disks contains at least one disk.
|
||||
*
|
||||
* @return const FFDiskResult*
|
||||
*/
|
||||
const FFDiskResult* ffDetectDisks();
|
||||
|
||||
#endif
|
||||
|
||||
@@ -2,29 +2,60 @@
|
||||
|
||||
#include <sys/statvfs.h>
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <AppKit/AppKit.h>
|
||||
|
||||
void ffDetectDiskWithStatvfs(const char* folderPath, struct statvfs* fs, FFDiskResult* result);
|
||||
static bool getBool(NSURL* url, NSURLResourceKey key)
|
||||
{
|
||||
NSError *error;
|
||||
NSNumber* result;
|
||||
if([url getResourceValue:&result forKey:key error:&error] == NO)
|
||||
return false;
|
||||
|
||||
const char* ffDiskAutodetectFolders(FFinstance* instance, FFlist* folders)
|
||||
return result.boolValue;
|
||||
}
|
||||
|
||||
void ffDetectDisksImpl(FFDiskResult* disks)
|
||||
{
|
||||
NSArray *keys = [NSArray arrayWithObjects:NSURLVolumeNameKey, nil];
|
||||
NSArray *urls = [NSFileManager.defaultManager mountedVolumeURLsIncludingResourceValuesForKeys:keys
|
||||
options:NSVolumeEnumerationSkipHiddenVolumes];
|
||||
NSArray *urls = [NSFileManager.defaultManager mountedVolumeURLsIncludingResourceValuesForKeys:keys options:0];
|
||||
|
||||
if(urls == nil)
|
||||
return "[NSFileManager.defaultManager mountedVolumeURLsIncludingResourceValuesForKeys] failed";
|
||||
|
||||
for (NSURL *url in urls) {
|
||||
NSError *error;
|
||||
NSNumber* removable;
|
||||
if([url getResourceValue:&removable forKey:NSURLVolumeIsRemovableKey error:&error] == NO)
|
||||
continue;
|
||||
if(removable.boolValue && !instance->config.diskRemovable)
|
||||
continue;
|
||||
|
||||
FFDiskResult* folder = (FFDiskResult*)ffListAdd(folders);
|
||||
ffDetectDiskWithStatvfs([url.relativePath cStringUsingEncoding:NSUTF8StringEncoding], NULL, folder);
|
||||
folder->removable = removable.boolValue;
|
||||
{
|
||||
ffStrbufAppendS(&disks->error, "[NSFileManager.defaultManager mountedVolumeURLsIncludingResourceValuesForKeys] failed");
|
||||
return;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
for (NSURL *url in urls)
|
||||
{
|
||||
FFDisk* disk = ffListAdd(&disks->disks);
|
||||
|
||||
ffStrbufInitS(&disk->mountpoint, [url.relativePath cStringUsingEncoding:NSUTF8StringEncoding]);
|
||||
|
||||
NSString* filesystem;
|
||||
[[NSWorkspace sharedWorkspace] getFileSystemInfoForPath:url.relativePath
|
||||
isRemovable:nil
|
||||
isWritable:nil
|
||||
isUnmountable:nil
|
||||
description:nil
|
||||
type:&filesystem
|
||||
];
|
||||
ffStrbufInitS(&disk->filesystem, [filesystem cStringUsingEncoding:NSUTF8StringEncoding]);
|
||||
|
||||
if(getBool(url, NSURLVolumeIsRemovableKey))
|
||||
disk->type = FF_DISK_TYPE_EXTERNAL;
|
||||
else if(getBool(url, NSURLVolumeIsBrowsableKey))
|
||||
disk->type = FF_DISK_TYPE_REGULAR;
|
||||
else
|
||||
disk->type = FF_DISK_TYPE_HIDDEN;
|
||||
|
||||
struct statvfs fs;
|
||||
if(statvfs(disk->mountpoint.chars, &fs) != 0)
|
||||
memset(&fs, 0, sizeof(struct statvfs)); //Set all values to 0, so our values get initialized to 0 too
|
||||
|
||||
disk->bytesTotal = fs.f_blocks * fs.f_frsize;
|
||||
disk->bytesUsed = disk->bytesTotal - (fs.f_bavail * fs.f_frsize);
|
||||
|
||||
disk->filesTotal = (uint32_t) fs.f_files;
|
||||
disk->filesUsed = (uint32_t) (disk->filesTotal - fs.f_ffree);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,24 +1,81 @@
|
||||
#include "disk.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#include <sys/statvfs.h>
|
||||
|
||||
void ffDetectDiskWithStatvfs(const char* folderPath, struct statvfs* fs, FFDiskResult* result);
|
||||
|
||||
const char* ffDiskAutodetectFolders(FFinstance* instance, FFlist* folders)
|
||||
void ffDetectDisksImpl(FFDiskResult* disks)
|
||||
{
|
||||
FF_UNUSED(instance);
|
||||
FILE* mountsFile = fopen("/proc/mounts", "r");
|
||||
if(mountsFile == NULL)
|
||||
{
|
||||
ffStrbufAppendS(&disks->error, "fopen(\"/proc/mounts\", \"r\") == NULL");
|
||||
return;
|
||||
}
|
||||
|
||||
struct statvfs fsRoot;
|
||||
int rootRet = statvfs(FASTFETCH_TARGET_DIR_ROOT"/", &fsRoot);
|
||||
if(rootRet != 0)
|
||||
return "statvfs(\"/\") failed";
|
||||
char* line = NULL;
|
||||
size_t len = 0;
|
||||
|
||||
ffDetectDiskWithStatvfs(FASTFETCH_TARGET_DIR_ROOT"/", &fsRoot, (FFDiskResult*)ffListAdd(folders));
|
||||
while(getline(&line, &len, mountsFile) != EOF)
|
||||
{
|
||||
//Format of the file: "<device> <mountpoint> <filesystem> <options> ..." (Same as fstab)
|
||||
char* currentPos = line;
|
||||
|
||||
struct statvfs fsHome;
|
||||
int homeRet = statvfs(FASTFETCH_TARGET_DIR_HOME, &fsHome);
|
||||
if(homeRet == 0 && (fsRoot.f_fsid != fsHome.f_fsid))
|
||||
ffDetectDiskWithStatvfs(FASTFETCH_TARGET_DIR_HOME, &fsHome, (FFDiskResult*)ffListAdd(folders));
|
||||
//Non pseudo filesystems have their device in /dev/, we only add those
|
||||
if(strncasecmp(currentPos, "/dev/", 5) != 0)
|
||||
continue;
|
||||
|
||||
return NULL;
|
||||
//Skip /dev/
|
||||
currentPos += 5;
|
||||
|
||||
//Don't show loop file systems
|
||||
if(strncasecmp(currentPos, "loop", 4) == 0)
|
||||
continue;
|
||||
|
||||
FFDisk* disk = ffListAdd(&disks->disks);
|
||||
|
||||
//Go to mountpoint
|
||||
while(!isspace(*currentPos) && *currentPos != '\0')
|
||||
++currentPos;
|
||||
while(isspace(*currentPos))
|
||||
++currentPos;
|
||||
|
||||
ffStrbufInitA(&disk->mountpoint, 16);
|
||||
ffStrbufAppendSUntilC(&disk->mountpoint, currentPos, ' ');
|
||||
|
||||
//Go to filesystem
|
||||
currentPos += disk->mountpoint.length;
|
||||
while(isspace(*currentPos))
|
||||
++currentPos;
|
||||
|
||||
ffStrbufInitA(&disk->filesystem, 16);
|
||||
ffStrbufAppendSUntilC(&disk->filesystem, currentPos, ' ');
|
||||
|
||||
//Go to options, detect type
|
||||
currentPos += disk->filesystem.length;
|
||||
while(isspace(*currentPos))
|
||||
++currentPos;
|
||||
|
||||
if(strstr(currentPos, "nosuid") != NULL || strstr(currentPos, "nodev") != NULL)
|
||||
disk->type = FF_DISK_TYPE_EXTERNAL;
|
||||
else if(ffStrbufStartsWithS(&disk->mountpoint, "/boot") || ffStrbufStartsWithS(&disk->mountpoint, "/efi"))
|
||||
disk->type = FF_DISK_TYPE_HIDDEN;
|
||||
else
|
||||
disk->type = FF_DISK_TYPE_REGULAR;
|
||||
|
||||
//Detects stats
|
||||
struct statvfs fs;
|
||||
if(statvfs(disk->mountpoint.chars, &fs) != 0)
|
||||
memset(&fs, 0, sizeof(struct statvfs)); //Set all values to 0, so our values get initialized to 0 too
|
||||
|
||||
disk->bytesTotal = fs.f_blocks * fs.f_frsize;
|
||||
disk->bytesUsed = disk->bytesTotal - (fs.f_bavail * fs.f_frsize);
|
||||
|
||||
disk->filesTotal = (uint32_t) fs.f_files;
|
||||
disk->filesUsed = (uint32_t) (disk->filesTotal - fs.f_ffree);
|
||||
}
|
||||
|
||||
if(line != NULL)
|
||||
free(line);
|
||||
|
||||
fclose(mountsFile);
|
||||
}
|
||||
|
||||
@@ -1,66 +1,65 @@
|
||||
#include "disk.h"
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN 1
|
||||
#include <Windows.h>
|
||||
#include <windows.h>
|
||||
|
||||
static void detectDrive(const char* folderPath, uint32_t pathLen, FFDiskResult* result)
|
||||
void ffDetectDisksImpl(FFDiskResult* disks)
|
||||
{
|
||||
ffStrbufInitNS(&result->path, pathLen, folderPath);
|
||||
result->removable = false; //To be set at other place
|
||||
result->files = 0; //Unsupported
|
||||
|
||||
//According to https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getdiskfreespaceexa
|
||||
//GetDiskFreeSpaceExA does not have to specify the root directory on a disk. The function accepts any directory on a disk.
|
||||
uint64_t freeBytes;
|
||||
if(GetDiskFreeSpaceExA(folderPath, NULL, (PULARGE_INTEGER)&result->total, (PULARGE_INTEGER)&freeBytes)) {
|
||||
result->used = result->total - freeBytes;
|
||||
ffStrbufInit(&result->error);
|
||||
}
|
||||
else
|
||||
ffStrbufInitS(&result->error, "GetDiskFreeSpaceExA() failed");
|
||||
}
|
||||
|
||||
const char* ffDiskAutodetectFolders(FFinstance* instance, FFlist* folders)
|
||||
{
|
||||
FF_UNUSED(instance);
|
||||
|
||||
char buf[128]; // "C:\\\0D:\\\0"
|
||||
uint32_t length = GetLogicalDriveStringsA(sizeof(buf) / sizeof(*buf), buf);
|
||||
|
||||
for(size_t i = 0; i < length;)
|
||||
uint32_t length = GetLogicalDriveStringsA(0, NULL);
|
||||
if(length == 0)
|
||||
{
|
||||
const char* drive = buf + i;
|
||||
uint32_t driveLen = (uint32_t) strlen(drive);
|
||||
i += driveLen + 1;
|
||||
ffStrbufAppendS(&disks->error, "GetLogicalDriveStringsA failed");
|
||||
return;
|
||||
}
|
||||
|
||||
bool removable = GetDriveTypeA(drive) == DRIVE_REMOVABLE;
|
||||
if(removable && !instance->config.diskRemovable)
|
||||
char* buf = malloc(length + 1);
|
||||
GetLogicalDriveStringsA(length, buf);
|
||||
|
||||
for(uint32_t i = 0; i < length; i++)
|
||||
{
|
||||
const char* mountpoint = buf + i;
|
||||
|
||||
UINT driveType = GetDriveTypeA(mountpoint);
|
||||
if(driveType == DRIVE_NO_ROOT_DIR)
|
||||
{
|
||||
i += strlen(mountpoint);
|
||||
continue;
|
||||
}
|
||||
|
||||
FFDiskResult* folder = (FFDiskResult*)ffListAdd(folders);
|
||||
detectDrive(drive, driveLen, folder);
|
||||
folder->removable = removable;
|
||||
FFDisk* disk = ffListAdd(&disks->disks);
|
||||
ffStrbufInitS(&disk->mountpoint, mountpoint);
|
||||
|
||||
uint64_t bytesFree;
|
||||
if(!GetDiskFreeSpaceExA(mountpoint, NULL, (PULARGE_INTEGER)&disk->bytesTotal, (PULARGE_INTEGER)&bytesFree))
|
||||
{
|
||||
disk->bytesTotal = 0;
|
||||
bytesFree = 0;
|
||||
}
|
||||
disk->bytesUsed = disk->bytesTotal - bytesFree;
|
||||
|
||||
if(driveType == DRIVE_REMOVABLE || driveType == DRIVE_REMOTE || driveType == DRIVE_CDROM)
|
||||
disk->type = FF_DISK_TYPE_EXTERNAL;
|
||||
else if(driveType == DRIVE_FIXED)
|
||||
disk->type = FF_DISK_TYPE_REGULAR;
|
||||
else
|
||||
disk->type = FF_DISK_TYPE_HIDDEN;
|
||||
|
||||
ffStrbufInitA(&disk->filesystem, MAX_PATH + 1);
|
||||
GetVolumeInformationA(mountpoint,
|
||||
NULL, 0, //Volume name
|
||||
NULL, //Serial number
|
||||
NULL, //Max component length
|
||||
NULL, //File system flags
|
||||
disk->filesystem.chars, disk->filesystem.allocated
|
||||
);
|
||||
ffStrbufRecalculateLength(&disk->filesystem);
|
||||
|
||||
//TODO: implement
|
||||
disk->filesUsed = 0;
|
||||
disk->filesTotal = 0;
|
||||
|
||||
i += disk->mountpoint.length;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool ffDiskDetectDiskFolders(FFinstance* instance, FFlist* folders)
|
||||
{
|
||||
ffStrbufTrim(&instance->config.diskFolders, ';');
|
||||
if(instance->config.diskFolders.length == 0)
|
||||
return false;
|
||||
|
||||
uint32_t startIndex = 0;
|
||||
while(startIndex < instance->config.diskFolders.length)
|
||||
{
|
||||
uint32_t colonIndex = ffStrbufNextIndexC(&instance->config.diskFolders, startIndex, ';');
|
||||
instance->config.diskFolders.chars[colonIndex] = '\0';
|
||||
|
||||
detectDrive(instance->config.diskFolders.chars + startIndex, colonIndex - startIndex, (FFDiskResult*)ffListAdd(folders));
|
||||
|
||||
startIndex = colonIndex + 1;
|
||||
}
|
||||
|
||||
return true;
|
||||
free(buf);
|
||||
}
|
||||
|
||||
+14
-7
@@ -300,11 +300,16 @@ static inline void printCommandHelp(const char* command)
|
||||
}
|
||||
else if(strcasecmp(command, "disk-format") == 0)
|
||||
{
|
||||
constructAndPrintCommandHelpFormat("disk", "{}GiB / {}GiB ({4}%)", 4,
|
||||
"Used size",
|
||||
"Total size",
|
||||
"Percentage used",
|
||||
"Num files"
|
||||
constructAndPrintCommandHelpFormat("disk", "{1} / {2} ({3}%)", 9,
|
||||
"Size used",
|
||||
"Size total",
|
||||
"Size percentage",
|
||||
"Files used",
|
||||
"Files total",
|
||||
"Files percentage",
|
||||
"True if removable volume",
|
||||
"True if hidden volume",
|
||||
"Filesystem"
|
||||
);
|
||||
}
|
||||
else if(strcasecmp(command, "battery-format") == 0)
|
||||
@@ -1314,8 +1319,10 @@ static void parseOption(FFinstance* instance, FFdata* data, const char* key, con
|
||||
instance->config.titleFQDN = optionParseBoolean(value);
|
||||
else if(strcasecmp(key, "--disk-folders") == 0)
|
||||
optionParseString(key, value, &instance->config.diskFolders);
|
||||
else if(strcasecmp(key, "--disk-removable") == 0)
|
||||
instance->config.diskRemovable = optionParseBoolean(value);
|
||||
else if(strcasecmp(key, "--disk-show-removable") == 0)
|
||||
instance->config.diskShowRemovable = optionParseBoolean(value);
|
||||
else if(strcasecmp(key, "--disk-show-hidden") == 0)
|
||||
instance->config.diskShowHidden = optionParseBoolean(value);
|
||||
else if(strcasecmp(key, "--battery-dir") == 0)
|
||||
optionParseString(key, value, &instance->config.batteryDir);
|
||||
else if(strcasecmp(key, "--separator-string") == 0)
|
||||
|
||||
+2
-1
@@ -168,7 +168,8 @@ typedef struct FFconfig
|
||||
bool titleFQDN;
|
||||
|
||||
FFstrbuf diskFolders;
|
||||
bool diskRemovable;
|
||||
bool diskShowRemovable;
|
||||
bool diskShowHidden;
|
||||
|
||||
FFstrbuf batteryDir;
|
||||
|
||||
|
||||
+75
-33
@@ -4,78 +4,120 @@
|
||||
#include "detection/disk/disk.h"
|
||||
|
||||
#define FF_DISK_MODULE_NAME "Disk"
|
||||
#define FF_DISK_NUM_FORMAT_ARGS 4
|
||||
#define FF_DISK_NUM_FORMAT_ARGS 9
|
||||
|
||||
static void printFolder(FFinstance* instance, FFDiskResult* folder)
|
||||
static void printDisk(FFinstance* instance, const FFDisk* disk)
|
||||
{
|
||||
FFstrbuf key;
|
||||
ffStrbufInit(&key);
|
||||
|
||||
if(instance->config.disk.key.length == 0)
|
||||
{
|
||||
ffStrbufAppendF(&key, "%s (%*s)", FF_DISK_MODULE_NAME, folder->path.length, folder->path.chars);
|
||||
ffStrbufAppendF(&key, "%s (%s)", FF_DISK_MODULE_NAME, disk->mountpoint.chars);
|
||||
}
|
||||
else
|
||||
{
|
||||
ffParseFormatString(&key, &instance->config.disk.key, 1, (FFformatarg[]){
|
||||
{FF_FORMAT_ARG_TYPE_STRBUF, &folder->path}
|
||||
{FF_FORMAT_ARG_TYPE_STRBUF, &disk->mountpoint}
|
||||
});
|
||||
}
|
||||
|
||||
uint8_t percentage = (uint8_t) (((long double) folder->used / (long double) folder->total) * 100.0);
|
||||
|
||||
FFstrbuf usedPretty;
|
||||
ffStrbufInit(&usedPretty);
|
||||
ffParseSize(folder->used, instance->config.binaryPrefixType, &usedPretty);
|
||||
ffParseSize(disk->bytesUsed, instance->config.binaryPrefixType, &usedPretty);
|
||||
|
||||
FFstrbuf totalPretty;
|
||||
ffStrbufInit(&totalPretty);
|
||||
ffParseSize(folder->total, instance->config.binaryPrefixType, &totalPretty);
|
||||
ffParseSize(disk->bytesTotal, instance->config.binaryPrefixType, &totalPretty);
|
||||
|
||||
if(instance->config.disk.outputFormat.length == 0)
|
||||
{
|
||||
ffPrintLogoAndKey(instance, key.chars, 0, NULL);
|
||||
printf("%s / %s (%u%%)%s\n", usedPretty.chars, totalPretty.chars, percentage, folder->removable ? " [Removable]" : "");
|
||||
printf("%s / %s (%u%%)", usedPretty.chars, totalPretty.chars, disk->bytesPercentage);
|
||||
if(disk->type == FF_DISK_TYPE_EXTERNAL)
|
||||
printf(" [Removable]");
|
||||
putchar('\n');
|
||||
}
|
||||
else
|
||||
{
|
||||
ffPrintFormatString(instance, key.chars, 0, NULL, &instance->config.disk.outputFormat, FF_DISK_NUM_FORMAT_ARGS, (FFformatarg[]){
|
||||
{FF_FORMAT_ARG_TYPE_STRBUF, &usedPretty},
|
||||
{FF_FORMAT_ARG_TYPE_STRBUF, &totalPretty},
|
||||
{FF_FORMAT_ARG_TYPE_UINT8, &percentage},
|
||||
{FF_FORMAT_ARG_TYPE_UINT, &folder->files},
|
||||
{FF_FORMAT_ARG_TYPE_UINT8, &disk->bytesPercentage},
|
||||
{FF_FORMAT_ARG_TYPE_UINT, &disk->filesUsed},
|
||||
{FF_FORMAT_ARG_TYPE_UINT, &disk->filesTotal},
|
||||
{FF_FORMAT_ARG_TYPE_UINT8, &disk->filesPercentage},
|
||||
{FF_FORMAT_ARG_TYPE_BOOL, FF_FORMAT_ARG_VALUE_BOOL(disk->type == FF_DISK_TYPE_EXTERNAL)},
|
||||
{FF_FORMAT_ARG_TYPE_BOOL, FF_FORMAT_ARG_VALUE_BOOL(disk->type == FF_DISK_TYPE_HIDDEN)},
|
||||
{FF_FORMAT_ARG_TYPE_STRBUF, &disk->filesystem}
|
||||
});
|
||||
}
|
||||
|
||||
ffStrbufDestroy(&key);
|
||||
ffStrbufDestroy(&totalPretty);
|
||||
ffStrbufDestroy(&usedPretty);
|
||||
ffStrbufDestroy(&key);
|
||||
}
|
||||
|
||||
static void printMountpoint(FFinstance* instance, const FFlist* disks, const char* mountpoint)
|
||||
{
|
||||
for(uint32_t i = disks->length; i > 0; i--)
|
||||
{
|
||||
FFDisk* disk = ffListGet(disks, i - 1);
|
||||
if(strncmp(mountpoint, disk->mountpoint.chars, disk->mountpoint.length) == 0)
|
||||
{
|
||||
printDisk(instance, disk);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
ffPrintError(instance, FF_DISK_MODULE_NAME, 0, &instance->config.disk, "No disk found for mountpoint: %s", mountpoint);
|
||||
}
|
||||
|
||||
static void printMountpoints(FFinstance* instance, const FFlist* disks)
|
||||
{
|
||||
FFstrbuf mountpoints;
|
||||
ffStrbufInitCopy(&mountpoints, &instance->config.diskFolders);
|
||||
ffStrbufTrim(&mountpoints, ':');
|
||||
|
||||
uint32_t startIndex = 0;
|
||||
while(startIndex < mountpoints.length)
|
||||
{
|
||||
uint32_t colonIndex = ffStrbufNextIndexC(&mountpoints, startIndex, ':');
|
||||
mountpoints.chars[colonIndex] = '\0';
|
||||
|
||||
printMountpoint(instance, disks, mountpoints.chars + startIndex);
|
||||
|
||||
startIndex = colonIndex + 1;
|
||||
}
|
||||
}
|
||||
|
||||
static void printAutodetected(FFinstance* instance, const FFlist* disks)
|
||||
{
|
||||
for(uint32_t i = 0; i < disks->length; i++)
|
||||
{
|
||||
const FFDisk* disk = ffListGet(disks, i);
|
||||
|
||||
if(disk->type == FF_DISK_TYPE_EXTERNAL && !instance->config.diskShowRemovable)
|
||||
continue;
|
||||
|
||||
if(disk->type == FF_DISK_TYPE_HIDDEN && !instance->config.diskShowHidden)
|
||||
continue;
|
||||
|
||||
printDisk(instance, disk);
|
||||
}
|
||||
}
|
||||
|
||||
void ffPrintDisk(FFinstance* instance)
|
||||
{
|
||||
FFlist folders;
|
||||
ffListInit(&folders, sizeof(FFDiskResult));
|
||||
|
||||
const char* error = NULL;
|
||||
|
||||
if(!ffDiskDetectDiskFolders(instance, &folders))
|
||||
error = ffDiskAutodetectFolders(instance, &folders);
|
||||
|
||||
if(error)
|
||||
const FFDiskResult* disks = ffDetectDisks();
|
||||
if(disks->error.length > 0)
|
||||
{
|
||||
ffPrintError(instance, FF_DISK_MODULE_NAME, 0, &instance->config.disk, "%s", error);
|
||||
ffPrintError(instance, FF_DISK_MODULE_NAME, 0, &instance->config.disk, "%s", disks->error.chars);
|
||||
return;
|
||||
}
|
||||
|
||||
if(instance->config.diskFolders.length == 0)
|
||||
printAutodetected(instance, &disks->disks);
|
||||
else
|
||||
{
|
||||
for(uint32_t i = 0; i < folders.length; ++i)
|
||||
{
|
||||
FFDiskResult* folder = (FFDiskResult*)ffListGet(&folders, i);
|
||||
printFolder(instance, folder);
|
||||
ffStrbufDestroy(&folder->path);
|
||||
ffStrbufDestroy(&folder->error);
|
||||
}
|
||||
}
|
||||
|
||||
ffListDestroy(&folders);
|
||||
printMountpoints(instance, &disks->disks);
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define FF_LIST_DEFAULT_ALLOC 16
|
||||
|
||||
@@ -39,4 +40,9 @@ static inline void* ffListGet(const FFlist* list, uint32_t index)
|
||||
return list->data + (index * list->elementSize);
|
||||
}
|
||||
|
||||
static inline void ffListSort(FFlist* list, int(*compar)(const void*, const void*))
|
||||
{
|
||||
qsort(list->data, list->length, list->elementSize, compar);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -155,6 +155,18 @@ void ffStrbufAppendVF(FFstrbuf* strbuf, const char* format, va_list arguments)
|
||||
strbuf->chars[strbuf->length] = '\0';
|
||||
}
|
||||
|
||||
void ffStrbufAppendSUntilC(FFstrbuf* strbuf, const char* value, char until)
|
||||
{
|
||||
if(value == NULL)
|
||||
return;
|
||||
|
||||
char* end = strchr(value, until);
|
||||
if(end == NULL)
|
||||
ffStrbufAppendS(strbuf, value);
|
||||
else
|
||||
ffStrbufAppendNS(strbuf, (uint32_t) (end - value), value);
|
||||
}
|
||||
|
||||
void ffStrbufSetF(FFstrbuf* strbuf, const char* format, ...)
|
||||
{
|
||||
assert(format != NULL);
|
||||
|
||||
@@ -45,6 +45,7 @@ void ffStrbufAppendNSExludingC(FFstrbuf* strbuf, uint32_t length, const char* va
|
||||
void ffStrbufAppendTransformS(FFstrbuf* strbuf, const char* value, int(*transformFunc)(int));
|
||||
FF_C_PRINTF(2, 3) void ffStrbufAppendF(FFstrbuf* strbuf, const char* format, ...);
|
||||
void ffStrbufAppendVF(FFstrbuf* strbuf, const char* format, va_list arguments);
|
||||
void ffStrbufAppendSUntilC(FFstrbuf* strbuf, const char* value, char until);
|
||||
|
||||
void ffStrbufPrependNS(FFstrbuf* strbuf, uint32_t length, const char* value);
|
||||
|
||||
@@ -147,6 +148,11 @@ static inline int ffStrbufComp(const FFstrbuf* strbuf, const FFstrbuf* comp)
|
||||
return memcmp(strbuf->chars, comp->chars, length + 1);
|
||||
}
|
||||
|
||||
static inline int ffStrbufCompAlphabetically(const FFstrbuf* strbuf, const FFstrbuf* comp)
|
||||
{
|
||||
return strcmp(strbuf->chars, comp->chars);
|
||||
}
|
||||
|
||||
static inline FF_C_NODISCARD bool ffStrbufEqual(const FFstrbuf* strbuf, const FFstrbuf* comp)
|
||||
{
|
||||
return ffStrbufComp(strbuf, comp) == 0;
|
||||
|
||||
Reference in New Issue
Block a user