Disk Tools
Forest OS provides a full suite of disk management utilities covering data copying, filesystem creation, mounting, partition inspection, and integrity checking. All tools are implemented in userspace and interact with the kernel through standard Linux syscalls.
Overview
The disk tool suite in /home/bluet/forest/userspace/ includes:
| Tool | Purpose | Source |
|---|---|---|
dd |
Data conversion and block-level copying | dd/dd.c |
df |
Filesystem disk space usage reporting | df/df.c |
du |
Directory space usage estimation | du/du.c |
fdisk |
MBR partition table inspection | fdisk/fdisk.c |
mkfs |
Filesystem creation (FAT32, ext2) | mkfs/mkfs.c |
mount |
Attach filesystems to the tree | mount/mount.c |
umount |
Detach filesystems from the tree | umount/umount.c |
blkid |
Block device identification | blkid/blkid.c |
losetup |
Loop device management | losetup/losetup.c |
fsck |
Filesystem integrity checking | fsck/fsck.c |
Data Conversion and Copying (dd)
dd copies data between files and devices at the block level. It is the workhorse for creating disk images, writing boot sectors, and raw device operations.
Usage
dd if=INPUT of=OUTPUT [bs=BYTES] [count=N] [skip=N] [seek=N] [conv=CONV] [iflag=FLAGS] [oflag=FLAGS]
Key Parameters
| Parameter | Description |
|---|---|
bs=BYTES |
Block size for both read and write (default 512) |
ibs=BYTES |
Input block size |
obs=BYTES |
Output block size |
count=N |
Copy only N input blocks |
skip=N |
Skip N blocks at start of input |
seek=N |
Skip N blocks at start of output |
if=FILE |
Input file (default stdin) |
of=FILE |
Output file (default stdout) |
conv=noerror |
Continue past read errors |
conv=sync |
Pad incomplete blocks with NUL |
conv=notrunc |
Do not truncate output file |
conv=excl |
Fail if output already exists |
conv=fdatasync |
Flush output data before completing |
iflag=direct |
Use O_DIRECT (bypass page cache) |
iflag=dsync |
Use O_DSYNC for data writes |
oflag=append |
Open output in append mode |
Examples
# Create a 1MB disk image file
dd if=/dev/zero of=disk.img bs=1M count=1
# Write an ISO to a USB device
dd if=forest.iso of=/dev/sdb bs=4M
# Read the MBR of a disk
dd if=/dev/sda of=mbr.bin bs=512 count=1
# Copy with direct I/O for benchmarking
dd if=/dev/sda of=/dev/sdb bs=1M iflag=direct oflag=direct
Implementation Notes
- Uses
xread()/xwrite()wrappers that handle partial reads/writes andEINTRinterruptions. - Supports human-friendly size suffixes:
k/K(1024),m/M(1024²),g/G(1024³). - Signal handling allows graceful
SIGINTinterrupts with partial progress stats. - Reports throughput in MB/s after completion.
Disk Usage Reporting (df, du)
df — Filesystem Space Usage
df reads /proc/mounts (or /etc/mtab) to enumerate mounted filesystems, then calls statfs() on each mount point to retrieve block counts.
Usage
df [-hHkmaTP] [-t TYPE] [-x TYPE] [--total] [file ...]
Key Options
| Option | Description |
|---|---|
-h |
Human-readable sizes (powers of 1024) |
-H |
SI units (powers of 1000) |
-k |
Show sizes in 1K blocks (default) |
-m |
Show sizes in 1M blocks |
-T |
Print filesystem type column |
-t TYPE |
Include only filesystems of TYPE |
-x TYPE |
Exclude filesystems of TYPE |
-a |
Show pseudo-filesystems (proc, sysfs, etc.) |
-P |
POSIX output format |
--total |
Print a grand total line |
Filtering
df automatically hides pseudo-filesystems (proc, sysfs, devtmpfs, tmpfs, cgroup, etc.) unless -a is passed. The should_show() function checks the filesystem type string against a hardcoded list of virtual filesystems.
Kernel Interface
df makes a direct syscall(SYS_statfs, path, &buf) call. The returned struct statfs contains:
f_blocks— total data blocksf_bfree— free blocks (including reserved)f_bavail— free blocks available to non-rootf_bsize— optimal transfer block sizef_files— total inodesf_ffree— free inodes
Example
Filesystem 1024-blocks Used Available Use% Mounted on
/dev/sda1 102400000 51200000 51200000 50% /
tmpfs 512000 128 511872 1% /tmp
du — Directory Space Usage
du recursively walks directories using opendir()/readdir() and stat() to accumulate block counts.
Usage
du [-hHkmsacd:LxP] [--total] [--max-depth=N] [file ...]
Key Options
| Option | Description |
|---|---|
-h |
Human-readable (1024-based) |
-H |
Human-readable (1000-based) |
-k |
Kilobytes (default) |
-m |
Megabytes |
-s |
Summarize — show only totals |
-a |
Show sizes for all files, not just directories |
-c |
Print grand total |
-d N |
Limit recursion depth to N |
-L |
Follow symbolic links |
-P |
Do not follow symlinks (default) |
-x |
Stay on the same filesystem |
Kernel Interface
Uses lstat() (or stat() with -L) to get st_blocks from struct stat. Each filesystem block is 512 bytes, so the tool divides st_blocks / 2 to get 1K block counts.
Partition Management (fdisk)
fdisk reads and displays MBR (Master Boot Record) partition tables. It supports listing partitions, querying partition sizes, and identifying partition types.
Usage
fdisk [-lpsv] [-s PARTITION] device
| Option | Description |
|---|---|
-l |
List all partitions on the device |
-p |
Print in parseable CSV format |
-s PARTITION |
Print size of partition N in sectors |
-v |
Print version |
MBR Layout
The tool reads the 512-byte MBR structure:
Offset Size Description
0 446 Boot code
446 16 Partition entry 1
462 16 Partition entry 2
478 16 Partition entry 3
494 16 Partition entry 4
510 2 Signature (0xAA55)
Each partition entry contains:
- Boot indicator (0x80 = active/bootable)
- CHS addresses (not used in LBA mode)
- Partition type byte
- LBA start sector and sector count
Supported Partition Types
The tool recognizes 50+ partition types including:
0x83— Linux0x82— Linux swap0x0C— FAT32 LBA0x07— NTFS0xEE— EFI GPT0xA5— FreeBSD0xA6— OpenBSD
Example
Disk /dev/sda: 500107862 sectors
Device Boot Start End Sectors Size Type
/dev/sda1 * 0 2097151 2097152 1.0 GiB Linux
/dev/sda2 2097152 10485759 8388608 4.0 GiB Linux swap
/dev/sda3 10485760 97677311 87191551 41.5 GiB Linux
Filesystem Creation (mkfs)
mkfs creates filesystems on block devices or regular files. It currently supports FAT32 and ext2.
Usage
mkfs [-t fat32|ext2] [-b BLOCK_SIZE] [-i INODES] [-L LABEL] [-v] [-f] device
| Option | Description |
|---|---|
-t TYPE |
Filesystem type: fat32/vfat or ext2 |
-b SIZE |
Block size (must be power of 2) |
-i COUNT |
Number of inodes |
-L LABEL |
Volume label (up to 11 chars for FAT32) |
-v |
Verbose output |
-f |
Force (skip existing partition check) |
FAT32 Creation
The FAT32 creator:
- Calculates cluster geometry based on volume size
- Writes the Volume Boot Record (VBR) with a complete BPB (BIOS Parameter Block)
- Initializes the FSInfo sector with free cluster hints
- Creates both FAT copies with media type and root directory markers
- Writes an empty root directory at cluster 2
- Updates the MBR partition type to 0x0C (FAT32 LBA)
Cluster sizing adapts to volume size: 1 sector/cluster for < 1GB, scaling up to 64 sectors/cluster for > 32GB.
ext2 Creation
The ext2 creator:
- Writes the superblock at offset 1024 with magic
0xEF53 - Initializes block group descriptors
- Creates block and inode bitmaps marking system blocks as used
- Writes the inode table with a root inode (mode 040755)
- Creates the root directory with
.and..entries - Sets MBR partition type to 0x83 (Linux)
Kernel Interface
mkfs uses:
stat()to determine device size (for regular files)open()withO_WRONLY(orO_RDWRwith-f)lseek()+read()/write()for raw sector I/O
Mounting and Unmounting (mount, umount)
mount — Attach Filesystems
mount attaches a filesystem to the directory tree using the mount() syscall.
Usage
mount [-t TYPE] [-o OPTIONS] [-rvwfn] [-a] device mountpoint
| Option | Description |
|---|---|
-t TYPE |
Filesystem type |
-o OPTIONS |
Comma-separated mount options |
-r |
Mount read-only |
-w |
Mount read-write |
-v |
Verbose output |
-f |
Fake mount (don't actually mount) |
-n |
Don't write to /etc/mtab |
-a |
Mount all entries from /etc/fstab |
Supported Mount Options
The option parser translates string options to kernel MS_* flags:
| Option | Flag | Description |
|---|---|---|
ro |
MS_RDONLY |
Read-only |
rw |
— | Read-write |
nosuid |
MS_NOSUID |
Ignore SUID/SGID bits |
nodev |
MS_NODEV |
No device nodes |
noexec |
MS_NOEXEC |
No program execution |
sync |
MS_SYNCHRONOUS |
Synchronous I/O |
remount |
MS_REMOUNT |
Remount with new flags |
bind |
MS_BIND |
Bind mount |
noatime |
MS_NOATIME |
No access time updates |
relatime |
MS_RELATIME |
Relative access time |
Loop Device Support
When mounting a regular file (e.g., a disk image), mount automatically:
- Scans
/dev/loop0through/dev/loop7for a free device - Opens the loop device and the backing file
- Calls
ioctl(fd, LOOP_SET_FD, filefd)to associate them - Performs the mount on the loop device
fstab Integration
mount -a reads /etc/fstab and mounts all entries not marked noauto. Each line is parsed as: device mountpoint fstype options dump pass.
mtab Updates
After a successful mount, the tool writes an entry to /etc/mtab with the device, mountpoint, filesystem type, and options string.
umount — Detach Filesystems
umount detaches filesystems using the umount2() syscall.
Usage
umount [-a] [-r] [-f] [-n] [-v] [-l] [mountpoint...]
| Option | Description |
|---|---|
-a |
Unmount all (except /, /proc, /sys, /dev, /run) |
-r |
Remount read-only before unmounting |
-f |
Force unmount |
-n |
Don't write to /etc/mtab |
-v |
Verbose output |
-l |
Lazy unmount (MNT_DETACH) |
Lazy Unmount
The -l flag uses MNT_DETACH, which immediately disconnects the filesystem from the namespace. Any in-progress I/O continues in the background, and resources are cleaned up when all references are released. This is useful for unmounting busy filesystems.
mtab Cleanup
umount removes the corresponding entry from /etc/mtab by:
- Reading all mtab entries into memory
- Writing all non-matching entries to a temp file
- Atomically renaming the temp file over the original
Block Device Identification (blkid)
blkid probes block devices to identify their filesystem type, UUID, and label. It reads magic numbers and metadata structures directly from disk.
Usage
blkid [-o FORMAT] [-p] [-s TAG] [-t TAG] [device ...]
| Option | Description |
|---|---|
-o FORMAT |
Output format: full, value, device, export |
-p |
Low-level probing mode |
-s TAG |
Show only a specific tag |
-t TAG |
Search for devices with tag |
Detection Methods
The probe chain tries each detection method in order:
- ext2/3/4 — Reads superblock at offset 1024, checks magic
0xEF53, then examines feature flags to distinguish ext2 (none), ext3 (INCOMPAT_JOURNAL), and ext4 (RO_COMPAT_LARGE_FILE) - FAT — Reads boot sector, checks jump instruction (0xEB or 0xE9), calculates total clusters to determine FAT12/FAT16/FAT32, reads volume serial and label from extended BPB
- NTFS — Checks "NTFS" signature at offset 3, follows MFT entry to extract volume name
- ISO 9660 — Reads "CD001" signature at offset 0x8001
- Swap — Checks for "SWAPSPACE2" or "SWAP1" magic at offset 4086
Output Formats
# full (default)
/dev/sda1: TYPE="ext4" UUID="A1B2-C3D4-E5F6-7890-ABCDEF012345" LABEL="root"
# value
ext4
# device
/dev/sda1
# export (shell-sourceable)
DEVNAME=/dev/sda1
TYPE=ext4
UUID=A1B2-C3D4-E5F6-7890-ABCDEF012345
LABEL=root
Device Scanning
Without arguments, blkid probes a built-in list: /dev/sda through /dev/sdd, /dev/hda-hdb, /dev/vda-vdc.
Loop Device Management (losetup)
losetup manages loop devices — block devices that provide a block-level interface to regular files.
Usage
losetup [options] file [device]
losetup -a
losetup -d device
losetup -f
| Option | Description |
|---|---|
-a, --all |
List all configured loop devices |
-d DEV, --detach DEV |
Detach a loop device |
-f, --find |
Find the first unused loop device |
-o OFFSET, --offset N |
Start at byte offset N |
--sizelimit N |
Maximum size of loop device |
-r, --read-only |
Set up read-only loop device |
-P, --partscan |
Scan for partitions |
--show |
Print device name on success |
Kernel Interface
Loop devices are controlled entirely through ioctl() calls:
| ioctl | Purpose |
|---|---|
LOOP_SET_FD |
Associate a file descriptor with the loop device |
LOOP_CLR_FD |
Detach the backing file |
LOOP_SET_STATUS64 |
Set offset, size limit, read-only flag |
LOOP_GET_STATUS64 |
Query current loop device status |
Loop Status Structure
The loop_info64 structure returned by LOOP_GET_STATUS64 contains:
lo_device— device number (0 if not configured)lo_inode— inode number of backing filelo_offset— byte offset into backing filelo_sizelimit— maximum size (0 = no limit)lo_flags—LO_FLAGS_READ_ONLY, etc.lo_file_name— path to backing file
Examples
# Create a loop device for a disk image
losetup /dev/loop0 disk.img
# Create with an offset (e.g., skip MBR to access partition)
losetup -o 1048576 --show disk.img
# List all active loop devices
losetup -a
# Find and use the first free loop device
losetup -f --show disk.img
# Detach a loop device
losetup -d /dev/loop0
Filesystem Checking (fsck)
fsck examines filesystems for structural integrity and optionally repairs errors. It supports ext2/ext3/ext4 and FAT32.
Usage
fsck [-t TYPE] [-a] [-y] [-n] [-r] [-f] [-p] [-C] [-v] device
| Option | Description |
|---|---|
-t TYPE |
Filesystem type hint |
-a |
Auto-fix errors |
-y |
Answer yes to all repair questions |
-n |
No-fixes mode (read-only check) |
-r |
Interactive repair |
-f |
Force check even if filesystem appears clean |
-p |
Preen mode (automatic safe repairs) |
-C |
Show progress |
-v |
Verbose output |
Detection
If no -t is specified, fsck auto-detects the filesystem type:
- Reads sector 0 and checks for FAT boot signature (0xEB/0xE9 jump instruction)
- Reads superblock at offset 1024 and checks for ext2 magic
0xEF53 - Distinguishes ext2/ext3/ext4 via feature flags
ext2/3/4 Checks
The checker performs these validations:
- Superblock validation — magic number, block size (1024/2048/4096/8192), inode/block counts, free count consistency
- Block group descriptors — validates block bitmap, inode bitmap, and inode table block references
- Inode allocation — checks inode table structure
- Block allocation — checks block bitmap consistency
- Directory structure — validates directory entry chains
FAT32 Checks
- Boot sector — validates BPB fields (bytes per sector, sectors per cluster, FAT count), checks boot signature (0x55AA)
- FAT table — reads first FAT sector, verifies media type signature
- Cluster chains — basic chain validation
- Directory entries — entry structure validation
Error Handling
errors_foundanderrors_fixedcounters track progressask_user()prompts for confirmation in interactive mode- Auto-fix mode (
-a) corrects safe issues without prompting - Read-only mode (
-n) reports issues without modification
Kernel Syscall Interactions
All disk tools ultimately communicate with the kernel through a small set of syscalls:
| Syscall | Used By | Purpose |
|---|---|---|
open() |
All tools | Open devices and files |
read() / write() |
dd, mkfs, fsck, blkid | Raw block I/O |
pread() |
blkid | Positioned reads at specific offsets |
lseek() |
dd, mkfs, fsck | Seek to specific positions |
close() |
All tools | Release file descriptors |
stat() / lstat() |
du, mkfs, fsck | Get file metadata |
statfs() |
df | Get filesystem statistics |
mount() |
mount | Attach filesystem to VFS tree |
umount2() |
umount, mount | Detach filesystem from VFS tree |
ioctl() |
losetup, mount | Loop device control |
mkdir() |
mount | Create mount points |
opendir() / readdir() |
du | Directory traversal |
signal() |
dd | Handle SIGINT gracefully |
syscall(SYS_statfs, ...) |
df | Direct syscall for statfs |
Direct Syscall Usage
df uses syscall(SYS_statfs, path, buf) instead of the libc wrapper, giving it direct control over the kernel interface. This is useful in minimal environments where libc wrappers may not be available.
Implementation Highlights
Error Resilience
ddcontinues past read errors withconv=noerrorand can pad incomplete blocks withconv=syncfsckseparates error detection from correction, allowing read-only auditingumountusesMNT_DETACHfor lazy unmounting of busy filesystems
Portable Conventions
- All tools use POSIX
getopt()/getopt_long()for argument parsing - Size parsing supports suffixes (k, M, G) consistently across tools
- Output formatting follows standard conventions for scriptability
Filesystem Support Matrix
| Tool | ext2 | ext3 | ext4 | FAT12 | FAT16 | FAT32 | NTFS | iso9660 | swap |
|---|---|---|---|---|---|---|---|---|---|
| blkid | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
| fsck | ✓ | ✓ | ✓ | — | — | ✓ | — | — | — |
| mkfs | ✓ | — | — | — | — | ✓ | — | — | — |
| fdisk | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | — | ✓ |
Design Patterns
- Sector-level I/O — All filesystem creators/checkers use direct
lseek()+read()/write()rather than higher-level abstractions, giving full control over byte positioning - Signal safety —
dduses a volatile flag andsignal()handler to allow graceful SIGINT interruption without data corruption - Atomic mtab updates —
umountwrites to a temp file and renames atomically, preventing corruption of/etc/mtabon crash - Automatic loop detection —
mountscans/dev/loop*for free devices when mounting image files
Quick Reference
| Command | What It Does |
|---|---|
dd if=/dev/zero of=test.img bs=1M count=100 |
Create a 100MB zeroed image |
dd if=disk.img of=/dev/sdb bs=4M |
Write image to USB device |
df -h |
Show disk usage in human-readable format |
df -t ext4 |
Show only ext4 filesystems |
du -sh /home |
Total size of /home |
du --max-depth=1 -h |
One-level directory sizes |
fdisk -l /dev/sda |
List partitions on sda |
fdisk -s /dev/sda1 |
Size of partition 1 in sectors |
mkfs -t fat32 -L MYDISK /dev/sdb1 |
Create FAT32 filesystem |
mkfs -t ext2 -L root /dev/sda1 |
Create ext2 filesystem |
mount /dev/sda1 /mnt |
Mount partition to /mnt |
mount -o loop disk.img /mnt |
Mount image file via loop |
mount -a |
Mount all from fstab |
mount |
List mounted filesystems |
umount /mnt |
Unmount /mnt |
umount -a |
Unmount all non-essential filesystems |
umount -l /mnt |
Lazy unmount |
blkid /dev/sda1 |
Identify filesystem type and UUID |
blkid -o export /dev/sda1 |
Export format for scripts |
losetup -f --show disk.img |
Create loop device for image |
losetup -a |
List active loop devices |
losetup -d /dev/loop0 |
Detach loop device |
fsck /dev/sda1 |
Check filesystem integrity |
fsck -a /dev/sda1 |
Auto-fix filesystem errors |
fsck -n /dev/sda1 |
Read-only check (no fixes) |