feat: add 'vol' command

This commit is contained in:
daniel committed 2026-09-19 08:54:15 +02:00
1 parent 420a7c996c
commit 80b5beb17d
17 files changed
+284 -17

No files matched your search

+1 -1
View File
@@ -12,4 +12,4 @@
#pragma once
#define MONTAUK_BUILD_NUMBER 221
#define MONTAUK_BUILD_NUMBER 223
+42
View File
@@ -57,6 +57,48 @@ namespace montauk::abi {
return count;
}
// Fill a user buffer with one entry per mounted volume. Returns the number
// of entries written, or -1 for a bad buffer.
static int Sys_VolInfo(VolInfo* buf, int maxCount) {
if (buf == nullptr || maxCount <= 0) return 0;
if (!UserMemory::Range((uint64_t)buf, (uint64_t)maxCount * sizeof(VolInfo), true)) return -1;
int drives[Fs::Vfs::MaxDrives];
int n = Fs::Vfs::VfsDriveList(drives, Fs::Vfs::MaxDrives);
if (n > maxCount) n = maxCount;
for (int i = 0; i < n; i++) {
VolInfo& v = buf[i];
v = VolInfo{};
v.drive = drives[i];
v.blockDev = -1;
v.partIndex = -1;
Fs::Vfs::VfsDriveLabel(v.drive, v.label, sizeof(v.label));
Fs::Vfs::VfsDriveFsType(v.drive, v.fsType, sizeof(v.fsType));
v.partIndex = Fs::FsProbe::GetPartitionForDrive(v.drive);
if (v.partIndex < 0) continue; // ramdisk: no backing partition
auto* part = Drivers::Storage::Gpt::GetPartition(v.partIndex);
if (part == nullptr) continue;
v.blockDev = part->BlockDevIndex;
v.startLba = part->StartLba;
v.sectorCount = part->SectorCount;
dl_strcpy_s(v.partName, part->Name, sizeof(v.partName));
auto* dev = Drivers::Storage::GetBlockDevice(v.blockDev);
if (dev == nullptr) continue;
v.kind = dev->Kind;
v.sectorSize = dev->SectorSize;
dl_strcpy_s(v.model, dev->Model, sizeof(v.model));
}
return n;
}
// Read sectors from a block device. Returns bytes read, or -1 on error.
static int64_t Sys_DiskRead(int blockDev, uint64_t lba, uint32_t count, void* buffer) {
if (buffer == nullptr || count == 0) return -1;
+5 -1
View File
@@ -29,7 +29,7 @@
#include "MemInfo.hpp" // SYS_MEMSTATS
#include "Device.hpp" // SYS_DEVLIST, SYS_DISKINFO
#include "Input.hpp" // SYS_INPUT_WAIT
#include "Storage.hpp" // SYS_PARTLIST, SYS_DISKREAD, SYS_DISKWRITE
#include "Storage.hpp" // SYS_PARTLIST, SYS_VOLINFO, SYS_DISKREAD, SYS_DISKWRITE
#include "Window.hpp" // SYS_WINCREATE, SYS_WINDESTROY, SYS_WINPRESENT, SYS_WINPOLL, SYS_WINENUM, SYS_WINMAP, SYS_WINSENDEVENT, SYS_WINRESIZE, SYS_WINSETCURSOR, SYS_WINSETFLAGS, SYS_WINSETSCALE, SYS_WINGETSCALE
#include "Audio.hpp" // SYS_AUDIOOPEN, SYS_AUDIOCLOSE, SYS_AUDIOWRITE, SYS_AUDIOCTL
#include "BluetoothSyscall.hpp" // SYS_BTSCAN, SYS_BTCONNECT, SYS_BTDISCONNECT, SYS_BTLIST, SYS_BTINFO
@@ -425,6 +425,10 @@ namespace montauk::abi {
if ((int64_t)frame->arg2 < 0) return -1;
if (!UserMemory::Range(frame->arg1, (uint64_t)frame->arg2 * sizeof(PartInfo), true)) return -1;
return (int64_t)Sys_PartList((PartInfo*)frame->arg1, (int)frame->arg2);
case SYS_VOLINFO:
if ((int64_t)frame->arg2 < 0) return -1;
if (!UserMemory::Range(frame->arg1, (uint64_t)frame->arg2 * sizeof(VolInfo), true)) return -1;
return (int64_t)Sys_VolInfo((VolInfo*)frame->arg1, (int)frame->arg2);
case SYS_DISKREAD:
if (!Sched::HasCapability(CAP_RAW_STORAGE)) return SYS_ERR_PERMISSION;
return (int64_t)Sys_DiskRead((int)frame->arg1, frame->arg2,
+25
View File
@@ -349,6 +349,9 @@ namespace montauk::abi {
/* Process.hpp -- the caller's own capability masks. */
static constexpr uint64_t SYS_GETCAPS = 189; // (SpawnCapabilities*) -> 0, -1 bad pointer
/* Storage.hpp */
static constexpr uint64_t SYS_VOLINFO = 190; // (VolInfo*, maxCount) -> count, -1 bad pointer
/* Kernel-owned process capabilities. User identities may namespace
per-user resources, but never participate in authorization decisions. */
static constexpr uint64_t CAP_PROCESS_ADMIN = 1ULL << 0;
@@ -679,6 +682,28 @@ namespace montauk::abi {
char typeName[24]; // human-readable type name
};
// One mounted volume (returned by SYS_VOLINFO). A volume is a single
// mounted filesystem, which is what a drive number names: one physical
// disk with three partitions occupies three drive numbers.
//
// A volume with no backing partition -- the boot ramdisk -- reports
// blockDev and partIndex as -1 and leaves the geometry fields zero.
struct VolInfo {
int32_t drive; // VFS drive number ("N:/")
int32_t blockDev; // backing block device index, -1 if none
int32_t partIndex; // global GPT partition index, -1 if none
uint32_t kind; // BlockDeviceKind: 0=none/ramdisk, 1=SATA, 2=SATAPI, 3=NVMe, 4=USB MSC
uint64_t startLba; // partition start LBA, 0 if none
uint64_t sectorCount; // partition length in sectors, 0 if none
uint32_t sectorSize; // logical sector size in bytes, 0 if none
uint32_t _pad0;
char label[36]; // filesystem volume label, "" if unset
char fsType[12]; // "ext2", "FAT32", "ramdisk", "" if unknown
char partName[72]; // GPT partition name, "" if none
char model[41]; // backing disk model, "" if none
char _pad1[3];
};
struct GptAddParams {
int32_t blockDev;
uint32_t _pad0;
+2
View File
@@ -67,6 +67,7 @@ namespace Fs {
int RdMkdir(void*, const char* p) { return Ramdisk::Mkdir(p); }
int RdRename(void*, const char* o, const char* n) { return Ramdisk::Rename(o, n); }
const char* RdGetLabel(void*) { return Ramdisk::GetLabel(); }
const char* RdGetFsType(void*) { return "ramdisk"; }
int RdReadDirAt(void*, const char* p, const char** o, int m, int s) { return Ramdisk::ReadDirAt(p, o, m, s); }
int RdStat(void*, const char* p, Vfs::StatInfo* out) {
@@ -99,6 +100,7 @@ namespace Fs {
.Mkdir = RdMkdir,
.Rename = RdRename,
.GetLabel = RdGetLabel,
.GetFsType = RdGetFsType,
.ReadDirAt = RdReadDirAt,
.Stat = RdStat,
.SetTimes = nullptr,
+2
View File
@@ -1861,6 +1861,7 @@ namespace Fs::Ext2 {
static int DrvMkdir(void* c, const char* p) { return MkdirImpl(CtxToInst(c), p); }
static int DrvRename(void* c, const char* o, const char* n) { return RenameImpl(CtxToInst(c), o, n); }
static const char* DrvGetLabel(void* c) { return GetLabelImpl(CtxToInst(c)); }
static const char* DrvGetFsType(void*) { return "ext2"; }
static int DrvStat(void* c, const char* p, Vfs::StatInfo* o) { return StatImpl(CtxToInst(c), p, o); }
static int DrvSetTimes(void* c, const char* p, int64_t a, int64_t m) { return SetTimesImpl(CtxToInst(c), p, a, m); }
@@ -2071,6 +2072,7 @@ namespace Fs::Ext2 {
.Mkdir = DrvMkdir,
.Rename = DrvRename,
.GetLabel = DrvGetLabel,
.GetFsType = DrvGetFsType,
.ReadDirAt = DrvReadDirAt,
.Stat = DrvStat,
.SetTimes = DrvSetTimes,
+2
View File
@@ -1894,6 +1894,7 @@ namespace Fs::Fat32 {
static int DrvMkdir(void* c, const char* p) { return MkdirImpl(CtxToInst(c), p); }
static int DrvRename(void* c, const char* o, const char* n) { return RenameImpl(CtxToInst(c), o, n); }
static const char* DrvGetLabel(void* c) { return GetLabelImpl(CtxToInst(c)); }
static const char* DrvGetFsType(void*) { return "FAT32"; }
static int DrvStat(void* c, const char* p, Vfs::StatInfo* o) { return StatImpl(CtxToInst(c), p, o); }
// Release everything the mount owns. The driver is either not registered
@@ -2101,6 +2102,7 @@ namespace Fs::Fat32 {
.Mkdir = DrvMkdir,
.Rename = DrvRename,
.GetLabel = DrvGetLabel,
.GetFsType = DrvGetFsType,
.ReadDirAt = DrvReadDirAt,
.Stat = DrvStat,
.SetTimes = nullptr,
+9 -5
View File
@@ -154,18 +154,22 @@ namespace Fs::FsProbe {
return -1;
}
int GetBlockDeviceForDrive(int driveNum) {
int GetPartitionForDrive(int driveNum) {
if (driveNum < 0) return -1;
int partCount = Drivers::Storage::Gpt::GetPartitionCount();
for (int i = 0; i < partCount && i < Drivers::Storage::Gpt::MaxPartitions; i++) {
if (g_mounted[i] && g_driveForPart[i] == driveNum) {
auto* part = Drivers::Storage::Gpt::GetPartition(i);
if (part) return part->BlockDevIndex;
}
if (g_mounted[i] && g_driveForPart[i] == driveNum) return i;
}
return -1;
}
int GetBlockDeviceForDrive(int driveNum) {
int partIndex = GetPartitionForDrive(driveNum);
if (partIndex < 0) return -1;
auto* part = Drivers::Storage::Gpt::GetPartition(partIndex);
return part ? part->BlockDevIndex : -1;
}
int UnmountPartitionsForBlockDevice(int blockDevIndex) {
int partCount = Drivers::Storage::Gpt::GetPartitionCount();
int unmounted = 0;
+4
View File
@@ -38,6 +38,10 @@ namespace Fs::FsProbe {
// drive isn't backed by a partition (e.g. ramdisk).
int GetBlockDeviceForDrive(int driveNum);
// Return the global GPT partition index backing a mounted VFS drive, or -1
// if the drive isn't backed by a partition (e.g. ramdisk).
int GetPartitionForDrive(int driveNum);
// Prepare persistent storage for power-off: flush every block device's
// write cache to media, then cleanly unmount all disk-backed VFS drives.
// The ramdisk (which has no backing block device) is left mounted. Returns
+18 -10
View File
@@ -350,10 +350,10 @@ namespace Fs::Vfs {
vfsLock.Release();
return count;
}
int VfsDriveLabel(int driveNumber, char* outLabel, int maxLen) {
if (outLabel == nullptr || maxLen <= 0) return -1;
outLabel[0] = '\0';
static int CopyDriveString(int driveNumber, const char* (*FsDriver::*hook)(void*),
char* out, int maxLen) {
if (out == nullptr || maxLen <= 0) return -1;
out[0] = '\0';
vfsLock.Acquire();
FsDriver* driver = DriverForLocked(driveNumber);
@@ -362,28 +362,36 @@ namespace Fs::Vfs {
return -1;
}
if (driver->GetLabel == nullptr) {
if (driver->*hook == nullptr) {
vfsLock.Release();
return 0;
}
const char* label = driver->GetLabel(driver->ctx);
if (label == nullptr || label[0] == '\0') {
const char* value = (driver->*hook)(driver->ctx);
if (value == nullptr || value[0] == '\0') {
vfsLock.Release();
return 0;
}
int copied = 0;
while (label[copied] != '\0' && copied < maxLen - 1) {
outLabel[copied] = label[copied];
while (value[copied] != '\0' && copied < maxLen - 1) {
out[copied] = value[copied];
copied++;
}
outLabel[copied] = '\0';
out[copied] = '\0';
vfsLock.Release();
return copied;
}
int VfsDriveLabel(int driveNumber, char* outLabel, int maxLen) {
return CopyDriveString(driveNumber, &FsDriver::GetLabel, outLabel, maxLen);
}
int VfsDriveFsType(int driveNumber, char* outType, int maxLen) {
return CopyDriveString(driveNumber, &FsDriver::GetFsType, outType, maxLen);
}
int VfsRename(const char* oldPath, const char* newPath) {
int oldDrive, newDrive;
const char* oldLocal;
+4
View File
@@ -59,6 +59,9 @@ namespace Fs::Vfs {
int (*Mkdir)(void* ctx, const char* path);
int (*Rename)(void* ctx, const char* oldPath, const char* newPath);
const char* (*GetLabel)(void* ctx);
// Optional: short name of the on-disk format ("ext2", "FAT32", ...).
// Drivers that leave this null report an empty type string.
const char* (*GetFsType)(void* ctx);
// Optional: paginated directory read returning entries [startIndex, startIndex+maxEntries).
// Drivers that leave this null are read via ReadDir at startIndex 0 only.
int (*ReadDirAt)(void* ctx, const char* path, const char** outNames, int maxEntries, int startIndex);
@@ -103,5 +106,6 @@ namespace Fs::Vfs {
// Returns number of registered drives, fills outDrives[] with their indices
int VfsDriveList(int* outDrives, int maxEntries);
int VfsDriveLabel(int driveNumber, char* outLabel, int maxLen);
int VfsDriveFsType(int driveNumber, char* outType, int maxLen);
}
+25
View File
@@ -262,6 +262,9 @@ namespace montauk::abi {
// The caller's own capability masks.
static constexpr uint64_t SYS_GETCAPS = 189; // (SpawnCapabilities*) -> 0, -1 bad pointer
/* Storage.hpp */
static constexpr uint64_t SYS_VOLINFO = 190; // (VolInfo*, maxCount) -> count, -1 bad pointer
/* Kernel-owned process capabilities. User identities may namespace
per-user resources, but never participate in authorization decisions. */
static constexpr uint64_t CAP_PROCESS_ADMIN = 1ULL << 0;
@@ -603,6 +606,28 @@ namespace montauk::abi {
char typeName[24]; // human-readable type name
};
// One mounted volume (returned by SYS_VOLINFO). A volume is a single
// mounted filesystem, which is what a drive number names: one physical
// disk with three partitions occupies three drive numbers.
//
// A volume with no backing partition -- the boot ramdisk -- reports
// blockDev and partIndex as -1 and leaves the geometry fields zero.
struct VolInfo {
int32_t drive; // VFS drive number ("N:/")
int32_t blockDev; // backing block device index, -1 if none
int32_t partIndex; // global GPT partition index, -1 if none
uint32_t kind; // BlockDeviceKind: 0=none/ramdisk, 1=SATA, 2=SATAPI, 3=NVMe, 4=USB MSC
uint64_t startLba; // partition start LBA, 0 if none
uint64_t sectorCount; // partition length in sectors, 0 if none
uint32_t sectorSize; // logical sector size in bytes, 0 if none
uint32_t _pad0;
char label[36]; // filesystem volume label, "" if unset
char fsType[12]; // "ext2", "FAT32", "ramdisk", "" if unknown
char partName[72]; // GPT partition name, "" if none
char model[41]; // backing disk model, "" if none
char _pad1[3];
};
struct GptAddParams {
int32_t blockDev;
uint32_t _pad0;
+1
View File
@@ -213,6 +213,7 @@ extern "C" {
#define MTK_SYS_ALLOC_EAGER 187
#define MTK_SYS_BATTERYINFO 188
#define MTK_SYS_GETCAPS 189
#define MTK_SYS_VOLINFO 190
/* @SYSCALLS-END */
#define MTK_SOCK_TCP 1
+4
View File
@@ -514,6 +514,10 @@ namespace montauk {
inline int partlist(montauk::abi::PartInfo* buf, int max) {
return (int)syscall2(montauk::abi::SYS_PARTLIST, (uint64_t)buf, (uint64_t)max);
}
// One entry per mounted volume (one filesystem, i.e. one drive number).
inline int volinfo(montauk::abi::VolInfo* buf, int max) {
return (int)syscall2(montauk::abi::SYS_VOLINFO, (uint64_t)buf, (uint64_t)max);
}
// Raw block device I/O (driver-agnostic)
inline int64_t disk_read(int blockDev, uint64_t lba, uint32_t sectorCount, void* buf) {
+34
View File
@@ -0,0 +1,34 @@
.TH VOL 1
.SH NAME
vol - list mounted volumes
.SH SYNOPSIS
vol
.SH DESCRIPTION
Prints information about volumes present on the system.
Drive numbers (column "Vol") represent volumes rather than physical disk devices.
The boot ramdisk, if present, reports "-" for its size, disk, and partition.
.SH OUTPUT
Vol Type Label Size Disk Part Partition
0:/ ramdisk MontaukOS - - - -
1:/ ext2 Montauk 118.4 GiB 0 0 Montauk
2:/ FAT32 EFI 512.0 MiB 0 1 EFI System
Disks:
0 NVMe Samsung SSD 990 PRO 1TB
.SH COLUMNS
Vol Drive number, as written in paths ("1:/file.txt").
Type Filesystem type (ext2, FAT32, ramdisk).
Label Filesystem volume label, or "-" if unset.
Size Partition size, binary prefixes.
Disk Block device index (see disk legend below the table).
Part Partition index on that disk.
Partition GPT partition name, or "-" if unset.
.SH SEE ALSO
disks(1), shell(1), syscalls(2)
+1
View File
@@ -62,6 +62,7 @@ void cmd_help() {
montauk::print(" edit [file] Text editor\n");
montauk::print(" whoami Print current username\n");
montauk::print(" info Show system information\n");
montauk::print(" vol List mounted volumes\n");
montauk::print(" date Show current date and time\n");
montauk::print(" uptime Show uptime\n");
montauk::print(" clear Clear the screen\n");
+105
View File
@@ -0,0 +1,105 @@
/*
* main.cpp
* vol - List mounted volumes and the disks they live on
* Copyright (c) 2026 Daniel Hammer
*/
#include <montauk/syscall.h>
#include <libc/stdio.h>
static constexpr int MaxVolumes = 64;
static const char* kind_name(unsigned kind) {
switch (kind) {
case 1: return "SATA";
case 2: return "SATAPI";
case 3: return "NVMe";
case 4: return "USB";
default: return "-";
}
}
static void format_size(uint64_t bytes, char* out, int outMax) {
static const char* units[] = { "B", "KiB", "MiB", "GiB", "TiB", "PiB" };
int unit = 0;
uint64_t whole = bytes;
uint64_t rem = 0;
while (whole >= 1024 && unit < 5) {
rem = whole % 1024;
whole /= 1024;
unit++;
}
if (unit == 0) {
snprintf(out, outMax, "%llu B", (unsigned long long)whole);
return;
}
unsigned tenths = (unsigned)((rem * 10) / 1024);
snprintf(out, outMax, "%llu.%u %s", (unsigned long long)whole, tenths, units[unit]);
}
extern "C" void _start() {
montauk::abi::VolInfo vols[MaxVolumes] = {};
int n = montauk::volinfo(vols, MaxVolumes);
if (n <= 0) {
montauk::print("No volumes are mounted.\n");
montauk::exit(n < 0 ? 1 : 0);
}
printf("%-5s %-8s %-18s %10s %5s %5s %s\n",
"Vol", "Type", "Label", "Size", "Disk", "Part", "Partition");
for (int i = 0; i < n; i++) {
const montauk::abi::VolInfo& v = vols[i];
char drive[8];
snprintf(drive, sizeof(drive), "%d:/", v.drive);
char size[16];
if (v.sectorCount != 0 && v.sectorSize != 0) {
format_size(v.sectorCount * (uint64_t)v.sectorSize, size, sizeof(size));
} else {
snprintf(size, sizeof(size), "-");
}
char disk[8];
char part[8];
if (v.blockDev >= 0) snprintf(disk, sizeof(disk), "%d", v.blockDev);
else snprintf(disk, sizeof(disk), "-");
if (v.partIndex >= 0) snprintf(part, sizeof(part), "%d", v.partIndex);
else snprintf(part, sizeof(part), "-");
printf("%-5s %-8s %-18s %10s %5s %5s %s\n",
drive,
v.fsType[0] ? v.fsType : "-",
v.label[0] ? v.label : "-",
size, disk, part,
v.partName[0] ? v.partName : "-");
}
bool printedHeader = false;
for (int i = 0; i < n; i++) {
if (vols[i].blockDev < 0) continue;
bool seen = false;
for (int j = 0; j < i; j++) {
if (vols[j].blockDev == vols[i].blockDev) { seen = true; break; }
}
if (seen) continue;
if (!printedHeader) {
montauk::print("\nDisks:\n");
printedHeader = true;
}
printf(" %d %-6s %s\n",
vols[i].blockDev,
kind_name(vols[i].kind),
vols[i].model[0] ? vols[i].model : "(unknown)");
}
montauk::exit(0);
}