diff --git a/Makefile b/Makefile index d86558d..8cb015a 100644 --- a/Makefile +++ b/Makefile @@ -25,6 +25,7 @@ $(LIBOBJS): %.o: %.c test: $(TARGET) PATH=$(PWD):$$PATH sudo test/busexmp.sh PATH=$(PWD):$$PATH sudo test/signal_termination.sh + PATH=$(PWD):$$PATH sudo test/loopback_device.sh clean: rm -f $(TARGET) $(OBJS) $(STATIC_LIB) diff --git a/loopback.c b/loopback.c index 57c3767..b927d2a 100644 --- a/loopback.c +++ b/loopback.c @@ -21,10 +21,11 @@ #define _LARGEFILE64_SOURCE #include +#include #include #include +#include #include -#include #include #include @@ -34,7 +35,10 @@ static int fd; static void usage(void) { - fprintf(stderr, "Usage: loopback \n"); + fprintf(stderr, + "Usage: loopback \n" + " for example: loopback path/to/file /dev/nbd0\n" + ); } static int loopback_read(void *buf, u_int32_t len, u_int64_t offset, void *userdata) @@ -77,7 +81,6 @@ static struct buse_operations bop = { int main(int argc, char *argv[]) { struct stat buf; - int err; int64_t size; if (argc != 3) { @@ -88,16 +91,17 @@ int main(int argc, char *argv[]) fd = open(argv[1], O_RDWR|O_LARGEFILE); assert(fd != -1); - /* Let's verify that this file is actually a block device. We could support - * regular files, too, but we don't need to right now. */ - fstat(fd, &buf); - assert(S_ISBLK(buf.st_mode)); + /* Figure out the size of the file or underlying block device. */ + if (fstat(fd, &buf) != 0) err(EXIT_FAILURE, NULL); + if (S_ISBLK(buf.st_mode)) { + /* it's a block dev */ + if(ioctl(fd, BLKGETSIZE64, &size) != 0) err(EXIT_FAILURE, NULL); + } else { + /* a file */ + size = buf.st_size; + } - /* Figure out the size of the underlying block device. */ - err = ioctl(fd, BLKGETSIZE64, &size); - assert(err != -1); - (void)err; - fprintf(stderr, "The size of this device is %ld bytes.\n", size); + fprintf(stderr, "The size of this device/file is %ld bytes.\n", size); bop.size = size; buse_main(argv[2], &bop, NULL); diff --git a/test/busexmp.sh b/test/busexmp.sh index e72f846..80438a4 100755 --- a/test/busexmp.sh +++ b/test/busexmp.sh @@ -1,23 +1,17 @@ #!/usr/bin/env bash set -e +source ./test/utils.sh BLOCKDEV=/dev/nbd0 # quiet version of dd DD="dd status=none" -# verify if blockdev is not currently in use -set +e -nbd-client -c "$BLOCKDEV" > /dev/null -if [ $? -ne 1 ]; then - echo "device $BLOCKDEV is not ready to use (already in use or corrupted)" - exit 1 -fi -set -e +ensure_buse_device_free "$BLOCKDEV" # on exit do cleanup actions function cleanup () { - # kill and wait for BUSE background job - nbd-client -d "$BLOCKDEV" > /dev/null + # disconnect and wait for BUSE background job + disconnect_buse_device "$BLOCKDEV" wait $BUSEPID # remove the test file rm -f "$TESTFILE" diff --git a/test/loopback_device.sh b/test/loopback_device.sh new file mode 100755 index 0000000..51f28cb --- /dev/null +++ b/test/loopback_device.sh @@ -0,0 +1,54 @@ +#!/usr/bin/env bash +set -e +source ./test/utils.sh + +BLOCKDEV=/dev/nbd0 +FAKE_BLOCK_DEVICE=/dev/fake-dev0 +# quiet version of dd +DD="dd status=none" + +ensure_buse_device_free "$BLOCKDEV" + +# ensure FAKE_BLOCK_DEVICE is not in use +set +e +losetup "$FAKE_BLOCK_DEVICE" 2> /dev/null +if [ $? -ne 1 ]; then + echo "device $FAKE_BLOCK_DEVICE is not ready to use (already in use or corrupted)" + exit 1 +fi +set -e + +# on exit do cleanup actions +function cleanup () { + # kill and wait for BUSE background job + disconnect_buse_device "$BLOCKDEV" + wait $BUSEPID + # remove fake block device + losetup -d "$FAKE_BLOCK_DEVICE" + rm -f "$FAKE_BLOCK_DEVICE" + # remove the test file + rm -f "$TESTFILE" +} +trap cleanup EXIT + +# prepare fake block device +TESTFILE=$(mktemp) +$DD if=/dev/urandom of="$TESTFILE" bs=16M count=1 +mknod "$FAKE_BLOCK_DEVICE" b 7 200 +losetup "$FAKE_BLOCK_DEVICE" "$TESTFILE" + +# attach BUSE device +loopback "$FAKE_BLOCK_DEVICE" "$BLOCKDEV" & +sleep 1 +BUSEPID=$! + +### do checks ### + +# compare data read from nbd with TESTFILE contents +cmp <($DD if="$BLOCKDEV" ibs=1k count=5 skip=54) <($DD if="$TESTFILE" ibs=1k count=5 skip=54) + +# write data at the end +$DD if="$TESTFILE" of="$BLOCKDEV" bs=1M count=2 seek=14 + +# read extending past the end of device +cmp <($DD if="$BLOCKDEV" bs=1M count=5 skip=14) <($DD if="$TESTFILE" bs=1M count=2) diff --git a/test/signal_termination.sh b/test/signal_termination.sh index c14916e..571d444 100755 --- a/test/signal_termination.sh +++ b/test/signal_termination.sh @@ -1,21 +1,15 @@ #!/usr/bin/env bash set -e +source ./test/utils.sh BLOCKDEV=/dev/nbd0 SIZE=16M -# verify if blockdev is not currently in use -set +e -nbd-client -c "$BLOCKDEV" > /dev/null -if [ $? -ne 1 ]; then - echo "device $BLOCKDEV is not ready to use (already in use or corrupted)" - exit 1 -fi -set -e +ensure_buse_device_free "$BLOCKDEV" # on exit make sure nbd is disconnected function cleanup () { - nbd-client -d "$BLOCKDEV" > /dev/null + disconnect_buse_device "$BLOCKDEV" } trap cleanup EXIT diff --git a/test/utils.sh b/test/utils.sh new file mode 100644 index 0000000..678a970 --- /dev/null +++ b/test/utils.sh @@ -0,0 +1,14 @@ +function ensure_buse_device_free () { + # verify if blockdev is not currently in use + set +e + nbd-client -c "$1" > /dev/null + if [ $? -ne 1 ]; then + echo "device $1 is not ready to use (already in use or corrupted)" + exit 1 + fi + set -e +} + +function disconnect_buse_device () { + nbd-client -d "$1" > /dev/null +}