[Pkg-libvirt-commits] [libguestfs] 22/66: fuse: Rewrite test-fuse.sh in C.

Hilko Bengen bengen at moszumanska.debian.org
Fri Oct 3 14:47:37 UTC 2014


This is an automated email from the git hooks/post-receive script.

bengen pushed a commit to annotated tag debian/1%1.27.54-1
in repository libguestfs.

commit aca076e2e2b3e03f4cf5b09cf7766925f97e4b68
Author: Richard W.M. Jones <rjones at redhat.com>
Date:   Sun Sep 21 21:40:13 2014 +0100

    fuse: Rewrite test-fuse.sh in C.
    
    This gives us finer control over how system calls are done,
    and also potentially lets us test more.
    
    Currently two tests are disabled:
    
     - utimens because of https://bugzilla.redhat.com/show_bug.cgi?id=1144766
    
     - utimes because our stat call does not return the nanosecond fields
---
 .gitignore        |   1 +
 fuse/Makefile.am  |  22 +-
 fuse/test-fuse.c  | 698 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 fuse/test-fuse.sh | 264 ---------------------
 po/POTFILES       |   1 +
 5 files changed, 720 insertions(+), 266 deletions(-)

diff --git a/.gitignore b/.gitignore
index 86158eb..269d735 100644
--- a/.gitignore
+++ b/.gitignore
@@ -184,6 +184,7 @@ Makefile.in
 /fuse/guestunmount.1
 /fuse/stamp-guestmount.pod
 /fuse/stamp-guestunmount.pod
+/fuse/test-fuse
 /fuse/test-guestmount-fd
 /fuse/test-guestunmount-fd
 /generator/.depend
diff --git a/fuse/Makefile.am b/fuse/Makefile.am
index 0286338..8bd1acf 100644
--- a/fuse/Makefile.am
+++ b/fuse/Makefile.am
@@ -131,7 +131,7 @@ TESTS = \
 
 if ENABLE_APPLIANCE
 TESTS += \
-	test-fuse.sh \
+	test-fuse \
 	test-fuse-umount-race.sh \
 	test-guestmount-fd
 endif ENABLE_APPLIANCE
@@ -140,7 +140,25 @@ TESTS_ENVIRONMENT = \
 	top_builddir=.. \
 	$(top_builddir)/run --test
 
-check_PROGRAMS = test-guestmount-fd test-guestunmount-fd
+check_PROGRAMS = test-fuse test-guestmount-fd test-guestunmount-fd
+
+test_fuse_SOURCES = \
+	test-fuse.c
+
+test_fuse_CPPFLAGS = \
+	-I$(top_srcdir)/src -I$(top_builddir)/src \
+	-I$(srcdir)/../gnulib/lib -I../gnulib/lib
+
+test_fuse_CFLAGS = \
+	$(WARN_CFLAGS) $(WERROR_CFLAGS)
+
+test_fuse_LDADD = \
+	$(top_builddir)/src/libutils.la \
+	$(top_builddir)/src/libguestfs.la \
+	$(LIBXML2_LIBS) \
+	$(LIBVIRT_LIBS) \
+	$(ACL_LIBS) \
+	../gnulib/lib/libgnu.la
 
 test_guestmount_fd_SOURCES = \
 	test-guestmount-fd.c
