Compare commits

...

8 commits

Author SHA1 Message Date
Imbus
f37e28c4ef Remove accidental inclusion of unfinished WI_FILE check 2026-02-09 14:44:42 +01:00
Imbus
4127ad6333 More tests
Include some notes about cleanup and accidentally deleting loop-control
2026-02-09 14:42:56 +01:00
Imbus
d1d3b3cd45 Rename dev_name and filename to iname/oname in preparation for enabling file outputs 2026-02-09 14:42:28 +01:00
Imbus
36a98b2630 Simple test 2026-02-09 13:59:10 +01:00
Imbus
9723924222 Use stylized name in help section 2026-02-09 13:53:46 +01:00
Imbus
d0a3db77e9 Remove commented CFLAGS appends for libudev 2026-02-09 13:53:26 +01:00
Imbus
078ba792f0 Get version string from git, instead of hardcoded in makefile 2026-02-09 13:52:57 +01:00
Imbus
734c1c10ec Use bitmasking to keep track of flags 2026-02-09 13:36:59 +01:00
3 changed files with 99 additions and 32 deletions

View file

@ -1,7 +1,7 @@
GITREV ?= $(shell git describe --dirty --always) GITREV ?= $(shell git describe --dirty --always)
BLDDATE ?= $(shell date -I) BLDDATE ?= $(shell date -I)
CR_YEAR ?= $(shell date +%Y) CR_YEAR ?= $(shell date +%Y)
VERSION ?= "v0.2.1" VERSION ?= "$(shell git describe --tags --always --abbrev=0 2>/dev/null || git rev-parse --short HEAD)"
CFLAGS ?= -Wall -Wextra -Wpedantic -O2 -std=gnu99 CFLAGS ?= -Wall -Wextra -Wpedantic -O2 -std=gnu99
CFLAGS += -DGITREV='"$(GITREV)"' CFLAGS += -DGITREV='"$(GITREV)"'
@ -10,10 +10,6 @@ CFLAGS += -DCR_YEAR='"$(CR_YEAR)"'
CFLAGS += -DVERSION='$(VERSION)' CFLAGS += -DVERSION='$(VERSION)'
CFLAGS += $(EXTRA_CFLAGS) CFLAGS += $(EXTRA_CFLAGS)
# Soon...
# CFLAGS += $(shell pkg-config --cflags libudev)
# LIBS += $(shell pkg-config --libs libudev)
PREFIX ?= /usr/local PREFIX ?= /usr/local
DESTDIR ?= DESTDIR ?=

65
test.sh Normal file
View file

@ -0,0 +1,65 @@
#!/usr/env/bin bash
set -e
# set -x # For debugging
# If you ever mess this up:
# $ sudo mknod /dev/loop-control c 10 237
# $ sudo chmod 600 /dev/loop-control
# $ sudo chown root:root /dev/loop-control
#
# For cleanup:
# $ sudo find /dev -maxdepth 1 -type b -name 'loop[0-9]*' -exec rm -f {} \;
DISKFILE="/tmp/disk.img"
BINFILE="/tmp/file.bin"
LOOPNUM=$((RANDOM % 156 + 100))
LOOPDEV="/dev/loop${LOOPNUM}"
echo "Using device: ${LOOPDEV}"
cleanup() {
echo "Cleaning up..."
set +e -x
sudo losetup -d ${LOOPDEV}
sudo rm ${LOOPDEV}
sudo rm ${BINFILE} ${DISKFILE}
}
trap cleanup EXIT INT TERM
if losetup ${LOOPDEV} >/dev/null 2>&1; then
echo "${LOOPDEV} already in use" >&2
cleanup
exit 1
fi
if [ ! -f ${DISKFILE} ]; then
dd if=/dev/zero of=${DISKFILE} bs=1M count=256
fi
if [ ! -f ${BINFILE} ]; then
dd if=/dev/urandom of=${BINFILE} bs=1M count=64
fi
if [ ! -e ${LOOPDEV} ]; then
sudo losetup ${LOOPDEV} ${DISKFILE}
fi
sudo ./writeimg -nd ${LOOPDEV} ${BINFILE}
sudo ./writeimg -vnd ${LOOPDEV} ${BINFILE}
sudo ./writeimg -nd ${LOOPDEV} ./writeimg
sudo ./writeimg -vnd ${LOOPDEV} ./writeimg
sudo ./writeimg -nd ${LOOPDEV} ./LICENSE
sudo ./writeimg -vnd ${LOOPDEV} ./LICENSE
# Redirect this to avoid confusion
! sudo ./writeimg -vnd ${LOOPDEV} ./crc32.h 2>/dev/null
GREEN="\e[32m"
RESET="\e[0m"
echo -e "\n\n${GREEN}Looks good!${RESET}"

