commit: 7d963c3fe6e89216f169bbf81b7d4e5f6329754b
parent 9698dc42e958be417bec48032a0b16932fb46446
Author: Haelwenn (lanodan) Monnier <contact@hacktivis.me>
Date: Sun, 31 Mar 2024 08:14:51 +0200
cmd/df: Add support for arguments
Diffstat:
3 files changed, 75 insertions(+), 33 deletions(-)
diff --git a/cmd/df.1 b/cmd/df.1
@@ -1,7 +1,7 @@
.\" utils-std: Collection of commonly available Unix tools
.\" Copyright 2017 Haelwenn (lanodan) Monnier <contact+utils@hacktivis.me>
.\" SPDX-License-Identifier: MPL-2.0
-.Dd 2024-03-09
+.Dd 2024-03-31
.Dt DF 1
.Os
.Sh NAME
@@ -12,10 +12,17 @@
.Op Fl ahlPkT
.Op Fl t Ar mnt_type
.Op Fl x Ar mnt_type
+.Op Ar file...
.Sh DESCRIPTION
.Nm
displays the current usage and mountpoints of mounted filesystems in a space-separated list containing:
Filesystem, Total, Used, Available, Use percentage, Mountpoint.
+If
+.Ar file
+is given
+.Nm
+filters to the first filesystem containing each
+.Ar file .
.Pp
Unlike some implementations the table formatting isn't perfect, you might want to use
.Xr column 1
@@ -58,7 +65,7 @@ Option can be passed multiple times to exclude multiple types.
.Xr statvfs 3
.Sh STANDARDS
.Nm
-lacks getting a list of filesystems as argument to be compliant with the
+should be compliant with the
.St -p1003.1-2008
specification.
.Pp
diff --git a/cmd/df.c b/cmd/df.c
@@ -101,6 +101,21 @@ main(int argc, char *argv[])
argc -= optind;
argv += optind;
+ int args_left = argc != 0 ? argc : 1;
+
+ dev_t arg_devs[argc];
+ for(int i = 0; i < argc; i++)
+ {
+ struct stat file_stats;
+ if(stat(argv[i], &file_stats) != 0)
+ {
+ fprintf(stderr, "df: Error stat(\"%s\", _): %s\n", argv[i], strerror(errno));
+ return 1;
+ }
+
+ arg_devs[i] = file_stats.st_dev;
+ }
+
// Begin: Print header
printf("%-*s ", fs_col_width, "Filesystem");
@@ -132,7 +147,8 @@ main(int argc, char *argv[])
dev_t devices[4096];
size_t devices_found = 0;
- while(1)
+ // Even with argc>0 we still need to go over mntent for the filesystem mountpoint and type
+ while(args_left > 0)
{
struct mntent *mntent = getmntent(mounted);
if(mntent == NULL) break;
@@ -179,6 +195,47 @@ main(int argc, char *argv[])
if(remote) continue;
}
+ struct stat file_stats;
+ if(!opt_a || argc > 0)
+ {
+ if(stat(mntent->mnt_dir, &file_stats) != 0)
+ fprintf(stderr, "df: Warning stat(\"%s\", _): %s\n", mntent->mnt_dir, strerror(errno));
+ }
+
+ if(argc > 0)
+ {
+ bool found = false;
+ for(size_t i = 0; i < argc; i++)
+ if(arg_devs[i] == file_stats.st_dev)
+ {
+ found = true;
+ break;
+ }
+
+ if(!found) continue;
+
+ args_left--;
+ }
+
+ if(!opt_a)
+ {
+ bool dupe = false;
+ 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;
+ }
+
// Note: musl prior to 1.2.5 has broken getmntent when octal sequences and carriage return is used
// https://git.musl-libc.org/cgit/musl/commit/src/misc/mntent.c?id=f314e133929b6379eccc632bef32eaebb66a7335
// https://git.musl-libc.org/cgit/musl/commit/src/misc/mntent.c?id=ee1d39bc1573c1ae49ee6b658938b56bbef95a6c
@@ -202,36 +259,8 @@ main(int argc, char *argv[])
continue;
}
- 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;
- }
- }
+ // Skip null filesystems
+ if(!opt_a && stats.f_blocks == 0) continue;
// Needs to be done after calling statvfs(3) and stat(3)
static_escape(mntent->mnt_fsname);
diff --git a/test-cmd/df b/test-cmd/df
@@ -17,8 +17,14 @@ posix_body() {
atf_check -e ignore -o 'match:^[^ ]* *[0-9]* *[0-9]* *[0-9]* *[0-9]*% [^ ]$' sh -c '../cmd/df -Pak | sed -n 2,\$p'
}
+atf_test_case args
+args_body() {
+ atf_check -e ignore -o 'match:^[^ ]* *[0-9]* *[0-9]* *[0-9]* *[0-9]*% /$' sh -c '../cmd/df -P / | sed -n 2,\$p'
+}
+
atf_init_test_cases() {
cd "$(atf_get_srcdir)" || exit 1
atf_add_test_case posix
+ atf_add_test_case args
}