diff --git a/fuse/test-fuse.c b/fuse/test-fuse.c
new file mode 100644
index 0000000..dda6fde
--- /dev/null
+++ b/fuse/test-fuse.c
@@ -0,0 +1,698 @@
+/* Test FUSE.
+ * Copyright (C) 2009-2014 Red Hat Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/* This used to be a shell script test, but using C gives us finer
+ * control over exactly which system calls are being used, as well as
+ * allowing us to avoid one launch of the appliance during the test.
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#ifdef HAVE_ACL
+#include <sys/acl.h>
+#endif
+
+#ifdef HAVE_ATTR_XATTR_H
+#include <attr/xattr.h>
+#else
+#ifdef HAVE_SYS_XATTR_H
+#include <sys/xattr.h>
+#endif
+#endif
+
+#include <guestfs.h>
+#include "guestfs-internal-frontend.h"
+
+#include "ignore-value.h"
+
+static guestfs_h *g;
+
+#define SIZE INT64_C(1024*1024*1024)
+
+/* NB: Must be a path that does not need quoting. */
+static char mountpoint[] = "/tmp/testfuseXXXXXX";
+
+static int acl_available;
+static int linuxxattrs_available;
+
+static void create_initial_filesystem (void);
+static int test_fuse (void);
+
+int
+main (int argc, char *argv[])
+{
+  const char *s;
+  const char *acl_group[] = { "acl", NULL };
+  const char *linuxxattrs_group[] = { "linuxxattrs", NULL };
+  int debug_calls, r, res;
+  pid_t pid;
+  struct sigaction sa;
+  char cmd[128];
+
+  /* Allow the test to be skipped.  Note I'm using the old shell
+   * script name here.
+   */
+  s = getenv ("SKIP_TEST_FUSE_SH");
+  if (s && STRNEQ (s, "")) {
+    printf ("%s: test skipped because environment variable is set\n",
+            argv[0]);
+    exit (77);
+  }
+
+  if (access ("/dev/fuse", W_OK) == -1) {
+    perror ("/dev/fuse");
+    exit (77);
+  }
+
+  g = guestfs_create ();
+  if (g == NULL) {
+    perror ("guestfs_create");
+    exit (EXIT_FAILURE);
+  }
+
+  if (guestfs_add_drive_scratch (g, SIZE, -1) == -1)
+    exit (EXIT_FAILURE);
+
+  if (guestfs_launch (g) == -1)
+    exit (EXIT_FAILURE);
+
+  /* Test features. */
+  acl_available = guestfs_feature_available (g, (char **) acl_group);
+  if (acl_available == -1) exit (EXIT_FAILURE);
+
+  linuxxattrs_available =
+    guestfs_feature_available (g, (char **) linuxxattrs_group);
+  if (linuxxattrs_available == -1) exit (EXIT_FAILURE);
+
+  create_initial_filesystem ();
+
+  /* Make a mountpoint. */
+  if (mkdtemp (mountpoint) == NULL)
+    exit (EXIT_FAILURE);
+
+  /* Mount the filesystem on the host using FUSE. */
+  debug_calls = guestfs_get_trace (g);
+  if (guestfs_mount_local (g, mountpoint,
+                           GUESTFS_MOUNT_LOCAL_DEBUGCALLS, debug_calls,
+                           -1) == -1)
+    exit (EXIT_FAILURE);
+
+  /* Fork to run the next part of the test. */
+  pid = fork ();
+  if (pid == -1) {
+    perror ("fork");
+    exit (EXIT_FAILURE);
+  }
+
+  if (pid == 0) {               /* Child. */
+    /* Move into the mountpoint for the tests. */
+    if (chdir (mountpoint) == -1) {
+      perror (mountpoint);
+      _exit (EXIT_FAILURE);
+    }
+
+    res = test_fuse ();
+
+    /* Move out of the mountpoint (otherwise our cwd will prevent the
+     * mountpoint from being unmounted below).
+     */
+    ignore_value (chdir ("/"));
+
+    /* Who's using the mountpoint?  Should be no one. */
+    snprintf (cmd, sizeof cmd, "/sbin/fuser %s", mountpoint);
+    ignore_value (system (cmd));
+
+    snprintf (cmd, sizeof cmd, "guestunmount %s", mountpoint);
+    r = system (cmd);
+    if (!WIFEXITED (r) || WEXITSTATUS (r) != EXIT_SUCCESS)
+      fprintf (stderr, "%s: warning: guestunmount command failed\n", argv[0]);
+
+    _exit (res == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
+  }
+
+  /* Parent. */
+
+  /* Ignore signals in the parent while running the child. */
+  memset (&sa, 0, sizeof sa);
+  sa.sa_handler = SIG_IGN;
+  sigaction (SIGINT, &sa, NULL);
+  sigaction (SIGTERM, &sa, NULL);
+
+  if (guestfs_mount_local_run (g) == -1)
+    exit (EXIT_FAILURE);
+
+  /* Clean up and exit. */
+  if (waitpid (pid, &r, 0) == -1) {
+    perror ("waitpid");
+    exit (EXIT_FAILURE);
+  }
+
+  if (rmdir (mountpoint) == -1) {
+    perror (mountpoint);
+    exit (EXIT_FAILURE);
+  }
+
+  if (guestfs_shutdown (g) == -1)
+    exit (EXIT_FAILURE);
+
+  guestfs_close (g);
+
+  /* Did the child process fail? */
+  exit (!WIFEXITED (r) || WEXITSTATUS (r) != 0 ? EXIT_FAILURE : EXIT_SUCCESS);
+}
+
+/* Create a filesystem with some initial content. */
+static void
+create_initial_filesystem (void)
+{
+  if (guestfs_part_disk (g, "/dev/sda", "mbr") == -1)
+    exit (EXIT_FAILURE);
+
+  /* Use ext4 because it supports modern features.  Use >= 256 byte
+   * inodes because these support nanosecond timestamps.
+   */
+  if (guestfs_mkfs_opts (g, "ext4", "/dev/sda1",
+                         GUESTFS_MKFS_OPTS_INODE, 256,
+                         -1) == -1)
+    exit (EXIT_FAILURE);
+
+  if (guestfs_mount_options (g, "acl,user_xattr", "/dev/sda1", "/") == -1)
+    exit (EXIT_FAILURE);
+
+  if (guestfs_write (g, "/hello.txt", "hello", 5) == -1)
+    exit (EXIT_FAILURE);
+
+  if (guestfs_write (g, "/world.txt", "hello world", 11) == -1)
+    exit (EXIT_FAILURE);
+
+  if (guestfs_touch (g, "/empty") == -1)
+    exit (EXIT_FAILURE);
+
+  if (linuxxattrs_available) {
+    if (guestfs_touch (g, "/user_xattr") == -1)
+      exit (EXIT_FAILURE);
+
+    if (guestfs_setxattr (g, "user.test", "hello123", 8, "/user_xattr") == -1)
+      exit (EXIT_FAILURE);
+  }
+
+  if (acl_available) {
+    if (guestfs_touch (g, "/acl") == -1)
+      exit (EXIT_FAILURE);
+
+    if (guestfs_acl_set_file (g, "/acl", "access",
+                              "u::rwx,u:500:r,g::rwx,m::rwx,o::r-x") == -1)
+      exit (EXIT_FAILURE);
+  }
+}
+
+/* Run FUSE tests.  Mountpoint is current directory. */
+static int
+test_fuse (void)
+{
+  int stage = 0;
+#define STAGE(fs,...)                                   \
+  printf ("%02d: " fs "\n", ++stage, ##__VA_ARGS__);    \
+  fflush (stdout)
+  FILE *fp;
+  char *line = NULL;
+  size_t len;
+  struct stat statbuf;
+  char buf[128];
+  ssize_t r;
+  unsigned u, u1;
+#if 0
+  int fd;
+  struct timeval tv[2];
+  struct timespec ts[2];
+#endif
+  acl_t acl;
+  char *acl_text;
+
+  STAGE ("checking initial files exist");
+
+  if (access ("empty", F_OK) == -1) {
+    perror ("access: empty");
+    return -1;
+  }
+  if (access ("hello.txt", F_OK) == -1) {
+    perror ("access: hello.txt");
+    return -1;
+  }
+  if (access ("world.txt", F_OK) == -1) {
+    perror ("access: world.txt");
+    return -1;
+  }
+
+  STAGE ("checking initial files contain expected content");
+
+  fp = fopen ("hello.txt", "r");
+  if (fp == NULL) {
+    perror ("open: hello.txt");
+    return -1;
+  }
+  if (getline (&line, &len, fp) == -1) {
+    perror ("getline: hello.txt");
+    return -1;
+  }
+  if (STRNEQ (line, "hello")) {
+    fprintf (stderr, "'hello.txt' does not contain expected content\n");
+    return -1;
+  }
+  fclose (fp);
+
+  fp = fopen ("world.txt", "r");
+  if (fp == NULL) {
+    perror ("open: world.txt");
+    return -1;
+  }
+  if (getline (&line, &len, fp) == -1) {
+    perror ("getline: world.txt");
+    return -1;
+  }
+  if (STRNEQ (line, "hello world")) {
+    fprintf (stderr, "'world.txt' does not contain expected content\n");
+    return -1;
+  }
+  fclose (fp);
+
+  STAGE ("checking file modes and sizes of initial content");
+
+  if (stat ("empty", &statbuf) == -1) {
+    perror ("stat: empty");
+    return -1;
+  }
+  if ((statbuf.st_mode & 0777) != 0644) {
+    fprintf (stderr, "'empty' has invalid mode (%o)\n", statbuf.st_mode);
+    return -1;
+  }
+  if (statbuf.st_size != 0) {
+    fprintf (stderr, "'empty' has invalid size (%d)\n", (int) statbuf.st_size);
+    return -1;
+  }
+
+  if (stat ("hello.txt", &statbuf) == -1) {
+    perror ("stat: hello.txt");
+    return -1;
+  }
+  if ((statbuf.st_mode & 0777) != 0644) {
+    fprintf (stderr, "'hello.txt' has invalid mode (%o)\n", statbuf.st_mode);
+    return -1;
+  }
+  if (statbuf.st_size != 5) {
+    fprintf (stderr, "'hello.txt' has invalid size (%d)\n",
+             (int) statbuf.st_size);
+    return -1;
+  }
+
+  if (stat ("world.txt", &statbuf) == -1) {
+    perror ("stat: world.txt");
+    return -1;
+  }
+  if ((statbuf.st_mode & 0777) != 0644) {
+    fprintf (stderr, "'world.txt' has invalid mode (%o)\n", statbuf.st_mode);
+    return -1;
+  }
+  if (statbuf.st_size != 11) {
+    fprintf (stderr, "'world.txt' has invalid size (%d)\n",
+             (int) statbuf.st_size);
+    return -1;
+  }
+
+  STAGE ("checking unlink");
+
+  fp = fopen ("new", "w");
+  if (fp == NULL) {
+    perror ("open: new");
+    return -1;
+  }
+  fclose (fp);
+
+  if (unlink ("new") == -1) {
+    perror ("unlink: new");
+    return -1;
+  }
+
+  STAGE ("checking symbolic link");
+
+  if (symlink ("hello.txt", "symlink") == -1) {
+    perror ("symlink: hello.txt, symlink");
+    return -1;
+  }
+  if (lstat ("symlink", &statbuf) == -1) {
+    perror ("lstat: symlink");
+    return -1;
+  }
+  if (!S_ISLNK (statbuf.st_mode)) {
+    fprintf (stderr, "'symlink' is not a symlink (mode = %o)\n",
+             statbuf.st_mode);
+    return -1;
+  }
+
+  STAGE ("checking readlink");
+
+  r = readlink ("symlink", buf, sizeof buf);
+  if (r == -1) {
+    perror ("readlink: symlink");
+    return -1;
+  }
+  /* readlink return buffer is not \0-terminated, hence: */
+  if (r != 9 || memcmp (buf, "hello.txt", r) != 0) {
+    fprintf (stderr, "readlink on 'symlink' returned incorrect result\n");
+    return -1;
+  }
+
+  STAGE ("checking hard link");
+
+  if (stat ("hello.txt", &statbuf) == -1) {
+    perror ("stat: hello.txt");
+    return -1;
+  }
+  if (statbuf.st_nlink != 1) {
+    fprintf (stderr, "nlink of 'hello.txt' was %d (expected 1)\n",
+             (int) statbuf.st_nlink);
+    return -1;
+  }
+
+  if (link ("hello.txt", "link") == -1) {
+    perror ("link: hello.txt, link");
+    return -1;
+  }
+
+  if (stat ("link", &statbuf) == -1) {
+    perror ("stat: link");
+    return -1;
+  }
+  if (statbuf.st_nlink != 2) {
+    fprintf (stderr, "nlink of 'link' was %d (expected 2)\n",
+             (int) statbuf.st_nlink);
+    return -1;
+  }
+
+  if (stat ("hello.txt", &statbuf) == -1) {
+    perror ("stat: hello.txt");
+    return -1;
+  }
+  if (statbuf.st_nlink != 2) {
+    fprintf (stderr, "nlink of 'hello.txt' was %d (expected 2)\n",
+             (int) statbuf.st_nlink);
+    return -1;
+  }
+
+  if (unlink ("link") == -1) {
+    perror ("unlink: link");
+    return -1;
+  }
+
+#if 0
+  /* This fails because of caching.  The problem is that the linked file
+   * ("hello.txt") is cached with a link count of 2.  unlink("link")
+   * invalidates the cache for "link", but _not_ for "hello.txt" which
+   * still has the now-incorrect cached value.  However there's not much
+   * we can do about this since searching for all linked inodes of a file
+   * is an O(n) operation.
+   */
+  if (stat ("hello.txt", &statbuf) == -1) {
+    perror ("stat: hello.txt");
+    return -1;
+  }
+  if (statbuf.st_nlink != 1) {
+    fprintf (stderr, "nlink of 'hello.txt' was %d (expected 1)\n",
+             (int) statbuf.st_nlink);
+    return -1;
+  }
+#endif
+
+  STAGE ("checking mkdir");
+
+  if (mkdir ("newdir", 0755) == -1) {
+    perror ("mkdir: newdir");
+    return -1;
+  }
+
+  STAGE ("checking rmdir");
+
+  if (rmdir ("newdir") == -1) {
+    perror ("rmdir: newdir");
+    return -1;
+  }
+
+  STAGE ("checking rename");
+
+  fp = fopen ("old", "w");
+  if (fp == NULL) {
+    perror ("open: old");
+    return -1;
+  }
+  fclose (fp);
+  if (rename ("old", "new") == -1) {
+    perror ("rename: old, new");
+    return -1;
+  }
+  if (access ("new", F_OK) == -1) {
+    perror ("access: new");
+    return -1;
+  }
+  if (access ("old", F_OK) == 0) {
+    fprintf (stderr, "file 'old' exists after rename\n");
+    return -1;
+  }
+  if (unlink ("new") == -1) {
+    perror ("unlink: new");
+    return -1;
+  }
+
+  STAGE ("checking chmod");
+
+  fp = fopen ("new", "w");
+  if (fp == NULL) {
+    perror ("open: new");
+    return -1;
+  }
+  fclose (fp);
+  for (u = 0; u < 0777; u += 0111) {
+    if (chmod ("new", u) == -1) {
+      perror ("chmod: new");
+      return -1;
+    }
+    if (stat ("new", &statbuf) == -1) {
+      perror ("stat: new");
+      return -1;
+    }
+    if ((statbuf.st_mode & 0777) != u) {
+      fprintf (stderr, "unexpected mode: was %o expected %o\n",
+               statbuf.st_mode, u);
+      return -1;
+    }
+  }
+  if (unlink ("new") == -1) {
+    perror ("unlink: new");
+    return -1;
+  }
+
+  STAGE ("checking truncate");
+
+  fp = fopen ("truncated", "w");
+  if (fp == NULL) {
+    perror ("open: truncated");
+    return -1;
+  }
+  fclose (fp);
+  for (u = 10000; u <= 10000; u -= 1000) {
+    if (truncate ("truncated", u) == -1) {
+      perror ("truncate");
+      return -1;
+    }
+    if (stat ("truncated", &statbuf) == -1) {
+      perror ("stat: truncated");
+      return -1;
+    }
+    if (statbuf.st_size != u) {
+      fprintf (stderr, "unexpected size: was %u expected %u\n",
+               (unsigned) statbuf.st_size, u);
+      return -1;
+    }
+  }
+  if (unlink ("truncated") == -1) {
+    perror ("unlink: truncated");
+    return -1;
+  }
+
+#if 0
+  STAGE ("checking utimes");
+
+  fd = open ("timestamp", O_WRONLY|O_CREAT|O_TRUNC|O_NOCTTY|O_CLOEXEC, 0644);
+  if (fd == -1) {
+    perror ("open: timestamp");
+    return -1;
+  }
+  close (fd);
+  tv[0].tv_sec = 23;            /* atime */
+  tv[0].tv_usec = 45;
+  tv[1].tv_sec = 67;            /* mtime */
+  tv[1].tv_usec = 89;
+  if (utimes ("timestamp", tv) == -1) {
+    perror ("utimes: timestamp");
+    return -1;
+  }
+  if (stat ("timestamp", &statbuf) == -1) {
+    perror ("fstat: timestamp");
+    return -1;
+  }
+  if (statbuf.st_atime != 23 ||
+      statbuf.st_atim.tv_nsec != 45000 ||
+      statbuf.st_mtime != 67 ||
+      statbuf.st_mtim.tv_nsec != 89000) {
+    fprintf (stderr, "utimes did not set time (%d/%d/%d/%d)\n",
+             (int) statbuf.st_atime, (int) statbuf.st_atim.tv_nsec,
+             (int) statbuf.st_mtime, (int) statbuf.st_mtim.tv_nsec);
+    return -1;
+  }
+#endif
+
+#if 0
+  /* Does not work! See https://bugzilla.redhat.com/show_bug.cgi?id=1144766 */
+  STAGE ("checking utimens");
+
+  fd = open ("timestamp", O_WRONLY|O_CREAT|O_TRUNC|O_NOCTTY|O_CLOEXEC, 0644);
+  if (fd == -1) {
+    perror ("open: timestamp");
+    return -1;
+  }
+  ts[0].tv_sec = 12;            /* atime */
+  ts[0].tv_nsec = 34;
+  ts[1].tv_sec = 56;            /* mtime */
+  ts[1].tv_nsec = 78;
+  if (futimens (fd, ts) == -1) {
+    perror ("futimens: timestamp");
+    return -1;
+  }
+  if (fstat (fd, &statbuf) == -1) {
+    perror ("fstat: timestamp");
+    return -1;
+  }
+  if (statbuf.st_atime != 12 ||
+      statbuf.st_atim.tv_nsec != 34 ||
+      statbuf.st_mtime != 56 ||
+      statbuf.st_mtim.tv_nsec != 78) {
+    fprintf (stderr, "utimens did not set time (%d/%d/%d/%d)\n",
+             (int) statbuf.st_atime, (int) statbuf.st_atim.tv_nsec,
+             (int) statbuf.st_mtime, (int) statbuf.st_mtim.tv_nsec);
+    return -1;
+  }
+  close (fd);
+#endif
+
+  STAGE ("checking writes");
+
+  fp = fopen ("new.txt", "w");
+  if (fp == NULL) {
+    perror ("open: new.txt");
+    return -1;
+  }
+  for (u = 0; u < 1000; ++u) {
+    if (fprintf (fp, "line %u\n", u) == -1) {
+      perror ("fprintf: new.txt");
+      return -1;
+    }
+  }
+  if (fclose (fp) == -1) {
+    perror ("fclose: new.txt");
+    return -1;
+  }
+
+  fp = fopen ("new.txt", "r");
+  if (fp == NULL) {
+    perror ("open: new.txt");
+    return -1;
+  }
+  for (u = 0; u < 1000; ++u) {
+    if (getline (&line, &len, fp) == -1) {
+      perror ("getline: new.txt");
+      return -1;
+    }
+    if (sscanf (line, "line %u", &u1) != 1 || u != u1) {
+      fprintf (stderr, "unexpected content: %s\n", line);
+      return -1;
+    }
+  }
+  fclose (fp);
+
+#ifdef HAVE_ACL
+  if (acl_available) {
+    STAGE ("checking POSIX ACL read operation");
+
+    acl = acl_get_file ("acl", ACL_TYPE_ACCESS);
+    if (acl == (acl_t) NULL) {
+      perror ("acl_get_file: acl");
+      return -1;
+    }
+    acl_text = acl_to_text (acl, NULL);
+    if (acl_text == NULL) {
+      perror ("acl_to_text: acl");
+      return -1;
+    }
+    if (STRNEQ (acl_text, "user::rwx\nuser:500:r--\ngroup::rwx\nmask::rwx\nother::r-x\n")) {
+      fprintf (stderr, "unexpected acl: %s\n", acl_text);
+      return -1;
+    }
+    acl_free (acl);
+  }
+#endif
+
+#if HAVE_GETXATTR
+  if (linuxxattrs_available) {
+    STAGE ("checking extended attribute (xattr) read operation");
+
+    r = getxattr ("user_xattr", "user.test", buf, sizeof buf);
+    if (r == -1) {
+      perror ("getxattr");
+      return -1;
+    }
+    if (r != 8 || memcmp (buf, "hello123", r) != 0) {
+      fprintf (stderr, "user.test xattr on file user_xattr was incorrect\n");
+      return -1;
+    }
+  }
+#endif
+
+  /* XXX:
+     These ones are not yet tested by the current program:
+     - statfs/statvfs
+
+     These ones cannot easily be tested by the current program, because
+     this program doesn't run as root:
+     - fsync
+     - chown
+     - mknod
+  */
+
+  free (line);
+  return 0;
+}
diff --git a/fuse/test-fuse.sh b/fuse/test-fuse.sh
deleted file mode 100755
index 13d1bd3..0000000
--- a/fuse/test-fuse.sh
+++ /dev/null
@@ -1,264 +0,0 @@
-#!/bin/bash -
-# libguestfs
-# Copyright (C) 2009-2014 Red Hat Inc.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-
-unset CDPATH
-set -e
-#set -v
-
-if [ -n "$SKIP_TEST_FUSE_SH" ]; then
-    echo "$0: test skipped because environment variable is set."
-    exit 77
-fi
-
-if [ ! -w /dev/fuse ]; then
-    echo "SKIPPING guestmount test, because there is no /dev/fuse."
-    exit 77
-fi
-
-if ! setfacl --help >/dev/null 2>&1; then
-    echo "SKIPPING guestmount test, because setfacl is not installed."
-    exit 77
-fi
-
-if [ -z "$top_builddir" ]; then
-    echo "$0: error: environment variable \$top_builddir must be set"
-    exit 1
-fi
-
-nr_stages=$(grep "^stage " $0 | wc -l)
-
-# Allow top_builddir to be a relative path, but also make it absolute,
-# and move to that directory for the initial phase of the script.
-top_builddir=$(cd "$top_builddir" > /dev/null; pwd)
-
-# Paths to the other files.  NB: Must be absolute paths.
-image="$top_builddir/fuse/test-fuse.img"
-mp="$top_builddir/fuse/test-fuse-mp"
-
-if ! guestfish --help >/dev/null 2>&1 || ! guestmount --help >/dev/null 2>&1 || ! guestunmount --help >/dev/null 2>&1
-then
-    echo "$0: error: guestfish, guestmount or guestunmount are not available"
-    exit 1
-fi
-
-# Ensure the mountpoint directory exists and is not being used.
-rm -f "$image"
-mkdir -p "$mp"
-fusermount -u "$mp" >/dev/null 2>&1 ||:
-
-# Ensure everything is cleaned up on exit.
-mounted=
-
-function cleanup ()
-{
-    status=$?
-    set +e
-    [ $status = 0 ] || echo "*** FAILED ***"
-    echo "Unmounting filesystem and cleaning up."
-
-    # Move out of the mountpoint (otherwise our cwd will prevent the
-    # mountpoint from being unmounted).
-    cd "$top_builddir"
-
-    # Who's using this?  Should be no one, but see below.
-    if [ -x /sbin/fuser ]; then /sbin/fuser "$mp"; fi
-
-    if [ -n "$mounted" ]; then
-        guestunmount "$mp"
-    fi
-
-    rm -f "$image"
-    rm -rf "$mp"
-    exit $status
-}
-trap cleanup INT TERM QUIT EXIT
-
-s=1
-function stage ()
-{
-    echo "test-fuse: $s/$nr_stages:" "$@" "..."
-    ((s++))
-}
-
-stage Create filesystem with some initial content
-guestfish <<EOF
-  sparse "$image" 10M
-  run
-  part-disk /dev/sda mbr
-  mkfs ext2 /dev/sda1
-  mount_options acl,user_xattr /dev/sda1 /
-  write /hello.txt hello
-  write /world.txt "hello world"
-  touch /empty
-  touch /user_xattr
-  setxattr user.test hello123 8 /user_xattr
-  touch /acl
-  # XXX hack until libguestfs gets ACL support
-  debug sh "setfacl -m u:500:r /sysroot/acl" | cat > /dev/null
-EOF
-
-stage Mounting the filesystem
-guestmount \
-    -a "$image" -m /dev/sda1:/:acl,user_xattr \
-    -o uid="$(id -u)" -o gid="$(id -g)" "$mp"
-# To debug guestmount, add this to the end of the preceding command:
-# -v -x & sleep 60
-mounted=yes
-
-stage Changing into mounted directory
-cd "$mp"
-
-stage Checking initial files exist
-[ -n "$(echo *)" ]
-[ "$(ls empty hello.txt world.txt)" = "empty
-hello.txt
-world.txt" ]
-
-stage Checking initial files contain expected content
-[ "$(cat hello.txt)" = "hello" ]
-[ "$(cat world.txt)" = "hello world" ]
-cat empty ;# should print nothing
-[ -z "$(cat empty)" ]
-
-stage Checking file modes of initial content
-[ "$(stat -c %a empty)" = "644" ]
-[ "$(stat -c %a hello.txt)" = "644" ]
-[ "$(stat -c %a world.txt)" = "644" ]
-
-stage Checking sizes of initial content
-[ "$(stat -c %s empty)" -eq 0 ]
-[ "$(stat -c %s hello.txt)" -eq 5 ]
-[ "$(stat -c %s world.txt)" -eq 11 ]
-
-stage Checking unlink
-touch new
-rm -f new ;# force because file is "owned" by root
-
-stage Checking symbolic link
-ln -s hello.txt symlink
-[ -L symlink ]
-
-stage Checking readlink
-[ "$(readlink symlink)" = "hello.txt" ]
-
-stage Checking hard link
-[ "$(stat -c %h hello.txt)" -eq 1 ]
-ln hello.txt link
-[ "$(stat -c %h link)" -eq 2 ]
-[ "$(stat -c %h hello.txt)" -eq 2 ]
-rm -f link
-[ ! -e link ]
-
-# This fails because of caching.  The problem is that the linked file
-# ("hello.txt") is cached with a link count of 2.  unlink("link")
-# invalidates the cache for "link", but _not_ for "hello.txt" which
-# still has the now-incorrect cached value.  However there's not much
-# we can do about this since searching for all linked inodes of a file
-# is an O(n) operation.
-#[ "$(stat -c %h hello.txt)" -eq 1 ]
-
-stage Checking mkdir
-mkdir newdir
-[ -d newdir ]
-
-stage Checking rmdir
-rmdir newdir
-[ ! -e newdir ]
-
-stage Checking rename
-touch old
-mv old new
-[ -f new ]
-[ ! -e old ]
-rm -f new
-
-stage Checking chmod
-touch new
-chmod a+x new
-[ -x new ]
-chmod a-x new
-[ ! -x new ]
-chmod a-w new
-[ ! -w new ]
-chmod a+w new
-[ -w new ]
-chmod a-r new
-[ ! -r new ]
-chmod a+r new
-[ -r new ]
-rm -f new
-
-stage Checking truncate
-# RHEL 5 didn't have the truncate command.
-if truncate --help >/dev/null 2>&1; then
-    truncate -s 10000 truncated
-    [ "$(stat -c %s truncated)" -eq 10000 ]
-    truncate -c -s 1000 truncated
-    [ "$(stat -c %s truncated)" -eq 1000 ]
-    truncate -c -s 10 truncated
-    [ "$(stat -c %s truncated)" -eq 10 ]
-    truncate -c -s 0 truncated
-    [ "$(stat -c %s truncated)" -eq 0 ]
-    rm -f truncated
-fi
-
-stage Checking utimens and timestamps
-for ts in 12345 1234567 987654321; do
-    # NB: It's not possible to set the ctime with touch.
-    touch -a -d @$ts timestamp
-    [ "$(stat -c %X timestamp)" -eq $ts ]
-    touch -m -d @$ts timestamp
-    [ "$(stat -c %Y timestamp)" -eq $ts ]
-    touch    -d @$ts timestamp
-    [ "$(stat -c %X timestamp)" -eq $ts ]
-    [ "$(stat -c %Y timestamp)" -eq $ts ]
-done
-
-stage Checking writes
-cp hello.txt copy.txt
-echo >> copy.txt
-echo world >> copy.txt
-echo bigger >> copy.txt
-echo biggest >> copy.txt
-[ "$(cat copy.txt)" = "hello
-world
-bigger
-biggest" ]
-
-stage 'Checking extended attribute (xattr) read operation'
-if getfattr --help > /dev/null 2>&1 ; then
-  [ "$(getfattr -d user_xattr | grep -v ^#)" = 'user.test="hello123"' ]
-fi
-
-stage Checking POSIX ACL read operation
-if getfacl --help > /dev/null 2>&1 ; then
-  [ "$(getfacl -n acl | grep -v ^#)" = "user::rw-
-user:500:r--
-group::r--
-mask::r--
-other::r--" ]
-fi
-
-# These ones are not yet tested by the current script:
-#stage XXX statfs/statvfs
-
-# These ones cannot easily be tested by the current script, eg because
-# this script doesn't run as root:
-#stage XXX fsync
-#stage XXX chown
-#stage XXX mknod
diff --git a/po/POTFILES b/po/POTFILES
index 59233c9..add74b6 100644
--- a/po/POTFILES
+++ b/po/POTFILES
@@ -166,6 +166,7 @@ fish/windows.c
 format/format.c
 fuse/guestmount.c
 fuse/guestunmount.c
+fuse/test-fuse.c
 fuse/test-guestmount-fd.c
 fuse/test-guestunmount-fd.c
 gobject/src/optargs-add_domain.c

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-libvirt/libguestfs.git



More information about the Pkg-libvirt-commits mailing list