xref: /haiku/src/bin/df.cpp (revision 2222d0559df303a9846a2fad53741f8b20b14d7c)
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, "%Ld", 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, "%Ld", 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.: %ld\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 (%Ld byte)\n", ByteString(info.io_size, 1), info.io_size);
128 	printf("   Block Size: %10s (%Ld byte)\n", ByteString(info.block_size, 1), info.block_size);
129 	printf(" Total Blocks: %10s (%Ld blocks)\n", ByteString(info.total_blocks, info.block_size), info.total_blocks);
130 	printf("  Free Blocks: %10s (%Ld blocks)\n", ByteString(info.free_blocks, info.block_size), info.free_blocks);
131 	printf("  Total Nodes: %Ld\n", info.total_nodes);
132 	printf("   Free Nodes: %Ld\n", info.free_nodes);
133 	printf("   Root Inode: %Ld\n", info.root);
134 }
135 
136 
137 void
138 PrintCompact(dev_t device, bool showBlocks, bool all)
139 {
140 	fs_info info;
141 	if (fs_stat_dev(device, &info) != B_OK)
142 		return;
143 
144 	if (!all && (info.flags & B_FS_IS_PERSISTENT) == 0)
145 		return;
146 
147 	PrintMountPoint(info.dev, false);
148 	PrintType(info.fsh_name);
149 	PrintBlocks(info.total_blocks, info.block_size, showBlocks);
150 	PrintBlocks(info.free_blocks, info.block_size, showBlocks);
151 
152 	printf(" ");
153 	PrintFlag(info.flags, B_FS_HAS_QUERY, "Q", "-");
154 	PrintFlag(info.flags, B_FS_HAS_ATTR, "A", "-");
155 	PrintFlag(info.flags, B_FS_HAS_MIME, "M", "-");
156 	PrintFlag(info.flags, B_FS_IS_SHARED, "S", "-");
157 	PrintFlag(info.flags, B_FS_IS_PERSISTENT, "P", "-");
158 	PrintFlag(info.flags, B_FS_IS_REMOVABLE, "R", "-");
159 	PrintFlag(info.flags, B_FS_IS_READONLY, "-", "W");
160 
161 	printf(" %s\n", info.device_name);
162 }
163 
164 
165 void
166 ShowUsage(const char *programName)
167 {
168 	printf("usage: %s [--help | --blocks, -b | -all, -a] [<path-to-device>]\n"
169 		"  -a, --all\tinclude all file systems, also those not visible from Tracker\n"
170 		"  -b, --blocks\tshow device size in blocks of 1024 bytes\n"
171 		"If <path-to-device> is used, detailed info for that device only will be listed.\n"
172 		"Flags:\n"
173 		"   Q: has query\n"
174 		"   A: has attribute\n"
175 		"   M: has mime\n"
176 		"   S: is shared\n"
177 		"   P: is persistent (visible in Tracker)\n"
178 		"   R: is removable\n"
179 		"   W: is writable\n", programName);
180 	exit(0);
181 }
182 
183 
184 int
185 main(int argc, char **argv)
186 {
187 	char *programName = argv[0];
188 	if (strrchr(programName, '/'))
189 		programName = strrchr(programName, '/') + 1;
190 
191 	bool showBlocks = false;
192 	bool all = false;
193 	dev_t device = -1;
194 
195 	while (*++argv) {
196 		char *arg = *argv;
197 		if (*arg == '-') {
198 			while (*++arg && isalpha(*arg)) {
199 				switch (arg[0]) {
200 					case 'a':
201 						all = true;
202 						break;
203 					case 'b':
204 						showBlocks = true;
205 						break;
206 					default:
207 						ShowUsage(programName);
208 				}
209 			}
210 			if (arg[0] == '-') {
211 				arg++;
212 				if (!strcmp(arg, "all"))
213 					all = true;
214 				else if (!strcmp(arg, "blocks"))
215 					showBlocks = true;
216 				else
217 					ShowUsage(programName);
218 			}
219 		} else
220 			break;
221 	}
222 
223 	// Do we already have a device? Then let's print out detailed info about that
224 
225 	if (argv[0] != NULL) {
226 		PrintVerbose(dev_for_path(argv[0]));
227 		return 0;
228 	}
229 
230 	// If not, then just iterate over all devices and give a compact summary
231 
232 	printf("Mount           Type      Total     Free     Flags   Device\n"
233 		"--------------- -------- --------- --------- ------- --------------------------\n");
234 
235 	int32 cookie = 0;
236 	while ((device = next_dev(&cookie)) >= B_OK) {
237 		PrintCompact(device, showBlocks, all);
238 	}
239 
240 	return 0;
241 }
242