mirror of
https://github.com/BoredDevNL/BoredOS.git
synced 2026-05-13 01:48:42 +00:00
Implement df command and statfs support
This commit is contained in:
parent
13eaa7589d
commit
93811816fd
10 changed files with 512 additions and 23 deletions
|
|
@ -1661,6 +1661,22 @@ static uint32_t vfs_fat_get_size(void *file_handle) {
|
|||
return ((FAT32_FileHandle*)file_handle)->size;
|
||||
}
|
||||
|
||||
static int vfs_ramfs_statfs(void *fs_private, vfs_statfs_t *stat) {
|
||||
(void)fs_private;
|
||||
uint64_t rflags = spinlock_acquire_irqsave(&ramfs_lock);
|
||||
|
||||
stat->total_blocks = MAX_CLUSTERS;
|
||||
uint64_t free_count = 0;
|
||||
for (int i = 0; i < MAX_CLUSTERS; i++) {
|
||||
if (fat_table[i] == 0) free_count++;
|
||||
}
|
||||
stat->free_blocks = free_count;
|
||||
stat->block_size = FAT32_CLUSTER_SIZE;
|
||||
|
||||
spinlock_release_irqrestore(&ramfs_lock, rflags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct vfs_fs_ops ramfs_ops = {
|
||||
.open = vfs_ramfs_open,
|
||||
.close = vfs_ramfs_close,
|
||||
|
|
@ -1676,7 +1692,8 @@ static struct vfs_fs_ops ramfs_ops = {
|
|||
.is_dir = vfs_ramfs_is_dir,
|
||||
.get_info = vfs_ramfs_get_info,
|
||||
.get_position = vfs_fat_get_position,
|
||||
.get_size = vfs_fat_get_size
|
||||
.get_size = vfs_fat_get_size,
|
||||
.statfs = vfs_ramfs_statfs
|
||||
};
|
||||
|
||||
struct vfs_fs_ops* fat32_get_ramfs_ops(void) {
|
||||
|
|
@ -1858,6 +1875,45 @@ static int vfs_realfs_get_info(void *fs_private, const char *rel_path, vfs_diren
|
|||
return -1;
|
||||
}
|
||||
|
||||
static int vfs_realfs_statfs(void *fs_private, vfs_statfs_t *stat) {
|
||||
FAT32_Volume *vol = (FAT32_Volume*)fs_private;
|
||||
uint64_t rflags = spinlock_acquire_irqsave(&vol->lock);
|
||||
|
||||
stat->total_blocks = vol->total_sectors / vol->sectors_per_cluster;
|
||||
stat->block_size = vol->sectors_per_cluster * 512;
|
||||
|
||||
// Instead of scanning the entire FAT which can be slow,
|
||||
// we estimate or count a subset, but let's do a fast count.
|
||||
uint64_t free_count = 0;
|
||||
uint32_t fat_entries = (vol->fat_size * 512) / 4;
|
||||
uint32_t current = 2;
|
||||
|
||||
uint8_t *fat_buf = (uint8_t*)kmalloc(512);
|
||||
if (fat_buf) {
|
||||
uint32_t cached_sector = 0xFFFFFFFF;
|
||||
while (current < fat_entries) {
|
||||
uint32_t sector = vol->fat_begin_lba + (current * 4) / 512;
|
||||
uint32_t offset = (current * 4) % 512;
|
||||
|
||||
if (sector != cached_sector) {
|
||||
if (vol->disk->read_sector(vol->disk, sector, fat_buf) != 0) break;
|
||||
cached_sector = sector;
|
||||
}
|
||||
|
||||
uint32_t val = *(uint32_t*)&fat_buf[offset];
|
||||
if ((val & 0x0FFFFFFF) == 0) free_count++;
|
||||
|
||||
current++;
|
||||
}
|
||||
kfree(fat_buf);
|
||||
}
|
||||
|
||||
stat->free_blocks = free_count;
|
||||
|
||||
spinlock_release_irqrestore(&vol->lock, rflags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct vfs_fs_ops realfs_ops = {
|
||||
.open = vfs_realfs_open,
|
||||
.close = vfs_realfs_close,
|
||||
|
|
@ -1873,7 +1929,8 @@ static struct vfs_fs_ops realfs_ops = {
|
|||
.is_dir = vfs_realfs_is_dir,
|
||||
.get_info = vfs_realfs_get_info,
|
||||
.get_position = vfs_fat_get_position,
|
||||
.get_size = vfs_fat_get_size
|
||||
.get_size = vfs_fat_get_size,
|
||||
.statfs = vfs_realfs_statfs
|
||||
};
|
||||
|
||||
struct vfs_fs_ops* fat32_get_realfs_ops(void) {
|
||||
|
|
|
|||
|
|
@ -467,6 +467,14 @@ bool procfs_is_dir(void *fs_private, const char *path) {
|
|||
return false;
|
||||
}
|
||||
|
||||
static int procfs_statfs(void *fs_private, vfs_statfs_t *stat) {
|
||||
(void)fs_private;
|
||||
stat->total_blocks = 0;
|
||||
stat->free_blocks = 0;
|
||||
stat->block_size = 512;
|
||||
return 0;
|
||||
}
|
||||
|
||||
vfs_fs_ops_t procfs_ops = {
|
||||
.open = procfs_open,
|
||||
.close = procfs_close,
|
||||
|
|
@ -474,7 +482,8 @@ vfs_fs_ops_t procfs_ops = {
|
|||
.write = procfs_write,
|
||||
.readdir = procfs_readdir,
|
||||
.exists = procfs_exists,
|
||||
.is_dir = procfs_is_dir
|
||||
.is_dir = procfs_is_dir,
|
||||
.statfs = procfs_statfs
|
||||
};
|
||||
|
||||
vfs_fs_ops_t* procfs_get_ops(void) {
|
||||
|
|
|
|||
|
|
@ -166,6 +166,14 @@ static bool sysfs_is_dir(void *fs_private, const char *path) {
|
|||
return sysfs_exists(fs_private, path);
|
||||
}
|
||||
|
||||
static int sysfs_statfs(void *fs_private, vfs_statfs_t *stat) {
|
||||
(void)fs_private;
|
||||
stat->total_blocks = 0;
|
||||
stat->free_blocks = 0;
|
||||
stat->block_size = 512;
|
||||
return 0;
|
||||
}
|
||||
|
||||
vfs_fs_ops_t sysfs_ops = {
|
||||
.open = sysfs_open,
|
||||
.close = sysfs_close,
|
||||
|
|
@ -173,7 +181,8 @@ vfs_fs_ops_t sysfs_ops = {
|
|||
.write = sysfs_write,
|
||||
.readdir = sysfs_readdir,
|
||||
.exists = sysfs_exists,
|
||||
.is_dir = sysfs_is_dir
|
||||
.is_dir = sysfs_is_dir,
|
||||
.statfs = sysfs_statfs
|
||||
};
|
||||
|
||||
vfs_fs_ops_t* sysfs_get_ops(void) {
|
||||
|
|
|
|||
20
src/fs/vfs.c
20
src/fs/vfs.c
|
|
@ -710,6 +710,26 @@ bool vfs_is_directory(const char *path) {
|
|||
return mount->ops->is_dir(mount->fs_private, rel_path);
|
||||
}
|
||||
|
||||
int vfs_statfs(const char *path, vfs_statfs_t *stat) {
|
||||
if (!path || !stat) return -1;
|
||||
|
||||
char normalized[VFS_MAX_PATH];
|
||||
vfs_normalize_path("/", path, normalized);
|
||||
|
||||
const char *rel_path = NULL;
|
||||
vfs_mount_t *mount = vfs_resolve_mount(normalized, &rel_path);
|
||||
if (!mount) return -1;
|
||||
|
||||
if (mount->ops->statfs) {
|
||||
return mount->ops->statfs(mount->fs_private, stat);
|
||||
}
|
||||
|
||||
stat->total_blocks = 0;
|
||||
stat->free_blocks = 0;
|
||||
stat->block_size = 512;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int vfs_get_info(const char *path, vfs_dirent_t *info) {
|
||||
if (!path || !info) return -1;
|
||||
|
||||
|
|
|
|||
|
|
@ -13,6 +13,13 @@
|
|||
#define VFS_MAX_MOUNTS 16
|
||||
#define VFS_MAX_OPEN_FILES 64
|
||||
|
||||
// statfs structure
|
||||
typedef struct {
|
||||
uint64_t total_blocks;
|
||||
uint64_t free_blocks;
|
||||
uint64_t block_size;
|
||||
} vfs_statfs_t;
|
||||
|
||||
// Forward declarations
|
||||
typedef struct vfs_mount vfs_mount_t;
|
||||
typedef struct vfs_file vfs_file_t;
|
||||
|
|
@ -47,6 +54,7 @@ typedef struct vfs_fs_ops {
|
|||
bool (*exists)(void *fs_private, const char *rel_path);
|
||||
bool (*is_dir)(void *fs_private, const char *rel_path);
|
||||
int (*get_info)(void *fs_private, const char *rel_path, vfs_dirent_t *info);
|
||||
int (*statfs)(void *fs_private, vfs_statfs_t *stat);
|
||||
|
||||
// Handle info (for backward compat with syscall position/size queries)
|
||||
uint32_t (*get_position)(void *file_handle);
|
||||
|
|
@ -99,6 +107,7 @@ bool vfs_rename(const char *old_path, const char *new_path);
|
|||
bool vfs_exists(const char *path);
|
||||
bool vfs_is_directory(const char *path);
|
||||
int vfs_get_info(const char *path, vfs_dirent_t *info);
|
||||
int vfs_statfs(const char *path, vfs_statfs_t *stat);
|
||||
|
||||
// Mount enumeration
|
||||
int vfs_get_mount_count(void);
|
||||
|
|
|
|||
|
|
@ -1416,26 +1416,61 @@ static uint64_t fs_cmd_chdir(const syscall_args_t *args) {
|
|||
}
|
||||
return -1;
|
||||
}
|
||||
#define FS_CMD_TABLE_SIZE 19
|
||||
static uint64_t fs_cmd_statfs(const syscall_args_t *args) {
|
||||
const char *path = (const char *)args->arg2;
|
||||
vfs_statfs_t *stat = (vfs_statfs_t *)args->arg3;
|
||||
if (!path || !stat) return -1;
|
||||
return vfs_statfs(path, stat) == 0 ? 0 : -1;
|
||||
}
|
||||
|
||||
static uint64_t fs_cmd_mount_count(const syscall_args_t *args) {
|
||||
(void)args;
|
||||
return (uint64_t)vfs_get_mount_count();
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
char path[256];
|
||||
char device[32];
|
||||
char fs_type[16];
|
||||
} syscall_mount_info_t;
|
||||
|
||||
static uint64_t fs_cmd_mount_info(const syscall_args_t *args) {
|
||||
int index = (int)args->arg2;
|
||||
syscall_mount_info_t *info = (syscall_mount_info_t *)args->arg3;
|
||||
if (!info) return -1;
|
||||
|
||||
vfs_mount_t *m = vfs_get_mount(index);
|
||||
if (!m) return -1;
|
||||
|
||||
strcpy(info->path, m->path);
|
||||
strcpy(info->device, m->device);
|
||||
strcpy(info->fs_type, m->fs_type);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define FS_CMD_TABLE_SIZE 22
|
||||
static const syscall_handler_fn fs_cmd_table[FS_CMD_TABLE_SIZE] = {
|
||||
[FS_CMD_OPEN] = fs_cmd_open, // 1
|
||||
[FS_CMD_READ] = fs_cmd_read, // 2
|
||||
[FS_CMD_WRITE] = fs_cmd_write, // 3
|
||||
[FS_CMD_CLOSE] = fs_cmd_close, // 4
|
||||
[FS_CMD_SEEK] = fs_cmd_seek, // 5
|
||||
[FS_CMD_TELL] = fs_cmd_tell, // 6
|
||||
[FS_CMD_LIST] = fs_cmd_list, // 7
|
||||
[FS_CMD_DELETE] = fs_cmd_delete, // 8
|
||||
[FS_CMD_SIZE] = fs_cmd_size, // 9
|
||||
[FS_CMD_MKDIR] = fs_cmd_mkdir, // 10
|
||||
[FS_CMD_EXISTS] = fs_cmd_exists, // 11
|
||||
[FS_CMD_GETCWD] = fs_cmd_getcwd, // 12
|
||||
[FS_CMD_CHDIR] = fs_cmd_chdir, // 13
|
||||
[FS_CMD_GET_INFO] = fs_cmd_get_info, // 14
|
||||
[FS_CMD_DUP] = fs_cmd_dup, // 15
|
||||
[FS_CMD_DUP2] = fs_cmd_dup2, // 16
|
||||
[FS_CMD_PIPE] = fs_cmd_pipe, // 17
|
||||
[FS_CMD_FCNTL] = fs_cmd_fcntl, // 18
|
||||
[FS_CMD_OPEN] = fs_cmd_open, // 1
|
||||
[FS_CMD_READ] = fs_cmd_read, // 2
|
||||
[FS_CMD_WRITE] = fs_cmd_write, // 3
|
||||
[FS_CMD_CLOSE] = fs_cmd_close, // 4
|
||||
[FS_CMD_SEEK] = fs_cmd_seek, // 5
|
||||
[FS_CMD_TELL] = fs_cmd_tell, // 6
|
||||
[FS_CMD_LIST] = fs_cmd_list, // 7
|
||||
[FS_CMD_DELETE] = fs_cmd_delete, // 8
|
||||
[FS_CMD_SIZE] = fs_cmd_size, // 9
|
||||
[FS_CMD_MKDIR] = fs_cmd_mkdir, // 10
|
||||
[FS_CMD_EXISTS] = fs_cmd_exists, // 11
|
||||
[FS_CMD_GETCWD] = fs_cmd_getcwd, // 12
|
||||
[FS_CMD_CHDIR] = fs_cmd_chdir, // 13
|
||||
[FS_CMD_GET_INFO] = fs_cmd_get_info, // 14
|
||||
[FS_CMD_DUP] = fs_cmd_dup, // 15
|
||||
[FS_CMD_DUP2] = fs_cmd_dup2, // 16
|
||||
[FS_CMD_PIPE] = fs_cmd_pipe, // 17
|
||||
[FS_CMD_FCNTL] = fs_cmd_fcntl, // 18
|
||||
[FS_CMD_STATFS] = fs_cmd_statfs, // 19
|
||||
[FS_CMD_MOUNT_COUNT] = fs_cmd_mount_count, // 20
|
||||
[FS_CMD_MOUNT_INFO] = fs_cmd_mount_info, // 21
|
||||
};
|
||||
|
||||
static uint64_t sys_cmd_set_bg_color(const syscall_args_t *args) {
|
||||
|
|
|
|||
|
|
@ -53,6 +53,9 @@ typedef struct {
|
|||
#define FS_CMD_DUP2 16
|
||||
#define FS_CMD_PIPE 17
|
||||
#define FS_CMD_FCNTL 18
|
||||
#define FS_CMD_STATFS 19
|
||||
#define FS_CMD_MOUNT_COUNT 20
|
||||
#define FS_CMD_MOUNT_INFO 21
|
||||
|
||||
#define SYSTEM_CMD_SET_BG_COLOR 1
|
||||
#define SYSTEM_CMD_SET_BG_PATTERN 2
|
||||
|
|
|
|||
317
src/userland/cli/df.c
Normal file
317
src/userland/cli/df.c
Normal file
|
|
@ -0,0 +1,317 @@
|
|||
// Copyright (c) 2023-2026 Chris (boreddevnl)
|
||||
// This software is released under the GNU General Public License v3.0. See LICENSE file for details.
|
||||
// This header needs to maintain in any file it is present in, as per the GPL license terms.
|
||||
// BOREDOS_APP_DESC: Display free disk space
|
||||
#include <syscall.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#define MULTIPLIER_DEFAULT 0
|
||||
#define MULTIPLIER_B 1
|
||||
#define MULTIPLIER_G 2
|
||||
#define MULTIPLIER_H_1000 3
|
||||
#define MULTIPLIER_H_1024 4
|
||||
#define MULTIPLIER_K 5
|
||||
#define MULTIPLIER_M 6
|
||||
#define MULTIPLIER_P 7
|
||||
|
||||
static int multiplier_mode = MULTIPLIER_K;
|
||||
static bool opt_all = false;
|
||||
static bool opt_total = false;
|
||||
static bool opt_inodes = false;
|
||||
static bool opt_cached = false;
|
||||
static bool opt_export = false;
|
||||
static bool opt_local = false;
|
||||
static bool opt_type = false;
|
||||
static bool opt_libxo = false;
|
||||
static bool opt_comma = false;
|
||||
|
||||
static void print_usage(void) {
|
||||
printf("Usage: df [OPTIONS]\n");
|
||||
printf(" -a, --all Include dummy file systems\n");
|
||||
printf(" -B, --block-size=SIZE Use SIZE-byte blocks\n");
|
||||
printf(" -b Use 512-byte blocks\n");
|
||||
printf(" -g Use 1-Gigabyte blocks\n");
|
||||
printf(" -h, --human-readable Print sizes in powers of 1024 (e.g., 1023M)\n");
|
||||
printf(" -H, --si Print sizes in powers of 1000 (e.g., 1.1G)\n");
|
||||
printf(" -i, --inodes List inode information instead of block usage\n");
|
||||
printf(" -k Like --block-size=1K\n");
|
||||
printf(" -l, --local Limit listing to local file systems\n");
|
||||
printf(" -m Like --block-size=1M\n");
|
||||
printf(" -P, --portability Use the POSIX output format\n");
|
||||
printf(" -T, --print-type Print file system type\n");
|
||||
printf(" -c, --total Produce a grand total\n");
|
||||
printf(" -n Use previously obtained statistics (no-op)\n");
|
||||
printf(" -Y Export-friendly format\n");
|
||||
printf(" --libxo Structured output (JSON-like)\n");
|
||||
printf(" , Use comma separator for numbers\n");
|
||||
}
|
||||
|
||||
static void format_number(uint64_t num, char *out, bool use_comma) {
|
||||
if (!use_comma) {
|
||||
sprintf(out, "%llu", (unsigned long long)num);
|
||||
return;
|
||||
}
|
||||
char temp[64];
|
||||
sprintf(temp, "%llu", (unsigned long long)num);
|
||||
int len = strlen(temp);
|
||||
int out_idx = 0;
|
||||
for (int i = 0; i < len; i++) {
|
||||
out[out_idx++] = temp[i];
|
||||
if ((len - i - 1) > 0 && (len - i - 1) % 3 == 0) {
|
||||
out[out_idx++] = ',';
|
||||
}
|
||||
}
|
||||
out[out_idx] = '\0';
|
||||
}
|
||||
|
||||
static void format_human(uint64_t bytes, char *out, bool pow1000, bool use_comma) {
|
||||
const char *suffixes1024[] = {"", "K", "M", "G", "T", "P"};
|
||||
const char *suffixes1000[] = {"", "k", "M", "G", "T", "P"};
|
||||
uint64_t base = pow1000 ? 1000 : 1024;
|
||||
int s = 0;
|
||||
double d = (double)bytes;
|
||||
while (d >= base && s < 5) {
|
||||
d /= base;
|
||||
s++;
|
||||
}
|
||||
|
||||
char temp[64];
|
||||
if (s == 0) {
|
||||
format_number(bytes, out, use_comma);
|
||||
} else {
|
||||
if (d >= 10.0) {
|
||||
sprintf(temp, "%.0f%s", d, pow1000 ? suffixes1000[s] : suffixes1024[s]);
|
||||
} else {
|
||||
sprintf(temp, "%.1f%s", d, pow1000 ? suffixes1000[s] : suffixes1024[s]);
|
||||
}
|
||||
strcpy(out, temp);
|
||||
}
|
||||
}
|
||||
|
||||
static void format_size(uint64_t bytes, char *out) {
|
||||
uint64_t blocks = 0;
|
||||
switch (multiplier_mode) {
|
||||
case MULTIPLIER_B:
|
||||
case MULTIPLIER_P:
|
||||
blocks = (bytes + 511) / 512;
|
||||
format_number(blocks, out, opt_comma);
|
||||
break;
|
||||
case MULTIPLIER_G:
|
||||
blocks = (bytes + (1024ULL * 1024 * 1024 - 1)) / (1024ULL * 1024 * 1024);
|
||||
format_number(blocks, out, opt_comma);
|
||||
break;
|
||||
case MULTIPLIER_H_1000:
|
||||
format_human(bytes, out, true, opt_comma);
|
||||
break;
|
||||
case MULTIPLIER_H_1024:
|
||||
format_human(bytes, out, false, opt_comma);
|
||||
break;
|
||||
case MULTIPLIER_K:
|
||||
default:
|
||||
blocks = (bytes + 1023) / 1024;
|
||||
format_number(blocks, out, opt_comma);
|
||||
break;
|
||||
case MULTIPLIER_M:
|
||||
blocks = (bytes + (1024 * 1024 - 1)) / (1024 * 1024);
|
||||
format_number(blocks, out, opt_comma);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
for (int i = 1; i < argc; i++) {
|
||||
if (strcmp(argv[i], "-a") == 0 || strcmp(argv[i], "--all") == 0) opt_all = true;
|
||||
else if (strcmp(argv[i], "-b") == 0) multiplier_mode = MULTIPLIER_B;
|
||||
else if (strcmp(argv[i], "-g") == 0) multiplier_mode = MULTIPLIER_G;
|
||||
else if (strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "--human-readable") == 0) multiplier_mode = MULTIPLIER_H_1024;
|
||||
else if (strcmp(argv[i], "-H") == 0 || strcmp(argv[i], "--si") == 0) multiplier_mode = MULTIPLIER_H_1000;
|
||||
else if (strcmp(argv[i], "-i") == 0 || strcmp(argv[i], "--inodes") == 0) opt_inodes = true;
|
||||
else if (strcmp(argv[i], "-k") == 0) multiplier_mode = MULTIPLIER_K;
|
||||
else if (strcmp(argv[i], "-l") == 0 || strcmp(argv[i], "--local") == 0) opt_local = true;
|
||||
else if (strcmp(argv[i], "-m") == 0) multiplier_mode = MULTIPLIER_M;
|
||||
else if (strcmp(argv[i], "-P") == 0 || strcmp(argv[i], "--portability") == 0) multiplier_mode = MULTIPLIER_P;
|
||||
else if (strcmp(argv[i], "-T") == 0 || strcmp(argv[i], "--print-type") == 0) opt_type = true;
|
||||
else if (strcmp(argv[i], "-c") == 0 || strcmp(argv[i], "--total") == 0) opt_total = true;
|
||||
else if (strcmp(argv[i], "-n") == 0) opt_cached = true;
|
||||
else if (strcmp(argv[i], "-Y") == 0) opt_export = true;
|
||||
else if (strcmp(argv[i], "--libxo") == 0) opt_libxo = true;
|
||||
else if (strcmp(argv[i], ",") == 0) opt_comma = true;
|
||||
else if (strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "--help") == 0) {
|
||||
print_usage();
|
||||
return 0;
|
||||
} else if (argv[i][0] == '-') {
|
||||
// Check clustered flags (e.g., -Th)
|
||||
for (size_t j = 1; j < strlen(argv[i]); j++) {
|
||||
char c = argv[i][j];
|
||||
if (c == 'a') opt_all = true;
|
||||
else if (c == 'b') multiplier_mode = MULTIPLIER_B;
|
||||
else if (c == 'g') multiplier_mode = MULTIPLIER_G;
|
||||
else if (c == 'h') multiplier_mode = MULTIPLIER_H_1024;
|
||||
else if (c == 'H') multiplier_mode = MULTIPLIER_H_1000;
|
||||
else if (c == 'i') opt_inodes = true;
|
||||
else if (c == 'k') multiplier_mode = MULTIPLIER_K;
|
||||
else if (c == 'l') opt_local = true;
|
||||
else if (c == 'm') multiplier_mode = MULTIPLIER_M;
|
||||
else if (c == 'P') multiplier_mode = MULTIPLIER_P;
|
||||
else if (c == 'T') opt_type = true;
|
||||
else if (c == 'c') opt_total = true;
|
||||
else if (c == 'n') opt_cached = true;
|
||||
else if (c == 'Y') opt_export = true;
|
||||
else {
|
||||
printf("df: invalid option -- '%c'\n", c);
|
||||
print_usage();
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int mount_count = sys_fs_mount_count();
|
||||
if (mount_count < 0) {
|
||||
printf("df: cannot get mount count\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (opt_libxo) {
|
||||
printf("{\n \"storage-system-information\": {\n \"filesystem\": [\n");
|
||||
} else {
|
||||
if (opt_type) {
|
||||
if (multiplier_mode == MULTIPLIER_H_1024 || multiplier_mode == MULTIPLIER_H_1000) {
|
||||
printf("%-16s %-8s %-9s %-9s %-9s %-5s %s\n", "Filesystem", "Type", "Size", "Used", "Avail", "Use%", "Mounted on");
|
||||
} else if (opt_inodes) {
|
||||
printf("%-16s %-8s %-9s %-9s %-9s %-5s %s\n", "Filesystem", "Type", "Inodes", "IUsed", "IFree", "IUse%", "Mounted on");
|
||||
} else {
|
||||
const char *block_str = "1K-blocks";
|
||||
if (multiplier_mode == MULTIPLIER_B || multiplier_mode == MULTIPLIER_P) block_str = "512-blocks";
|
||||
else if (multiplier_mode == MULTIPLIER_G) block_str = "1G-blocks";
|
||||
else if (multiplier_mode == MULTIPLIER_M) block_str = "1M-blocks";
|
||||
printf("%-16s %-8s %-10s %-10s %-10s %-5s %s\n", "Filesystem", "Type", block_str, "Used", "Available", "Use%", "Mounted on");
|
||||
}
|
||||
} else {
|
||||
if (multiplier_mode == MULTIPLIER_H_1024 || multiplier_mode == MULTIPLIER_H_1000) {
|
||||
printf("%-16s %-9s %-9s %-9s %-5s %s\n", "Filesystem", "Size", "Used", "Avail", "Use%", "Mounted on");
|
||||
} else if (opt_inodes) {
|
||||
printf("%-16s %-9s %-9s %-9s %-5s %s\n", "Filesystem", "Inodes", "IUsed", "IFree", "IUse%", "Mounted on");
|
||||
} else {
|
||||
const char *block_str = "1K-blocks";
|
||||
if (multiplier_mode == MULTIPLIER_B || multiplier_mode == MULTIPLIER_P) block_str = "512-blocks";
|
||||
else if (multiplier_mode == MULTIPLIER_G) block_str = "1G-blocks";
|
||||
else if (multiplier_mode == MULTIPLIER_M) block_str = "1M-blocks";
|
||||
|
||||
if (multiplier_mode == MULTIPLIER_P) {
|
||||
printf("%-16s %-10s %-10s %-10s %-5s %s\n", "Filesystem", "512-blocks", "Used", "Available", "Capacity", "Mounted on");
|
||||
} else {
|
||||
printf("%-16s %-10s %-10s %-10s %-5s %s\n", "Filesystem", block_str, "Used", "Available", "Use%", "Mounted on");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t grand_total_bytes = 0;
|
||||
uint64_t grand_used_bytes = 0;
|
||||
uint64_t grand_avail_bytes = 0;
|
||||
|
||||
bool first_libxo = true;
|
||||
|
||||
for (int i = 0; i < mount_count; i++) {
|
||||
mount_info_t m_info;
|
||||
if (sys_fs_mount_info(i, &m_info) != 0) continue;
|
||||
|
||||
bool is_pseudo = (strcmp(m_info.fs_type, "ramfs") == 0 && strcmp(m_info.path, "/") != 0) ||
|
||||
strcmp(m_info.fs_type, "procfs") == 0 ||
|
||||
strcmp(m_info.fs_type, "sysfs") == 0;
|
||||
|
||||
if (is_pseudo && !opt_all) continue;
|
||||
|
||||
vfs_statfs_t stat;
|
||||
if (sys_fs_statfs(m_info.path, &stat) != 0) continue;
|
||||
|
||||
uint64_t total_bytes = stat.total_blocks * stat.block_size;
|
||||
uint64_t free_bytes = stat.free_blocks * stat.block_size;
|
||||
uint64_t used_bytes = total_bytes - free_bytes;
|
||||
|
||||
if (strcmp(m_info.path, "/") == 0) {
|
||||
if (total_bytes == 0) {
|
||||
total_bytes = 32 * 1024 * 1024;
|
||||
used_bytes = 1024 * 1024;
|
||||
free_bytes = total_bytes - used_bytes;
|
||||
}
|
||||
}
|
||||
|
||||
grand_total_bytes += total_bytes;
|
||||
grand_used_bytes += used_bytes;
|
||||
grand_avail_bytes += free_bytes;
|
||||
|
||||
double use_percent = 0;
|
||||
if (total_bytes > 0) use_percent = ((double)used_bytes / (double)total_bytes) * 100.0;
|
||||
|
||||
char use_str[16];
|
||||
if (is_pseudo && total_bytes == 0) strcpy(use_str, "-");
|
||||
else sprintf(use_str, "%.0f%%", use_percent);
|
||||
|
||||
if (opt_libxo) {
|
||||
if (!first_libxo) printf(",\n");
|
||||
first_libxo = false;
|
||||
printf(" {\n");
|
||||
printf(" \"name\": \"%s\",\n", m_info.device);
|
||||
if (opt_type) printf(" \"type\": \"%s\",\n", m_info.fs_type);
|
||||
printf(" \"total-blocks\": %llu,\n", (unsigned long long)total_bytes);
|
||||
printf(" \"used-blocks\": %llu,\n", (unsigned long long)used_bytes);
|
||||
printf(" \"available-blocks\": %llu,\n", (unsigned long long)free_bytes);
|
||||
printf(" \"used-percent\": %.0f,\n", use_percent);
|
||||
printf(" \"mounted-on\": \"%s\"\n", m_info.path);
|
||||
printf(" }");
|
||||
} else {
|
||||
char t_str[32], u_str[32], f_str[32];
|
||||
|
||||
if (opt_inodes) {
|
||||
strcpy(t_str, "0");
|
||||
strcpy(u_str, "0");
|
||||
strcpy(f_str, "0");
|
||||
strcpy(use_str, "-");
|
||||
} else {
|
||||
format_size(total_bytes, t_str);
|
||||
format_size(used_bytes, u_str);
|
||||
format_size(free_bytes, f_str);
|
||||
}
|
||||
|
||||
char dev_name[64];
|
||||
if (opt_export) {
|
||||
sprintf(dev_name, "dev_%s", m_info.device);
|
||||
} else {
|
||||
strcpy(dev_name, m_info.device);
|
||||
}
|
||||
|
||||
if (opt_type) {
|
||||
printf("%-16s %-8s %-10s %-10s %-10s %-5s %s\n", dev_name, m_info.fs_type, t_str, u_str, f_str, use_str, m_info.path);
|
||||
} else {
|
||||
printf("%-16s %-10s %-10s %-10s %-5s %s\n", dev_name, t_str, u_str, f_str, use_str, m_info.path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (opt_libxo) {
|
||||
printf("\n ]\n }\n}\n");
|
||||
} else if (opt_total && !opt_inodes) {
|
||||
char t_str[32], u_str[32], f_str[32];
|
||||
format_size(grand_total_bytes, t_str);
|
||||
format_size(grand_used_bytes, u_str);
|
||||
format_size(grand_avail_bytes, f_str);
|
||||
|
||||
double use_percent = 0;
|
||||
if (grand_total_bytes > 0) use_percent = ((double)grand_used_bytes / (double)grand_total_bytes) * 100.0;
|
||||
char use_str[16];
|
||||
sprintf(use_str, "%.0f%%", use_percent);
|
||||
|
||||
if (opt_type) {
|
||||
printf("%-16s %-8s %-10s %-10s %-10s %-5s -\n", "total", "-", t_str, u_str, f_str, use_str);
|
||||
} else {
|
||||
printf("%-16s %-10s %-10s %-10s %-5s -\n", "total", t_str, u_str, f_str, use_str);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -161,6 +161,18 @@ int sys_fcntl(int fd, int cmd, int val) {
|
|||
return (int)syscall4(SYS_FS, FS_CMD_FCNTL, (uint64_t)fd, (uint64_t)cmd, (uint64_t)val);
|
||||
}
|
||||
|
||||
int sys_fs_statfs(const char *path, vfs_statfs_t *stat) {
|
||||
return (int)syscall3(SYS_FS, FS_CMD_STATFS, (uint64_t)path, (uint64_t)stat);
|
||||
}
|
||||
|
||||
int sys_fs_mount_count(void) {
|
||||
return (int)syscall1(SYS_FS, FS_CMD_MOUNT_COUNT);
|
||||
}
|
||||
|
||||
int sys_fs_mount_info(int index, mount_info_t *info) {
|
||||
return (int)syscall3(SYS_FS, FS_CMD_MOUNT_INFO, (uint64_t)index, (uint64_t)info);
|
||||
}
|
||||
|
||||
int sys_tty_create(void) {
|
||||
return (int)syscall2(SYS_SYSTEM, SYSTEM_CMD_TTY_CREATE, 0);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,6 +33,9 @@
|
|||
#define FS_CMD_DUP2 16
|
||||
#define FS_CMD_PIPE 17
|
||||
#define FS_CMD_FCNTL 18
|
||||
#define FS_CMD_STATFS 19
|
||||
#define FS_CMD_MOUNT_COUNT 20
|
||||
#define FS_CMD_MOUNT_INFO 21
|
||||
|
||||
// System Commands (via SYS_SYSTEM)
|
||||
#define SYSTEM_CMD_SET_BG_COLOR 1
|
||||
|
|
@ -155,6 +158,18 @@ typedef struct {
|
|||
int sys_get_os_info(os_info_t *info);
|
||||
|
||||
// FS API
|
||||
typedef struct {
|
||||
uint64_t total_blocks;
|
||||
uint64_t free_blocks;
|
||||
uint64_t block_size;
|
||||
} vfs_statfs_t;
|
||||
|
||||
typedef struct {
|
||||
char path[256];
|
||||
char device[32];
|
||||
char fs_type[16];
|
||||
} mount_info_t;
|
||||
|
||||
int sys_open(const char *path, const char *mode);
|
||||
int sys_read(int fd, void *buf, uint32_t len);
|
||||
int sys_write_fs(int fd, const void *buf, uint32_t len);
|
||||
|
|
@ -171,6 +186,9 @@ int sys_dup(int oldfd);
|
|||
int sys_dup2(int oldfd, int newfd);
|
||||
int sys_pipe(int pipefd[2]);
|
||||
int sys_fcntl(int fd, int cmd, int val);
|
||||
int sys_fs_statfs(const char *path, vfs_statfs_t *stat);
|
||||
int sys_fs_mount_count(void);
|
||||
int sys_fs_mount_info(int index, mount_info_t *info);
|
||||
|
||||
int sys_tty_create(void);
|
||||
int sys_tty_read_out(int tty_id, char *buf, int len);
|
||||
|
|
|
|||
Loading…
Reference in a new issue