Add a simple LD_PRELOAD toy to make cat and cp nfs-aware
authorRonnie Sahlberg <ronniesahlberg@gmail.com>
Mon, 3 Feb 2014 02:03:50 +0000 (18:03 -0800)
committerRonnie Sahlberg <ronniesahlberg@gmail.com>
Mon, 3 Feb 2014 02:03:50 +0000 (18:03 -0800)
README
examples/ld_nfs.c [new file with mode: 0644]

diff --git a/README b/README
index f717c07deb7f1a21007d18037c95859e81feb88d..4e312da9e70a8b65bf78da6c03dc8d21ddb7acca 100644 (file)
--- a/README
+++ b/README
@@ -86,6 +86,25 @@ Android:
 AROS: - Build with 'make -f aros/Makefile.AROS'
 
 
+LD_PRELOAD
+==========
+examples/ld_nfs.c contains a LD_PRELOADable module that can be used to make
+several standard utilities nfs aware.
+It is still very incomplete but can be used for basic things such as cat and cp.
+Patches to add more coverage is welcome.
+
+Compile with :
+gcc -fPIC -shared -o ld_nfs.so examples/ld_nfs.c -ldl -lnfs
+
+Then try things like
+LD_NFS_DEBUG=9 LD_PRELOAD=./ld_nfs.so cat nfs://127.0.0.1/data/tmp/foo123
+
+LD_NFS_DEBUG=9 LD_PRELOAD=./ld_nfs.so cp nfs://127.0.0.1/data/tmp/foo123 nfs://127.0.0.1/data/tmp/foo123.copy
+
+This is just a toy preload module. Don't open bugs if it does not work. Send
+patches to make it better instead.
+
+
 RELEASE TARBALLS
 ================
 Release tarballs are available at https://sites.google.com/site/libnfstarballs/li
