xref: /haiku/src/bin/df.cpp (revision e1c4049fed1047bdb957b0529e1921e97ef94770)
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, char yes, char no)
24 {
25 	printf("%c", 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 	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(" %24s ", info.device_name);
166 	PrintMountPoint(info.dev, false);
167 	printf("\n");
168 }
169 
170 
171 void
172 ShowUsage(const char *programName)
173 {
174 	printf("usage: %s [--help | --blocks, -b | -all, -a] [<path-to-device>]\n"
175 		"  -a, --all\tinclude all file systems, also those not visible from Tracker\n"
176 		"  -b, --blocks\tshow device size in blocks of 1024 bytes\n"
177 		"If <path-to-device> is used, detailed info for that device only will be listed.\n"
178 		"Flags:\n"
179 		"   Q: has query\n"
180 		"   A: has attribute\n"
181 		"   M: has mime\n"
182 		"   S: is shared\n"
183 		"   P: is persistent (visible in Tracker)\n"
184 		"   R: is removable\n"
185 		"   W: is writable\n", programName);
186 	exit(0);
187 }
188 
189 
190 int
191 main(int argc, char **argv)
192 {
193 	char *programName = argv[0];
194 	if (strrchr(programName, '/'))
195 		programName = strrchr(programName, '/') + 1;
196 
197 	bool showBlocks = false;
198 	bool all = false;
199 	dev_t device = -1;
200 
201 	while (*++argv) {
202 		char *arg = *argv;
203 		if (*arg == '-') {
204 			while (*++arg && isalpha(*arg)) {
205 				switch (arg[0]) {
206 					case 'a':
207 						all = true;
208 						break;
209 					case 'b':
210 						showBlocks = true;
211 						break;
212 					case 'h':
213 						// human readable units in Unix df
214 						break;
215 					default:
216 						ShowUsage(programName);
217 				}
218 			}
219 			if (arg[0] == '-') {
220 				arg++;
221 				if (!strcmp(arg, "all"))
222 					all = true;
223 				else if (!strcmp(arg, "blocks"))
224 					showBlocks = true;
225 				else
226 					ShowUsage(programName);
227 			}
228 		} else
229 			break;
230 	}
231 
232 	// Do we already have a device? Then let's print out detailed info about that
233 
234 	if (argv[0] != NULL) {
235 		PrintVerbose(dev_for_path(argv[0]));
236 		return 0;
237 	}
238 
239 	// If not, then just iterate over all devices and give a compact summary
240 
241 	printf(" Type      Total     Free      Flags   Device                   Mounted on\n"
242 		   "--------- --------- --------- ------- ------------------------ -----------------\n");
243 
244 	int32 cookie = 0;
245 	while ((device = next_dev(&cookie)) >= B_OK) {
246 		PrintCompact(device, showBlocks, all);
247 	}
248 
249 	return 0;
250 }
251