2 Copyright (C) 2014 by Ronnie Sahlberg <ronniesahlberg@gmail.com>
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 3 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, see <http://www.gnu.org/licenses/>.
20 #include <sys/types.h>
27 #include <asm/fcntl.h>
29 #include <nfsc/libnfs.h>
31 #include <sys/syscall.h>
34 #define NFS_MAX_FD 255
39 #define discard_const(ptr) ((void *)((intptr_t)(ptr)))
42 #define LD_NFS_DPRINTF(level, fmt, args...) \
44 if ((debug) >= level) { \
45 fprintf(stderr,"ld_nfs: "); \
46 fprintf(stderr, (fmt), ##args); \
47 fprintf(stderr,"\n"); \
53 struct nfs_context
*nfs
;
56 /* so we can reopen and emulate dup2() */
62 static struct nfs_fd_list nfs_fd_list
[NFS_MAX_FD
];
64 int (*real_open
)(__const
char *path
, int flags
, mode_t mode
);
66 int open(const char *path
, int flags
, mode_t mode
)
68 if (!strncmp(path
, "nfs:", 4)) {
69 struct nfs_context
*nfs
;
71 struct nfsfh
*fh
= NULL
;
74 LD_NFS_DPRINTF(9, "open(%s, %x, %o)", path
, flags
, mode
);
75 nfs
= nfs_init_context();
77 LD_NFS_DPRINTF(1, "Failed to create context");
82 url
= nfs_parse_url_full(nfs
, path
);
84 LD_NFS_DPRINTF(1, "Failed to parse URL: %s\n",
86 nfs_destroy_context(nfs
);
91 if (nfs_mount(nfs
, url
->server
, url
->path
) != 0) {
92 LD_NFS_DPRINTF(1, "Failed to mount nfs share : %s\n",
95 nfs_destroy_context(nfs
);
100 if (flags
& O_CREAT
) {
101 if ((ret
= nfs_creat(nfs
, url
->file
, mode
, &fh
)) != 0) {
102 LD_NFS_DPRINTF(1, "Failed to creat nfs file : "
103 "%s\n", nfs_get_error(nfs
));
104 nfs_destroy_url(url
);
105 nfs_destroy_context(nfs
);
110 if ((ret
= nfs_open(nfs
, url
->file
, flags
, &fh
)) != 0) {
111 LD_NFS_DPRINTF(1, "Failed to open nfs file : "
112 "%s\n", nfs_get_error(nfs
));
113 nfs_destroy_url(url
);
114 nfs_destroy_context(nfs
);
120 fd
= nfs_get_fd(nfs
);
121 if (fd
>= NFS_MAX_FD
) {
122 LD_NFS_DPRINTF(1, "Too many files open");
123 nfs_destroy_url(url
);
124 nfs_destroy_context(nfs
);
129 nfs_fd_list
[fd
].is_nfs
= 1;
130 nfs_fd_list
[fd
].nfs
= nfs
;
131 nfs_fd_list
[fd
].fh
= fh
;
132 nfs_fd_list
[fd
].path
= strdup(path
);
133 nfs_fd_list
[fd
].flags
= flags
;
134 nfs_fd_list
[fd
].mode
= mode
;
136 nfs_destroy_url(url
);
138 LD_NFS_DPRINTF(9, "open(%s) == %d", path
, fd
);
142 return real_open(path
, flags
, mode
);
145 int open64(const char *path
, int flags
, mode_t mode
)
147 return open(path
, flags
| O_LARGEFILE
, mode
);
150 int (*real_close
)(int fd
);
154 if (nfs_fd_list
[fd
].is_nfs
== 1) {
157 LD_NFS_DPRINTF(9, "close(%d)", fd
);
159 nfs_fd_list
[fd
].is_nfs
= 0;
161 nfs_close(nfs_fd_list
[fd
].nfs
, nfs_fd_list
[fd
].fh
);
162 nfs_fd_list
[fd
].fh
= NULL
;
164 nfs_destroy_context(nfs_fd_list
[fd
].nfs
);
165 nfs_fd_list
[fd
].nfs
= NULL
;
167 free(discard_const(nfs_fd_list
[fd
].path
));
168 nfs_fd_list
[fd
].path
= NULL
;
173 return real_close(fd
);
176 ssize_t (*real_read
)(int fd
, void *buf
, size_t count
);
178 ssize_t
read(int fd
, void *buf
, size_t count
)
180 if (nfs_fd_list
[fd
].is_nfs
== 1) {
183 LD_NFS_DPRINTF(9, "read(fd:%d count:%d)", fd
, (int)count
);
184 if ((ret
= nfs_read(nfs_fd_list
[fd
].nfs
, nfs_fd_list
[fd
].fh
,
191 return real_read(fd
, buf
, count
);
194 ssize_t (*real_pread
)(int fd
, void *buf
, size_t count
, off_t offset
);
195 ssize_t
pread(int fd
, void *buf
, size_t count
, off_t offset
) {
196 if (nfs_fd_list
[fd
].is_nfs
== 1) {
199 LD_NFS_DPRINTF(9, "pread(fd:%d offset:%d count:%d)", fd
,
200 (int)offset
, (int)count
);
201 if ((ret
= nfs_pread(nfs_fd_list
[fd
].nfs
, nfs_fd_list
[fd
].fh
,
202 offset
, count
, buf
)) < 0) {
208 return real_pread(fd
, buf
, count
, offset
);
211 ssize_t (*real_write
)(int fd
, const void *buf
, size_t count
);
213 ssize_t
write(int fd
, const void *buf
, size_t count
)
215 if (nfs_fd_list
[fd
].is_nfs
== 1) {
218 LD_NFS_DPRINTF(9, "write(fd:%d count:%d)", fd
, (int)count
);
219 if ((ret
= nfs_write(nfs_fd_list
[fd
].nfs
, nfs_fd_list
[fd
].fh
,
221 (char *)discard_const(buf
))) < 0) {
227 return real_write(fd
, buf
, count
);
230 ssize_t (*real_pwrite
)(int fd
, const void *buf
, size_t count
, off_t offset
);
231 ssize_t
pwrite(int fd
, const void *buf
, size_t count
, off_t offset
) {
232 if (nfs_fd_list
[fd
].is_nfs
== 1) {
235 LD_NFS_DPRINTF(9, "pwrite(fd:%d offset:%d count:%d)", fd
,
236 (int)offset
, (int)count
);
237 if ((ret
= nfs_pwrite(nfs_fd_list
[fd
].nfs
, nfs_fd_list
[fd
].fh
,
239 (char *)discard_const(buf
))) < 0) {
245 return real_pwrite(fd
, buf
, count
, offset
);
248 int (*real_dup2
)(int oldfd
, int newfd
);
250 int dup2(int oldfd
, int newfd
)
254 if (nfs_fd_list
[oldfd
].is_nfs
== 1) {
255 struct nfs_context
*nfs
;
257 struct nfsfh
*fh
= NULL
;
260 LD_NFS_DPRINTF(9, "dup2(%s:%d, %d)", nfs_fd_list
[oldfd
].path
,
262 nfs
= nfs_init_context();
264 LD_NFS_DPRINTF(1, "Failed to create context");
269 url
= nfs_parse_url_full(nfs
, nfs_fd_list
[oldfd
].path
);
271 LD_NFS_DPRINTF(1, "Failed to parse URL: %s\n",
273 nfs_destroy_context(nfs
);
278 if (nfs_mount(nfs
, url
->server
, url
->path
) != 0) {
279 LD_NFS_DPRINTF(1, "Failed to mount nfs share : %s\n",
281 nfs_destroy_url(url
);
282 nfs_destroy_context(nfs
);
287 if ((ret
= nfs_open(nfs
, url
->file
, nfs_fd_list
[oldfd
].mode
,
289 LD_NFS_DPRINTF(1, "Failed to open nfs file : %s\n",
291 nfs_destroy_url(url
);
292 nfs_destroy_context(nfs
);
297 /* We could actually end on the right descriptor by chance */
298 if (nfs_get_fd(nfs
) != newfd
) {
299 if (real_dup2(nfs_get_fd(nfs
), newfd
) < 0) {
300 LD_NFS_DPRINTF(1, "Failed to dup2 file : %d",
305 close(rpc_get_fd(nfs_get_rpc_context(nfs
)));
306 rpc_set_fd(nfs_get_rpc_context(nfs
), newfd
);
309 fd
= nfs_get_fd(nfs
);
310 if (fd
>= NFS_MAX_FD
) {
311 LD_NFS_DPRINTF(1, "Too many files open");
312 nfs_destroy_url(url
);
313 nfs_destroy_context(nfs
);
318 nfs_fd_list
[fd
].is_nfs
= 1;
319 nfs_fd_list
[fd
].nfs
= nfs
;
320 nfs_fd_list
[fd
].fh
= fh
;
321 nfs_fd_list
[fd
].path
= strdup(nfs_fd_list
[oldfd
].path
);
322 nfs_fd_list
[fd
].flags
= nfs_fd_list
[oldfd
].flags
;
323 nfs_fd_list
[fd
].mode
= nfs_fd_list
[oldfd
].mode
;
325 nfs_destroy_url(url
);
327 LD_NFS_DPRINTF(9, "dup2(%s) successful",
328 nfs_fd_list
[oldfd
].path
);
332 return real_dup2(oldfd
, newfd
);
335 int (*real_xstat
)(int ver
, __const
char *path
, struct stat
*buf
);
337 int __xstat(int ver
, const char *path
, struct stat
*buf
)
339 if (!strncmp(path
, "nfs:", 4)) {
342 LD_NFS_DPRINTF(9, "__xstat(%s)", path
);
343 fd
= open(path
, 0, 0);
348 ret
= __fxstat(ver
, fd
, buf
);
353 return real_xstat(ver
, path
, buf
);
356 int (*real_xstat64
)(int ver
, __const
char *path
, struct stat64
*buf
);
358 int __xstat64(int ver
, const char *path
, struct stat64
*buf
)
360 if (!strncmp(path
, "nfs:", 4)) {
363 LD_NFS_DPRINTF(9, "__xstat64(%s)", path
);
364 fd
= open(path
, 0, 0);
369 ret
= __fxstat64(ver
, fd
, buf
);
374 return real_xstat64(ver
, path
, buf
);
377 int (*real_lxstat
)(int ver
, __const
char *path
, struct stat
*buf
);
379 int __lxstat(int ver
, const char *path
, struct stat
*buf
)
381 if (!strncmp(path
, "nfs:", 4)) {
384 LD_NFS_DPRINTF(9, "__lxstat(%s)", path
);
385 fd
= open(path
, 0, 0);
390 ret
= __fxstat(ver
, fd
, buf
);
395 return real_lxstat(ver
, path
, buf
);
398 int (*real_lxstat64
)(int ver
, __const
char *path
, struct stat64
*buf
);
400 int __lxstat64(int ver
, const char *path
, struct stat64
*buf
)
402 if (!strncmp(path
, "nfs:", 4)) {
405 LD_NFS_DPRINTF(9, "__lxstat64(%s)", path
);
406 fd
= open(path
, 0, 0);
411 ret
= __fxstat64(ver
, fd
, buf
);
416 return real_lxstat64(ver
, path
, buf
);
419 int (*real_fxstat
)(int ver
, int fd
, struct stat
*buf
);
421 int __fxstat(int ver
, int fd
, struct stat
*buf
)
423 if (nfs_fd_list
[fd
].is_nfs
== 1) {
427 LD_NFS_DPRINTF(9, "__fxstat(%d)", fd
);
428 if ((ret
= nfs_fstat(nfs_fd_list
[fd
].nfs
, nfs_fd_list
[fd
].fh
,
429 (void *)&st64
)) < 0) {
434 buf
->st_dev
= st64
.st_dev
;
435 buf
->st_ino
= st64
.st_ino
;
436 buf
->st_mode
= st64
.st_mode
;
437 buf
->st_nlink
= st64
.st_nlink
;
438 buf
->st_uid
= st64
.st_uid
;
439 buf
->st_gid
= st64
.st_gid
;
440 buf
->st_rdev
= st64
.st_rdev
;
441 buf
->st_size
= st64
.st_size
;
442 buf
->st_blksize
= st64
.st_blksize
;
443 buf
->st_blocks
= st64
.st_blocks
;
444 buf
->st_atime
= st64
.st_atime
;
445 buf
->st_mtime
= st64
.st_mtime
;
446 buf
->st_ctime
= st64
.st_ctime
;
448 LD_NFS_DPRINTF(9, "__fxstat(%d) success", fd
);
452 return real_fxstat(ver
, fd
, buf
);
455 int (*real_fxstat64
)(int ver
, int fd
, struct stat64
*buf
);
457 int __fxstat64(int ver
, int fd
, struct stat64
*buf
)
459 if (nfs_fd_list
[fd
].is_nfs
== 1) {
463 LD_NFS_DPRINTF(9, "__fxstat64(%d)", fd
);
464 if ((ret
= nfs_fstat(nfs_fd_list
[fd
].nfs
, nfs_fd_list
[fd
].fh
,
465 (void *)&st64
)) < 0) {
470 buf
->st_dev
= st64
.st_dev
;
471 buf
->st_ino
= st64
.st_ino
;
472 buf
->st_mode
= st64
.st_mode
;
473 buf
->st_nlink
= st64
.st_nlink
;
474 buf
->st_uid
= st64
.st_uid
;
475 buf
->st_gid
= st64
.st_gid
;
476 buf
->st_rdev
= st64
.st_rdev
;
477 buf
->st_size
= st64
.st_size
;
478 buf
->st_blksize
= st64
.st_blksize
;
479 buf
->st_blocks
= st64
.st_blocks
;
480 buf
->st_atime
= st64
.st_atime
;
481 buf
->st_mtime
= st64
.st_mtime
;
482 buf
->st_ctime
= st64
.st_ctime
;
484 LD_NFS_DPRINTF(9, "__fxstat64(%d) success", fd
);
488 return real_fxstat64(ver
, fd
, buf
);
491 int (*real_fallocate
)(int fd
, int mode
, off_t offset
, off_t len
);
493 int fallocate(int fd
, int mode
, off_t offset
, off_t len
)
495 if (nfs_fd_list
[fd
].is_nfs
== 1) {
496 LD_NFS_DPRINTF(9, "fallocate(%d)", fd
);
501 return real_fallocate(fd
, mode
, offset
, len
);
504 int (*real_ftruncate
)(int fd
, off_t len
);
506 int ftruncate(int fd
, off_t len
)
508 if (nfs_fd_list
[fd
].is_nfs
== 1) {
511 LD_NFS_DPRINTF(9, "ftruncate(%d, %d)", fd
, (int)len
);
512 if ((ret
= nfs_ftruncate(nfs_fd_list
[fd
].nfs
,
521 return real_ftruncate(fd
, len
);
524 int (*real_truncate
)(const char *path
, off_t len
);
526 int truncate(const char *path
, off_t len
)
528 if (!strncmp(path
, "nfs:", 4)) {
531 LD_NFS_DPRINTF(9, "truncate(%s, %d)", path
, (int)len
);
532 fd
= open(path
, 0, 0);
537 ret
= ftruncate(fd
, len
);
542 return real_truncate(path
, len
);
545 int (*real_fchmod
)(int fd
, mode_t mode
);
547 int fchmod(int fd
, mode_t mode
)
549 if (nfs_fd_list
[fd
].is_nfs
== 1) {
552 LD_NFS_DPRINTF(9, "fchmod(%d, %o)", fd
, (int)mode
);
553 if ((ret
= nfs_fchmod(nfs_fd_list
[fd
].nfs
,
562 return real_fchmod(fd
, mode
);
565 int (*real_chmod
)(const char *path
, mode_t mode
);
567 int chmod(const char *path
, mode_t mode
)
569 if (!strncmp(path
, "nfs:", 4)) {
572 LD_NFS_DPRINTF(9, "chmod(%s, %o)", path
, (int)mode
);
573 fd
= open(path
, 0, 0);
578 ret
= fchmod(fd
, mode
);
583 return real_chmod(path
, mode
);
586 static void __attribute__((constructor
)) _init(void)
590 if (getenv("LD_NFS_DEBUG") != NULL
) {
591 debug
= atoi(getenv("LD_NFS_DEBUG"));
594 real_open
= dlsym(RTLD_NEXT
, "open");
595 if (real_open
== NULL
) {
596 LD_NFS_DPRINTF(0, "Failed to dlsym(open)");
600 real_close
= dlsym(RTLD_NEXT
, "close");
601 if (real_close
== NULL
) {
602 LD_NFS_DPRINTF(0, "Failed to dlsym(close)");
606 real_read
= dlsym(RTLD_NEXT
, "read");
607 if (real_read
== NULL
) {
608 LD_NFS_DPRINTF(0, "Failed to dlsym(read)");
612 real_pread
= dlsym(RTLD_NEXT
, "pread");
613 if (real_pread
== NULL
) {
614 LD_NFS_DPRINTF(0, "Failed to dlsym(pread)");
618 real_write
= dlsym(RTLD_NEXT
, "write");
619 if (real_write
== NULL
) {
620 LD_NFS_DPRINTF(0, "Failed to dlsym(write)");
624 real_pwrite
= dlsym(RTLD_NEXT
, "pwrite");
625 if (real_pwrite
== NULL
) {
626 LD_NFS_DPRINTF(0, "Failed to dlsym(pwrite)");
630 real_xstat
= dlsym(RTLD_NEXT
, "__xstat");
631 if (real_xstat
== NULL
) {
632 LD_NFS_DPRINTF(0, "Failed to dlsym(__xstat)");
636 real_xstat64
= dlsym(RTLD_NEXT
, "__xstat64");
637 if (real_xstat64
== NULL
) {
638 LD_NFS_DPRINTF(0, "Failed to dlsym(__xstat64)");
641 real_lxstat
= dlsym(RTLD_NEXT
, "__lxstat");
642 if (real_lxstat
== NULL
) {
643 LD_NFS_DPRINTF(0, "Failed to dlsym(__lxstat)");
647 real_lxstat64
= dlsym(RTLD_NEXT
, "__lxstat64");
648 if (real_lxstat64
== NULL
) {
649 LD_NFS_DPRINTF(0, "Failed to dlsym(_lxstat64)");
653 real_fxstat
= dlsym(RTLD_NEXT
, "__fxstat");
654 if (real_fxstat
== NULL
) {
655 LD_NFS_DPRINTF(0, "Failed to dlsym(__fxstat)");
659 real_fxstat64
= dlsym(RTLD_NEXT
, "__fxstat64");
660 if (real_fxstat64
== NULL
) {
661 LD_NFS_DPRINTF(0, "Failed to dlsym(__fxstat64)");
665 real_fallocate
= dlsym(RTLD_NEXT
, "fallocate");
666 if (real_fallocate
== NULL
) {
667 LD_NFS_DPRINTF(0, "Failed to dlsym(fallocate)");
671 real_dup2
= dlsym(RTLD_NEXT
, "dup2");
672 if (real_dup2
== NULL
) {
673 LD_NFS_DPRINTF(0, "Failed to dlsym(dup2)");
677 real_truncate
= dlsym(RTLD_NEXT
, "truncate");
678 if (real_truncate
== NULL
) {
679 LD_NFS_DPRINTF(0, "Failed to dlsym(truncate)");
683 real_ftruncate
= dlsym(RTLD_NEXT
, "ftruncate");
684 if (real_ftruncate
== NULL
) {
685 LD_NFS_DPRINTF(0, "Failed to dlsym(ftruncate)");
689 real_chmod
= dlsym(RTLD_NEXT
, "chmod");
690 if (real_chmod
== NULL
) {
691 LD_NFS_DPRINTF(0, "Failed to dlsym(chmod)");
695 real_fchmod
= dlsym(RTLD_NEXT
, "fchmod");
696 if (real_fchmod
== NULL
) {
697 LD_NFS_DPRINTF(0, "Failed to dlsym(fchmod)");