| .clang-format | ||
| .gitignore | ||
| crc32.h | ||
| LICENSE | ||
| Makefile | ||
| README.md | ||
| test.sh | ||
| writeimg.1 | ||
| writeimg.c | ||
WriteIMG Image Writer
WriteIMG is a simple dd-like image writer with additional security checks for Linux and soon FreeBSD. It tells you what you're about to do and warns you about potential problems before they occur. It also features automatic image verifications, and uses a suitable block size for fast and gentle writing.
Say goodbye to fried flash and overwritten bootloaders, no more footguns!
WriteIMG v0.2.3, Rev. d02fc5f
In honor of SwePwnage - the OG disk destroyer
Copyright (C) 2026 Imbus, BSD-2-Clause
Build date: 2026-02-21
Usage:
writeimg [-v] -d <device> <file.img>
Args:
<file.img> Binary image file
-v Verify only
-d device Target block device
-h, --help Print this help message
-n, --noconfirm Do not ask for permission
-V, --version Print version
We also provide a manpage, which targets OpenBSD-level quality. Incorrect or outdated information is a bug.
Testing
For testing, there is a shell script "test.sh" included. It sets up a block dev and writes (and verifies) a bunch of nonsense to it. It boils down to:
dd if=/dev/zero of=./disk.img bs=1M count=1024
losetup -fP ./disk.img
losetup -a
losedup -d /dev/loop0
Writes to a regular files is not currently in scope, although it would simplify testing.
Design Considerations
Most of the sanity checking is currently highly Linux specific. We should prefer general/posix solutions that reach at least FreeBSD, preferably OpenBSD and Solaris as well. FreeBSD did implement procfs, but its a Linux-ism and it has since been deprecated. I would prefer not to turn this rather simple code into macro-mozaic, as i've seen other similar projects do. After all, this is just a juiced-up dd-rewrite at its core.
Apple products are unsupported. Im simply not interested in ensuring compatibility with a walled-garden ecosystem. If you are, we can change that.
At the time of writing, my FreeBSD server is down for maintenance, which means all of my development and testing is focused on AMD64, AArch64 and AArch32 Linux.
In the setup phase of the program, we can absolutely afford to do lots of sanity checking via syscalls. Between each block write, we flush the disk buffers. These flushes are larger (1 MiB when buffer is full) than the sector size (often 4k or 64k) of the flash, so as far as i know, this is a gentle way to write flash, and should not incur any significant performance overhead. 1 MiB is also a multiple of the most common sector sizes. We could write it all with no flushing, but that would mean the progress indicator will measure buffered writes, which is useless.
It should be possible to induce optimal block size, but this idea has not been explored yet.
Currently when verifying the written data, we read from both the input file and the output block device and do a byte-by-byte comparison. A CRC32 is also calculated in the first pass of the input file read. In the second pass (the verification stage), we calculate the CRC32 of the block device data and compare that to our previous result. This means that we currently use two separate methods of verification. The program allocates two separate buffers in the startup phase for comparisons. This will change in the coming releases, and we will rely only on the CRC.
De-allocation is handled in the interrupt vector as well as in the 'sad-paths', but ultimately this program can be regarded as samurai-principled. We try to handle deallocation, but exit on failure and let the kernel handle the rest.
The use of a crypto-grade checksumming algorithm was considered, but was ultimately rejected in favour of a lookup based CRC32. Its simpler, faster and easier to understand (See: crc32.h). We may include a compile-time option to disable the lookup table to reduce size for really small targets, but we speculate that those targets are already satisfied with busybox-dd.
We also considered using libudev or any of its analogues, to determine the type of block device (spinning or flash), but my somewhat inconclusive research indicates that it does not include functionality to determine the medium type (usb/sd/sata), which is ultimately what i would like to warn the user about. The libudev library is also Linux specific.
We also need completion scripts for the most common shells. This includes csh, bash and zsh. Should be easy enough when we set our minds to it.
See:
grep -nE 'BLK[A-Za-z0-9]+' /usr/include/linux/fs.h
In particular, we're interested in BLKGETSIZE64 and BLKFLSBUF for now.
We can read the device info from:
- /sys/class/block/[name]/* Like:
- /sys/class/block/[name]/device/model
- /sys/class/block/[name]/size
Inspiration
See: