-
-
Save insinfo/3780396bb30aee87ce51230af1c9de5f to your computer and use it in GitHub Desktop.
Get disk usage with statvfs()
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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