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