libc, libutil: remove compat hacks
[minix.git] / commands / df / df.c
blobbe07620b86cb34bd2959b89412be6b51e7024ebb
1 /* df - disk free block printout Author: Andy Tanenbaum
3 * 91/04/30 Kees J. Bot (kjb@cs.vu.nl)
4 * Map filename arguments to the devices they live on.
5 * Changed output to show percentages.
7 * 92/12/12 Kees J. Bot
8 * Posixized. (Almost, the normal output is in kilobytes, it should
9 * be 512-byte units. 'df -P' and 'df -kP' are as it should be.)
13 #include <stdio.h>
14 #include <sys/types.h>
15 #include <sys/statvfs.h>
16 #include <sys/stat.h>
17 #include <errno.h>
18 #include <unistd.h>
19 #include <stdlib.h>
20 #include <string.h>
21 #include <minix/minlib.h>
23 struct mtab { /* List of mounted devices from /etc/mtab. */
24 struct mtab *next;
25 dev_t device;
26 char *devname;
27 char *mountpoint;
28 } *mtab= NULL;
30 struct mtab *searchtab(char *name);
31 static void readmtab(const char *type);
32 int df(const struct mtab *mt);
34 int iflag= 0; /* Focus on inodes instead of blocks. */
35 int Pflag= 0; /* Posix standard output. */
36 int kflag= 0; /* Output in kilobytes instead of 512 byte units for -P. */
37 int istty; /* isatty(1) */
39 void usage(void)
41 fprintf(stderr, "Usage: df [-ikP] [-t type] [device]...\n");
42 exit(1);
45 int unitsize;
47 int main(int argc, char *argv[])
49 int i;
50 struct mtab *mt;
51 char *type= "dev";
52 int ex= 0;
54 while (argc > 1 && argv[1][0] == '-') {
55 char *opt= argv[1]+1;
57 while (*opt != 0) {
58 switch (*opt++) {
59 case 'i': iflag= 1; break;
60 case 'k': kflag= 1; break;
61 case 'P': Pflag= 1; break;
62 case 't':
63 if (argc < 3) usage();
64 type= argv[2];
65 argv++;
66 argc--;
67 break;
68 default:
69 usage();
72 argc--;
73 argv++;
76 istty= isatty(1);
78 readmtab(type);
80 if(!Pflag || (Pflag && kflag)) unitsize = 1024;
81 else unitsize = 512;
83 if (Pflag) {
84 if (!iflag)
85 printf("\
86 Filesystem %4d-blocks Used Available Capacity Mounted on\n",
87 unitsize);
88 else
89 printf("\
90 Filesystem Inodes IUsed IFree %%IUsed Mounted on\n"
92 } else {
93 printf("%s\n", !iflag ? "\
94 Filesystem Size (kB) Free Used % Files% Mounted on" : "\
95 Filesystem Files Free Used % BUsed% Mounted on"
99 if (argc == 1) {
100 for (mt= mtab; mt != NULL; mt= mt->next) ex |= df(mt);
101 } else {
102 for (i = 1; i < argc; i++) ex |= df(searchtab(argv[i]));
104 exit(ex);
107 static void readmtab(const char *type)
108 /* Turn the mounted file table into a list. */
110 struct mtab **amt= &mtab, *new;
111 struct stat st;
112 char devname[PATH_MAX], mountpoint[PATH_MAX], version[MNTNAMELEN],
113 rw_flag[MNTFLAGLEN];
115 if (load_mtab("df") < 0) exit(1);
117 while (get_mtab_entry(devname, mountpoint, version, rw_flag),
118 devname[0] != 0) {
119 if (strcmp(type, "dev") != 0 && strcmp(type, version) != 0) continue;
121 /* Make new list cell. */
122 if ((new= (struct mtab *) malloc(sizeof(*new))) == NULL
123 || (new->devname= (char *) malloc(strlen(devname) + 1)) == NULL
124 || (new->mountpoint= (char *) malloc(strlen(mountpoint) + 1)) == NULL
125 ) break;
127 if (strcmp(devname, "none") != 0 && stat(devname, &st) == 0 &&
128 S_ISBLK(st.st_mode)) {
129 new->device= st.st_rdev;
130 } else if (stat(mountpoint, &st) == 0) {
131 new->device= st.st_dev;
133 strcpy(new->devname, devname);
134 strcpy(new->mountpoint, mountpoint);
136 *amt= new; /* Add the cell to the end. */
137 amt= &new->next;
138 *amt= NULL;
142 struct mtab *searchtab(char *name)
143 /* See what we can do with a user supplied name, there are three possibilities:
144 * 1. It's a device and it is in the mtab: Return mtab entry.
145 * 2. It's a file and lives on a device in the mtab: Return mtab entry.
146 * 3. It's anything else: Return something df() will choke on.
149 static struct mtab unknown;
150 struct mtab *mt;
151 struct stat st;
153 unknown.devname= name;
154 unknown.mountpoint= "";
156 if (stat(name, &st) < 0) return &unknown; /* Case 3. */
158 unknown.device= S_ISBLK(st.st_mode) ? st.st_rdev : st.st_dev;
160 for (mt= mtab; mt != NULL; mt= mt->next) {
161 if (unknown.device == mt->device)
162 return mt; /* Case 1 & 2. */
165 return &unknown; /* Case 3. */
168 /* (num / tot) in percentages rounded up. */
169 #define percent(num, tot) \
170 ((tot > 0) ? ((int) ((100ULL * (num) + ((tot) - 1)) / (tot))) : 0)
172 int df(const struct mtab *mt)
174 long totblocks, busyblocks, totinodes, busyinodes;
175 struct statvfs sv;
176 int n;
178 if (statvfs(mt->mountpoint, &sv) < 0) {
179 fprintf(stderr, "df: %s: %s\n", mt->devname, strerror(errno));
180 return(1);
183 /* Print results. */
184 printf("%s", mt->devname);
185 n= strlen(mt->devname);
186 if (n > 15 && istty) { putchar('\n'); n= 0; }
187 while (n < 15) { putchar(' '); n++; }
189 totblocks = sv.f_blocks;
190 busyblocks = sv.f_blocks - sv.f_bfree;
192 busyblocks = busyblocks * (sv.f_bsize/512) / (unitsize/512);
193 totblocks = totblocks * (sv.f_bsize/512) / (unitsize/512);
195 totinodes = sv.f_files;
196 busyinodes = sv.f_files - sv.f_ffree;
198 if (!Pflag && !iflag) {
199 printf(" %9ld %9ld %9ld %3d%% %3d%% %s\n",
200 totblocks, /* Blocks */
201 totblocks - busyblocks, /* free */
202 busyblocks, /* used */
203 percent(busyblocks, totblocks), /* % */
204 percent(busyinodes, totinodes), /* FUsed% */
205 mt->mountpoint /* Mounted on */
208 if (!Pflag && iflag) {
209 printf(" %9ld %9ld %9ld %3d%% %3d%% %s\n",
210 totinodes, /* Files */
211 totinodes - busyinodes, /* free */
212 busyinodes, /* used */
213 percent(busyinodes, totinodes), /* % */
214 percent(busyblocks, totblocks), /* BUsed% */
215 mt->mountpoint /* Mounted on */
218 if (Pflag && !iflag) {
219 printf(" %9ld %9ld %9ld %4d%% %s\n",
220 totblocks, /* Blocks */
221 busyblocks, /* Used */
222 totblocks - busyblocks, /* Available */
223 percent(busyblocks, totblocks), /* Capacity */
224 mt->mountpoint /* Mounted on */
227 if (Pflag && iflag) {
228 printf(" %9ld %9ld %9ld %4d%% %s\n",
229 totinodes, /* Inodes */
230 busyinodes, /* IUsed */
231 totinodes - busyinodes, /* IAvail */
232 percent(busyinodes, totinodes), /* Capacity */
233 mt->mountpoint /* Mounted on */
236 return(0);