You can also run only the root tests using:
sudo make check-root
---
.gitignore | 1 +
Makefile.am | 3 +
README | 7 ++
tests/Makefile.am | 10 +-
tests/test-file-block.c | 217 ++++++++++++++++++++++++++++++++++++++++
5 files changed, 237 insertions(+), 1 deletion(-)
diff --git a/.gitignore b/.gitignore
index d6686ea..a3d504e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -69,6 +69,7 @@ Makefile.in
/tests/test-exit-with-parent
/tests/test-ext2
/tests/test-file
+/tests/test-file-block
/tests/test-gzip
/tests/test-layers
/tests/test-lua
diff --git a/Makefile.am b/Makefile.am
index 0a79e56..c411ed6 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -64,6 +64,9 @@ SUBDIRS += tests
check-valgrind:
$(MAKE) -C tests check-valgrind
+check-root:
+ $(MAKE) -C tests check-root
+
# Maintainer only: check no files are missing from EXTRA_DIST rules,
# and that all generated files have been included in the tarball.
# (Note you must have done 'make dist')
diff --git a/README b/README
index 473eea8..145cc49 100644
--- a/README
+++ b/README
@@ -125,6 +125,8 @@ To test for memory leaks (‘make check-valgrind’):
For non-essential enhancements to the test suite:
+ - losetup (from util-linux package)
+
- qemu-io (usually shipped with qemu)
- socat
@@ -175,6 +177,11 @@ nbdkit + plugins as a captive process, and tests them using
libguestfs. If there is a failure, look at the corresponding
‘tests/*.log’ file for debug information.
+A few tests require root privileges, and are skipped by default. To
+run them you must do:
+
+ sudo make check-root
+
DOWNLOAD TARBALLS
=================
diff --git a/tests/Makefile.am b/tests/Makefile.am
index ce383c2..e0ae6b3 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -95,6 +95,10 @@ EXTRA_DIST = \
check-valgrind:
NBDKIT_VALGRIND=1 $(MAKE) check
+# To run only tests which require root, use:
+check-root:
+ $(MAKE) check TESTS="test-file-block"
+
#----------------------------------------------------------------------
# Basic server command line and start-up tests.
@@ -307,12 +311,16 @@ endif HAVE_GUESTFISH
endif HAVE_EXT2
# file plugin test.
-LIBGUESTFS_TESTS += test-file
+LIBGUESTFS_TESTS += test-file test-file-block
test_file_SOURCES = test-file.c test.h
test_file_CFLAGS = $(WARNINGS_CFLAGS) $(LIBGUESTFS_CFLAGS)
test_file_LDADD = libtest.la $(LIBGUESTFS_LIBS)
+test_file_block_SOURCES = test-file-block.c test.h
+test_file_block_CFLAGS = $(WARNINGS_CFLAGS) $(LIBGUESTFS_CFLAGS)
+test_file_block_LDADD = libtest.la $(LIBGUESTFS_LIBS)
+
# gzip plugin test.
if HAVE_ZLIB
if HAVE_GUESTFISH
diff --git a/tests/test-file-block.c b/tests/test-file-block.c
new file mode 100644
index 0000000..75c2c61
--- /dev/null
+++ b/tests/test-file-block.c
@@ -0,0 +1,217 @@
+/* nbdkit
+ * Copyright (C) 2013-2018 Red Hat Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of Red Hat nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY RED HAT AND CONTRIBUTORS ''AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RED HAT OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <inttypes.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+
+#include <guestfs.h>
+
+#include "test.h"
+
+static char *loopdev; /* Name of the loop device. */
+static void detach_loopdev (void);
+
+int
+main (int argc, char *argv[])
+{
+ guestfs_h *g;
+ int r;
+ int fd;
+ char cmd[64], buf[64];
+ char disk[] = "/tmp/diskXXXXXX"; /* Backing disk. */
+ FILE *pp;
+ char *data;
+ size_t len;
+ char *s;
+
+ /* This test can only be run as root, and will be skipped otherwise. */
+ if (geteuid () != 0) {
+ fprintf (stderr, "%s: this test has to be run as root.\n",
+ program_name);
+ exit (77);
+ }
+
+ /* losetup must be available. */
+ r = system ("losetup --version");
+ if (r != 0) {
+ fprintf (stderr, "%s: losetup program must be installed.\n",
+ program_name);
+ exit (77);
+ }
+
+ /* Create the temporary backing disk. */
+ fd = mkstemp (disk);
+ if (fd == -1) {
+ perror ("mkstemp");
+ exit (EXIT_FAILURE);
+ }
+ if (ftruncate (fd, 100 * 1024 * 1024) == -1) {
+ perror ("ftruncate");
+ unlink (disk);
+ exit (EXIT_FAILURE);
+ }
+
+ /* Create the loopback device. */
+ snprintf (cmd, sizeof cmd, "losetup -f --show %s", disk);
+ pp = popen (cmd, "r");
+ if (pp == NULL) {
+ perror ("popen: losetup");
+ unlink (disk);
+ exit (EXIT_FAILURE);
+ }
+ if (fgets (buf, sizeof buf, pp) == NULL) {
+ fprintf (stderr, "%s: could not read loop device name from losetup\n",
+ program_name);
+ unlink (disk);
+ exit (EXIT_FAILURE);
+ }
+ len = strlen (buf);
+ if (len > 0 && buf[len-1] == '\n') {
+ buf[len-1] = '\0';
+ len--;
+ }
+ pclose (pp);
+
+ /* We can delete the backing disk. The loop device will hold it open. */
+ unlink (disk);
+
+ /* If we get to this point, set up an atexit handler to detach the
+ * loop device.
+ */
+ loopdev = malloc (len+1);
+ if (loopdev == NULL) {
+ perror ("malloc");
+ exit (EXIT_FAILURE);
+ }
+ strcpy (loopdev, buf);
+ atexit (detach_loopdev);
+
+ /* Start nbdkit. */
+ snprintf (buf, sizeof buf, "file=%s", loopdev);
+ if (test_start_nbdkit ("file", buf, NULL) == -1)
+ exit (EXIT_FAILURE);
+
+ g = guestfs_create ();
+ if (g == NULL) {
+ perror ("guestfs_create");
+ exit (EXIT_FAILURE);
+ }
+
+ r = guestfs_add_drive_opts (g, "",
+ GUESTFS_ADD_DRIVE_OPTS_FORMAT, "raw",
+ GUESTFS_ADD_DRIVE_OPTS_PROTOCOL, "nbd",
+ GUESTFS_ADD_DRIVE_OPTS_SERVER, server,
+ -1);
+ if (r == -1)
+ exit (EXIT_FAILURE);
+
+ if (guestfs_launch (g) == -1)
+ exit (EXIT_FAILURE);
+
+ /* Partition the disk. */
+ if (guestfs_part_disk (g, "/dev/sda", "mbr") == -1)
+ exit (EXIT_FAILURE);
+ if (guestfs_mkfs (g, "ext4", "/dev/sda1") == -1)
+ exit (EXIT_FAILURE);
+
+ if (guestfs_mount (g, "/dev/sda1", "/") == -1)
+ exit (EXIT_FAILURE);
+
+#define filename "/hello.txt"
+#define content "hello, people of the world"
+
+ if (guestfs_write (g, filename, content, strlen (content)) == -1)
+ exit (EXIT_FAILURE);
+
+ data = guestfs_cat (g, filename);
+ if (!data)
+ exit (EXIT_FAILURE);
+
+ if (strcmp (data, content) != 0) {
+ fprintf (stderr, "%s FAILED: unexpected content of %s file (actual: %s,
expected: %s)\n",
+ program_name, filename, data, content);
+ exit (EXIT_FAILURE);
+ }
+
+ /* Run sync to test flush path. */
+ if (guestfs_sync (g) == -1)
+ exit (EXIT_FAILURE);
+
+ /* Run fstrim to test trim path. However only recent versions of
+ * libguestfs have this, and it probably only works in recent
+ * versions of qemu.
+ */
+#ifdef GUESTFS_HAVE_FSTRIM
+ if (guestfs_fstrim (g, "/", -1) == -1)
+ exit (EXIT_FAILURE);
+#endif
+
+ /* Run fallocate(1) on the device to test zero path. */
+ if (guestfs_umount (g, "/") == -1)
+ exit (EXIT_FAILURE);
+ const char *sh[] = { "fallocate", "-nzl", "64k",
"/dev/sda", NULL };
+ s = guestfs_debug (g, "sh", (char **) sh);
+ free (s);
+
+ if (guestfs_shutdown (g) == -1)
+ exit (EXIT_FAILURE);
+
+ guestfs_close (g);
+
+ /* The atexit handler should detach the loop device and clean up
+ * the backing disk.
+ */
+ exit (EXIT_SUCCESS);
+}
+
+/* atexit handler. */
+static void
+detach_loopdev (void)
+{
+ char cmd[64];
+
+ if (loopdev == NULL)
+ return;
+
+ snprintf (cmd, sizeof cmd, "losetup -d %s", loopdev);
+ system (cmd);
+ free (loopdev);
+ loopdev = NULL;
+}
--
2.18.0