// df - for Haiku // // authors, in order of contribution: // jonas.sundstrom@kirilla.com // axeld@pinc-software.de // #include #include #include #include #include #include #include #include #include enum FormatType { k512Block, k1024Block, kHumanReadable, kUnspecified }; void PrintFlag(uint32 deviceFlags, uint32 testFlag, char yes, char no) { printf("%c", deviceFlags & testFlag ? yes : no); } void PrintMountPoint(dev_t device, bool verbose) { char mount[B_PATH_NAME_LENGTH]; mount[0] = '\0'; BVolume volume(device); BDirectory root; if (volume.GetRootDirectory(&root) == B_OK) { BPath path(&root, NULL); if (path.InitCheck() == B_OK) strlcpy(mount, path.Path(), sizeof(mount)); else strlcpy(mount, "?", sizeof(mount)); } if (verbose) printf(" Mounted at: %s\n", mount); else { printf("%-17s ", mount); if (strlen(mount) > 17) printf("\n%17s ", ""); } } void PrintType(const char *fileSystem) { char type[16]; strlcpy(type, fileSystem, sizeof(type)); printf("%11s ", type); } const char * ByteString(int64 numBlocks, int64 blockSize) { double blocks = 1. * numBlocks * blockSize; static char string[64]; if (blocks < 1024) sprintf(string, "%" B_PRId64, numBlocks * blockSize); else { const char *units[] = {"KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB", NULL}; int32 i = -1; do { blocks /= 1024.0; i++; } while (blocks >= 1024 && units[i + 1]); sprintf(string, "%.1f %s", blocks, units[i]); } return string; } const char * UsePercentage(int64 totalBlocks, int64 freeBlocks, bool compact = false) { float usage; static char string[8]; if (totalBlocks == 0 && freeBlocks == 0) usage = 100; else if (totalBlocks == 0) usage = 0; else usage = 100 - 100 * (1. * freeBlocks / totalBlocks); if (compact) { if (usage < 10) sprintf(string, " %.0f%%", round(usage)); else if (usage < 100) sprintf(string, " %.0f%%", round(usage)); else sprintf(string, "%.0f%%", round(usage)); } else { if (usage < 10) sprintf(string, " %.1f %%", usage); else if (usage < 100) sprintf(string, " %.1f %%", usage); else sprintf(string, "%.1f %%", usage); } return string; } void PrintBlocks(int64 blocks, int64 blockSize, FormatType format) { char temp[1024]; if (format == k1024Block) sprintf(temp, "%" B_PRId64, blocks * (blockSize / 1024)); else if (format == k512Block) sprintf(temp, "%" B_PRId64, blocks * (blockSize / 512)); else strcpy(temp, ByteString(blocks, blockSize)); printf("%10s", temp); } void PrintVerbose(dev_t device) { fs_info info; if (fs_stat_dev(device, &info) != B_OK) { fprintf(stderr, "Could not stat fs: %s\n", strerror(errno)); return; } int64 usedBlocks = info.total_blocks - info.free_blocks; // Used blocks can't be negative, but ramfs reports available RAM as free_blocks, // and always 0 for total_blocks, so we need to check for that. if (usedBlocks < 0) usedBlocks = 0; printf(" Device No.: %" B_PRIdDEV "\n", info.dev); PrintMountPoint(info.dev, true); printf(" Volume Name: \"%s\"\n", info.volume_name); printf(" File System: %s\n", info.fsh_name); printf(" Device: %s\n", info.device_name); printf(" Flags: "); PrintFlag(info.flags, B_FS_HAS_QUERY, 'Q', '-'); PrintFlag(info.flags, B_FS_HAS_ATTR, 'A', '-'); PrintFlag(info.flags, B_FS_HAS_MIME, 'M', '-'); PrintFlag(info.flags, B_FS_IS_SHARED, 'S', '-'); PrintFlag(info.flags, B_FS_IS_PERSISTENT, 'P', '-'); PrintFlag(info.flags, B_FS_IS_REMOVABLE, 'R', '-'); PrintFlag(info.flags, B_FS_IS_READONLY, '-', 'W'); printf("\n I/O Size: %10s (%" B_PRIdOFF " byte)\n", ByteString(info.io_size, 1), info.io_size); printf(" Block Size: %10s (%" B_PRIdOFF " byte)\n", ByteString(info.block_size, 1), info.block_size); printf(" Total Blocks: %10s (%" B_PRIdOFF " blocks)\n", ByteString(info.total_blocks, info.block_size), info.total_blocks); printf(" Used Blocks: %10s (%" B_PRIdOFF " blocks)\n", ByteString(usedBlocks, info.block_size), usedBlocks); printf(" Free Blocks: %10s (%" B_PRIdOFF " blocks)\n", ByteString(info.free_blocks, info.block_size), info.free_blocks); printf(" Usage %%: %s\n", UsePercentage(info.total_blocks, info.free_blocks)); printf(" Total Nodes: %" B_PRIdOFF "\n", info.total_nodes); printf(" Used Nodes: %" B_PRIdOFF "\n", info.total_nodes - info.free_nodes); printf(" Free Nodes: %" B_PRIdOFF "\n", info.free_nodes); printf(" Root Inode: %" B_PRIdINO "\n", info.root); } void PrintCompact(dev_t device, FormatType format, bool strictPosix, bool all) { fs_info info; if (fs_stat_dev(device, &info) != B_OK) return; if (!all && (info.flags & B_FS_IS_PERSISTENT) == 0) return; int64 usedBlocks = info.total_blocks - info.free_blocks; // Used blocks can't be negative, but ramfs reports available RAM as free_blocks, // and always 0 for total_blocks, so we need to check for that. if (usedBlocks < 0) usedBlocks = 0; if (strictPosix) { printf("%24s ", info.device_name); PrintBlocks(info.total_blocks, info.block_size, format); PrintBlocks(usedBlocks, info.block_size, format); PrintBlocks(info.free_blocks, info.block_size, format); printf(" %s ", UsePercentage(info.total_blocks, info.free_blocks, true)); PrintMountPoint(info.dev, false); } else { printf("\x1B[1m"); PrintMountPoint(info.dev, false); printf("\x1B[0m\n"); PrintType(info.fsh_name); PrintBlocks(info.total_blocks, info.block_size, format); PrintBlocks(usedBlocks, info.block_size, format); printf(" "); PrintFlag(info.flags, B_FS_HAS_QUERY, 'Q', '-'); PrintFlag(info.flags, B_FS_HAS_ATTR, 'A', '-'); PrintFlag(info.flags, B_FS_HAS_MIME, 'M', '-'); PrintFlag(info.flags, B_FS_IS_SHARED, 'S', '-'); PrintFlag(info.flags, B_FS_IS_PERSISTENT, 'P', '-'); PrintFlag(info.flags, B_FS_IS_REMOVABLE, 'R', '-'); PrintFlag(info.flags, B_FS_IS_READONLY, '-', 'W'); printf(" %6s ", UsePercentage(info.total_blocks, info.free_blocks, true)); printf("%-24s", info.device_name); } printf("\n"); } void ShowUsage(const char *programName) { printf("usage: %s [--help | --blocks, -b | -all, -a] []\n" " -a, --all\tinclude all file systems, also those not visible from Tracker\n" " -b, --blocks\tshow device size in blocks of 512 bytes\n" " -h, --human\tshow device size in blocks of 1024 bytes\n" " -k, --kilobytes\tshow device size in blocks of 1024 bytes\n" " -P, --posix\tproduce output in the format specified by POSIX\n" "If is used, detailed info for that volume only will be listed.\n" "Flags:\n" " Q: has query\n" " A: has attribute\n" " M: has mime\n" " S: is shared\n" " P: is persistent (visible in Tracker)\n" " R: is removable\n" " W: is writable\n", programName); exit(0); } int main(int argc, char **argv) { char *programName = argv[0]; if (strrchr(programName, '/')) programName = strrchr(programName, '/') + 1; FormatType format = kUnspecified; bool strictPosix = false; bool all = false; dev_t device = -1; while (*++argv) { char *arg = *argv; if (*arg == '-') { while (*++arg && isalpha(*arg)) { switch (arg[0]) { case 'a': all = true; break; case 'b': format = k512Block; break; case 'h': // human readable units in Unix df format = kHumanReadable; break; case 'k': format = k1024Block; break; case 'P': strictPosix = true; break; default: ShowUsage(programName); } } if (arg[0] == '-') { arg++; if (!strcmp(arg, "all")) all = true; else if (!strcmp(arg, "blocks")) format = k512Block; else if (!strcmp(arg, "human")) format = kHumanReadable; else if (!strcmp(arg, "kilobytes")) format = k1024Block; else if (!strcmp(arg, "posix")) strictPosix = true; else ShowUsage(programName); } } else break; } // Determine default format if nothing was specified // This is done after option parsing so that -k -P gives kilobytes as expected // Otherwise -P could force 512-block format, but it would overwrite the effect of other // options. if (format == kUnspecified) { if (strictPosix) format = k512Block; else format = kHumanReadable; } // Do we already have a device? Then let's print out detailed info about that if (argv[0] != NULL) { PrintVerbose(dev_for_path(argv[0])); return 0; } // If not, then just iterate over all devices and give a compact summary if (strictPosix) { printf(" Filesystem %11s Used Available Capacity Mounted on\n", format == kHumanReadable ? "Capacity" : (format == k512Block ? "512-blocks" : "1024-blocks")); } else { printf("\x1B[1mVolume\x1B[0m\n" " Type Total Free Flags Used%% Device\n" "----------- ---------- --------- ------- ------ -------------------\n"); } int32 cookie = 0; while ((device = next_dev(&cookie)) >= B_OK) { PrintCompact(device, format, strictPosix, all); } return 0; }