# Litho — developer documentation
User-facing overview: [README.md](../README.md).
This document covers features in depth, library usage, architecture, build variants, protocols, and platform notes.
---
## Features (detailed)
| **Flash** | Write `.img` / `.iso` / `.img.xz` to a whole block device; optional post-write SHA-256 verify |
| **Clone** | Read a whole block device to an image file |
| **Query** | List storage devices (Linux `/sys/block`, Windows WMI) |
| **Device safety** | Refuse system disks, partitions, busy mounts; typed `DeviceError` |
| **Progress API** | `OperationProgress` (phase, bytes, percentage, message) |
| **Cooperative cancel** | Between block ops; TUI in-process; CLI `--cancel-file` for elevated sidecars |
| **TUI** | Device/file pickers, verify checkbox, elevation (`pkexec` / `sudo` / UAC), logging |
| **GUI protocol** | `-o gui` line protocol for [Lithographer](https://github.com/girish946/lithographer) |
| **Platform traits** | `DeviceInventory`, `DevicePathOps`, `DeviceSafety`, `VolumeOps`, `PrivilegeOps`, I/O traits |
`.xz` images are **stream-decompressed** into the write loop (no temporary uncompressed file).
---
## Requirements (development)
- Rust **1.70+** (edition 2021)
- Linux or Windows for production flash/clone testing
- **Linux elevation:** `pkexec` (polkit) and/or `sudo`
- **Windows:** UAC; release CI uses OpenSSL + vcpkg `liblzma` for the sidecar stack (see Lithographer CI)
- Terminal ≥ **60×24** for TUI
---
## Build variants
### Feature flags
| `simulated-io` | **yes** | Simulator — no real block writes; safe for `cargo test` |
| `real-io` | no | Real `flash` / `clone` via `io_backend` |
```bash
# Dev / tests (default features)
cargo build
cargo test
# Production CLI + TUI
cargo build --release --no-default-features --features real-io --bin litho --bin litho-tui
```
The TUI status line shows `(simulation — disk writes disabled)` under `simulated-io`.
GitHub Actions (and Lithographer’s sidecar script) build with `real-io`.
### Portable Linux `litho` binary (musl)
Bleeding-edge glibc hosts can produce binaries that fail on older distros (`GLIBC_2.xx not found`).
```bash
rustup target add x86_64-unknown-linux-musl
cargo build --release --target x86_64-unknown-linux-musl \
--no-default-features --features real-io --bin litho
```
Output: `target/x86_64-unknown-linux-musl/release/litho`
Alternatively, build in an older container (e.g. `rust:1.80-slim-bookworm`).
Copy the binary into Lithographer as the sidecar when packaging:
`lithographer/src-tauri/binaries/litho` (name may include target triple — see Lithographer scripts).
`litho-tui` is usually built for the host, not as a static portable binary.
---
## CLI reference (full)
User-facing quick start is in the [README](../README.md). Extended options:
### Global options
| `-o, --output-mode` | `terminal` (default) or `gui` |
| `--dry-run` | Validate only |
| `--cancel-file <path>` | Poll file for `cancel` line (GUI / pkexec) |
| `--yes` | Confirm automatic unmount/dismount |
### Output modes
- **`terminal`** — in-place progress bar on TTY; newline updates when piped
- **`gui`** — structured lines: `@progress …` (stdout), `@error …` (stderr), `@done ok|cancelled`. Exit code **`3`** on cooperative cancel
### Flash
```bash
sudo litho flash -f image.img -d /dev/sdX
sudo litho flash -f image.img.xz -d /dev/sdX -b 4096 --verify
sudo litho flash -f image.img -d /dev/sdX -o gui
sudo litho --dry-run flash -f image.img -d /dev/sdX
```
| `-f, --file` | Image file |
| `-d, --device` | Target whole disk |
| `-b, --block-size` | Buffer size (default `4096`) |
| `-s, --silent` | Suppress progress |
| `--verify` | Post-write SHA-256 |
**Windows:** volumes on the target disk are dismounted after confirmation (`--yes` or TUI). Partition-table region is written last to reduce mid-flash re-mount races.
### Clone
```bash
sudo litho clone -d /dev/sdX -f backup.img -b 1048576
```
### Query
```bash
litho query
litho query --device /dev/sdb # currently filters the full list
```
### Device validation (preflight)
Before flash/clone (including dry-run):
- Whole-disk path only (not a partition)
- Not the system disk
- No busy mounts unless auto-unmount is confirmed
- TUI/Lithographer: path must appear in the current device list
---
## TUI (developer notes)
### Privilege elevation
**Linux**
1. Unprivileged user confirms elevation in the TUI.
2. Terminal is restored; process elevates via **`pkexec`** or **`sudo`** (see `PrivilegeOps` / `platform/linux/privilege.rs`).
3. Elevated relaunch gets `--mode`, `--device`, `--image` only — **not** `--start` from the elevating path; user must Start again unless already root with `--start`.
**Windows**
- UAC via `ShellExecuteW` `runas`.
- Volume-dismount confirmation before flash/clone.
- Logs under `%LOCALAPPDATA%\litho\litho-tui.log`.
### Cooperative cancel
- Checked between block I/O operations.
- TUI: in-process `AtomicBool`.
- CLI: `--cancel-file` for cross-privilege cancel (pkexec does not reliably forward stdin/signals).
- Cancelled clone removes incomplete output; CLI exit code `3`.
### Logging
Default: `~/.cache/litho/litho-tui.log` (`$XDG_CACHE_HOME` / Windows `LOCALAPPDATA`).
```bash
litho-tui --log-level debug --log-file /tmp/litho-tui.log
# stderr: --log-file=- or LITHO_LOG_STDERR=1
```
Rotation to `.log.old` above ~5 MiB.
### Device list
- **Linux:** `/sys/block`
- **Windows:** WMI on a dedicated thread
- Fixed (non-removable) selection requires extra confirmation
---
## Library API (`liblitho`)
```toml
[dependencies]
liblitho = { path = "../litho" } # or crates.io / git when published
log = "0.4"
```
Public flash/clone take **`&str` paths** and an optional cancel flag:
```rust
use liblitho::progress::{OperationPhase, OperationProgress};
use liblitho::{clone, flash};
use std::sync::atomic::AtomicBool;
fn on_progress(p: OperationProgress) {
if let Some(pct) = p.percentage {
eprintln!("{:?}: {:.1}%", p.phase, pct);
}
}
// Clone device → file
clone(
"/dev/sdb",
"/tmp/backup.img",
4096,
false, // silent
Some(on_progress),
None, // Option<&AtomicBool> cancel
)?;
// Flash file → device
flash(
"/path/to/image.img",
"/dev/sdb",
4096,
false,
false, // verify
Some(|p| {
if p.phase == OperationPhase::Verifying {
println!("Verifying…");
}
}),
None,
)?;
```
### Progress types
```rust
use liblitho::progress::{OperationPhase, OperationProgress};
// Phases: Preparing, Decompressing, Writing, Syncing, Verifying,
// Complete, Failed, Cancelled
let p = OperationProgress::new(OperationPhase::Writing)
.with_bytes(1024, Some(4096))
.with_message("Writing…");
```
### Devices façade
```rust
use liblitho::devices::{
get_storage_devices, optimal_io_block_size, validate_device_safe_for_io, DeviceError,
};
validate_device_safe_for_io("/dev/sdb")?;
let block_size = optimal_io_block_size("/dev/sdb");
for dev in get_storage_devices()? {
println!("{} — {} {}", dev.device_name, dev.vendor_name, dev.model_name);
}
```
Prefer `io_backend::{flash_io, clone_io}` from binaries so `simulated-io` / `real-io` apply consistently.
---
## Architecture
```
liblitho
flash / clone / progress / cancel # portable algorithms
devices # DTOs, DeviceError, thin façade → platform::Active
platform/
traits/ # I/O, inventory, path, safety, volume, privilege
linux/ | windows/ | macos/ # OS implementations
mod.rs # type Active = …; PlatformDevice factory
io_backend # feature-gated real vs simulated I/O
bin litho # clap CLI + cancel watchers + output modes
bin litho-tui # ratatui UI; privilege via platform façade
```
Design notes: [platform-segregation-plan.md](platform-segregation-plan.md).
### Platform support matrix
| Build CLI | ✅ | ⚠️ | ✅ |
| Build TUI | ✅ | ❌ | ✅ |
| `flash` / `clone` (real-io) | ✅ root | ⚠️ partial | ✅ Admin |
| Device listing | ✅ | ❌ stubs | ✅ WMI |
| Privilege elevation | ✅ pkexec/sudo | ⚠️ stubs | ✅ UAC |
| Cooperative cancel | ✅ | — | ✅ |
---
## GUI protocol (`-o gui`)
Used by Lithographer. Typical events:
```
@status phase=preparing msg="…"
@progress phase=writing pct=12.5 bytes=… total=…
@error msg="…"
@done ok
@done cancelled
```
Cancel: write `cancel` to `--cancel-file` (and/or stdin when not elevated through pkexec).
---
## Safety (developer)
- Treat every path as destructive until validation passes.
- Do not enable `real-io` for automated tests that might touch real disks (`io_backend` compile-errors real-io under `cfg(test)`).
- Windows exclusive volume locks are held on the open writer (`VolumeOps::Guard`); preflight unmounts without holding that session.
---
## Related
- [Lithographer](https://github.com/girish946/lithographer) — Tauri GUI
- [CHANGELOG.md](../CHANGELOG.md)
## License
MIT — see `Cargo.toml`.