summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorShehjar Tikoo <shehjart@gluster.com>2009-09-15 01:03:56 +0000
committerAnand V. Avati <avati@dev.gluster.com>2009-09-15 00:01:50 -0700
commita5f0b3d7d1b23053ce9327be91323e92ce554b32 (patch)
treed9aee1e46b23b3b40c26c8da1501fe2d3ac9e5cf
parentad33df39dec4850c249c453822a99b3038b41389 (diff)
extras: Add LD_PRELOAD test tool
This tool allows us to check the sanity of the LD_PRELOAD mechanism so that we can be sure that an application's syscalls will be redirected into booster when that library is LD_PRELOADed. In case of failed syscalls, this tool should be run first to see if the calls are redirected as required. Signed-off-by: Anand V. Avati <avati@dev.gluster.com> BUG: 251 (Improve booster debugging through ld-preload testing tool) URL: http://bugs.gluster.com/cgi-bin/bugzilla3/show_bug.cgi?id=251
-rw-r--r--extras/test/ld-preload-test/Makefile28
-rw-r--r--extras/test/ld-preload-test/README40
-rw-r--r--extras/test/ld-preload-test/ld-preload-lib.c637
-rw-r--r--extras/test/ld-preload-test/ld-preload-test.c377
-rwxr-xr-xextras/test/ld-preload-test/test-preload.sh7
5 files changed, 1089 insertions, 0 deletions
diff --git a/extras/test/ld-preload-test/Makefile b/extras/test/ld-preload-test/Makefile
new file mode 100644
index 00000000000..97aa016518d
--- /dev/null
+++ b/extras/test/ld-preload-test/Makefile
@@ -0,0 +1,28 @@
+TOOL_CFLAGS32=-g -O0 -Wall
+TOOL_CFLAGS64=-g -O0 -D_GNU_SOURCE -Wall -D_FILE_OFFSET_BITS=64
+LIB_CFLAGS=-g -O0 -fPIC -Wall -shared -ldl
+%LIB_CFLAGS=-g -O0 -D_GNU_SOURCE -fPIC -Wall -shared -D_FILE_OFFSET_BITS=64 -ldl
+
+all: ld-preload-test32 ld-preload-test64 ld-preload-lib
+
+
+copy32:
+ cp ld-preload-test.c test32.c
+
+ld-preload-test32: copy32
+ gcc ${TOOL_CFLAGS32} test32.c -o ld-preload-test32
+ rm -f test32.c
+
+copy64:
+ cp ld-preload-test.c test64.c
+
+ld-preload-test64: copy64
+ gcc ${TOOL_CFLAGS64} test64.c -o ld-preload-test64
+ rm -f test64.c
+
+ld-preload-lib: ld-preload-lib.c
+ gcc ${LIB_CFLAGS} ld-preload-lib.c -o ld-preload-lib.so
+
+clean:
+ rm -f ld-preload-test32 ld-preload-test64 ld-preload-lib.so
+
diff --git a/extras/test/ld-preload-test/README b/extras/test/ld-preload-test/README
new file mode 100644
index 00000000000..725b94023c8
--- /dev/null
+++ b/extras/test/ld-preload-test/README
@@ -0,0 +1,40 @@
+ld-preload-test
+===============
+1. The idea of this test tool is to check the sanity of the LD_PRELOAD
+mechanism in libc for the system on which booster needs to run.
+
+2. Basically, this test tool calls various system calls for which there is
+support in the booster library. Combined with the logging output from this
+tool and the preload-test-lib, one can determine whether the
+pre-loading mechanism is working working in order for booster to initialize.
+
+3. This tool does not test GlusterFS functionality running under booster
+although the path specified to the tool can be a GlusterFS mountpoint but
+that is not very useful.
+
+4. This tool is incomplete without the preload-test-lib and the
+accompanyung shell script that needs to be run for running the test.
+
+ld-preload-lib.so
+=================
+A very simple library that intercepts booster supported system calls
+and prints a log message to stdout.
+Combined with the ld-preload-test, we cam determine whether all system calls
+are getting redirected into this library when LD_PRELOAD'ed. This helps us
+conduct a basic test to ensure that the required syscalls actually will
+be intercepted by the booster library.
+
+
+Instructions
+============
+
+1. Build the binaries.
+ $ make
+
+(We've tested the tool on Debian and CentOS. If there are build errors or
+warnings, please do report them to glusterfs-devel@nongnu.org.)
+
+2. Run the test.
+ $ ./test-preload.sh > preload.log
+
+3. Mail the log to glusterfs-devel@nongnu.org.
diff --git a/extras/test/ld-preload-test/ld-preload-lib.c b/extras/test/ld-preload-test/ld-preload-lib.c
new file mode 100644
index 00000000000..8a7504e9c09
--- /dev/null
+++ b/extras/test/ld-preload-test/ld-preload-lib.c
@@ -0,0 +1,637 @@
+/*
+ Copyright (c) 2007-2009 Z RESEARCH, Inc. <http://www.zresearch.com>
+ This file is part of GlusterFS.
+
+ GlusterFS 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 3 of the License,
+ or (at your option) any later version.
+
+ GlusterFS 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, see
+ <http://www.gnu.org/licenses/>.
+*/
+
+
+/* LD PRELOAD'able library
+ * A very simple library that intercepts booster supported system calls
+ * and prints a log message to stdout.
+ *
+ * Combined with the ld-preload-test, we cam determine whether all system calls
+ * are getting redirected into this library when LD_PRELOAD'ed. This helps us
+ * conduct a basic test to ensure that the required syscalls actually will
+ * be intercepted by the booster library.
+ */
+
+#include <dlfcn.h>
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <inttypes.h>
+#include <string.h>
+#include <assert.h>
+#include <errno.h>
+#include <utime.h>
+#include <sys/statfs.h>
+#include <sys/statvfs.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <attr/xattr.h>
+#include <sys/sendfile.h>
+
+/* Err number that is assigned to errno so that test application can
+ * verify that the function was intercepted correctly.
+ */
+#define PRELOAD_ERRNO_VERF 6449
+#define set_errno() (errno = PRELOAD_ERRNO_VERF)
+
+inline void
+intercept (char *call, int tabs)
+{
+ while (tabs > 0) {
+ fprintf (stdout, "\t");
+ --tabs;
+ }
+
+ fprintf (stdout, "Intercepted by %s", call);
+}
+
+int
+creat64 (const char *pathname, mode_t mode)
+{
+ intercept ("creat64", 2);
+ set_errno ();
+ return -1;
+}
+
+int
+creat (const char *pathname, mode_t mode)
+{
+ intercept ("creat", 2);
+ set_errno ();
+ return -1;
+}
+
+
+int
+close (int fd)
+{
+ intercept ("close", 2);
+ set_errno ();
+ return -1;
+}
+
+int
+open64 (const char *pathname, int flags, ...)
+{
+ intercept ("open64", 2);
+ set_errno ();
+ return -1;
+}
+
+
+int
+open (const char *pathname, int flags, ...)
+{
+ intercept ("open", 2);
+ set_errno ();
+ return -1;
+}
+
+ssize_t
+read (int fd, void *buf, size_t count)
+{
+ intercept ("read", 2);
+ set_errno ();
+ return -1;
+}
+
+ssize_t
+readv (int fd, const struct iovec *vector, int count)
+{
+ intercept ("readv", 2);
+ set_errno ();
+ return -1;
+}
+
+ssize_t
+pread (int fd, void *buf, size_t count, unsigned long offset)
+{
+ intercept ("pread", 2);
+ set_errno ();
+ return -1;
+}
+
+
+ssize_t
+pread64 (int fd, void *buf, size_t count, uint64_t offset)
+{
+ intercept ("pread64", 2);
+ set_errno ();
+ return -1;
+}
+
+ssize_t
+write (int fd, const void *buf, size_t count)
+{
+ intercept ("write", 2);
+ set_errno ();
+ return -1;
+}
+
+ssize_t
+writev (int fd, const struct iovec *vector, int count)
+{
+ intercept ("writev", 2);
+ set_errno ();
+ return -1;
+}
+
+ssize_t
+pwrite (int fd, const void *buf, size_t count, unsigned long offset)
+{
+ intercept ("pwrite", 2);
+ set_errno ();
+ return -1;
+}
+
+ssize_t
+pwrite64 (int fd, const void *buf, size_t count, uint64_t offset)
+{
+ intercept ("pwrite64", 2);
+ set_errno ();
+ return -1;
+}
+
+
+off_t
+lseek (int fildes, unsigned long offset, int whence)
+{
+ intercept ("lseek", 2);
+ set_errno ();
+ return -1;
+}
+
+off_t
+lseek64 (int fildes, uint64_t offset, int whence)
+{
+ intercept ("lseek64", 2);
+ set_errno ();
+ return -1;
+}
+
+
+int
+dup (int fd)
+{
+ intercept ("dup", 2);
+ set_errno ();
+ return -1;
+}
+
+int
+dup2 (int oldfd, int newfd)
+{
+ intercept ("dup2", 2);
+ set_errno ();
+ return -1;
+}
+
+int
+mkdir (const char *pathname, mode_t mode)
+{
+ intercept ("mkdir", 2);
+ set_errno ();
+ return -1;
+}
+
+int
+rmdir (const char *pathname)
+{
+ intercept ("rmdir", 2);
+ set_errno ();
+ return -1;
+}
+
+int
+chmod (const char *pathname, mode_t mode)
+{
+ intercept ("chmod", 2);
+ set_errno ();
+ return -1;
+}
+
+int
+chown (const char *pathname, uid_t owner, gid_t group)
+{
+ intercept ("chown", 2);
+ set_errno ();
+ return -1;
+}
+
+int
+fchmod (int fd, mode_t mode)
+{
+ intercept ("fchmod", 2);
+ set_errno ();
+ return -1;
+}
+
+int
+fchown (int fd, uid_t uid, gid_t gid)
+{
+ intercept ("fchown", 2);
+ set_errno ();
+ return -1;
+}
+
+int fsync (int fd)
+{
+ intercept ("fsync", 2);
+ set_errno ();
+ return -1;
+}
+
+
+int
+ftruncate (int fd, off_t length)
+{
+ intercept ("ftruncate", 1);
+ set_errno ();
+ return -1;
+}
+
+
+int
+ftruncate64 (int fd, off_t length)
+{
+ intercept ("ftruncate64", 1);
+ set_errno ();
+ return -1;
+}
+
+int
+link (const char *oldpath, const char *newname)
+{
+ intercept ("link", 2);
+ set_errno ();
+ return -1;
+}
+
+int
+rename (const char *oldpath, const char *newpath)
+{
+ intercept ("rename", 2);
+ set_errno ();
+ return -1;
+}
+
+int
+utimes (const char *path, const struct timeval times[2])
+{
+ intercept ("utimes", 2);
+ set_errno ();
+ return -1;
+}
+
+int
+utime (const char *path, const struct utimbuf *buf)
+{
+ intercept ("utime", 2);
+ set_errno ();
+ return -1;
+}
+
+
+int
+mknod (const char *path, mode_t mode, dev_t dev)
+{
+ intercept ("mknod", 2);
+ set_errno ();
+ return -1;
+}
+
+int
+__xmknod (int ver, const char *path, mode_t mode, dev_t *dev)
+{
+ intercept ("__xmknod", 2);
+ set_errno ();
+ return -1;
+}
+
+int
+mkfifo (const char *path, mode_t mode)
+{
+ intercept ("mkfifo", 2);
+ set_errno ();
+ return -1;
+}
+
+int
+unlink (const char *path)
+{
+ intercept ("unlink", 2);
+ set_errno ();
+ return -1;
+}
+
+
+int
+symlink (const char *oldpath, const char *newpath)
+{
+ intercept ("symlink", 2);
+ set_errno ();
+ return -1;
+}
+
+int
+readlink (const char *path, char *buf, size_t bufsize)
+{
+ intercept ("readlink", 1);
+ set_errno ();
+ return -1;
+}
+
+
+char *
+realpath (const char *path, char *resolved)
+{
+ intercept ("realpath", 1);
+ set_errno ();
+ return NULL;
+}
+
+
+DIR *
+opendir (const char *path)
+{
+ intercept ("opendir", 2);
+ set_errno ();
+ return NULL;
+}
+
+
+struct dirent *
+readdir (DIR *dir)
+{
+ intercept ("readdir\t", 2);
+ set_errno ();
+ return NULL;
+}
+
+struct dirent *
+readdir64 (DIR *dir)
+{
+ intercept ("readdir64", 2);
+ set_errno ();
+ return NULL;
+}
+
+
+int
+readdir_r (DIR *dir, struct dirent *entry, struct dirent **result)
+{
+ intercept ("readdir_r", 1);
+ set_errno ();
+ return -1;
+}
+
+int
+readdir64_r (DIR *dir, struct dirent *entry, struct dirent **result)
+{
+ intercept ("readdir64_r", 1);
+ set_errno ();
+ return -1;
+}
+
+
+int
+closedir (DIR *dh)
+{
+ intercept ("closedir", 1);
+ set_errno ();
+ return -1;
+}
+
+int
+__xstat (int ver, const char *path, struct stat *buf)
+{
+ intercept ("__xstat\t", 2);
+ set_errno ();
+ return -1;
+}
+
+
+int
+__xstat64 (int ver, const char *path, struct stat *buf)
+{
+ intercept ("__xstat64", 2);
+ set_errno ();
+ return -1;
+}
+
+int
+stat (const char *path, struct stat *buf)
+{
+ intercept ("stat", 2);
+ set_errno ();
+ return -1;
+}
+
+int
+stat64 (const char *path, struct stat *buf)
+{
+ intercept ("stat64", 2);
+ set_errno ();
+ return -1;
+}
+
+int
+__fxstat (int ver, int fd, struct stat *buf)
+{
+ intercept ("__fxstat\t", 2);
+ set_errno ();
+ return -1;
+}
+
+
+int
+__fxstat64 (int ver, int fd, struct stat *buf)
+{
+ intercept ("__fxstat64", 2);
+ set_errno ();
+ return -1;
+}
+
+int
+fstat (int fd, struct stat *buf)
+{
+ intercept ("fstat", 2);
+ set_errno ();
+ return -1;
+}
+
+int
+fstat64 (int fd , struct stat *buf)
+{
+ intercept ("fstat64", 2);
+ set_errno ();
+ return -1;
+}
+
+int
+__lxstat (int ver, const char *path, struct stat *buf)
+{
+ intercept ("__lxstat\t", 2);
+ set_errno ();
+ return -1;
+}
+
+int
+__lxstat64 (int ver, const char *path, struct stat *buf)
+{
+ intercept ("__lxstat64", 2);
+ set_errno ();
+ return -1;
+}
+
+int
+lstat (const char *path, struct stat *buf)
+{
+ intercept ("lstat", 2);
+ set_errno ();
+ return -1;
+}
+
+int
+lstat64 (const char *path, struct stat *buf)
+{
+ intercept ("lstat64", 2);
+ set_errno ();
+ return -1;
+}
+
+int
+statfs (const char *path, struct statfs *buf)
+{
+ intercept ("statfs", 2);
+ set_errno ();
+ return -1;
+}
+
+
+int
+statfs64 (const char *path, struct statfs *buf)
+{
+ intercept ("statfs64", 2);
+ set_errno ();
+ return -1;
+}
+
+int
+statvfs (const char *path, struct statvfs *buf)
+{
+ intercept ("statvfs\t", 2);
+ set_errno ();
+ return -1;
+}
+
+
+int
+statvfs64 (const char *path, struct statvfs *buf)
+{
+ intercept ("statvfs64", 2);
+ set_errno ();
+ return -1;
+}
+
+ssize_t
+getxattr (const char *path, const char *name, void *value, size_t size)
+{
+ intercept ("getxattr", 1);
+ set_errno ();
+ return -1;
+}
+
+ssize_t
+lgetxattr (const char *path, const char *name, void *value, size_t size)
+{
+ intercept ("lgetxattr", 1);
+ set_errno ();
+ return -1;
+}
+
+
+int
+remove (const char* path)
+{
+ intercept ("remove", 2);
+ set_errno ();
+ return -1;
+}
+
+int
+lchown (const char *path, uid_t owner, gid_t group)
+{
+ intercept ("lchown", 2);
+ set_errno ();
+ return -1;
+}
+
+void
+rewinddir (DIR *dirp)
+{
+ intercept ("rewinddir", 1);
+ set_errno ();
+ return;
+}
+
+void
+seekdir (DIR *dirp, off_t offset)
+{
+ intercept ("seekdir", 2);
+ set_errno ();
+ return;
+}
+
+off_t
+telldir (DIR *dirp)
+{
+ intercept ("telldir", 2);
+ set_errno ();
+ return -1;
+}
+
+ssize_t
+sendfile (int out_fd, int in_fd, off_t *offset, size_t count)
+{
+ intercept ("sendfile\t", 1);
+ set_errno ();
+ return -1;
+}
+
+ssize_t
+sendfile64 (int out_fd, int in_fd, off_t *offset, size_t count)
+{
+ intercept ("sendfile64", 1);
+ set_errno ();
+ return -1;
+}
+
+
+int
+fcntl (int fd, int cmd, ...)
+{
+ intercept ("fcntl", 2);
+ set_errno ();
+ return -1;
+}
+
diff --git a/extras/test/ld-preload-test/ld-preload-test.c b/extras/test/ld-preload-test/ld-preload-test.c
new file mode 100644
index 00000000000..d4e9c675cc4
--- /dev/null
+++ b/extras/test/ld-preload-test/ld-preload-test.c
@@ -0,0 +1,377 @@
+/*
+ Copyright (c) 2007-2009 Z RESEARCH, Inc. <http://www.zresearch.com>
+ This file is part of GlusterFS.
+
+ GlusterFS 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 3 of the License,
+ or (at your option) any later version.
+
+ GlusterFS 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, see
+ <http://www.gnu.org/licenses/>.
+*/
+
+
+/*
+ * LD PRELOAD Test Tool
+ *
+ * 1. The idea of this test tool is to check the sanity of the LD_PRELOAD
+ * mechanism in libc for the system on which booster needs to run.
+ *
+ * 2. Basically, this test tool calls various system calls for which there is
+ * support in the booster library. Combined with the logging output from this
+ * tool and the preload-test-lib, one can determine whether the
+ * pre-loading mechanism is working working in order for booster to initialize.
+ *
+ * 3. This tool does not test GlusterFS functionality running under booster
+ * although the path specified to the tool can be a GlusterFS mountpoint but
+ * that is not very useful.
+ *
+ * 4. This tool is incomplete without the preload-test-lib and the
+ * accompanyung shell script that needs to be run for running the test.
+ */
+#define _XOPEN_SOURCE 500
+
+#include <dlfcn.h>
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <inttypes.h>
+#include <string.h>
+#include <assert.h>
+#include <errno.h>
+#include <dirent.h>
+#include <sys/statfs.h>
+#include <sys/statvfs.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/uio.h>
+#include <utime.h>
+#include <sys/time.h>
+#include <attr/xattr.h>
+#include <sys/sendfile.h>
+
+
+#define PRELOAD_ERRNO_VERF 6449
+inline void
+check_err(int ret, char *call, int tabs)
+{
+ while (tabs > 0) {
+ fprintf (stdout, "\t");
+ --tabs;
+ }
+ if (ret != -1) {
+ fprintf (stdout, "Not intercepted: %s\n", call);
+ return;
+ }
+
+ if (errno != PRELOAD_ERRNO_VERF) {
+ fprintf (stdout, "Not intercepted: %s: err: %s\n", call,
+ strerror (errno));
+ return;
+ }
+
+ fprintf (stdout, "Intercept verified: %s\n", call);
+ return;
+}
+
+void
+usage (FILE *fp)
+{
+ fprintf (fp, "Usage: ld-preload-test <Options>\n");
+ fprintf (fp, "Options\n");
+ fprintf (fp, "\t--path\t\tPathname is used as the file/directory"
+ " created for the test.\n");
+
+}
+
+
+int
+run_file_tests (char *testfile)
+{
+ int ret = -1;
+ struct stat buf;
+
+ assert (testfile);
+ fprintf (stdout, "Testing creat");
+ ret = creat (testfile, S_IRWXU);
+ check_err (ret, "creat", 2);
+
+ fprintf (stdout, "Testing close");
+ ret = close (ret);
+ check_err (ret, "close", 2);
+
+ fprintf (stdout, "Testing open");
+ ret = open (testfile, O_RDONLY);
+ check_err (ret, "open", 2);
+
+ fprintf (stdout, "Testing read");
+ ret = read (0, NULL, 0);
+ check_err (ret, "read", 2);
+
+ fprintf (stdout, "Testing readv");
+ ret = readv (0, NULL, 0);
+ check_err (ret, "readv", 2);
+
+ fprintf (stdout, "Testing pread");
+ ret = pread (0, NULL, 0, 0);
+ check_err (ret, "pread", 2);
+
+ fprintf (stdout, "Testing write");
+ ret = write (0, NULL, 0);
+ check_err (ret, "write", 2);
+
+ fprintf (stdout, "Testing writev");
+ ret = writev (0, NULL, 0);
+ check_err (ret, "writev", 2);
+
+ fprintf (stdout, "Testing pwrite");
+ ret = pwrite (0, NULL, 0, 0);
+ check_err (ret, "pwrite", 2);
+
+ fprintf (stdout, "Testing lseek");
+ ret = lseek (0, 0, 0);
+ check_err (ret, "lseek", 2);
+
+ fprintf (stdout, "Testing dup");
+ ret = dup (0);
+ check_err (ret, "dup", 2);
+
+ fprintf (stdout, "Testing dup2");
+ ret = dup2 (0, 0);
+ check_err (ret, "dup2", 2);
+
+ fprintf (stdout, "Testing fchmod");
+ ret = fchmod (0, 0);
+ check_err (ret, "fchmod", 2);
+
+ fprintf (stdout, "Testing fchown");
+ ret = fchown (0, 0, 0);
+ check_err (ret, "fchown", 2);
+
+ fprintf (stdout, "Testing fsync");
+ ret = fsync (0);
+ check_err (ret, "fsync", 2);
+
+ fprintf (stdout, "Testing ftruncate");
+ ret = ftruncate (0, 0);
+ check_err (ret, "ftruncate", 1);
+
+ fprintf (stdout, "Testing fstat");
+ ret = fstat (0, &buf);
+ check_err (ret, "fstat", 1);
+
+ fprintf (stdout, "Testing sendfile");
+ ret = sendfile (0, 0, NULL, 0);
+ check_err (ret, "sendfile", 1);
+
+ fprintf (stdout, "Testing fcntl");
+ ret = fcntl (0, 0, NULL);
+ check_err (ret, "fcntl", 2);
+
+ fprintf (stdout, "Testing close");
+ ret = close (ret);
+ check_err (ret, "close", 2);
+
+ fprintf (stdout, "Testing remove");
+ ret = remove (testfile);
+ check_err (ret, "remove", 2);
+
+ return ret;
+}
+
+
+int
+run_attr_tests (char *testfile)
+{
+ int ret = -1;
+ char *res = NULL;
+ struct stat buf;
+ struct statfs sbuf;
+ struct statvfs svbuf;
+
+ assert (testfile);
+
+ fprintf (stdout, "Testing chmod");
+ ret = chmod (testfile, 0);
+ check_err (ret, "chmod", 2);
+
+ fprintf (stdout, "Testing chown");
+ ret = chown (testfile, 0, 0);
+ check_err (ret, "chown", 2);
+
+ fprintf (stdout, "Testing link");
+ ret = link (testfile, testfile);
+ check_err (ret, "link", 2);
+
+ fprintf (stdout, "Testing rename");
+ ret = rename (testfile, testfile);
+ check_err (ret, "rename", 2);
+
+ fprintf (stdout, "Testing utimes");
+ ret = utimes (testfile, NULL);
+ check_err (ret, "utimes", 2);
+
+ fprintf (stdout, "Testing utime");
+ ret = utime (testfile, NULL);
+ check_err (ret, "utime", 2);
+
+ fprintf (stdout, "Testing unlink");
+ ret = unlink (testfile);
+ check_err (ret, "unlink", 2);
+
+ fprintf (stdout, "Testing symlink");
+ ret = symlink (testfile, testfile);
+ check_err (ret, "symlink", 2);
+
+ fprintf (stdout, "Testing readlink");
+ ret = readlink (testfile, testfile, 0);
+ check_err (ret, "readlink", 2);
+
+ fprintf (stdout, "Testing realpath");
+ ret = 0;
+ res = realpath ((const char *)testfile, testfile);
+ if (!res)
+ ret = -1;
+ check_err (ret, "realpath", 2);
+
+ fprintf (stdout, "Testing stat");
+ ret = stat (testfile, &buf);
+ check_err (ret, "stat", 1);
+
+ fprintf (stdout, "Testing lstat");
+ ret = lstat (testfile, &buf);
+ check_err (ret, "lstat", 1);
+
+ fprintf (stdout, "Testing statfs");
+ ret = statfs (testfile, &sbuf);
+ check_err (ret, "statfs", 2);
+
+ fprintf (stdout, "Testing statvfs");
+ ret = statvfs (testfile, &svbuf);
+ check_err (ret, "statvfs", 1);
+
+ fprintf (stdout, "Testing getxattr");
+ ret = getxattr (testfile, NULL, NULL, 0);
+ check_err (ret, "getxattr", 2);
+
+ fprintf (stdout, "Testing lgetxattr");
+ ret = lgetxattr (testfile, NULL, NULL, 0);
+ check_err (ret, "lgetxattr", 1);
+
+ fprintf (stdout, "Testing lchown");
+ ret = lchown (testfile, 0, 0);
+ check_err (ret, "lchown", 2);
+ return 0;
+}
+
+
+int
+run_dev_tests (char *testfile)
+{
+ int ret = -1;
+
+ assert (testfile);
+
+ fprintf (stdout, "Testing mknod");
+ ret = mknod (testfile, 0, 0);
+ check_err (ret, "mknod", 2);
+
+ fprintf (stdout, "Testing mkfifo");
+ ret = mkfifo (testfile, 0);
+ check_err (ret, "mkfifo", 2);
+ return 0;
+}
+
+int
+run_dir_tests (char *testpath)
+{
+ int ret = -1;
+ DIR *dh = NULL;
+ struct dirent *dire = NULL;
+
+ assert (testpath);
+
+ fprintf (stdout, "Testing mkdir");
+ ret = mkdir (testpath, 0);
+ check_err (ret, "mkdir", 2);
+
+ fprintf (stdout, "Testing rmdir");
+ ret = rmdir (testpath);
+ check_err (ret, "rmdir", 2);
+
+ fprintf (stdout, "Testing opendir");
+ ret = 0;
+ dh = opendir (testpath);
+ if (!dh)
+ ret = -1;
+ check_err (ret, "opendir", 2);
+
+ fprintf (stdout, "Testing readdir");
+ ret = 0;
+ dire = readdir (dh);
+ if (!dire)
+ ret = -1;
+ check_err (ret, "readdir", 1);
+
+ fprintf (stdout, "Testing readdir_r");
+ ret = readdir_r (dh, dire, &dire);
+ check_err (ret, "readdir_r", 1);
+
+ fprintf (stdout, "Testing rewinddir");
+ rewinddir (dh);
+ check_err (-1, "rewinddir", 1);
+
+ fprintf (stdout, "Testing seekdir");
+ seekdir (dh, 0);
+ check_err (-1, "seekdir", 2);
+
+ fprintf (stdout, "Testing telldir");
+ ret = telldir (dh);
+ check_err (ret, "telldir", 2);
+
+ fprintf (stdout, "Testing closedir");
+ ret = closedir (dh);
+ check_err (ret, "closedir", 2);
+ return 0;
+}
+
+
+
+int
+main (int argc, char *argv[])
+{
+ char *testpath = NULL;
+ int x = 0;
+
+ for (;x < argc; ++x) {
+ if (strcmp (argv[x], "--path") == 0) {
+ testpath = argv[x+1];
+ continue;
+ }
+
+ }
+
+ if (!testpath) {
+ fprintf (stderr, "--path not specified\n");
+ usage (stderr);
+ return -1;
+ }
+
+ run_file_tests (testpath);
+ run_dir_tests (testpath);
+ run_attr_tests (testpath);
+ run_dev_tests (testpath);
+
+ return 0;
+}
+
+
diff --git a/extras/test/ld-preload-test/test-preload.sh b/extras/test/ld-preload-test/test-preload.sh
new file mode 100755
index 00000000000..faed5cee345
--- /dev/null
+++ b/extras/test/ld-preload-test/test-preload.sh
@@ -0,0 +1,7 @@
+#!/bin/sh
+
+echo "Testing 32-bit offsets build"
+LD_PRELOAD="$(pwd)/ld-preload-lib.so" $(pwd)/ld-preload-test32 --path /tmp/testfile
+echo
+echo "Testing 64-bit offsets build"
+LD_PRELOAD="$(pwd)/ld-preload-lib.so" $(pwd)/ld-preload-test64 --path /tmp/testfile