View file

@ -32,6 +32,10 @@
#define BLOCKSIZE (1024 * 1024) #define BLOCKSIZE (1024 * 1024)
#endif #endif
#define WI_VERIFY (1 << 0)
#define WI_WRITE (1 << 1)
#define WI_ASK (1 << 2)
#define BYTES_TO_MIB(bts) ((double)bts / (1024 * 1024)) #define BYTES_TO_MIB(bts) ((double)bts / (1024 * 1024))
#define BAR_WIDTH 50 #define BAR_WIDTH 50
@ -69,14 +73,14 @@ const char help[] =
const char copyright[] = "Copyright (C) %s Imbus, BSD-2-Clause\n"; const char copyright[] = "Copyright (C) %s Imbus, BSD-2-Clause\n";
struct write_job { struct write_job {
char *filename; char *iname;
char *dev_name; char *oname;
char *buffer; char *buffer;
char *buffer2; /* For memcmp integrity checks */ char *buffer2; /* For memcmp integrity checks */
size_t bufsize; size_t bufsize;
size_t block_size; size_t block_size;
size_t total_bytes; size_t total_bytes;
char verify_only; char flags;
} wjob = {0}; } wjob = {0};
typedef struct write_job write_job_t; typedef struct write_job write_job_t;
@ -94,8 +98,8 @@ void int_handler(int signum) {
} }
int perform_write(write_job_t *job) { int perform_write(write_job_t *job) {
int block_fd = open(job->dev_name, O_RDWR); int block_fd = open(job->oname, O_RDWR);
int file_fd = open(job->filename, O_RDONLY); int file_fd = open(job->iname, O_RDONLY);
assert(block_fd >= 0); assert(block_fd >= 0);
assert(file_fd >= 0); assert(file_fd >= 0);
@ -114,7 +118,7 @@ int perform_write(write_job_t *job) {
if (read_bytes == 0) { if (read_bytes == 0) {
crc = crc32_finalize(crc); crc = crc32_finalize(crc);
if (!job->verify_only) { if (job->flags & WI_WRITE) {
printf("\nWriting done...\n"); printf("\nWriting done...\n");
assert(job->total_bytes == b_written); assert(job->total_bytes == b_written);
} else } else
@ -124,17 +128,17 @@ int perform_write(write_job_t *job) {
} }
if (read_bytes < 0) { if (read_bytes < 0) {
fprintf(stderr, "%s: Read error\n", job->filename); fprintf(stderr, "%s: Read error\n", job->iname);
perror("Read"); perror("Read");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
crc = crc32_update(crc, job->buffer, read_bytes); crc = crc32_update(crc, job->buffer, read_bytes);
if (!job->verify_only) { if (job->flags & WI_WRITE) {
ssize_t written_bytes = write(block_fd, job->buffer, read_bytes); ssize_t written_bytes = write(block_fd, job->buffer, read_bytes);
if (written_bytes < 0) { if (written_bytes < 0) {
fprintf(stderr, "%s: Write error\n", job->dev_name); fprintf(stderr, "%s: Write error\n", job->oname);
perror("Write"); perror("Write");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
@ -195,7 +199,7 @@ static const struct option longopts[] = {
}; };
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
printf("%s %s, Rev. %s\n", basename(argv[0]), VERSION, GITREV); printf("%s %s, Rev. %s\n", "WriteIMG", VERSION, GITREV);
/* Line buffering, system allocated */ /* Line buffering, system allocated */
setvbuf(stdout, NULL, _IOLBF, 0); setvbuf(stdout, NULL, _IOLBF, 0);
@ -206,14 +210,18 @@ int main(int argc, char *argv[]) {
signal(SIGHUP, int_handler); signal(SIGHUP, int_handler);
signal(SIGTERM, int_handler); signal(SIGTERM, int_handler);
int ask_permission = 1; wjob.flags = WI_VERIFY | WI_WRITE | WI_ASK;
int c = {0}; int c = {0};
while ((c = getopt_long(argc, argv, "vd:hnV", longopts, 0)) != -1) { while ((c = getopt_long(argc, argv, "vd:hnV", longopts, 0)) != -1) {
switch (c) { switch (c) {
case 'v': ++wjob.verify_only; continue; case 'v':
case 'd': wjob.dev_name = optarg; continue; wjob.flags |= WI_VERIFY;
wjob.flags &= ~WI_WRITE;
continue;
case 'd': wjob.oname = optarg; continue;
case 'h': break; case 'h': break;
case 'n': --ask_permission; continue; case 'n': wjob.flags &= ~WI_ASK; continue;
case 'V': exit(EXIT_SUCCESS); case 'V': exit(EXIT_SUCCESS);
} }
printf("In honor of SwePwnage - the OG disk destroyer\n"); printf("In honor of SwePwnage - the OG disk destroyer\n");
@ -236,27 +244,27 @@ int main(int argc, char *argv[]) {
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
wjob.filename = argv[0]; wjob.iname = argv[0];
struct stat file_stat = {0}; struct stat file_stat = {0};
if (0 != stat(wjob.filename, &file_stat)) { if (0 != stat(wjob.iname, &file_stat)) {
printf("File does not exist...\n"); printf("File does not exist...\n");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
if (NULL == wjob.dev_name) { if (NULL == wjob.oname) {
printf("You need to specify a device.\n"); printf("You need to specify a device.\n");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
if (0 != strncmp(wjob.dev_name, "/dev/", 4)) { if (0 != strncmp(wjob.oname, "/dev/", 4)) {
printf("\"%s\" does not appear to be a block device...\n", wjob.dev_name); printf("\"%s\" does not appear to be a block device...\n", wjob.oname);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
/* Seems to be the cleanest way to check for write perm on a blockdev */ /* Seems to be the cleanest way to check for write perm on a blockdev */
int fd = open(wjob.dev_name, O_WRONLY); int fd = open(wjob.oname, O_WRONLY);
if (fd < 0) { if (fd < 0) {
printf("Cannot write to \"%s\", do you have write permissions?\n", wjob.dev_name); printf("Cannot write to \"%s\", do you have write permissions?\n", wjob.oname);
exit(1); exit(1);
} }
close(fd); close(fd);
@ -264,13 +272,11 @@ int main(int argc, char *argv[]) {
wjob.total_bytes = file_stat.st_size; wjob.total_bytes = file_stat.st_size;
assert(file_stat.st_size >= 0); assert(file_stat.st_size >= 0);
if (!wjob.verify_only) if (wjob.flags & WI_WRITE)
printf("Writing \"%s\" (%.1f MiB) to \"%s\"\n", printf(
basename(wjob.filename), "Writing \"%s\" (%.1f MiB) to \"%s\"\n", basename(wjob.iname), BYTES_TO_MIB(wjob.total_bytes), wjob.oname);
BYTES_TO_MIB(wjob.total_bytes),
wjob.dev_name);
if (ask_permission && !wjob.verify_only) { if ((wjob.flags & WI_ASK) && (wjob.flags & WI_WRITE)) {
printf("Is this okay? (y/N): "); printf("Is this okay? (y/N): ");
fflush(stdout); fflush(stdout);
if ('y' != getchar()) { if ('y' != getchar()) {