Take maintenance for libnfs
[deb_libnfs.git] / examples / ld_nfs.c
1 /*
2 Copyright (C) 2014 by Ronnie Sahlberg <ronniesahlberg@gmail.com>
3
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.
8
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.
13
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/>.
16 */
17
18 #define _GNU_SOURCE
19
20 #include <sys/types.h>
21 #include <sys/stat.h>
22 #include <unistd.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <errno.h>
26 #include <stdio.h>
27 #include <asm/fcntl.h>
28
29 #include <nfsc/libnfs.h>
30
31 #include <sys/syscall.h>
32 #include <dlfcn.h>
33
34 #define NFS_MAX_FD 255
35
36 static int debug = 0;
37
38 #ifndef discard_const
39 #define discard_const(ptr) ((void *)((intptr_t)(ptr)))
40 #endif
41
42 #define LD_NFS_DPRINTF(level, fmt, args...) \
43 do { \
44 if ((debug) >= level) { \
45 fprintf(stderr,"ld_nfs: "); \
46 fprintf(stderr, (fmt), ##args); \
47 fprintf(stderr,"\n"); \
48 } \
49 } while (0);
50
51 struct nfs_fd_list {
52 int is_nfs;
53 struct nfs_context *nfs;
54 struct nfsfh *fh;
55
56 /* so we can reopen and emulate dup2() */
57 const char *path;
58 int flags;
59 mode_t mode;
60 };
61
62 static struct nfs_fd_list nfs_fd_list[NFS_MAX_FD];
63
64 int (*real_open)(__const char *path, int flags, mode_t mode);
65
66 int open(const char *path, int flags, mode_t mode)
67 {
68 if (!strncmp(path, "nfs:", 4)) {
69 struct nfs_context *nfs;
70 struct nfs_url *url;
71 struct nfsfh *fh = NULL;
72 int ret, fd;
73
74 LD_NFS_DPRINTF(9, "open(%s, %x, %o)", path, flags, mode);
75 nfs = nfs_init_context();
76 if (nfs == NULL) {
77 LD_NFS_DPRINTF(1, "Failed to create context");
78 errno = ENOMEM;
79 return -1;
80 }
81
82 url = nfs_parse_url_full(nfs, path);
83 if (url == NULL) {
84 LD_NFS_DPRINTF(1, "Failed to parse URL: %s\n",
85 nfs_get_error(nfs));
86 nfs_destroy_context(nfs);
87 errno = EINVAL;
88 return -1;
89 }
90
91 if (nfs_mount(nfs, url->server, url->path) != 0) {
92 LD_NFS_DPRINTF(1, "Failed to mount nfs share : %s\n",
93 nfs_get_error(nfs));
94 nfs_destroy_url(url);
95 nfs_destroy_context(nfs);
96 errno = EINVAL;
97 return -1;
98 }
99
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);
106 errno = -ret;
107 return -1;
108 }
109 } else {
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);
115 errno = -ret;
116 return -1;
117 }
118 }
119
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);
125 errno = ENFILE;
126 return -1;
127 }
128
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;
135
136 nfs_destroy_url(url);
137
138 LD_NFS_DPRINTF(9, "open(%s) == %d", path, fd);
139 return fd;
140 }
141
142 return real_open(path, flags, mode);
143 }
144
145 int open64(const char *path, int flags, mode_t mode)
146 {
147 return open(path, flags | O_LARGEFILE, mode);
148 }
149
150 int (*real_close)(int fd);
151
152 int close(int fd)
153 {
154 if (nfs_fd_list[fd].is_nfs == 1) {
155 int i;
156
157 LD_NFS_DPRINTF(9, "close(%d)", fd);
158
159 nfs_fd_list[fd].is_nfs = 0;
160
161 nfs_close(nfs_fd_list[fd].nfs, nfs_fd_list[fd].fh);
162 nfs_fd_list[fd].fh = NULL;
163
164 nfs_destroy_context(nfs_fd_list[fd].nfs);
165 nfs_fd_list[fd].nfs = NULL;
166
167 free(discard_const(nfs_fd_list[fd].path));
168 nfs_fd_list[fd].path = NULL;
169
170 return 0;
171 }
172
173 return real_close(fd);
174 }
175
176 ssize_t (*real_read)(int fd, void *buf, size_t count);
177
178 ssize_t read(int fd, void *buf, size_t count)
179 {
180 if (nfs_fd_list[fd].is_nfs == 1) {
181 int ret;
182
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,
185 count, buf)) < 0) {
186 errno = -ret;
187 return -1;
188 }
189 return ret;
190 }
191 return real_read(fd, buf, count);
192 }
193
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) {
197 int ret;
198
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) {
203 errno = -ret;
204 return -1;
205 }
206 return ret;
207 }
208 return real_pread(fd, buf, count, offset);
209 }
210
211 ssize_t (*real_write)(int fd, const void *buf, size_t count);
212
213 ssize_t write(int fd, const void *buf, size_t count)
214 {
215 if (nfs_fd_list[fd].is_nfs == 1) {
216 int ret;
217
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,
220 count,
221 (char *)discard_const(buf))) < 0) {
222 errno = -ret;
223 return -1;
224 }
225 return ret;
226 }
227 return real_write(fd, buf, count);
228 }
229
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) {
233 int ret;
234
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,
238 offset, count,
239 (char *)discard_const(buf))) < 0) {
240 errno = -ret;
241 return -1;
242 }
243 return ret;
244 }
245 return real_pwrite(fd, buf, count, offset);
246 }
247
248 int (*real_dup2)(int oldfd, int newfd);
249
250 int dup2(int oldfd, int newfd)
251 {
252 close(newfd);
253
254 if (nfs_fd_list[oldfd].is_nfs == 1) {
255 struct nfs_context *nfs;
256 struct nfs_url *url;
257 struct nfsfh *fh = NULL;
258 int ret, fd;
259
260 LD_NFS_DPRINTF(9, "dup2(%s:%d, %d)", nfs_fd_list[oldfd].path,
261 oldfd, newfd);
262 nfs = nfs_init_context();
263 if (nfs == NULL) {
264 LD_NFS_DPRINTF(1, "Failed to create context");
265 errno = ENOMEM;
266 return -1;
267 }
268
269 url = nfs_parse_url_full(nfs, nfs_fd_list[oldfd].path);
270 if (url == NULL) {
271 LD_NFS_DPRINTF(1, "Failed to parse URL: %s\n",
272 nfs_get_error(nfs));
273 nfs_destroy_context(nfs);
274 errno = EINVAL;
275 return -1;
276 }
277
278 if (nfs_mount(nfs, url->server, url->path) != 0) {
279 LD_NFS_DPRINTF(1, "Failed to mount nfs share : %s\n",
280 nfs_get_error(nfs));
281 nfs_destroy_url(url);
282 nfs_destroy_context(nfs);
283 errno = EINVAL;
284 return -1;
285 }
286
287 if ((ret = nfs_open(nfs, url->file, nfs_fd_list[oldfd].mode,
288 &fh)) != 0) {
289 LD_NFS_DPRINTF(1, "Failed to open nfs file : %s\n",
290 nfs_get_error(nfs));
291 nfs_destroy_url(url);
292 nfs_destroy_context(nfs);
293 errno = -ret;
294 return -1;
295 }
296
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",
301 errno);
302 return -1;
303 }
304
305 close(rpc_get_fd(nfs_get_rpc_context(nfs)));
306 rpc_set_fd(nfs_get_rpc_context(nfs), newfd);
307 }
308
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);
314 errno = ENFILE;
315 return -1;
316 }
317
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;
324
325 nfs_destroy_url(url);
326
327 LD_NFS_DPRINTF(9, "dup2(%s) successful",
328 nfs_fd_list[oldfd].path);
329 return fd;
330 }
331
332 return real_dup2(oldfd, newfd);
333 }
334
335 int (*real_xstat)(int ver, __const char *path, struct stat *buf);
336
337 int __xstat(int ver, const char *path, struct stat *buf)
338 {
339 if (!strncmp(path, "nfs:", 4)) {
340 int fd, ret;
341
342 LD_NFS_DPRINTF(9, "__xstat(%s)", path);
343 fd = open(path, 0, 0);
344 if (fd == -1) {
345 return fd;
346 }
347
348 ret = __fxstat(ver, fd, buf);
349 close(fd);
350 return ret;
351 }
352
353 return real_xstat(ver, path, buf);
354 }
355
356 int (*real_xstat64)(int ver, __const char *path, struct stat64 *buf);
357
358 int __xstat64(int ver, const char *path, struct stat64 *buf)
359 {
360 if (!strncmp(path, "nfs:", 4)) {
361 int fd, ret;
362
363 LD_NFS_DPRINTF(9, "__xstat64(%s)", path);
364 fd = open(path, 0, 0);
365 if (fd == -1) {
366 return fd;
367 }
368
369 ret = __fxstat64(ver, fd, buf);
370 close(fd);
371 return ret;
372 }
373
374 return real_xstat64(ver, path, buf);
375 }
376
377 int (*real_lxstat)(int ver, __const char *path, struct stat *buf);
378
379 int __lxstat(int ver, const char *path, struct stat *buf)
380 {
381 if (!strncmp(path, "nfs:", 4)) {
382 int fd, ret;
383
384 LD_NFS_DPRINTF(9, "__lxstat(%s)", path);
385 fd = open(path, 0, 0);
386 if (fd == -1) {
387 return fd;
388 }
389
390 ret = __fxstat(ver, fd, buf);
391 close(fd);
392 return ret;
393 }
394
395 return real_lxstat(ver, path, buf);
396 }
397
398 int (*real_lxstat64)(int ver, __const char *path, struct stat64 *buf);
399
400 int __lxstat64(int ver, const char *path, struct stat64 *buf)
401 {
402 if (!strncmp(path, "nfs:", 4)) {
403 int fd, ret;
404
405 LD_NFS_DPRINTF(9, "__lxstat64(%s)", path);
406 fd = open(path, 0, 0);
407 if (fd == -1) {
408 return fd;
409 }
410
411 ret = __fxstat64(ver, fd, buf);
412 close(fd);
413 return ret;
414 }
415
416 return real_lxstat64(ver, path, buf);
417 }
418
419 int (*real_fxstat)(int ver, int fd, struct stat *buf);
420
421 int __fxstat(int ver, int fd, struct stat *buf)
422 {
423 if (nfs_fd_list[fd].is_nfs == 1) {
424 int ret;
425 struct stat64 st64;
426
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) {
430 errno = -ret;
431 return -1;
432 }
433
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;
447
448 LD_NFS_DPRINTF(9, "__fxstat(%d) success", fd);
449 return ret;
450 }
451
452 return real_fxstat(ver, fd, buf);
453 }
454
455 int (*real_fxstat64)(int ver, int fd, struct stat64 *buf);
456
457 int __fxstat64(int ver, int fd, struct stat64 *buf)
458 {
459 if (nfs_fd_list[fd].is_nfs == 1) {
460 int ret;
461 struct stat64 st64;
462
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) {
466 errno = -ret;
467 return -1;
468 }
469
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;
483
484 LD_NFS_DPRINTF(9, "__fxstat64(%d) success", fd);
485 return ret;
486 }
487
488 return real_fxstat64(ver, fd, buf);
489 }
490
491 int (*real_fallocate)(int fd, int mode, off_t offset, off_t len);
492
493 int fallocate(int fd, int mode, off_t offset, off_t len)
494 {
495 if (nfs_fd_list[fd].is_nfs == 1) {
496 LD_NFS_DPRINTF(9, "fallocate(%d)", fd);
497 errno = EOPNOTSUPP;
498 return -1;
499 }
500
501 return real_fallocate(fd, mode, offset, len);
502 }
503
504 int (*real_ftruncate)(int fd, off_t len);
505
506 int ftruncate(int fd, off_t len)
507 {
508 if (nfs_fd_list[fd].is_nfs == 1) {
509 int ret;
510
511 LD_NFS_DPRINTF(9, "ftruncate(%d, %d)", fd, (int)len);
512 if ((ret = nfs_ftruncate(nfs_fd_list[fd].nfs,
513 nfs_fd_list[fd].fh,
514 len)) < 0) {
515 errno = -ret;
516 return -1;
517 }
518 return 0;
519 }
520
521 return real_ftruncate(fd, len);
522 }
523
524 int (*real_truncate)(const char *path, off_t len);
525
526 int truncate(const char *path, off_t len)
527 {
528 if (!strncmp(path, "nfs:", 4)) {
529 int fd, ret;
530
531 LD_NFS_DPRINTF(9, "truncate(%s, %d)", path, (int)len);
532 fd = open(path, 0, 0);
533 if (fd == -1) {
534 return fd;
535 }
536
537 ret = ftruncate(fd, len);
538 close(fd);
539 return ret;
540 }
541
542 return real_truncate(path, len);
543 }
544
545 int (*real_fchmod)(int fd, mode_t mode);
546
547 int fchmod(int fd, mode_t mode)
548 {
549 if (nfs_fd_list[fd].is_nfs == 1) {
550 int ret;
551
552 LD_NFS_DPRINTF(9, "fchmod(%d, %o)", fd, (int)mode);
553 if ((ret = nfs_fchmod(nfs_fd_list[fd].nfs,
554 nfs_fd_list[fd].fh,
555 mode)) < 0) {
556 errno = -ret;
557 return -1;
558 }
559 return 0;
560 }
561
562 return real_fchmod(fd, mode);
563 }
564
565 int (*real_chmod)(const char *path, mode_t mode);
566
567 int chmod(const char *path, mode_t mode)
568 {
569 if (!strncmp(path, "nfs:", 4)) {
570 int fd, ret;
571
572 LD_NFS_DPRINTF(9, "chmod(%s, %o)", path, (int)mode);
573 fd = open(path, 0, 0);
574 if (fd == -1) {
575 return fd;
576 }
577
578 ret = fchmod(fd, mode);
579 close(fd);
580 return ret;
581 }
582
583 return real_chmod(path, mode);
584 }
585
586 static void __attribute__((constructor)) _init(void)
587 {
588 int i;
589
590 if (getenv("LD_NFS_DEBUG") != NULL) {
591 debug = atoi(getenv("LD_NFS_DEBUG"));
592 }
593
594 real_open = dlsym(RTLD_NEXT, "open");
595 if (real_open == NULL) {
596 LD_NFS_DPRINTF(0, "Failed to dlsym(open)");
597 exit(10);
598 }
599
600 real_close = dlsym(RTLD_NEXT, "close");
601 if (real_close == NULL) {
602 LD_NFS_DPRINTF(0, "Failed to dlsym(close)");
603 exit(10);
604 }
605
606 real_read = dlsym(RTLD_NEXT, "read");
607 if (real_read == NULL) {
608 LD_NFS_DPRINTF(0, "Failed to dlsym(read)");
609 exit(10);
610 }
611
612 real_pread = dlsym(RTLD_NEXT, "pread");
613 if (real_pread == NULL) {
614 LD_NFS_DPRINTF(0, "Failed to dlsym(pread)");
615 exit(10);
616 }
617
618 real_write = dlsym(RTLD_NEXT, "write");
619 if (real_write == NULL) {
620 LD_NFS_DPRINTF(0, "Failed to dlsym(write)");
621 exit(10);
622 }
623
624 real_pwrite = dlsym(RTLD_NEXT, "pwrite");
625 if (real_pwrite == NULL) {
626 LD_NFS_DPRINTF(0, "Failed to dlsym(pwrite)");
627 exit(10);
628 }
629
630 real_xstat = dlsym(RTLD_NEXT, "__xstat");
631 if (real_xstat == NULL) {
632 LD_NFS_DPRINTF(0, "Failed to dlsym(__xstat)");
633 exit(10);
634 }
635
636 real_xstat64 = dlsym(RTLD_NEXT, "__xstat64");
637 if (real_xstat64 == NULL) {
638 LD_NFS_DPRINTF(0, "Failed to dlsym(__xstat64)");
639 }
640
641 real_lxstat = dlsym(RTLD_NEXT, "__lxstat");
642 if (real_lxstat == NULL) {
643 LD_NFS_DPRINTF(0, "Failed to dlsym(__lxstat)");
644 exit(10);
645 }
646
647 real_lxstat64 = dlsym(RTLD_NEXT, "__lxstat64");
648 if (real_lxstat64 == NULL) {
649 LD_NFS_DPRINTF(0, "Failed to dlsym(_lxstat64)");
650 exit(10);
651 }
652
653 real_fxstat = dlsym(RTLD_NEXT, "__fxstat");
654 if (real_fxstat == NULL) {
655 LD_NFS_DPRINTF(0, "Failed to dlsym(__fxstat)");
656 exit(10);
657 }
658
659 real_fxstat64 = dlsym(RTLD_NEXT, "__fxstat64");
660 if (real_fxstat64 == NULL) {
661 LD_NFS_DPRINTF(0, "Failed to dlsym(__fxstat64)");
662 exit(10);
663 }
664
665 real_fallocate = dlsym(RTLD_NEXT, "fallocate");
666 if (real_fallocate == NULL) {
667 LD_NFS_DPRINTF(0, "Failed to dlsym(fallocate)");
668 exit(10);
669 }
670
671 real_dup2 = dlsym(RTLD_NEXT, "dup2");
672 if (real_dup2 == NULL) {
673 LD_NFS_DPRINTF(0, "Failed to dlsym(dup2)");
674 exit(10);
675 }
676
677 real_truncate = dlsym(RTLD_NEXT, "truncate");
678 if (real_truncate == NULL) {
679 LD_NFS_DPRINTF(0, "Failed to dlsym(truncate)");
680 exit(10);
681 }
682
683 real_ftruncate = dlsym(RTLD_NEXT, "ftruncate");
684 if (real_ftruncate == NULL) {
685 LD_NFS_DPRINTF(0, "Failed to dlsym(ftruncate)");
686 exit(10);
687 }
688
689 real_chmod = dlsym(RTLD_NEXT, "chmod");
690 if (real_chmod == NULL) {
691 LD_NFS_DPRINTF(0, "Failed to dlsym(chmod)");
692 exit(10);
693 }
694
695 real_fchmod = dlsym(RTLD_NEXT, "fchmod");
696 if (real_fchmod == NULL) {
697 LD_NFS_DPRINTF(0, "Failed to dlsym(fchmod)");
698 exit(10);
699 }
700 }