feat: add 'vol' command
This commit is contained in:
1 parent
420a7c996c
commit
80b5beb17d
17 files changed
+284
-17
No files matched your search
@@ -12,4 +12,4 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#define MONTAUK_BUILD_NUMBER 221
|
||||
#define MONTAUK_BUILD_NUMBER 223
|
||||
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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)
|
||||
@@ -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");
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
Reference in new issue
Block a user