source: trunk/minix/commands/simple/df.c@ 20

Last change on this file since 20 was 9, checked in by Mattia Monga, 14 years ago

Minix 3.1.2a

File size: 11.3 KB
Line 
1/* df - disk free block printout Author: Andy Tanenbaum
2 *
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.
6 *
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.)
10 *
11 */
12
13#include <stdio.h>
14#include <sys/types.h>
15#include <sys/stat.h>
16#include <limits.h>
17#include <fcntl.h>
18#include <errno.h>
19#include <unistd.h>
20#include <stdio.h>
21#include <stdlib.h>
22#include <string.h>
23#include <dirent.h>
24#if __minix_vmd
25#include <sys/mnttab.h>
26#else
27#include <minix/minlib.h>
28#endif
29
30#include <minix/config.h>
31#include <minix/const.h>
32#include <minix/type.h>
33#include <servers/fs/const.h>
34#include <servers/fs/type.h>
35#include <servers/fs/super.h>
36#undef printf
37
38#if !__minix_vmd
39/* Map Minix-vmd names to Minix names. */
40#define v12_super_block super_block
41#define SUPER_V1 SUPER_MAGIC
42
43#endif
44
45#define ISDISK(mode) S_ISBLK(mode) /* || S_ISCHR for raw device??? */
46
47extern int errno;
48char MTAB[] = "/etc/mtab";
49
50struct mtab { /* List of mounted devices from /etc/mtab. */
51 struct mtab *next;
52 dev_t device;
53 char *devname;
54 char *mountpoint;
55} *mtab= NULL;
56
57struct mtab *searchtab(char *name);
58void readmtab(char *type);
59int df(const struct mtab *mt);
60bit_t bit_count(unsigned blocks, bit_t bits, int fd, int bs);
61
62int iflag= 0; /* Focus on inodes instead of blocks. */
63int Pflag= 0; /* Posix standard output. */
64int kflag= 0; /* Output in kilobytes instead of 512 byte units for -P. */
65int istty; /* isatty(1) */
66uid_t ruid, euid; /* To sometimes change identities. */
67gid_t rgid, egid;
68
69void usage(void)
70{
71 fprintf(stderr, "Usage: df [-ikP] [-t type] [device]...\n");
72 exit(1);
73}
74
75int unitsize;
76
77int main(int argc, char *argv[])
78{
79 int i;
80 struct mtab *mt;
81 char *type= "dev";
82 int ex= 0;
83
84 while (argc > 1 && argv[1][0] == '-') {
85 char *opt= argv[1]+1;
86
87 while (*opt != 0) {
88 switch (*opt++) {
89 case 'i': iflag= 1; break;
90 case 'k': kflag= 1; break;
91 case 'P': Pflag= 1; break;
92 case 't':
93 if (argc < 3) usage();
94 type= argv[2];
95 argv++;
96 argc--;
97 break;
98 default:
99 usage();
100 }
101 }
102 argc--;
103 argv++;
104 }
105
106 istty= isatty(1);
107 ruid= getuid(); euid= geteuid();
108 rgid= getgid(); egid= getegid();
109
110 readmtab(type);
111
112 if(!Pflag || (Pflag && kflag)) unitsize = 1024;
113 else unitsize = 512;
114
115 if (Pflag) {
116 printf(!iflag ? "\
117Filesystem %4d-blocks Used Available Capacity Mounted on\n" : "\
118Filesystem Inodes IUsed IFree %%IUsed Mounted on\n",
119 unitsize);
120 } else {
121 printf("%s\n", !iflag ? "\
122Filesystem Size (kB) Free Used % Files% Mounted on" : "\
123Filesystem Files Free Used % BUsed% Mounted on"
124 );
125 }
126
127 if (argc == 1) {
128 for (mt= mtab; mt != NULL; mt= mt->next) ex |= df(mt);
129 } else {
130 for (i = 1; i < argc; i++) ex |= df(searchtab(argv[i]));
131 }
132 exit(ex);
133}
134
135void readmtab(char *type)
136/* Turn the mounted file table into a list. */
137{
138 struct mtab **amt= &mtab, *new;
139 struct stat st;
140
141#if __minix_vmd
142 char *devname, *mountpoint;
143 FILE *mtf;
144 struct mnttab mte, look;
145
146 if ((mtf= fopen(MTAB, "r")) == NULL) {
147 fprintf(stderr, "df: can't open %s\n", MTAB);
148 return;
149 }
150
151 look.mnt_special= NULL;
152 look.mnt_mountp= NULL;
153 look.mnt_fstype= type;
154 look.mnt_mntopts= NULL;
155
156 while (getmntany(mtf, &mte, &look) >= 0) {
157 devname= mte.mnt_special;
158 mountpoint= mte.mnt_mountp;
159
160 /* Skip bad entries, can't complain about everything. */
161 if (stat(devname, &st) < 0 || !ISDISK(st.st_mode)) continue;
162
163 /* Make new list cell. */
164 if ((new= (struct mtab *) malloc(sizeof(*new))) == NULL
165 || (new->devname= (char *) malloc(strlen(devname) + 1)) == NULL
166 || (new->mountpoint= (char *) malloc(strlen(mountpoint) + 1)) == NULL
167 ) break;
168
169 new->device= st.st_rdev;
170 strcpy(new->devname, devname);
171 strcpy(new->mountpoint, mountpoint);
172
173 *amt= new; /* Add the cell to the end. */
174 amt= &new->next;
175 *amt= NULL;
176 }
177 fclose(mtf);
178
179#else /* __minix */
180 char devname[128], mountpoint[128], version[10], rw_flag[10];
181
182 if (load_mtab("df") < 0) exit(1);
183
184 while (get_mtab_entry(devname, mountpoint, version, rw_flag),
185 devname[0] != 0) {
186 if (strcmp(type, "dev") == 0) {
187 if (strcmp(version, "1") != 0 && strcmp(version, "2") != 0 &&
188 strcmp(version, "3"))
189 continue;
190 } else {
191 if (strcmp(type, version) != 0) continue;
192 }
193
194 /* Skip bad entries, can't complain about everything. */
195 if (stat(devname, &st) < 0 || !ISDISK(st.st_mode)) continue;
196
197 /* Make new list cell. */
198 if ((new= (struct mtab *) malloc(sizeof(*new))) == NULL
199 || (new->devname= (char *) malloc(strlen(devname) + 1)) == NULL
200 || (new->mountpoint= (char *) malloc(strlen(mountpoint) + 1)) == NULL
201 ) break;
202
203 new->device= st.st_rdev;
204 strcpy(new->devname, devname);
205 strcpy(new->mountpoint, mountpoint);
206
207 *amt= new; /* Add the cell to the end. */
208 amt= &new->next;
209 *amt= NULL;
210 }
211#endif
212}
213
214struct mtab *searchtab(char *name)
215/* See what we can do with a user supplied name, there are five possibilities:
216 * 1. It's a device and it is in the mtab: Return mtab entry.
217 * 2. It's a device and it is not in the mtab: Return device mounted on "".
218 * 3. It's a file and lives on a device in the mtab: Return mtab entry.
219 * 4. It's a file and it's not on an mtab device: Search /dev for the device
220 * and return this device as mounted on "???".
221 * 5. It's junk: Return something df() will choke on.
222 */
223{
224 static struct mtab unknown;
225 static char devname[5 + NAME_MAX + 1]= "/dev/";
226 struct mtab *mt;
227 struct stat st;
228 DIR *dp;
229 struct dirent *ent;
230
231 unknown.devname= name;
232 unknown.mountpoint= "";
233
234 if (stat(name, &st) < 0) return &unknown; /* Case 5. */
235
236 unknown.device= ISDISK(st.st_mode) ? st.st_rdev : st.st_dev;
237
238 for (mt= mtab; mt != NULL; mt= mt->next) {
239 if (unknown.device == mt->device)
240 return mt; /* Case 1 & 3. */
241 }
242
243 if (ISDISK(st.st_mode)) {
244 return &unknown; /* Case 2. */
245 }
246
247 if ((dp= opendir("/dev")) == NULL) return &unknown; /* Disaster. */
248
249 while ((ent= readdir(dp)) != NULL) {
250 if (ent->d_name[0] == '.') continue;
251 strcpy(devname + 5, ent->d_name);
252 if (stat(devname, &st) >= 0 && ISDISK(st.st_mode)
253 && unknown.device == st.st_rdev
254 ) {
255 unknown.devname= devname;
256 unknown.mountpoint= "???";
257 break;
258 }
259 }
260 closedir(dp);
261 return &unknown; /* Case 4. */
262}
263
264/* (num / tot) in percentages rounded up. */
265#define percent(num, tot) ((int) ((100L * (num) + ((tot) - 1)) / (tot)))
266
267/* One must be careful printing all these _t types. */
268#define L(n) ((long) (n))
269
270int df(const struct mtab *mt)
271{
272 int fd;
273 bit_t i_count, z_count;
274 block_t totblocks, busyblocks;
275 int n, block_size;
276 struct v12_super_block super, *sp;
277
278 /* Don't allow Joe User to df just any device. */
279 seteuid(*mt->mountpoint == 0 ? ruid : euid);
280 setegid(*mt->mountpoint == 0 ? rgid : egid);
281
282 if ((fd = open(mt->devname, O_RDONLY)) < 0) {
283 fprintf(stderr, "df: %s: %s\n", mt->devname, strerror(errno));
284 return(1);
285 }
286 lseek(fd, (off_t) SUPER_BLOCK_BYTES, SEEK_SET); /* skip boot block */
287
288 if (read(fd, (char *) &super, sizeof(super)) != (int) sizeof(super)) {
289 fprintf(stderr, "df: Can't read super block of %s\n", mt->devname);
290 close(fd);
291 return(1);
292 }
293
294 sp = &super;
295 if (sp->s_magic != SUPER_V1 && sp->s_magic != SUPER_V2
296 && sp->s_magic != SUPER_V3) {
297 fprintf(stderr, "df: %s: Not a valid file system\n", mt->devname);
298 close(fd);
299 return(1);
300 }
301
302 if(sp->s_magic != SUPER_V3) block_size = _STATIC_BLOCK_SIZE;
303 else block_size = super.s_block_size;
304
305 if(block_size < _MIN_BLOCK_SIZE || block_size > _MAX_BLOCK_SIZE) {
306 fprintf(stderr, "df: %s: funny block size (%d)\n",
307 mt->devname, block_size);
308 close(fd);
309 return(1);
310 }
311
312 if (sp->s_magic == SUPER_V1) sp->s_zones= sp->s_nzones;
313
314 lseek(fd, (off_t) block_size * 2L, SEEK_SET); /* skip rest of super block */
315
316 i_count = bit_count(sp->s_imap_blocks, (bit_t) (sp->s_ninodes+1),
317 fd, block_size);
318
319 if (i_count == -1) {
320 fprintf(stderr, "df: Can't find bit maps of %s\n", mt->devname);
321 close(fd);
322 return(1);
323 }
324 i_count--; /* There is no inode 0. */
325
326 /* The first bit in the zone map corresponds with zone s_firstdatazone - 1
327 * This means that there are s_zones - (s_firstdatazone - 1) bits in the map
328 */
329 z_count = bit_count(sp->s_zmap_blocks,
330 (bit_t) (sp->s_zones - (sp->s_firstdatazone - 1)), fd, block_size);
331
332 if (z_count == -1) {
333 fprintf(stderr, "df: Can't find bit maps of %s\n", mt->devname);
334 close(fd);
335 return(1);
336 }
337 /* Don't forget those zones before sp->s_firstdatazone - 1 */
338 z_count += sp->s_firstdatazone - 1;
339
340#ifdef __minix_vmd
341 totblocks = sp->s_zones;
342 busyblocks = z_count;
343#else
344 totblocks = (block_t) sp->s_zones << sp->s_log_zone_size;
345 busyblocks = (block_t) z_count << sp->s_log_zone_size;
346#endif
347
348 busyblocks = busyblocks * (block_size/512) / (unitsize/512);
349 totblocks = totblocks * (block_size/512) / (unitsize/512);
350
351 /* Print results. */
352 printf("%s", mt->devname);
353 n= strlen(mt->devname);
354 if (n > 15 && istty) { putchar('\n'); n= 0; }
355 while (n < 15) { putchar(' '); n++; }
356
357 if (!Pflag && !iflag) {
358 printf(" %9ld %9ld %9ld %3d%% %3d%% %s\n",
359 L(totblocks), /* Blocks */
360 L(totblocks - busyblocks), /* free */
361 L(busyblocks), /* used */
362 percent(busyblocks, totblocks), /* % */
363 percent(i_count, sp->s_ninodes), /* FUsed% */
364 mt->mountpoint /* Mounted on */
365 );
366 }
367 if (!Pflag && iflag) {
368 printf(" %9ld %9ld %9ld %3d%% %3d%% %s\n",
369 L(sp->s_ninodes), /* Files */
370 L(sp->s_ninodes - i_count), /* free */
371 L(i_count), /* used */
372 percent(i_count, sp->s_ninodes), /* % */
373 percent(busyblocks, totblocks), /* BUsed% */
374 mt->mountpoint /* Mounted on */
375 );
376 }
377 if (Pflag && !iflag) {
378 printf(" %9ld %9ld %9ld %4d%% %s\n",
379 L(totblocks), /* Blocks */
380 L(busyblocks), /* Used */
381 totblocks - busyblocks, /* Available */
382 percent(busyblocks, totblocks), /* Capacity */
383 mt->mountpoint /* Mounted on */
384 );
385 }
386 if (Pflag && iflag) {
387 printf(" %9ld %9ld %9ld %4d%% %s\n",
388 L(sp->s_ninodes), /* Inodes */
389 L(i_count), /* IUsed */
390 L(sp->s_ninodes - i_count), /* IAvail */
391 percent(i_count, sp->s_ninodes), /* Capacity */
392 mt->mountpoint /* Mounted on */
393 );
394 }
395 close(fd);
396 return(0);
397}
398
399bit_t bit_count(unsigned blocks, bit_t bits, int fd, int block_size)
400{
401 char *wptr;
402 int i, b;
403 bit_t busy;
404 char *wlim;
405 static char buf[_MAX_BLOCK_SIZE];
406 static char bits_in_char[1 << CHAR_BIT];
407
408 /* Precalculate bitcount for each char. */
409 if (bits_in_char[1] != 1) {
410 for (b = (1 << 0); b < (1 << CHAR_BIT); b <<= 1)
411 for (i = 0; i < (1 << CHAR_BIT); i++)
412 if (i & b) bits_in_char[i]++;
413 }
414
415 /* Loop on blocks, reading one at a time and counting bits. */
416 busy = 0;
417 for (i = 0; i < blocks && bits != 0; i++) {
418 if (read(fd, buf, block_size) != block_size) return(-1);
419
420 wptr = &buf[0];
421 if (bits >= CHAR_BIT * block_size) {
422 wlim = &buf[block_size];
423 bits -= CHAR_BIT * block_size;
424 } else {
425 b = bits / CHAR_BIT; /* whole chars in map */
426 wlim = &buf[b];
427 bits -= b * CHAR_BIT; /* bits in last char, if any */
428 b = *wlim & ((1 << bits) - 1); /* bit pattern from last ch */
429 busy += bits_in_char[b];
430 bits = 0;
431 }
432
433 /* Loop on the chars of a block. */
434 while (wptr != wlim)
435 busy += bits_in_char[*wptr++ & ((1 << CHAR_BIT) - 1)];
436 }
437 return(busy);
438}
439
440/*
441 * $PchId: df.c,v 1.7 1998/07/27 18:42:17 philip Exp $
442 */
Note: See TracBrowser for help on using the repository browser.