xref: /haiku/src/bin/df.cpp (revision 3216a856947f9746d8c4c1e720ccf3dc5c0ac786)
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("%s", 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("%-17s ", mount);
49 		if (strlen(mount) > 17)
50 			printf("\n%17s ", "");
51 	}
52 }
53 
54 
55 void
56 PrintType(const char *fileSystem)
57 {
58 	char type[16];
59 	strlcpy(type, fileSystem, sizeof(type));
60 
61 	printf("%-9s", 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[] = {"KiB", "MiB", "GiB", "TiB", "PiB", "EiB",
75 							   "ZiB", "YiB", NULL};
76 		int32 i = -1;
77 
78 		do {
79 			blocks /= 1024.0;
80 			i++;
81 		} while (blocks >= 1024 && units[i + 1]);
82 
83 		sprintf(string, "%.1f %s", blocks, units[i]);
84 	}
85 
86 	return string;
87 }
88 
89 
90 void
91 PrintBlocks(int64 blocks, int64 blockSize, bool showBlocks)
92 {
93 	char temp[1024];
94 
95 	if (showBlocks)
96 		sprintf(temp, "%" B_PRId64, blocks * (blockSize / 1024));
97 	else
98 		strcpy(temp, ByteString(blocks, blockSize));
99 
100 	printf("%10s", temp);
101 }
102 
103 
104 void
105 PrintVerbose(dev_t device)
106 {
107 	fs_info info;
108 	if (fs_stat_dev(device, &info) != B_OK) {
109 		fprintf(stderr, "Could not stat fs: %s\n", strerror(errno));
110 		return;
111 	}
112 
113 	printf("   Device No.: %" B_PRIdDEV "\n", info.dev);
114 	PrintMountPoint(info.dev, true);
115 	printf("  Volume Name: \"%s\"\n", info.volume_name);
116 	printf("  File System: %s\n", info.fsh_name);
117 	printf("       Device: %s\n", info.device_name);
118 
119 	printf("        Flags: ");
120 	PrintFlag(info.flags, B_FS_HAS_QUERY, "Q", "-");
121 	PrintFlag(info.flags, B_FS_HAS_ATTR, "A", "-");
122 	PrintFlag(info.flags, B_FS_HAS_MIME, "M", "-");
123 	PrintFlag(info.flags, B_FS_IS_SHARED, "S", "-");
124 	PrintFlag(info.flags, B_FS_IS_PERSISTENT, "P", "-");
125 	PrintFlag(info.flags, B_FS_IS_REMOVABLE, "R", "-");
126 	PrintFlag(info.flags, B_FS_IS_READONLY, "-", "W");
127 
128 	printf("\n     I/O Size: %10s (%" B_PRIdOFF " byte)\n",
129 		ByteString(info.io_size, 1), info.io_size);
130 	printf("   Block Size: %10s (%" B_PRIdOFF " byte)\n",
131 		ByteString(info.block_size, 1), info.block_size);
132 	printf(" Total Blocks: %10s (%" B_PRIdOFF " blocks)\n",
133 		ByteString(info.total_blocks, info.block_size), info.total_blocks);
134 	printf("  Free Blocks: %10s (%" B_PRIdOFF " blocks)\n",
135 		ByteString(info.free_blocks, info.block_size), info.free_blocks);
136 	printf("  Total Nodes: %" B_PRIdOFF "\n", info.total_nodes);
137 	printf("   Free Nodes: %" B_PRIdOFF "\n", info.free_nodes);
138 	printf("   Root Inode: %" B_PRIdINO "\n", info.root);
139 }
140 
141 
142 void
143 PrintCompact(dev_t device, bool showBlocks, bool all)
144 {
145 	fs_info info;
146 	if (fs_stat_dev(device, &info) != B_OK)
147 		return;
148 
149 	if (!all && (info.flags & B_FS_IS_PERSISTENT) == 0)
150 		return;
151 
152 	PrintMountPoint(info.dev, false);
153 	PrintType(info.fsh_name);
154 	PrintBlocks(info.total_blocks, info.block_size, showBlocks);
155 	PrintBlocks(info.free_blocks, info.block_size, showBlocks);
156 
157 	printf(" ");
158 	PrintFlag(info.flags, B_FS_HAS_QUERY, "Q", "-");
159 	PrintFlag(info.flags, B_FS_HAS_ATTR, "A", "-");
160 	PrintFlag(info.flags, B_FS_HAS_MIME, "M", "-");
161 	PrintFlag(info.flags, B_FS_IS_SHARED, "S", "-");
162 	PrintFlag(info.flags, B_FS_IS_PERSISTENT, "P", "-");
163 	PrintFlag(info.flags, B_FS_IS_REMOVABLE, "R", "-");
164 	PrintFlag(info.flags, B_FS_IS_READONLY, "-", "W");
165 
166 	printf(" %s\n", info.device_name);
167 }
168 
169 
170 void
171 ShowUsage(const char *programName)
172 {
173 	printf("usage: %s [--help | --blocks, -b | -all, -a] [<path-to-device>]\n"
174 		"  -a, --all\tinclude all file systems, also those not visible from Tracker\n"
175 		"  -b, --blocks\tshow device size in blocks of 1024 bytes\n"
176 		"If <path-to-device> is used, detailed info for that device only will be listed.\n"
177 		"Flags:\n"
178 		"   Q: has query\n"
179 		"   A: has attribute\n"
180 		"   M: has mime\n"
181 		"   S: is shared\n"
182 		"   P: is persistent (visible in Tracker)\n"
183 		"   R: is removable\n"
184 		"   W: is writable\n", programName);
185 	exit(0);
186 }
187 
188 
189 int
190 main(int argc, char **argv)
191 {
192 	char *programName = argv[0];
193 	if (strrchr(programName, '/'))
194 		programName = strrchr(programName, '/') + 1;
195 
196 	bool showBlocks = false;
197 	bool all = false;
198 	dev_t device = -1;
199 
200 	while (*++argv) {
201 		char *arg = *argv;
202 		if (*arg == '-') {
203 			while (*++arg && isalpha(*arg)) {
204 				switch (arg[0]) {
205 					case 'a':
206 						all = true;
207 						break;
208 					case 'b':
209 						showBlocks = true;
210 						break;
211 					case 'h':
212 						// human readable units in Unix df
213 						break;
214 					default:
215 						ShowUsage(programName);
216 				}
217 			}
218 			if (arg[0] == '-') {
219 				arg++;
220 				if (!strcmp(arg, "all"))
221 					all = true;
222 				else if (!strcmp(arg, "blocks"))
223 					showBlocks = true;
224 				else
225 					ShowUsage(programName);
226 			}
227 		} else
228 			break;
229 	}
230 
231 	// Do we already have a device? Then let's print out detailed info about that
232 
233 	if (argv[0] != NULL) {
234 		PrintVerbose(dev_for_path(argv[0]));
235 		return 0;
236 	}
237 
238 	// If not, then just iterate over all devices and give a compact summary
239 
240 	printf(" Mount             Type      Total     Free      Flags   Device\n"
241 		   "----------------- --------- --------- --------- ------- ------------------------\n");
242 
243 	int32 cookie = 0;
244 	while ((device = next_dev(&cookie)) >= B_OK) {
245 		PrintCompact(device, showBlocks, all);
246 	}
247 
248 	return 0;
249 }
250