Skip to content

Instantly share code, notes, and snippets.

@insinfo
Forked from vgerak/statvfs-df.c
Last active November 29, 2023 23:14
Show Gist options
  • Save insinfo/3780396bb30aee87ce51230af1c9de5f to your computer and use it in GitHub Desktop.
Save insinfo/3780396bb30aee87ce51230af1c9de5f to your computer and use it in GitHub Desktop.
Get disk usage with statvfs()
#include <limits.h>
#include <stdint.h>
#include <stdio.h>
#include <sys/statvfs.h>
#include <sys/types.h>
struct fs_usage {
uintmax_t fsu_blocksize; /* Size of a block. */
uintmax_t fsu_blocks; /* Total blocks. */
uintmax_t fsu_bfree; /* Free blocks available to superuser. */
uintmax_t fsu_bavail; /* Free blocks available to non-superuser. */
bool fsu_bavail_top_bit_set; /* 1 if fsu_bavail represents a value < 0. */
uintmax_t fsu_files; /* Total file nodes. */
uintmax_t fsu_ffree; /* Free file nodes. */
};
/* Many space usage primitives use all 1 bits to denote a value that is
not applicable or unknown. Propagate this information by returning
a uintmax_t value that is all 1 bits if X is all 1 bits, even if X
is unsigned and narrower than uintmax_t. */
#define PROPAGATE_ALL_ONES(x) \
((sizeof(x) < sizeof(uintmax_t) && \
(~(x) == (sizeof(x) < sizeof(int) ? -(1 << (sizeof(x) * CHAR_BIT)) : 0))) \
? UINTMAX_MAX \
: (uintmax_t)(x))
/* Extract the top bit of X as an uintmax_t value. */
#define EXTRACT_TOP_BIT(x) ((x) & ((uintmax_t)1 << (sizeof(x) * CHAR_BIT - 1)))
/* If a value is negative, many space usage primitives store it into an
integer variable by assignment, even if the variable's type is unsigned.
So, if a space usage variable X's top bit is set, convert X to the
uintmax_t value V such that (- (uintmax_t) V) is the negative of
the original value. If X's top bit is clear, just yield X.
Use PROPAGATE_TOP_BIT if the original value might be negative;
otherwise, use PROPAGATE_ALL_ONES. */
#define PROPAGATE_TOP_BIT(x) ((x) | ~(EXTRACT_TOP_BIT(x) - 1))
/* Fill in the fields of FSP with information about space usage for
the file system on which FILE resides.
DISK is the device on which FILE is mounted, for space-getting
methods that need to know it.
Return 0 if successful, -1 if not. When returning -1, ensure that
ERRNO is either a system error value, or zero if DISK is NULL
on a system that requires a non-NULL value. */
int get_fs_usage(char const *file, char const *disk, struct fs_usage *fsp) {
struct statvfs vfsd;
if (statvfs(file, &vfsd) < 0) return -1;
/* f_frsize isn't guaranteed to be supported. */
fsp->fsu_blocksize = (vfsd.f_frsize ? PROPAGATE_ALL_ONES(vfsd.f_frsize)
: PROPAGATE_ALL_ONES(vfsd.f_bsize));
fsp->fsu_blocks = PROPAGATE_ALL_ONES(vfsd.f_blocks);
fsp->fsu_bfree = PROPAGATE_ALL_ONES(vfsd.f_bfree);
fsp->fsu_bavail = PROPAGATE_TOP_BIT(vfsd.f_bavail);
fsp->fsu_bavail_top_bit_set = EXTRACT_TOP_BIT(vfsd.f_bavail) != 0;
fsp->fsu_files = PROPAGATE_ALL_ONES(vfsd.f_files);
fsp->fsu_ffree = PROPAGATE_ALL_ONES(vfsd.f_ffree);
return 0;
(void)disk; /* avoid argument-unused warning */
return 0;
}
int main(int argc, const char *argv[]) {
const unsigned int GB = (1024 * 1024) * 1024;
struct statvfs buffer;
int ret = statvfs("/", &buffer);
printf("ret: %d\n", ret);
if (!ret) {
const double total = (double)(buffer.f_blocks * buffer.f_frsize) / GB;
const double available = (double)(buffer.f_bfree * buffer.f_frsize) / GB;
const double used = total - available;
const double usedPercentage = (double)(used / total) * (double)100;
printf("Total: %f --> %.0f\n", total, total);
printf("Available: %f --> %.0f\n", available, available);
printf("Used: %f --> %.1f\n", used, used);
printf("Used Percentage: %f --> %.0f\n", usedPercentage, usedPercentage);
}
printf("\n");
struct fs_usage fsu;
ret = get_fs_usage("/", nullptr, &fsu);
printf("ret: %d\n", ret);
printf("fsu.fsu_blocks: %ld\n", fsu.fsu_blocks);
const double total = (double)(fsu.fsu_blocks * fsu.fsu_blocksize) / GB;
const double available = (double)(fsu.fsu_bfree * fsu.fsu_blocksize) / GB;
const double used = total - available;
const double usedPercentage = (double)(used / total) * (double)100;
printf("Total: %f --> %.0f\n", total, total);
printf("Available: %f --> %.0f\n", available, available);
printf("Used: %f --> %.1f\n", used, used);
printf("Used Percentage: %f --> %.0f\n", usedPercentage, usedPercentage);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment