logo

utils-std

Collection of commonly available Unix tools
commit: 2ff495382f01063adff6085a885b9deea139779b
parent b56ecbcaf9613b85c7ee04604d54de263e284ef2
Author: Haelwenn (lanodan) Monnier <contact@hacktivis.me>
Date:   Sun, 11 Feb 2024 20:13:02 +0100

cmd/df: new

Diffstat:

MMakefile4++++
Acmd/df.c172+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mconfigure16++++++++++++++++
Alib/humanize.c37+++++++++++++++++++++++++++++++++++++
Alib/humanize.h15+++++++++++++++
5 files changed, 244 insertions(+), 0 deletions(-)

diff --git a/Makefile b/Makefile @@ -64,3 +64,7 @@ cmd/sleep: cmd/sleep.c lib/strtodur.c Makefile test-lib/strtodur: test-lib/strtodur.c lib/strtodur.c Makefile $(CC) -std=c99 $(CFLAGS) $(ATF_CFLAGS) -o $@ test-lib/strtodur.c lib/strtodur.c $(LDFLAGS) $(ATF_LIBS) + +cmd/df: cmd/df.c lib/humanize.c Makefile + rm -f ${<:=.gcov} ${@:=.gcda} ${@:=.gcno} + $(CC) -std=c99 $(CFLAGS) -o $@ cmd/df.c lib/humanize.c $(LDFLAGS) $(LDSTATIC) diff --git a/cmd/df.c b/cmd/df.c @@ -0,0 +1,172 @@ +// utils-std: Collection of commonly available Unix tools +// SPDX-FileCopyrightText: 2017-2024 Haelwenn (lanodan) Monnier <contact+utils@hacktivis.me> +// SPDX-License-Identifier: MPL-2.0 + +#define _POSIX_C_SOURCE 200809L +#define _DEFAULT_SOURCE // mntent in glibc 2.19+ + +#include "../lib/humanize.h" + +#include <errno.h> // errno +#include <mntent.h> +#include <stdbool.h> +#include <stdio.h> // printf +#include <stdlib.h> // abort, exit +#include <string.h> // strerror +#include <sys/statvfs.h> +#include <unistd.h> // getopt + +size_t forced_bsize = 0; + +static void +unescape_path(char *path) +{ + char *needle = "\\040"; + size_t esc_len = 3; // 4 chars but leading-slash is kept for space + + char *str = strstr(path, needle); + + if(str != NULL) + { + size_t pos = 0; + + str[pos++] = ' '; + + while(str[pos] != '\0') + { + str[pos] = str[pos + esc_len]; + pos++; + } + + unescape_path(str + pos); + } +} + +int +main(int argc, char *argv[]) +{ + bool opt_P = false, opt_h = false; + + int c = EOF; + while((c = getopt(argc, argv, ":hPk")) != EOF) + { + switch(c) + { + case 'P': + if(forced_bsize == 0) forced_bsize = 512; + + opt_P = true; + break; + case 'k': + forced_bsize = 1024; + break; + case 'h': + opt_h = true; + break; + case ':': + fprintf(stderr, "df: Error: Missing operand for option: '-%c'\n", optopt); + return 1; + case '?': + fprintf(stderr, "df: Error: Unrecognised option: '-%c'\n", optopt); + return 1; + } + } + + argc -= optind; + argv += optind; + + if(forced_bsize != 0) + { + printf("Filesystem %zd-blocks Used Available Capacity Mounted on\n", forced_bsize); + } + else + { + printf("Filesystem Total Used Available Use%% Mountpoint\n"); + } + + FILE *mnt = setmntent(MOUNTED, "r"); + if(mnt == NULL) + { + fprintf(stderr, "df: Error opening setmntent(\"" MOUNTED "\", \"r\"): %s", strerror(errno)); + return 1; + } + + while(1) + { + struct mntent *mntent = getmntent(mnt); + if(mntent == NULL) break; + + // Linux escapes spaces in filesystems and mountpoints with \040 + // which statvfs(3) doesn't interprets + // Also shouldn't be printed out to not break parsing of df(1) output + char *mountpoint = strdup(mntent->mnt_dir); + if(mountpoint == NULL) + { + fprintf(stderr, "df: Failed duplicating mnt_dir string: %s\n", strerror(errno)); + return 1; + exit(1); + } + unescape_path(mountpoint); + + struct statvfs stats; + if(statvfs(mountpoint, &stats) != 0) + { + fprintf(stderr, "df: Error statvfs(\"%s\", _): %s\n", mountpoint, strerror(errno)); + printf("%s - - - - %s\n", mntent->mnt_fsname, mntent->mnt_dir); + + free(mountpoint); + continue; + } + free(mountpoint); + + size_t percent = 0; + size_t total = stats.f_frsize * stats.f_blocks; + size_t free = stats.f_bfree * stats.f_bsize; + size_t used = total - free; + + if(used + free) + { + percent = (used * 100) / (used + free); + if(used * 100 != percent * (used + free)) percent++; + } + + if(forced_bsize != 0) + { + total /= forced_bsize; + free /= forced_bsize; + used /= forced_bsize; + } + + if(opt_h && !opt_P) + { + struct si_scale total_scl = dtosi(total, true); + struct si_scale used_scl = dtosi(used, true); + struct si_scale free_scl = dtosi(free, true); + + // clang-format off + printf("%s %.2f%s %.2f%s %.2f%s %zd%% %s\n", + mntent->mnt_fsname, + total_scl.number, total_scl.prefix, + used_scl.number, used_scl.prefix, + free_scl.number, free_scl.prefix, + percent, + mntent->mnt_dir + ); + // clang-format on + } + else + { + printf("%s %zd %zd %zd %zd%% %s\n", + mntent->mnt_fsname, + total, + used, + free, + percent, + mntent->mnt_dir); + } + } + + endmntent(mnt); + + return 0; +} diff --git a/configure b/configure @@ -89,6 +89,17 @@ check_cmd() { command -v "$cmd" >/dev/null ; is_ok } +check_header() { + header="$1" + + printf 'Checking <%s> header ...' "$header" + + $CC -E - >/dev/null 2>/dev/null <<-EOF + #include <$header> + EOF + is_ok +} + ## User configuration # defaults @@ -215,6 +226,11 @@ if pkg_config_check --exists atf-c; then ATF_LIBS=$("${PKGCONFIG}" --libs atf-c) fi +if ! check_header mntent.h; then + echo 'Disabling cmd/df' + echo 'cmd/df' >> target_filter +fi + echo ## Configuration write diff --git a/lib/humanize.c b/lib/humanize.c @@ -0,0 +1,37 @@ +// utils-std: Collection of commonly available Unix tools +// SPDX-FileCopyrightText: 2017-2024 Haelwenn (lanodan) Monnier <contact+utils@hacktivis.me> +// SPDX-License-Identifier: MPL-2.0 + +#define _POSIX_C_SOURCE 200809L + +#include "../lib/humanize.h" + +#include <stdio.h> // snprintf + +struct si_scale +dtosi(double num, bool iec) +{ +#define PFX 11 + char *si_prefixes[PFX] = {"", "k", "M", "G", "T", "P", "E", "Z", "Y", "R", "Q"}; + char *iec_prefixes[PFX] = { + "B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB", "RiB", "QiB"}; + + int div = iec ? 1024 : 1000; + char **prefixes = iec ? iec_prefixes : si_prefixes; + + struct si_scale ret = { + .number = num, + .prefix = "", + .quotient = 0, + }; + + while(ret.number > div && ret.quotient < PFX) + { + ret.number /= div; + ret.quotient += 1; + } + + ret.prefix = prefixes[ret.quotient]; + + return ret; +} diff --git a/lib/humanize.h b/lib/humanize.h @@ -0,0 +1,15 @@ +// utils-std: Collection of commonly available Unix tools +// SPDX-FileCopyrightText: 2017-2024 Haelwenn (lanodan) Monnier <contact+utils@hacktivis.me> +// SPDX-License-Identifier: MPL-2.0 + +#include <stdbool.h> // bool +#include <stddef.h> // size_t + +struct si_scale +{ + double number; + char *prefix; + unsigned quotient; +}; + +struct si_scale dtosi(double num, bool iec);