diff --git a/examples/ld_nfs.c b/examples/ld_nfs.c
new file mode 100644 (file)
index 0000000..0620bd6
--- /dev/null
@@ -0,0 +1,700 @@
+/*
+   Copyright (C) 2014 by Ronnie Sahlberg <ronniesahlberg@gmail.com>
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as published by
+   the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#define _GNU_SOURCE
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <stdio.h>
+#include <asm/fcntl.h>
+
+#include <nfsc/libnfs.h>
+
+#include <sys/syscall.h>
+#include <dlfcn.h>
+
+#define NFS_MAX_FD  255
+
+static int debug = 0;
+
+#ifndef discard_const
+#define discard_const(ptr) ((void *)((intptr_t)(ptr)))
+#endif
+
+#define LD_NFS_DPRINTF(level, fmt, args...) \
+       do { \
+               if ((debug) >= level) { \
+                       fprintf(stderr,"ld_nfs: "); \
+                       fprintf(stderr, (fmt), ##args); \
+                       fprintf(stderr,"\n"); \
+               } \
+       } while (0);
+
+struct nfs_fd_list {
+       int is_nfs;
+       struct nfs_context *nfs;
+       struct nfsfh *fh;
+
+       /* so we can reopen and emulate dup2() */
+       const char *path;
+       int flags;
+       mode_t mode;
+};
+
+static struct nfs_fd_list nfs_fd_list[NFS_MAX_FD];
+
+int (*real_open)(__const char *path, int flags, mode_t mode);
+
+int open(const char *path, int flags, mode_t mode)
+{
+       if (!strncmp(path, "nfs:", 4)) {
+               struct nfs_context *nfs;
+               struct nfs_url *url;
+               struct nfsfh *fh = NULL;
+               int ret, fd;
+
+               LD_NFS_DPRINTF(9, "open(%s, %x, %o)", path, flags, mode);
+               nfs = nfs_init_context();
+               if (nfs == NULL) {
+                       LD_NFS_DPRINTF(1, "Failed to create context");
+                       errno = ENOMEM;
+                       return -1;
+               }
+
+               url = nfs_parse_url_full(nfs, path);
+               if (url == NULL) {
+                       LD_NFS_DPRINTF(1, "Failed to parse URL: %s\n",
+                               nfs_get_error(nfs));
+                       nfs_destroy_context(nfs);
+                       errno = EINVAL;
+                       return -1;
+               }
+
+               if (nfs_mount(nfs, url->server, url->path) != 0) {
+                       LD_NFS_DPRINTF(1, "Failed to mount nfs share : %s\n",
+                              nfs_get_error(nfs));
+                       nfs_destroy_url(url);
+                       nfs_destroy_context(nfs);
+                       errno = EINVAL;
+                       return -1;
+               }
+
+               if (flags & O_CREAT) {
+                       if ((ret = nfs_creat(nfs, url->file, mode, &fh)) != 0) {
+                               LD_NFS_DPRINTF(1, "Failed to creat nfs file : "
+                                       "%s\n", nfs_get_error(nfs));
+                               nfs_destroy_url(url);
+                               nfs_destroy_context(nfs);
+                               errno = -ret;
+                               return -1;
+                       }
+               } else {
+                       if ((ret = nfs_open(nfs, url->file, flags, &fh)) != 0) {
+                               LD_NFS_DPRINTF(1, "Failed to open nfs file : "
+                                       "%s\n", nfs_get_error(nfs));
+                               nfs_destroy_url(url);
+                               nfs_destroy_context(nfs);
+                               errno = -ret;
+                               return -1;
+                       }
+               }
+
+               fd = nfs_get_fd(nfs);
+               if (fd >= NFS_MAX_FD) {
+                       LD_NFS_DPRINTF(1, "Too many files open");
+                       nfs_destroy_url(url);
+                       nfs_destroy_context(nfs);
+                       errno = ENFILE;
+                       return -1;
+               }               
+
+               nfs_fd_list[fd].is_nfs     = 1;
+               nfs_fd_list[fd].nfs        = nfs;
+               nfs_fd_list[fd].fh         = fh;
+               nfs_fd_list[fd].path       = strdup(path);
+               nfs_fd_list[fd].flags      = flags;
+               nfs_fd_list[fd].mode       = mode;
+
+               nfs_destroy_url(url);
+
+               LD_NFS_DPRINTF(9, "open(%s) == %d", path, fd);
+               return fd;
+       }
+
+       return real_open(path, flags, mode);
+}
+
+int open64(const char *path, int flags, mode_t mode)
+{
+       return open(path, flags | O_LARGEFILE, mode);
+}
+
+int (*real_close)(int fd);
+
+int close(int fd)
+{
+       if (nfs_fd_list[fd].is_nfs == 1) {
+               int i;
+
+               LD_NFS_DPRINTF(9, "close(%d)", fd);
+
+               nfs_fd_list[fd].is_nfs = 0;
+
+               nfs_close(nfs_fd_list[fd].nfs, nfs_fd_list[fd].fh);
+               nfs_fd_list[fd].fh = NULL;
+
+               nfs_destroy_context(nfs_fd_list[fd].nfs);
+               nfs_fd_list[fd].nfs = NULL;
+
+               free(discard_const(nfs_fd_list[fd].path));
+               nfs_fd_list[fd].path = NULL;
+
+               return 0;
+       }
+
+        return real_close(fd);
+}
+
+ssize_t (*real_read)(int fd, void *buf, size_t count);
+
+ssize_t read(int fd, void *buf, size_t count)
+{
+       if (nfs_fd_list[fd].is_nfs == 1) {
+               int ret;
+
+               LD_NFS_DPRINTF(9, "read(fd:%d count:%d)", fd, (int)count);
+               if ((ret = nfs_read(nfs_fd_list[fd].nfs, nfs_fd_list[fd].fh,
+                               count, buf)) < 0) {
+                       errno = -ret;
+                       return -1;
+               }
+               return ret;
+       }
+       return real_read(fd, buf, count);
+}
+
+ssize_t (*real_pread)(int fd, void *buf, size_t count, off_t offset); 
+ssize_t pread(int fd, void *buf, size_t count, off_t offset) {
+       if (nfs_fd_list[fd].is_nfs == 1) {
+               int ret;
+
+               LD_NFS_DPRINTF(9, "pread(fd:%d offset:%d count:%d)", fd,
+                       (int)offset, (int)count);
+               if ((ret = nfs_pread(nfs_fd_list[fd].nfs, nfs_fd_list[fd].fh,
+                               offset, count, buf)) < 0) {
+                       errno = -ret;
+                       return -1;
+               }
+               return ret;
+       }
+       return real_pread(fd, buf, count, offset);
+}
+
+ssize_t (*real_write)(int fd, const void *buf, size_t count);
+
+ssize_t write(int fd, const void *buf, size_t count)
+{
+       if (nfs_fd_list[fd].is_nfs == 1) {
+               int ret;
+
+               LD_NFS_DPRINTF(9, "write(fd:%d count:%d)", fd, (int)count);
+               if ((ret = nfs_write(nfs_fd_list[fd].nfs, nfs_fd_list[fd].fh,
+                               count,
+                               (char *)discard_const(buf))) < 0) {
+                       errno = -ret;
+                       return -1;
+               }
+               return ret;
+       }
+       return real_write(fd, buf, count);
+}
+
+ssize_t (*real_pwrite)(int fd, const void *buf, size_t count, off_t offset); 
+ssize_t pwrite(int fd, const void *buf, size_t count, off_t offset) {
+       if (nfs_fd_list[fd].is_nfs == 1) {
+               int ret;
+
+               LD_NFS_DPRINTF(9, "pwrite(fd:%d offset:%d count:%d)", fd,
+                       (int)offset, (int)count);
+               if ((ret = nfs_pwrite(nfs_fd_list[fd].nfs, nfs_fd_list[fd].fh,
+                               offset, count,
+                               (char *)discard_const(buf))) < 0) {
+                       errno = -ret;
+                       return -1;
+               }
+               return ret;
+       }
+       return real_pwrite(fd, buf, count, offset);
+}
+
+int (*real_dup2)(int oldfd, int newfd);
+
+int dup2(int oldfd, int newfd)
+{
+       close(newfd);
+
+       if (nfs_fd_list[oldfd].is_nfs == 1) {
+               struct nfs_context *nfs;
+               struct nfs_url *url;
+               struct nfsfh *fh = NULL;
+               int ret, fd;
+
+               LD_NFS_DPRINTF(9, "dup2(%s:%d, %d)", nfs_fd_list[oldfd].path,
+                       oldfd, newfd);
+               nfs = nfs_init_context();
+               if (nfs == NULL) {
+                       LD_NFS_DPRINTF(1, "Failed to create context");
+                       errno = ENOMEM;
+                       return -1;
+               }
+
+               url = nfs_parse_url_full(nfs, nfs_fd_list[oldfd].path);
+               if (url == NULL) {
+                       LD_NFS_DPRINTF(1, "Failed to parse URL: %s\n",
+                               nfs_get_error(nfs));
+                       nfs_destroy_context(nfs);
+                       errno = EINVAL;
+                       return -1;
+               }
+
+               if (nfs_mount(nfs, url->server, url->path) != 0) {
+                       LD_NFS_DPRINTF(1, "Failed to mount nfs share : %s\n",
+                              nfs_get_error(nfs));
+                       nfs_destroy_url(url);
+                       nfs_destroy_context(nfs);
+                       errno = EINVAL;
+                       return -1;
+               }
+
+               if ((ret = nfs_open(nfs, url->file, nfs_fd_list[oldfd].mode,
+                               &fh)) != 0) {
+                       LD_NFS_DPRINTF(1, "Failed to open nfs file : %s\n",
+                              nfs_get_error(nfs));
+                       nfs_destroy_url(url);
+                       nfs_destroy_context(nfs);
+                       errno = -ret;
+                       return -1;
+               }
+
+               /* We could actually end on the right descriptor by chance */
+               if (nfs_get_fd(nfs) != newfd) {
+                       if (real_dup2(nfs_get_fd(nfs), newfd) < 0) {
+                               LD_NFS_DPRINTF(1, "Failed to dup2 file : %d",
+                                       errno);
+                               return -1;
+                       }
+
+                       close(rpc_get_fd(nfs_get_rpc_context(nfs)));
+                       rpc_set_fd(nfs_get_rpc_context(nfs), newfd);
+               }
+
+               fd = nfs_get_fd(nfs);
+               if (fd >= NFS_MAX_FD) {
+                       LD_NFS_DPRINTF(1, "Too many files open");
+                       nfs_destroy_url(url);
+                       nfs_destroy_context(nfs);
+                       errno = ENFILE;
+                       return -1;
+               }               
+
+               nfs_fd_list[fd].is_nfs     = 1;
+               nfs_fd_list[fd].nfs        = nfs;
+               nfs_fd_list[fd].fh         = fh;
+               nfs_fd_list[fd].path       = strdup(nfs_fd_list[oldfd].path);
+               nfs_fd_list[fd].flags      = nfs_fd_list[oldfd].flags;
+               nfs_fd_list[fd].mode       = nfs_fd_list[oldfd].mode;
+
+               nfs_destroy_url(url);
+
+               LD_NFS_DPRINTF(9, "dup2(%s) successful",
+                       nfs_fd_list[oldfd].path);
+               return fd;
+       }
+
+       return real_dup2(oldfd, newfd);
+}
+
+int (*real_xstat)(int ver, __const char *path, struct stat *buf);
+
+int __xstat(int ver, const char *path, struct stat *buf)
+{
+       if (!strncmp(path, "nfs:", 4)) {
+               int fd, ret;
+
+               LD_NFS_DPRINTF(9, "__xstat(%s)", path);
+               fd = open(path, 0, 0);
+               if (fd == -1) {
+                       return fd;
+               }
+
+               ret = __fxstat(ver, fd, buf);
+               close(fd);
+               return ret;
+       }
+
+       return real_xstat(ver, path, buf);
+}
+
+int (*real_xstat64)(int ver, __const char *path, struct stat64 *buf);
+
+int __xstat64(int ver, const char *path, struct stat64 *buf)
+{
+       if (!strncmp(path, "nfs:", 4)) {
+               int fd, ret;
+
+               LD_NFS_DPRINTF(9, "__xstat64(%s)", path);
+               fd = open(path, 0, 0);
+               if (fd == -1) {
+                       return fd;
+               }
+
+               ret = __fxstat64(ver, fd, buf);
+               close(fd);
+               return ret;
+       }
+
+       return real_xstat64(ver, path, buf);
+}
+
+int (*real_lxstat)(int ver, __const char *path, struct stat *buf);
+
+int __lxstat(int ver, const char *path, struct stat *buf)
+{
+       if (!strncmp(path, "nfs:", 4)) {
+               int fd, ret;
+
+               LD_NFS_DPRINTF(9, "__lxstat(%s)", path);
+               fd = open(path, 0, 0);
+               if (fd == -1) {
+                       return fd;
+               }
+
+               ret = __fxstat(ver, fd, buf);
+               close(fd);
+               return ret;
+       }
+
+       return real_lxstat(ver, path, buf);
+}
+
+int (*real_lxstat64)(int ver, __const char *path, struct stat64 *buf);
+
+int __lxstat64(int ver, const char *path, struct stat64 *buf)
+{
+       if (!strncmp(path, "nfs:", 4)) {
+               int fd, ret;
+
+               LD_NFS_DPRINTF(9, "__lxstat64(%s)", path);
+               fd = open(path, 0, 0);
+               if (fd == -1) {
+                       return fd;
+               }
+
+               ret = __fxstat64(ver, fd, buf);
+               close(fd);
+               return ret;
+       }
+
+       return real_lxstat64(ver, path, buf);
+}
+
+int (*real_fxstat)(int ver, int fd, struct stat *buf);
+
+int __fxstat(int ver, int fd, struct stat *buf)
+{
+       if (nfs_fd_list[fd].is_nfs == 1) {
+               int ret;
+               struct stat64 st64;
+
+               LD_NFS_DPRINTF(9, "__fxstat(%d)", fd);
+               if ((ret = nfs_fstat(nfs_fd_list[fd].nfs, nfs_fd_list[fd].fh,
+                               (void *)&st64)) < 0) {
+                       errno = -ret;
+                       return -1;
+               }
+
+               buf->st_dev     = st64.st_dev;
+               buf->st_ino     = st64.st_ino;
+               buf->st_mode    = st64.st_mode;
+               buf->st_nlink   = st64.st_nlink;
+               buf->st_uid     = st64.st_uid;
+               buf->st_gid     = st64.st_gid;
+               buf->st_rdev    = st64.st_rdev;
+               buf->st_size    = st64.st_size;
+               buf->st_blksize = st64.st_blksize;
+               buf->st_blocks  = st64.st_blocks;
+               buf->st_atime   = st64.st_atime;
+               buf->st_mtime   = st64.st_mtime;
+               buf->st_ctime   = st64.st_ctime;
+
+               LD_NFS_DPRINTF(9, "__fxstat(%d) success", fd);
+               return ret;
+       }
+
+       return real_fxstat(ver, fd, buf);
+}
+
+int (*real_fxstat64)(int ver, int fd, struct stat64 *buf);
+
+int __fxstat64(int ver, int fd, struct stat64 *buf)
+{
+       if (nfs_fd_list[fd].is_nfs == 1) {
+               int ret;
+               struct stat64 st64;
+
+               LD_NFS_DPRINTF(9, "__fxstat64(%d)", fd);
+               if ((ret = nfs_fstat(nfs_fd_list[fd].nfs, nfs_fd_list[fd].fh,
+                               (void *)&st64)) < 0) {
+                       errno = -ret;
+                       return -1;
+               }
+
+               buf->st_dev     = st64.st_dev;
+               buf->st_ino     = st64.st_ino;
+               buf->st_mode    = st64.st_mode;
+               buf->st_nlink   = st64.st_nlink;
+               buf->st_uid     = st64.st_uid;
+               buf->st_gid     = st64.st_gid;
+               buf->st_rdev    = st64.st_rdev;
+               buf->st_size    = st64.st_size;
+               buf->st_blksize = st64.st_blksize;
+               buf->st_blocks  = st64.st_blocks;
+               buf->st_atime   = st64.st_atime;
+               buf->st_mtime   = st64.st_mtime;
+               buf->st_ctime   = st64.st_ctime;
+
+               LD_NFS_DPRINTF(9, "__fxstat64(%d) success", fd);
+               return ret;
+       }
+
+       return real_fxstat64(ver, fd, buf);
+}
+
+int (*real_fallocate)(int fd, int mode, off_t offset, off_t len);
+
+int fallocate(int fd, int mode, off_t offset, off_t len)
+{
+       if (nfs_fd_list[fd].is_nfs == 1) {
+               LD_NFS_DPRINTF(9, "fallocate(%d)", fd);
+               errno = EOPNOTSUPP;
+               return -1;
+       }
+
+       return real_fallocate(fd, mode, offset, len);
+}
+
+int (*real_ftruncate)(int fd, off_t len);
+
+int ftruncate(int fd, off_t len)
+{
+       if (nfs_fd_list[fd].is_nfs == 1) {
+               int ret;
+
+               LD_NFS_DPRINTF(9, "ftruncate(%d, %d)", fd, (int)len);
+               if ((ret = nfs_ftruncate(nfs_fd_list[fd].nfs,
+                               nfs_fd_list[fd].fh,
+                               len)) < 0) {
+                       errno = -ret;
+                       return -1;
+               }
+               return 0;
+       }
+
+       return real_ftruncate(fd, len);
+}
+
+int (*real_truncate)(const char *path, off_t len);
+
+int truncate(const char *path, off_t len)
+{
+       if (!strncmp(path, "nfs:", 4)) {
+               int fd, ret;
+
+               LD_NFS_DPRINTF(9, "truncate(%s, %d)", path, (int)len);
+               fd = open(path, 0, 0);
+               if (fd == -1) {
+                       return fd;
+               }
+
+               ret = ftruncate(fd, len);
+               close(fd);
+               return ret;
+       }
+
+       return real_truncate(path, len);
+}
+
+int (*real_fchmod)(int fd, mode_t mode);
+
+int fchmod(int fd, mode_t mode)
+{
+       if (nfs_fd_list[fd].is_nfs == 1) {
+               int ret;
+
+               LD_NFS_DPRINTF(9, "fchmod(%d, %o)", fd, (int)mode);
+               if ((ret = nfs_fchmod(nfs_fd_list[fd].nfs,
+                               nfs_fd_list[fd].fh,
+                               mode)) < 0) {
+                       errno = -ret;
+                       return -1;
+               }
+               return 0;
+       }
+
+       return real_fchmod(fd, mode);
+}
+
+int (*real_chmod)(const char *path, mode_t mode);
+
+int chmod(const char *path, mode_t mode)
+{
+       if (!strncmp(path, "nfs:", 4)) {
+               int fd, ret;
+
+               LD_NFS_DPRINTF(9, "chmod(%s, %o)", path, (int)mode);
+               fd = open(path, 0, 0);
+               if (fd == -1) {
+                       return fd;
+               }
+
+               ret = fchmod(fd, mode);
+               close(fd);
+               return ret;
+       }
+
+       return real_chmod(path, mode);
+}
+
+static void __attribute__((constructor)) _init(void)
+{
+       int i;
+
+       if (getenv("LD_NFS_DEBUG") != NULL) {
+               debug = atoi(getenv("LD_NFS_DEBUG"));
+       }
+
+       real_open = dlsym(RTLD_NEXT, "open");
+       if (real_open == NULL) {
+               LD_NFS_DPRINTF(0, "Failed to dlsym(open)");
+               exit(10);
+       }
+
+       real_close = dlsym(RTLD_NEXT, "close");
+       if (real_close == NULL) {
+               LD_NFS_DPRINTF(0, "Failed to dlsym(close)");
+               exit(10);
+       }
+
+       real_read = dlsym(RTLD_NEXT, "read");
+       if (real_read == NULL) {
+               LD_NFS_DPRINTF(0, "Failed to dlsym(read)");
+               exit(10);
+       }
+
+       real_pread = dlsym(RTLD_NEXT, "pread");
+       if (real_pread == NULL) {
+               LD_NFS_DPRINTF(0, "Failed to dlsym(pread)");
+               exit(10);
+       }
+
+       real_write = dlsym(RTLD_NEXT, "write");
+       if (real_write == NULL) {
+               LD_NFS_DPRINTF(0, "Failed to dlsym(write)");
+               exit(10);
+       }
+
+       real_pwrite = dlsym(RTLD_NEXT, "pwrite");
+       if (real_pwrite == NULL) {
+               LD_NFS_DPRINTF(0, "Failed to dlsym(pwrite)");
+               exit(10);
+       }
+
+       real_xstat = dlsym(RTLD_NEXT, "__xstat");
+       if (real_xstat == NULL) {
+               LD_NFS_DPRINTF(0, "Failed to dlsym(__xstat)");
+               exit(10);
+       }
+
+       real_xstat64 = dlsym(RTLD_NEXT, "__xstat64");
+       if (real_xstat64 == NULL) {
+               LD_NFS_DPRINTF(0, "Failed to dlsym(__xstat64)");
+       }
+
+       real_lxstat = dlsym(RTLD_NEXT, "__lxstat");
+       if (real_lxstat == NULL) {
+               LD_NFS_DPRINTF(0, "Failed to dlsym(__lxstat)");
+               exit(10);
+       }
+
+       real_lxstat64 = dlsym(RTLD_NEXT, "__lxstat64");
+       if (real_lxstat64 == NULL) {
+               LD_NFS_DPRINTF(0, "Failed to dlsym(_lxstat64)");
+               exit(10);
+       }
+
+       real_fxstat = dlsym(RTLD_NEXT, "__fxstat");
+       if (real_fxstat == NULL) {
+               LD_NFS_DPRINTF(0, "Failed to dlsym(__fxstat)");
+               exit(10);
+       }
+
+       real_fxstat64 = dlsym(RTLD_NEXT, "__fxstat64");
+       if (real_fxstat64 == NULL) {
+               LD_NFS_DPRINTF(0, "Failed to dlsym(__fxstat64)");
+               exit(10);
+       }
+
+       real_fallocate = dlsym(RTLD_NEXT, "fallocate");
+       if (real_fallocate == NULL) {
+               LD_NFS_DPRINTF(0, "Failed to dlsym(fallocate)");
+               exit(10);
+       }
+
+       real_dup2 = dlsym(RTLD_NEXT, "dup2");
+       if (real_dup2 == NULL) {
+               LD_NFS_DPRINTF(0, "Failed to dlsym(dup2)");
+               exit(10);
+       }
+
+       real_truncate = dlsym(RTLD_NEXT, "truncate");
+       if (real_truncate == NULL) {
+               LD_NFS_DPRINTF(0, "Failed to dlsym(truncate)");
+               exit(10);
+       }
+
+       real_ftruncate = dlsym(RTLD_NEXT, "ftruncate");
+       if (real_ftruncate == NULL) {
+               LD_NFS_DPRINTF(0, "Failed to dlsym(ftruncate)");
+               exit(10);
+       }
+
+       real_chmod = dlsym(RTLD_NEXT, "chmod");
+       if (real_chmod == NULL) {
+               LD_NFS_DPRINTF(0, "Failed to dlsym(chmod)");
+               exit(10);
+       }
+
+       real_fchmod = dlsym(RTLD_NEXT, "fchmod");
+       if (real_fchmod == NULL) {
+               LD_NFS_DPRINTF(0, "Failed to dlsym(fchmod)");
+               exit(10);
+       }
+}