df.c revision b1aaba1fc8176ac0b7c202a664d2554aa0967116
1/* vi: set sw=4 ts=4:
2 *
3 * df.c - report free disk space.
4 *
5 * Copyright 2006 Rob Landley <rob@landley.net>
6 *
7 * See http://www.opengroup.org/onlinepubs/009695399/utilities/df.html
8
9USE_DF(NEWTOY(df, "Pkt*a", TOYFLAG_USR|TOYFLAG_SBIN))
10
11config DF
12	bool "df (disk free)"
13	default y
14	help
15	  usage: df [-t type] [FILESYSTEM ...]
16
17	  The "disk free" command, df shows total/used/available disk space for
18	  each filesystem listed on the command line, or all currently mounted
19	  filesystems.
20
21	  -t type
22		Display only filesystems of this type.
23
24config DF_PEDANTIC
25	bool "options -P and -k"
26	default y
27	depends on DF
28	help
29	  usage: df [-Pk]
30
31	  -P	The SUSv3 "Pedantic" option
32
33		Provides a slightly less useful output format dictated by
34		the Single Unix Specification version 3, and sets the
35		units to 512 bytes instead of the default 1024 bytes.
36
37	  -k	Sets units back to 1024 bytes (the default without -P)
38*/
39
40#include "toys.h"
41
42DEFINE_GLOBALS(
43	struct arg_list *fstype;
44
45	long units;
46)
47
48#define TT this.df
49
50static void show_mt(struct mtab_list *mt)
51{
52	int len;
53	long size, used, avail, percent;
54	uint64_t block;
55
56	// Return if it wasn't found (should never happen, but with /etc/mtab...)
57	if (!mt) return;
58
59	// If we have -t, skip other filesystem types
60	if (TT.fstype) {
61		struct arg_list *al;
62
63		for (al = TT.fstype; al; al = al->next) {
64			if (!strcmp(mt->type, al->arg)) break;
65		}
66		if (!al) return;
67	}
68
69	// If we don't have -a, skip synthetic filesystems
70	if (!(toys.optflags & 1) && !mt->statvfs.f_blocks) return;
71
72	// Figure out how much total/used/free space this filesystem has,
73	// forcing 64-bit math because filesystems are big now.
74	block = mt->statvfs.f_bsize ? : 1;
75	size = (long)((block * mt->statvfs.f_blocks) / TT.units);
76	used = (long)((block * (mt->statvfs.f_blocks-mt->statvfs.f_bfree))
77			/ TT.units);
78	avail = (long)((block
79				* (getuid() ? mt->statvfs.f_bavail : mt->statvfs.f_bfree))
80			/ TT.units);
81	percent = size ? 100-(long)((100*(uint64_t)avail)/size) : 0;
82
83	// Figure out appropriate spacing
84	len = 25 - strlen(mt->device);
85	if (len < 1) len = 1;
86	if (CFG_DF_PEDANTIC && (toys.optflags & 8)) {
87		printf("%s %ld %ld %ld %ld%% %s\n", mt->device, size, used, avail,
88				percent, mt->dir);
89	} else {
90		printf("%s% *ld % 10ld % 9ld % 3ld%% %s\n",mt->device, len,
91			size, used, avail, percent, mt->dir);
92	}
93}
94
95void df_main(void)
96{
97	struct mtab_list *mt, *mt2, *mtlist;
98
99	// Handle -P and -k
100	TT.units = 1024;
101	if (CFG_DF_PEDANTIC && (toys.optflags & 8)) {
102		// Units are 512 bytes if you select "pedantic" without "kilobytes".
103		if ((toys.optflags&3) == 1) TT.units = 512;
104		printf("Filesystem %ld-blocks Used Available Capacity Mounted on\n",
105			TT.units);
106	} else puts("Filesystem\t1K-blocks\tUsed Available Use% Mounted on");
107
108	mtlist = getmountlist(1);
109
110	// If we have a list of filesystems on the command line, loop through them.
111	if (*toys.optargs) {
112		char **next;
113
114		for(next = toys.optargs; *next; next++) {
115			struct stat st;
116
117			// Stat it (complain if we can't).
118			if(stat(*next, &st)) {
119				perror_msg("`%s'", *next);
120				toys.exitval = 1;
121				continue;
122			}
123
124			// Find and display this filesystem.  Use _last_ hit in case of
125			// -- bind mounts.
126			mt2 = NULL;
127			for (mt = mtlist; mt; mt = mt->next)
128				if (st.st_dev == mt->stat.st_dev) mt2 = mt;
129			show_mt(mt2);
130		}
131	} else {
132		// Get and loop through mount list.
133
134		for (mt = mtlist; mt; mt = mt->next) {
135			struct mtab_list *mt2, *mt3;
136
137			if (!mt->stat.st_dev) continue;
138
139			// Filter out overmounts.
140			mt3 = mt;
141			for (mt2 = mt->next; mt2; mt2 = mt2->next) {
142				if (mt->stat.st_dev == mt2->stat.st_dev) {
143					// For --bind mounts, take last match
144					if (!strcmp(mt->device, mt2->device)) mt3 = mt2;
145					// Filter out overmounts
146					mt2->stat.st_dev = 0;
147				}
148			}
149			show_mt(mt3);
150		}
151	}
152
153	if (CFG_TOYBOX_FREE) llist_free(mtlist, NULL);
154}
155