diff --git a/Kernel/Ext2FileSystem.cpp b/Kernel/Ext2FileSystem.cpp index 4ef19c48bc..f4a7f452be 100644 --- a/Kernel/Ext2FileSystem.cpp +++ b/Kernel/Ext2FileSystem.cpp @@ -1359,3 +1359,27 @@ bool Ext2FSInode::chmod(mode_t mode, int& error) set_metadata_dirty(true); return true; } + +unsigned Ext2FS::total_block_count() const +{ + LOCKER(m_lock); + return super_block().s_blocks_count; +} + +unsigned Ext2FS::free_block_count() const +{ + LOCKER(m_lock); + return super_block().s_free_blocks_count; +} + +unsigned Ext2FS::total_inode_count() const +{ + LOCKER(m_lock); + return super_block().s_inodes_count; +} + +unsigned Ext2FS::free_inode_count() const +{ + LOCKER(m_lock); + return super_block().s_free_inodes_count; +} diff --git a/Kernel/Ext2FileSystem.h b/Kernel/Ext2FileSystem.h index af96a4eb10..0d6a4dd47b 100644 --- a/Kernel/Ext2FileSystem.h +++ b/Kernel/Ext2FileSystem.h @@ -62,6 +62,11 @@ public: virtual ~Ext2FS() override; virtual bool initialize() override; + virtual unsigned total_block_count() const override; + virtual unsigned free_block_count() const override; + virtual unsigned total_inode_count() const override; + virtual unsigned free_inode_count() const override; + private: typedef unsigned BlockIndex; typedef unsigned GroupIndex; diff --git a/Kernel/FileSystem.h b/Kernel/FileSystem.h index 1bbd1d27ac..77169cd751 100644 --- a/Kernel/FileSystem.h +++ b/Kernel/FileSystem.h @@ -37,6 +37,11 @@ public: bool is_readonly() const { return m_readonly; } + virtual unsigned total_block_count() const { return 0; } + virtual unsigned free_block_count() const { return 0; } + virtual unsigned total_inode_count() const { return 0; } + virtual unsigned free_inode_count() const { return 0; } + struct DirectoryEntry { DirectoryEntry(const char* name, InodeIdentifier, byte file_type); DirectoryEntry(const char* name, size_t name_length, InodeIdentifier, byte file_type); diff --git a/Kernel/ProcFS.cpp b/Kernel/ProcFS.cpp index 93258a2420..62e34d1721 100644 --- a/Kernel/ProcFS.cpp +++ b/Kernel/ProcFS.cpp @@ -28,6 +28,7 @@ enum ProcFileType { __FI_Root_Start, FI_Root_mm, FI_Root_mounts, + FI_Root_df, FI_Root_kmalloc, FI_Root_all, FI_Root_summary, @@ -399,6 +400,27 @@ ByteBuffer procfs$mounts(InodeIdentifier) return builder.to_byte_buffer(); } +ByteBuffer procfs$df(InodeIdentifier) +{ + // FIXME: This is obviously racy against the VFS mounts changing. + StringBuilder builder; + VFS::the().for_each_mount([&builder] (auto& mount) { + auto& fs = mount.guest_fs(); + builder.appendf("%s,", fs.class_name()); + builder.appendf("%u,", fs.total_block_count()); + builder.appendf("%u,", fs.free_block_count()); + builder.appendf("%u,", fs.total_inode_count()); + builder.appendf("%u,", fs.free_inode_count()); + if (!mount.host().is_valid()) + builder.append("/"); + else { + builder.append(VFS::the().absolute_path(mount.host())); + } + builder.append('\n'); + }); + return builder.to_byte_buffer(); +} + ByteBuffer procfs$cpuinfo(InodeIdentifier) { StringBuilder builder; @@ -1076,6 +1098,7 @@ ProcFS::ProcFS() m_entries.resize(FI_MaxStaticFileIndex); m_entries[FI_Root_mm] = { "mm", FI_Root_mm, procfs$mm }; m_entries[FI_Root_mounts] = { "mounts", FI_Root_mounts, procfs$mounts }; + m_entries[FI_Root_df] = { "df", FI_Root_df, procfs$df }; m_entries[FI_Root_kmalloc] = { "kmalloc", FI_Root_kmalloc, procfs$kmalloc }; m_entries[FI_Root_all] = { "all", FI_Root_all, procfs$all }; m_entries[FI_Root_summary] = { "summary", FI_Root_summary, procfs$summary }; diff --git a/Kernel/sync.sh b/Kernel/sync.sh index 69e7890e79..54e1e1ead0 100755 --- a/Kernel/sync.sh +++ b/Kernel/sync.sh @@ -64,6 +64,7 @@ cp -v ../Userland/dmesg mnt/bin/dmesg cp -v ../Userland/chmod mnt/bin/chmod cp -v ../Userland/top mnt/bin/top cp -v ../Userland/ln mnt/bin/ln +cp -v ../Userland/df mnt/bin/df cp -v ../Applications/Terminal/Terminal mnt/bin/Terminal cp -v ../Applications/FontEditor/FontEditor mnt/bin/FontEditor cp -v ../Applications/Launcher/Launcher mnt/bin/Launcher diff --git a/Userland/.gitignore b/Userland/.gitignore index 4c4f51262a..45015daa24 100644 --- a/Userland/.gitignore +++ b/Userland/.gitignore @@ -32,3 +32,4 @@ top chmod pape ln +df diff --git a/Userland/Makefile b/Userland/Makefile index 4759c51e24..7232c194e4 100644 --- a/Userland/Makefile +++ b/Userland/Makefile @@ -27,6 +27,7 @@ OBJS = \ dmesg.o \ chmod.o \ top.o \ + df.o \ ln.o \ rm.o @@ -61,6 +62,7 @@ APPS = \ chmod \ top \ ln \ + df \ rm ARCH_FLAGS = @@ -174,6 +176,9 @@ top: top.o ln: ln.o $(LD) -o $@ $(LDFLAGS) $< ../LibC/LibC.a +df: df.o + $(LD) -o $@ $(LDFLAGS) $< ../LibC/LibC.a + .cpp.o: @echo "CXX $<"; $(CXX) $(CXXFLAGS) -o $@ -c $< diff --git a/Userland/df.cpp b/Userland/df.cpp new file mode 100644 index 0000000000..bce2e2268a --- /dev/null +++ b/Userland/df.cpp @@ -0,0 +1,55 @@ +#include +#include +#include +#include +#include +#include + +struct FileSystem { + String fs; + size_t total_block_count { 0 }; + size_t free_block_count { 0 }; + size_t total_inode_count { 0 }; + size_t free_inode_count { 0 }; + String mount_point; +}; + +int main(int, char**) +{ + FILE* fp = fopen("/proc/df", "r"); + if (!fp) { + perror("failed to open /proc/df"); + return 1; + } + printf("Filesystem Blocks Used Available Mount point\n"); + for (;;) { + char buf[4096]; + char* ptr = fgets(buf, sizeof(buf), fp); + if (!ptr) + break; + auto parts = String(buf, Chomp).split(','); + if (parts.size() < 6) + break; + bool ok; + String fs = parts[0]; + unsigned total_block_count = parts[1].to_uint(ok); + ASSERT(ok); + unsigned free_block_count = parts[2].to_uint(ok); + ASSERT(ok); + unsigned total_inode_count = parts[3].to_uint(ok); + ASSERT(ok); + unsigned free_inode_count = parts[4].to_uint(ok); + ASSERT(ok); + String mount_point = parts[5]; + + printf("% 10s", fs.characters()); + printf("%10u ", total_block_count); + printf("%10u ", total_block_count - free_block_count); + printf("%10u ", free_block_count); + printf("%s", mount_point.characters()); + printf("\n"); + } + int rc = fclose(fp); + ASSERT(rc == 0); + return 0; +}