commit: 39d8288731b3ee95975229fb36fbe5f41f957eca
parent 722a1008ed5cf8ecb3396d59e57e3c437e4f6a77
Author: Haelwenn (lanodan) Monnier <contact@hacktivis.me>
Date: Sat, 9 Mar 2024 13:49:10 +0100
cmd/df: Add support for -a option
Diffstat:
M | cmd/df.c | 61 | ++++++++++++++++++++++++++++++++++++++++++++++++++----------- |
1 file changed, 50 insertions(+), 11 deletions(-)
diff --git a/cmd/df.c b/cmd/df.c
@@ -11,9 +11,10 @@
#include <errno.h> // errno
#include <mntent.h>
#include <stdbool.h>
-#include <stdio.h> // printf
-#include <stdlib.h> // abort, exit
-#include <string.h> // strerror
+#include <stdio.h> // printf
+#include <stdlib.h> // abort, exit
+#include <string.h> // strerror
+#include <sys/stat.h> // stat, dev_t
#include <sys/statvfs.h>
#include <unistd.h> // getopt
@@ -23,20 +24,23 @@ size_t forced_bsize = 0;
static void
static_escape(char *str)
{
- for(int i = 0; i < strlen(str); i++)
+ for(size_t i = 0; i < strlen(str); i++)
if(iscntrl(str[i]) || isspace(str[i])) str[i] = '?';
}
int
main(int argc, char *argv[])
{
- bool opt_P = false, opt_h = false;
+ bool opt_P = false, opt_h = false, opt_a = false;
int c = EOF;
- while((c = getopt(argc, argv, ":hPk")) != EOF)
+ while((c = getopt(argc, argv, ":ahPk")) != EOF)
{
switch(c)
{
+ case 'a':
+ opt_a = true;
+ break;
case 'P':
if(forced_bsize == 0) forced_bsize = 512;
@@ -76,6 +80,10 @@ main(int argc, char *argv[])
return 1;
}
+ // FIXME: Fix maximum number of mount entries / devices
+ dev_t devices[4096];
+ size_t devices_found = 0;
+
while(1)
{
struct mntent *mntent = getmntent(mounted);
@@ -87,22 +95,53 @@ main(int argc, char *argv[])
struct statvfs stats;
if(statvfs(mntent->mnt_dir, &stats) != 0)
{
- fprintf(stderr, "df: Error statvfs(\"%s\", _): %s\n", mntent->mnt_dir, strerror(errno));
+ fprintf(stderr, "df: Warning: statvfs(\"%s\", _): %s\n", mntent->mnt_dir, strerror(errno));
static_escape(mntent->mnt_fsname);
static_escape(mntent->mnt_dir);
- printf("%s - - - - %s\n", mntent->mnt_fsname, mntent->mnt_dir);
+
+ if(opt_a) printf("%s - - - - %s\n", mntent->mnt_fsname, mntent->mnt_dir);
continue;
}
- // Needs to be done after calling statvfs(3)
+ if(!opt_a)
+ {
+ // Skip null filesystems
+ if(stats.f_blocks == 0) continue;
+
+ struct stat file_stats;
+ bool dupe = false;
+
+ if(stat(mntent->mnt_dir, &file_stats) != 0)
+ {
+ fprintf(stderr, "df: Warning stat(\"%s\", _): %s\n", mntent->mnt_dir, strerror(errno));
+ }
+ else
+ {
+ for(size_t i = 0; i < devices_found; i++)
+ if(devices[i] == file_stats.st_dev)
+ {
+ dupe = true;
+ break;
+ }
+
+ if(dupe) continue;
+
+ if(devices_found >= 4096)
+ fprintf(stderr, "df: Warning: Reached maximum amount of devices which can be deduplicated\n");
+
+ devices[devices_found++] = file_stats.st_dev;
+ }
+ }
+
+ // Needs to be done after calling statvfs(3) and stat(3)
static_escape(mntent->mnt_fsname);
static_escape(mntent->mnt_dir);
size_t percent = 0;
- size_t total = stats.f_frsize * stats.f_blocks;
- size_t free = stats.f_bfree * stats.f_bsize;
+ size_t total = stats.f_frsize * (stats.f_blocks != 0 ? stats.f_blocks : 1);
+ size_t free = stats.f_bfree * (stats.f_bsize != 0 ? stats.f_bsize : 1);
size_t used = total - free;
if(used + free)