xref: /haiku/src/bin/df.cpp (revision 894526b51a3d931c423878fc0eb8da610fa1fb2a)
1 //	df - for Haiku
2 //
3 //	authors, in order of contribution:
4 //	jonas.sundstrom@kirilla.com
5 //	axeld@pinc-software.de
6 //
7 
8 
9 #include <Volume.h>
10 #include <Directory.h>
11 #include <Path.h>
12 
13 #include <fs_info.h>
14 
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #include <ctype.h>
19 #include <errno.h>
20 
21 
22 void
23 PrintFlag(uint32 deviceFlags, uint32 testFlag, const char *yes, const char *no)
24 {
25 	printf(deviceFlags & testFlag ? yes : no);
26 }
27 
28 
29 void
30 PrintMountPoint(dev_t device, bool verbose)
31 {
32 	char mount[B_PATH_NAME_LENGTH];
33 	mount[0] = '\0';
34 
35 	BVolume	volume(device);
36 	BDirectory root;
37 	if (volume.GetRootDirectory(&root) == B_OK) {
38 		BPath path(&root, NULL);
39 		if (path.InitCheck() == B_OK)
40 			strlcpy(mount, path.Path(), sizeof(mount));
41 		else
42 			strlcpy(mount, "?", sizeof(mount));
43 	}
44 
45 	if (verbose)
46 		printf("   Mounted at: %s\n", mount);
47 	else {
48 		printf("%-15s ", mount);
49 		if (strlen(mount) > 15)
50 			printf("\n%15s ", "");
51 	}
52 }
53 
54 
55 void
56 PrintType(const char *fileSystem)
57 {
58 	char type[10];
59 	strlcpy(type, fileSystem, sizeof(type));
60 
61 	printf("%-8s", type);
62 }
63 
64 
65 const char *
66 ByteString(int64 numBlocks, int64 blockSize)
67 {
68 	double blocks = 1. * numBlocks * blockSize;
69 	static char string[64];
70 
71 	if (blocks < 1024)
72 		sprintf(string, "%" B_PRId64, numBlocks * blockSize);
73 	else {
74 		const char *units[] = {"K", "M", "G", NULL};
75 		int32 i = -1;
76 
77 		do {
78 			blocks /= 1024.0;
79 			i++;
80 		} while (blocks >= 1024 && units[i + 1]);
81 
82 		sprintf(string, "%.1f%s", blocks, units[i]);
83 	}
84 
85 	return string;
86 }
87 
88 
89 void
90 PrintBlocks(int64 blocks, int64 blockSize, bool showBlocks)
91 {
92 	char temp[1024];
93 
94 	if (showBlocks)
95 		sprintf(temp, "%" B_PRId64, blocks * (blockSize / 1024));
96 	else
97 		strcpy(temp, ByteString(blocks, blockSize));
98 
99 	printf("%10s", temp);
100 }
101 
102 
103 void
104 PrintVerbose(dev_t device)
105 {
106 	fs_info info;
107 	if (fs_stat_dev(device, &info) != B_OK) {
108 		fprintf(stderr, "Could not stat fs: %s\n", strerror(errno));
109 		return;
110 	}
111 
112 	printf("   Device No.: %" B_PRIdDEV "\n", info.dev);
113 	PrintMountPoint(info.dev, true);
114 	printf("  Volume Name: \"%s\"\n", info.volume_name);
115 	printf("  File System: %s\n", info.fsh_name);
116 	printf("       Device: %s\n", info.device_name);
117 
118 	printf("        Flags: ");
119 	PrintFlag(info.flags, B_FS_HAS_QUERY, "Q", "-");
120 	PrintFlag(info.flags, B_FS_HAS_ATTR, "A", "-");
121 	PrintFlag(info.flags, B_FS_HAS_MIME, "M", "-");
122 	PrintFlag(info.flags, B_FS_IS_SHARED, "S", "-");
123 	PrintFlag(info.flags, B_FS_IS_PERSISTENT, "P", "-");
124 	PrintFlag(info.flags, B_FS_IS_REMOVABLE, "R", "-");
125 	PrintFlag(info.flags, B_FS_IS_READONLY, "-", "W");
126 
127 	printf("\n     I/O Size: %10s (%" B_PRIdOFF " byte)\n",
128 		ByteString(info.io_size, 1), info.io_size);
129 	printf("   Block Size: %10s (%" B_PRIdOFF " byte)\n",
130 		ByteString(info.block_size, 1), info.block_size);
131 	printf(" Total Blocks: %10s (%" B_PRIdOFF " blocks)\n",
132 		ByteString(info.total_blocks, info.block_size), info.total_blocks);
133 	printf("  Free Blocks: %10s (%" B_PRIdOFF " blocks)\n",
134 		ByteString(info.free_blocks, info.block_size), info.free_blocks);
135 	printf("  Total Nodes: %" B_PRIdOFF "\n", info.total_nodes);
136 	printf("   Free Nodes: %" B_PRIdOFF "\n", info.free_nodes);
137 	printf("   Root Inode: %" B_PRIdINO "\n", info.root);
138 }
139 
140 
141 void
142 PrintCompact(dev_t device, bool showBlocks, bool all)
143 {
144 	fs_info info;
145 	if (fs_stat_dev(device, &info) != B_OK)
146 		return;
147 
148 	if (!all && (info.flags & B_FS_IS_PERSISTENT) == 0)
149 		return;
150 
151 	PrintMountPoint(info.dev, false);
152 	PrintType(info.fsh_name);
153 	PrintBlocks(info.total_blocks, info.block_size, showBlocks);
154 	PrintBlocks(info.free_blocks, info.block_size, showBlocks);
155 
156 	printf(" ");
157 	PrintFlag(info.flags, B_FS_HAS_QUERY, "Q", "-");
158 	PrintFlag(info.flags, B_FS_HAS_ATTR, "A", "-");
159 	PrintFlag(info.flags, B_FS_HAS_MIME, "M", "-");
160 	PrintFlag(info.flags, B_FS_IS_SHARED, "S", "-");
161 	PrintFlag(info.flags, B_FS_IS_PERSISTENT, "P", "-");
162 	PrintFlag(info.flags, B_FS_IS_REMOVABLE, "R", "-");
163 	PrintFlag(info.flags, B_FS_IS_READONLY, "-", "W");
164 
165 	printf(" %s\n", info.device_name);
166 }
167 
168 
169 void
170 ShowUsage(const char *programName)
171 {
172 	printf("usage: %s [--help | --blocks, -b | -all, -a] [<path-to-device>]\n"
173 		"  -a, --all\tinclude all file systems, also those not visible from Tracker\n"
174 		"  -b, --blocks\tshow device size in blocks of 1024 bytes\n"
175 		"If <path-to-device> is used, detailed info for that device only will be listed.\n"
176 		"Flags:\n"
177 		"   Q: has query\n"
178 		"   A: has attribute\n"
179 		"   M: has mime\n"
180 		"   S: is shared\n"
181 		"   P: is persistent (visible in Tracker)\n"
182 		"   R: is removable\n"
183 		"   W: is writable\n", programName);
184 	exit(0);
185 }
186 
187 
188 int
189 main(int argc, char **argv)
190 {
191 	char *programName = argv[0];
192 	if (strrchr(programName, '/'))
193 		programName = strrchr(programName, '/') + 1;
194 
195 	bool showBlocks = false;
196 	bool all = false;
197 	dev_t device = -1;
198 
199 	while (*++argv) {
200 		char *arg = *argv;
201 		if (*arg == '-') {
202 			while (*++arg && isalpha(*arg)) {
203 				switch (arg[0]) {
204 					case 'a':
205 						all = true;
206 						break;
207 					case 'b':
208 						showBlocks = true;
209 						break;
210 					case 'h':
211 						// human readable units in Unix df
212 						break;
213 					default:
214 						ShowUsage(programName);
215 				}
216 			}
217 			if (arg[0] == '-') {
218 				arg++;
219 				if (!strcmp(arg, "all"))
220 					all = true;
221 				else if (!strcmp(arg, "blocks"))
222 					showBlocks = true;
223 				else
224 					ShowUsage(programName);
225 			}
226 		} else
227 			break;
228 	}
229 
230 	// Do we already have a device? Then let's print out detailed info about that
231 
232 	if (argv[0] != NULL) {
233 		PrintVerbose(dev_for_path(argv[0]));
234 		return 0;
235 	}
236 
237 	// If not, then just iterate over all devices and give a compact summary
238 
239 	printf("Mount           Type      Total     Free     Flags   Device\n"
240 		"--------------- -------- --------- --------- ------- --------------------------\n");
241 
242 	int32 cookie = 0;
243 	while ((device = next_dev(&cookie)) >= B_OK) {
244 		PrintCompact(device, showBlocks, all);
245 	}
246 
247 	return 0;
248 }
249