I want to automate a remote proccess to know if a machine of mine is running out of inodes (something that happens quite often due to bad configuration...). Sadly it runs on a light weight linux that does not have -i option on the df command, so that option is unaviable. I have done some research and I have encountered some ways to find the folders with the most inodes and similar, but I don't want that.
I need a way (in C or bash) to know how many inodes my system has in total and currently aviable.
What you seek, is reported by the statvfs()
function, for each mounted filesystem (specified by providing a path to any file or directory on said mounted filesystem).
If the system has GNU coreutils installed, it has a small utility called stat
. For each path to a file or directory on a filesystem,
stat -c '%d %c' -f /path
reports the number of free inodes and the total number of inodes, one line per path given. If the system uses busybox, then
busybox stat -c '%d %c' -f /path
does the same thing.
If you need more control with the output, or neither of the above work for you for some reason, you can easily write your own utility to report a summary: Here is an example, inode-stats.c:
#define _POSIX_C_SOURCE 200809L
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/statvfs.h>
#include <stdint.h>
#include <inttypes.h>
#include <string.h>
#include <errno.h>
#include <stdio.h>
int main(int argc, char *argv[])
{
dev_t device[argc];
int devices = 0;
uint64_t total_inodes = 0;
uint64_t avail_inodes = 0; /* Free to normal users */
uint64_t free_inodes = 0; /* Free to superuser */
int arg, i;
if (argc < 2 || !strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) {
printf("\n");
printf("Usage: %s [ -h | --help ]\n", argv[0]);
printf(" %s mountpoint [ mountpoint ... ]\n", argv[0]);
printf("\n");
printf("This program will report the percentage of inodes in use,\n");
printf("the number free inodes available for normal users,\n");
printf("the number of free inodes available for root,\n");
printf("and the total number of inodes,\n");
printf("in the filesystems referred to the supplied paths.\n");
printf("\n");
printf("Each mount is only counted once, even if multiple paths\n");
printf("to the same mount are given as parameters.\n");
printf("\n");
return EXIT_SUCCESS;
}
for (arg = 1; arg < argc; arg++) {
struct stat info;
struct statvfs vfsinfo;
if (stat(argv[arg], &info) == -1) {
fprintf(stderr, "%s: %s.\n", argv[arg], strerror(errno));
continue;
}
if (statvfs(argv[arg], &vfsinfo) == -1) {
fprintf(stderr, "%s: %s.\n", argv[arg], strerror(errno));
continue;
}
/* Check if device already seen. */
for (i = 0; i < devices; i++)
if (info.st_dev == device[i])
break;
if (i < devices)
continue;
/* Add to known devices. */
device[devices++] = info.st_dev;
/* Add to inode counters. */
total_inodes += (uint64_t)vfsinfo.f_files;
avail_inodes += (uint64_t)vfsinfo.f_favail;
free_inodes += (uint64_t)vfsinfo.f_ffree;
}
if (total_inodes < 0) {
fprintf(stderr, "No inodes!\n");
return EXIT_FAILURE;
}
/* Print result. */
printf("%.3f%% - %" PRIu64 " free (%" PRIu64 " for root) out of %" PRIu64 " inodes.\n",
100.0 - 100.0 * (double)avail_inodes / (double)total_inodes,
avail_inodes, free_inodes, total_inodes);
return EXIT_SUCCESS;
}
Compile it using e.g.
gcc -Wall -O2 inode-stats.c -o inode-stats
optionally install it using e.g.
sudo install -o root -g root -m 0755 inode-stats /usr/bin
and run it, supplying a path to any directory or file in the mounts (mounted filesystems) you are interested in. For example,
inode-stats / /usr /var /home
The program is smart enough to only count mounts once, even if you supply multiple paths to directories/files in it -- unlike GNU coreutils' or busybox stat
.
You can trivially change the output report format, and easily add other statistics (like free disk space, using (uint64_t)vfsinfo.f_bavail * (uint64_t)vfsinfo.f_bsize
for amount of disk space available for normal users, and (uint64_t)vfsinfo.f_blocks * (uint64_t)vfsinfo.f_frsize
for total size of each filesystem).