minix/commands/df/df.c
David van Moolenbroek 870f6d08af df(1): use statvfs instead of raw disk access
As of this patch, df(1) no longer performs raw disk access; it
operates exclusively on mounted file systems. This also means
that df no longer needs to be setuid.
2012-10-17 22:51:17 +02:00

236 lines
5.8 KiB
C

/* df - disk free block printout Author: Andy Tanenbaum
*
* 91/04/30 Kees J. Bot (kjb@cs.vu.nl)
* Map filename arguments to the devices they live on.
* Changed output to show percentages.
*
* 92/12/12 Kees J. Bot
* Posixized. (Almost, the normal output is in kilobytes, it should
* be 512-byte units. 'df -P' and 'df -kP' are as it should be.)
*
*/
#include <stdio.h>
#include <sys/types.h>
#include <sys/statvfs.h>
#include <sys/stat.h>
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <minix/minlib.h>
struct mtab { /* List of mounted devices from /etc/mtab. */
struct mtab *next;
dev_t device;
char *devname;
char *mountpoint;
} *mtab= NULL;
struct mtab *searchtab(char *name);
static void readmtab(const char *type);
int df(const struct mtab *mt);
int iflag= 0; /* Focus on inodes instead of blocks. */
int Pflag= 0; /* Posix standard output. */
int kflag= 0; /* Output in kilobytes instead of 512 byte units for -P. */
int istty; /* isatty(1) */
void usage(void)
{
fprintf(stderr, "Usage: df [-ikP] [-t type] [device]...\n");
exit(1);
}
int unitsize;
int main(int argc, char *argv[])
{
int i;
struct mtab *mt;
char *type= "dev";
int ex= 0;
while (argc > 1 && argv[1][0] == '-') {
char *opt= argv[1]+1;
while (*opt != 0) {
switch (*opt++) {
case 'i': iflag= 1; break;
case 'k': kflag= 1; break;
case 'P': Pflag= 1; break;
case 't':
if (argc < 3) usage();
type= argv[2];
argv++;
argc--;
break;
default:
usage();
}
}
argc--;
argv++;
}
istty= isatty(1);
readmtab(type);
if(!Pflag || (Pflag && kflag)) unitsize = 1024;
else unitsize = 512;
if (Pflag) {
if (!iflag)
printf("\
Filesystem %4d-blocks Used Available Capacity Mounted on\n",
unitsize);
else
printf("\
Filesystem Inodes IUsed IFree %%IUsed Mounted on\n"
);
} else {
printf("%s\n", !iflag ? "\
Filesystem Size (kB) Free Used % Files% Mounted on" : "\
Filesystem Files Free Used % BUsed% Mounted on"
);
}
if (argc == 1) {
for (mt= mtab; mt != NULL; mt= mt->next) ex |= df(mt);
} else {
for (i = 1; i < argc; i++) ex |= df(searchtab(argv[i]));
}
exit(ex);
}
static void readmtab(const char *type)
/* Turn the mounted file table into a list. */
{
struct mtab **amt= &mtab, *new;
struct stat st;
char devname[128], mountpoint[128], version[10], rw_flag[10];
if (load_mtab("df") < 0) exit(1);
while (get_mtab_entry(devname, mountpoint, version, rw_flag),
devname[0] != 0) {
if (strcmp(type, "dev") != 0 && strcmp(type, version) != 0) continue;
/* Make new list cell. */
if ((new= (struct mtab *) malloc(sizeof(*new))) == NULL
|| (new->devname= (char *) malloc(strlen(devname) + 1)) == NULL
|| (new->mountpoint= (char *) malloc(strlen(mountpoint) + 1)) == NULL
) break;
if (strcmp(devname, "none") != 0 && stat(devname, &st) == 0 &&
S_ISBLK(st.st_mode)) {
new->device= st.st_rdev;
} else if (stat(mountpoint, &st) == 0) {
new->device= st.st_dev;
}
strcpy(new->devname, devname);
strcpy(new->mountpoint, mountpoint);
*amt= new; /* Add the cell to the end. */
amt= &new->next;
*amt= NULL;
}
}
struct mtab *searchtab(char *name)
/* See what we can do with a user supplied name, there are three possibilities:
* 1. It's a device and it is in the mtab: Return mtab entry.
* 2. It's a file and lives on a device in the mtab: Return mtab entry.
* 3. It's anything else: Return something df() will choke on.
*/
{
static struct mtab unknown;
struct mtab *mt;
struct stat st;
unknown.devname= name;
unknown.mountpoint= "";
if (stat(name, &st) < 0) return &unknown; /* Case 3. */
unknown.device= S_ISBLK(st.st_mode) ? st.st_rdev : st.st_dev;
for (mt= mtab; mt != NULL; mt= mt->next) {
if (unknown.device == mt->device)
return mt; /* Case 1 & 2. */
}
return &unknown; /* Case 3. */
}
/* (num / tot) in percentages rounded up. */
#define percent(num, tot) \
((tot > 0) ? ((int) ((100ULL * (num) + ((tot) - 1)) / (tot))) : 0)
int df(const struct mtab *mt)
{
long totblocks, busyblocks, totinodes, busyinodes;
struct statvfs sv;
int n;
if (statvfs(mt->mountpoint, &sv) < 0) {
fprintf(stderr, "df: %s: %s\n", mt->devname, strerror(errno));
return(1);
}
/* Print results. */
printf("%s", mt->devname);
n= strlen(mt->devname);
if (n > 15 && istty) { putchar('\n'); n= 0; }
while (n < 15) { putchar(' '); n++; }
totblocks = sv.f_blocks;
busyblocks = sv.f_blocks - sv.f_bfree;
busyblocks = busyblocks * (sv.f_bsize/512) / (unitsize/512);
totblocks = totblocks * (sv.f_bsize/512) / (unitsize/512);
totinodes = sv.f_files;
busyinodes = sv.f_files - sv.f_ffree;
if (!Pflag && !iflag) {
printf(" %9ld %9ld %9ld %3d%% %3d%% %s\n",
totblocks, /* Blocks */
totblocks - busyblocks, /* free */
busyblocks, /* used */
percent(busyblocks, totblocks), /* % */
percent(busyinodes, totinodes), /* FUsed% */
mt->mountpoint /* Mounted on */
);
}
if (!Pflag && iflag) {
printf(" %9ld %9ld %9ld %3d%% %3d%% %s\n",
totinodes, /* Files */
totinodes - busyinodes, /* free */
busyinodes, /* used */
percent(busyinodes, totinodes), /* % */
percent(busyblocks, totblocks), /* BUsed% */
mt->mountpoint /* Mounted on */
);
}
if (Pflag && !iflag) {
printf(" %9ld %9ld %9ld %4d%% %s\n",
totblocks, /* Blocks */
busyblocks, /* Used */
totblocks - busyblocks, /* Available */
percent(busyblocks, totblocks), /* Capacity */
mt->mountpoint /* Mounted on */
);
}
if (Pflag && iflag) {
printf(" %9ld %9ld %9ld %4d%% %s\n",
totinodes, /* Inodes */
busyinodes, /* IUsed */
totinodes - busyinodes, /* IAvail */
percent(busyinodes, totinodes), /* Capacity */
mt->mountpoint /* Mounted on */
);
}
return(0);
}