A fast, safe CLI tool for creating bootable USB drives, SD cards, and NVMe drives from ISO images.
Inspired by Balena Etcher, built for developers and automation.
New to Engraver? See the Quickstart Guide to get started in 5 minutes.
- Safety First - System drive protection prevents accidental overwrites
- Fast - High-performance block writing with progress tracking
- Reliable - Parallel write verification hashes data during write for fast integrity checks
- Remote Sources - Write directly from HTTP/HTTPS URLs
- Compression - Supports .gz, .xz, .zst, and .bz2 compressed images
- Resumable - Resume interrupted writes with checkpoint support
- USB Speed Detection - Warns if USB 3.0 device is connected at USB 2.0 speed
- Cross-Platform - Linux, macOS, and Windows support
- Developer-Friendly - Clean CLI, JSON output, scriptable
curl -fsSL https://raw.githubusercontent.com/mstephenholl/engraver/main/install.sh | bashThis installs the binary, shell completions, and man pages.
Verify the script before running (recommended)
# Download and inspect
curl -fsSL https://raw.githubusercontent.com/mstephenholl/engraver/main/install.sh -o install.sh
less install.sh
# Verify checksum
echo "3d310d2094281e011d80db8d7dcf2922cbbb71c018ffdf365ab2966dd976adda install.sh" | sha256sum -c
# Run after inspection
bash install.shcargo install --path crates/engraver-cliDownload from Releases.
# List available drives
engraver list
# Write an ISO to a USB drive
engraver write ubuntu.iso /dev/sdb
# Write directly from a URL
engraver write https://releases.ubuntu.com/24.04/ubuntu-24.04-desktop-amd64.iso /dev/sdb
# Write a compressed image (auto-detected)
engraver write ubuntu.iso.xz /dev/sdb
# Write with verification (hashes during write, then reads back to verify)
engraver write ubuntu.iso /dev/sdb --verify
# Skip confirmation prompt (for scripts)
engraver write ubuntu.iso /dev/sdb -y
# Silent mode (no output, implies -y)
engraver write ubuntu.iso /dev/sdb --silent
# Verify a device against an image
engraver verify ubuntu.iso /dev/sdb
# Calculate checksum (supports sha256, sha512, md5, crc32)
engraver checksum ubuntu.iso --algorithm sha256
# Enable checkpointing for resume support
engraver write ubuntu.iso /dev/sdb --checkpoint
# Resume an interrupted write
engraver write ubuntu.iso /dev/sdb --resume
# Auto-detect and verify checksum from .sha256/.sha512/.md5 files
engraver write ubuntu.iso /dev/sdb --auto-checksum
# Show partition layout before writing
engraver write ubuntu.iso /dev/sdb --show-partitions
# Benchmark drive write speed
engraver benchmark /dev/sdb
# Benchmark with custom settings
engraver benchmark /dev/sdb --size 1G --pattern random
# Test multiple block sizes to find optimal performance
engraver benchmark /dev/sdb --test-block-sizes "4K,64K,1M,4M,16M"
# Erase a drive (zero-fill)
engraver erase /dev/sdbEngraver supports resuming interrupted writes. If a write is cancelled (Ctrl+C) or fails due to an error, a checkpoint is saved automatically when using --checkpoint or --resume.
# Start a write with checkpointing enabled
engraver write large-image.iso /dev/sdb --checkpoint
# If interrupted, resume from where it left off
engraver write large-image.iso /dev/sdb --resumeResume limitations:
- Local files: Always resumable (seekable)
- HTTP/HTTPS sources: Resumable if the server supports Range headers
- Compressed files (.gz, .xz, .zst, .bz2): Cannot be resumed
Checkpoints are stored in:
- Linux/macOS:
~/.local/state/engraver/checkpoints/ - Windows:
%LOCALAPPDATA%\engraver\checkpoints\
Engraver can write images directly from HTTP/HTTPS URLs without downloading first:
# Write from a URL
engraver write https://example.com/image.iso /dev/sdb
# Combine with verification
engraver write https://example.com/image.iso /dev/sdb --verify
# Resume support works with URLs (if server supports Range headers)
engraver write https://example.com/large-image.iso /dev/sdb --checkpointWrite images directly from S3, Google Cloud Storage, or Azure Blob Storage:
# Write from Amazon S3
engraver write s3://my-bucket/images/firmware.img /dev/sdb
# Write from Google Cloud Storage
engraver write gs://my-bucket/images/ubuntu.iso /dev/sdb
# Write from Azure Blob Storage
engraver write az://my-container/images/debian.iso /dev/sdb
# Presigned URLs work as regular HTTPS URLs
engraver write "https://my-bucket.s3.amazonaws.com/image.iso?X-Amz-..." /dev/sdbCloud sources support resume via Range headers, just like HTTP/HTTPS. The cloud chunk size is configurable in the [network] section of the configuration file.
Note: Cloud storage support is an optional feature flag. Pre-built binaries include it by default. When building from source, enable it with
cargo build --features cloud.
Compressed images are automatically detected and decompressed during write:
| Format | Extensions |
|---|---|
| Gzip | .gz, .gzip |
| XZ | .xz |
| Zstandard | .zst, .zstd |
| Bzip2 | .bz2, .bzip2 |
# Write compressed images (format auto-detected by extension)
engraver write ubuntu.iso.xz /dev/sdb
engraver write raspbian.img.gz /dev/sdb
engraver write archlinux.iso.zst /dev/sdbCompressed images cannot be resumed if interrupted.
Securely wipe a drive by zero-filling the entire device:
# Erase a USB drive (with confirmation prompt)
engraver erase /dev/sdb
# Erase without confirmation (for scripting)
engraver erase /dev/sdb -y
# Erase with a larger block size for faster throughput
engraver erase /dev/sdb --block-size 16MSystem drive protection applies to erase just as it does to write — Engraver refuses to erase drives containing system partitions.
Preview the partition layout of a source image before writing:
# Show MBR or GPT partition table
engraver write ubuntu.iso /dev/sdb --show-partitionsThis displays partition type, sizes, and filesystem labels. Works with compressed sources by decompressing just the first 64 KB to read the partition table header.
Engraver works on Linux, macOS, and Windows. Device paths differ by platform:
| Platform | Example Device Path | List Command |
|---|---|---|
| Linux | /dev/sdb |
engraver list |
| macOS | /dev/disk2 |
engraver list |
| Windows | \\.\PhysicalDrive1 |
engraver list |
# macOS — write to an external drive
engraver write ubuntu.iso /dev/disk2 --verify
# Windows — write to a USB drive (run as Administrator)
engraver write ubuntu.iso \\.\PhysicalDrive1 --verifyOn macOS, Engraver uses F_FULLFSYNC for guaranteed physical media flush and DKIOCGETBLOCKSIZE ioctl for accurate block size detection. On Linux, standard fsync and /sys/block are used.
Engraver is designed to work well in scripts and CI/CD pipelines:
# JSON output for machine-readable drive listing
engraver list --json | jq -r '.[].path'
# Non-interactive write (skip confirmation)
engraver write ubuntu.iso /dev/sdb -y --verify
# Silent mode (no output except errors, implies -y)
engraver write ubuntu.iso /dev/sdb --silent --verify
# JSON benchmark results for performance tracking
engraver benchmark /dev/sdb --json --passes 3 -y
# Configuration as JSON
engraver config --json | jq '.write.block_size'| Code | Meaning |
|---|---|
0 |
Success |
1 |
Error (permission denied, device not found, verification failure, etc.) |
#!/bin/bash
set -euo pipefail
IMAGE="ubuntu-24.04-desktop-amd64.iso"
DEVICE="/dev/sdb"
# Verify the image checksum before writing
engraver checksum "$IMAGE" --algorithm sha256
# Write with verification, skip prompt
engraver write "$IMAGE" "$DEVICE" -y --verify --auto-checksum
echo "Write complete and verified."Engraver can generate shell completions for tab-completion of commands and arguments.
# Bash
engraver completions bash > ~/.local/share/bash-completion/completions/engraver
# Zsh - place in a directory on your fpath
engraver completions zsh > ~/.zfunc/_engraver
# Then add to .zshrc if not already present:
# fpath=(~/.zfunc $fpath)
# autoload -Uz compinit && compinit
# Fish
engraver completions fish > ~/.config/fish/completions/engraver.fish
# PowerShell - add to your profile
engraver completions powershell >> $PROFILE
# Elvish
engraver completions elvish > ~/.elvish/lib/engraver.elvEngraver supports a configuration file for persistent settings. This allows you to set default values for frequently used options.
- Linux/macOS:
~/.config/engraver/engraver_config.toml - Windows:
%APPDATA%\engraver\engraver_config.toml
# View current settings
engraver config
# View settings as JSON
engraver config --json
# Show config file path
engraver config --path
# Create a new config file with defaults
engraver config --init[write]
block_size = "4M"
verify = true
checkpoint = false
retry_attempts = 3
retry_delay_ms = 100
read_buffer_size = "64K"
[checksum]
algorithm = "sha256"
auto_detect = false
[behavior]
skip_confirmation = false
quiet = false
[benchmark]
block_size = "4M"
test_size = "256M"
pattern = "zeros"
passes = 1
json = false
[network]
http_timeout_secs = 30
validation_timeout_secs = 10
cloud_chunk_size = "4M"| Section | Option | Description | Default |
|---|---|---|---|
[write] |
block_size |
Default block size for writes | "4M" |
[write] |
verify |
Always verify writes | false |
[write] |
checkpoint |
Enable checkpointing by default | false |
[write] |
retry_attempts |
Number of retry attempts on transient errors | 3 |
[write] |
retry_delay_ms |
Delay between retries in milliseconds | 100 |
[write] |
read_buffer_size |
Buffer size for reading source data | "64K" |
[checksum] |
algorithm |
Default checksum algorithm | "sha256" |
[checksum] |
auto_detect |
Auto-detect checksum files | false |
[behavior] |
skip_confirmation |
Skip confirmation prompts | false |
[behavior] |
quiet |
Suppress non-error output | false |
[benchmark] |
block_size |
Default block size for benchmarks | "4M" |
[benchmark] |
test_size |
Default test data size | "256M" |
[benchmark] |
pattern |
Default data pattern (zeros, random, sequential) |
"zeros" |
[benchmark] |
passes |
Default number of benchmark passes | 1 |
[benchmark] |
json |
Output benchmark results in JSON format | false |
[network] |
http_timeout_secs |
HTTP request timeout | 30 |
[network] |
validation_timeout_secs |
URL validation timeout | 10 |
[network] |
cloud_chunk_size |
Chunk size for cloud storage downloads | "4M" |
Command-line flags always override configuration file settings.
Test drive write speed before committing to a long write operation:
# Basic benchmark (256 MB test, 4 MB blocks)
engraver benchmark /dev/sdb
# Custom test size and pattern
engraver benchmark /dev/sdb --size 1G --pattern random
# Test multiple block sizes to find optimal performance
engraver benchmark /dev/sdb --test-block-sizes "4K,64K,1M,4M,16M"
# JSON output for scripting
engraver benchmark /dev/sdb --json| Option | Description | Default |
|---|---|---|
--size |
Amount of data to write | 256M |
--block-size |
Block size for writes | 4M |
--pattern |
Data pattern: zeros, random, sequential |
zeros |
--passes |
Number of benchmark passes | 1 |
--test-block-sizes |
Test multiple block sizes (comma-separated) | - |
Note: --size and --test-block-sizes are mutually exclusive. All size values must be powers of 2, with block sizes limited to 64 MB maximum.
Warning: Benchmarking is a destructive operation that will overwrite data on the target device.
Engraver includes multiple safety mechanisms:
- System drive detection - Refuses to write to drives containing system partitions
- Removable-only by default - Only shows removable drives unless
--allis specified - Confirmation prompts - Requires explicit confirmation before writing
- Verification - Parallel write verification with
--verify(hashes source during write, reads back to compare)
- Rust 1.87+ (MSRV)
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | shThese are used by pre-commit hooks and standard development workflows:
| Tool | Purpose | Install |
|---|---|---|
| clippy | Linter | rustup component add clippy |
| rustfmt | Code formatter | rustup component add rustfmt |
Pre-commit hooks are managed by cargo-husky and install automatically on cargo build or cargo test. They run cargo fmt --check, cargo clippy, and cargo test --lib.
| Tool | Purpose | Install |
|---|---|---|
| cargo-deny | License compliance and dependency audit | cargo install cargo-deny --locked |
| cargo-audit | Security vulnerability scanning | cargo install cargo-audit --locked |
| cargo-llvm-cov | Code coverage | cargo install cargo-llvm-cov --locked |
| cargo-fuzz | Fuzz testing (requires nightly) | cargo install cargo-fuzz --locked |
| cargo-sbom | SBOM generation for releases | cargo install cargo-sbom --locked |
| Tool | Purpose | Install |
|---|---|---|
| musl-tools | Static Linux binaries | sudo apt-get install musl-tools |
| gcc-aarch64-linux-gnu | ARM64 cross-compilation | sudo apt-get install gcc-aarch64-linux-gnu |
| shellcheck | Shell script linting | sudo apt-get install shellcheck |
# Run tests
cargo test
# Run clippy
cargo clippy -- -D warnings
# Check formatting
cargo fmt --check
# Build release
cargo build --release
# Run CLI
cargo r -- list
# Run benchmarks
cargo bench -p engraver-core
# Run fuzz targets (requires nightly)
cargo +nightly fuzz run fuzz_writer -p engraver-core
# Generate code coverage
cargo llvm-cov --html
# Audit dependencies
cargo deny check
cargo auditMIT License - see LICENSE for details.