2 Copyright (C) 2010 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 Lesser General Public License as published by
6 the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
14 You should have received a copy of the GNU Lesser General Public License
15 along with this program; if not, see <http://www.gnu.org/licenses/>.
18 * High level api to nfs filesystems
26 #include <sys/types.h>
28 #include <sys/statvfs.h>
29 #include <sys/ioctl.h>
34 #include <sys/socket.h>
38 #include "libnfs-raw.h"
39 #include "libnfs-raw-mount.h"
40 #include "libnfs-raw-nfs.h"
41 #include "libnfs-private.h"
52 static void wait_for_reply(struct rpc_context
*rpc
, struct sync_cb_data
*cb_data
)
56 while (!cb_data
->is_finished
) {
58 pfd
.fd
= rpc_get_fd(rpc
);
59 pfd
.events
= rpc_which_events(rpc
);
60 if (poll(&pfd
, 1, -1) < 0) {
61 rpc_set_error(rpc
, "Poll failed");
62 cb_data
->status
= -EIO
;
65 if (rpc_service(rpc
, pfd
.revents
) < 0) {
66 rpc_set_error(rpc
, "rpc_service failed");
67 cb_data
->status
= -EIO
;
70 if (rpc_get_fd(rpc
) == -1) {
71 rpc_set_error(rpc
, "Socket closed\n");
77 static void wait_for_nfs_reply(struct nfs_context
*nfs
, struct sync_cb_data
*cb_data
)
81 while (!cb_data
->is_finished
) {
83 pfd
.fd
= nfs_get_fd(nfs
);
84 pfd
.events
= nfs_which_events(nfs
);
85 if (poll(&pfd
, 1, -1) < 0) {
86 nfs_set_error(nfs
, "Poll failed");
87 cb_data
->status
= -EIO
;
90 if (nfs_service(nfs
, pfd
.revents
) < 0) {
91 nfs_set_error(nfs
, "nfs_service failed");
92 cb_data
->status
= -EIO
;
95 if (nfs_get_fd(nfs
) == -1) {
96 char *server
= strdup(nfs_get_server(nfs
));
97 char *export
= strdup(nfs_get_export(nfs
));
99 if (nfs_mount(nfs
, server
, export
) != 0) {
100 nfs_set_error(nfs
, "Failed to reconnect to nfs server %s", nfs_get_error(nfs
));
117 * connect to the server and mount the export
119 static void mount_cb(int status
, struct nfs_context
*nfs
, void *data
, void *private_data
)
121 struct sync_cb_data
*cb_data
= private_data
;
123 cb_data
->is_finished
= 1;
124 cb_data
->status
= status
;
127 nfs_set_error(nfs
, "mount/mnt call failed with \"%s\"", (char *)data
);
132 int nfs_mount(struct nfs_context
*nfs
, const char *server
, const char *export
)
134 struct sync_cb_data cb_data
;
136 cb_data
.is_finished
= 0;
138 if (nfs_mount_async(nfs
, server
, export
, mount_cb
, &cb_data
) != 0) {
139 nfs_set_error(nfs
, "nfs_mount_async failed");
143 wait_for_nfs_reply(nfs
, &cb_data
);
145 return cb_data
.status
;
152 static void stat_cb(int status
, struct nfs_context
*nfs
, void *data
, void *private_data
)
154 struct sync_cb_data
*cb_data
= private_data
;
156 cb_data
->is_finished
= 1;
157 cb_data
->status
= status
;
160 nfs_set_error(nfs
, "stat call failed with \"%s\"", (char *)data
);
164 memcpy(cb_data
->return_data
, data
, sizeof(struct stat
));
167 int nfs_stat(struct nfs_context
*nfs
, const char *path
, struct stat
*st
)
169 struct sync_cb_data cb_data
;
171 cb_data
.is_finished
= 0;
172 cb_data
.return_data
= st
;
174 if (nfs_stat_async(nfs
, path
, stat_cb
, &cb_data
) != 0) {
175 nfs_set_error(nfs
, "nfs_stat_async failed");
179 wait_for_nfs_reply(nfs
, &cb_data
);
181 return cb_data
.status
;
190 static void open_cb(int status
, struct nfs_context
*nfs
, void *data
, void *private_data
)
192 struct sync_cb_data
*cb_data
= private_data
;
193 struct nfsfh
*fh
, **nfsfh
;
195 cb_data
->is_finished
= 1;
196 cb_data
->status
= status
;
199 nfs_set_error(nfs
, "open call failed with \"%s\"", (char *)data
);
204 nfsfh
= cb_data
->return_data
;
208 int nfs_open(struct nfs_context
*nfs
, const char *path
, int mode
, struct nfsfh
**nfsfh
)
210 struct sync_cb_data cb_data
;
212 cb_data
.is_finished
= 0;
213 cb_data
.return_data
= nfsfh
;
215 if (nfs_open_async(nfs
, path
, mode
, open_cb
, &cb_data
) != 0) {
216 nfs_set_error(nfs
, "nfs_open_async failed");
220 wait_for_nfs_reply(nfs
, &cb_data
);
222 return cb_data
.status
;
231 static void pread_cb(int status
, struct nfs_context
*nfs
, void *data
, void *private_data
)
233 struct sync_cb_data
*cb_data
= private_data
;
235 cb_data
->is_finished
= 1;
236 cb_data
->status
= status
;
239 nfs_set_error(nfs
, "pread call failed with \"%s\"", (char *)data
);
243 buffer
= cb_data
->return_data
;
244 memcpy(buffer
, (char *)data
, status
);
247 int nfs_pread(struct nfs_context
*nfs
, struct nfsfh
*nfsfh
, off_t offset
, size_t count
, char *buffer
)
249 struct sync_cb_data cb_data
;
251 cb_data
.is_finished
= 0;
252 cb_data
.return_data
= buffer
;
254 if (nfs_pread_async(nfs
, nfsfh
, offset
, count
, pread_cb
, &cb_data
) != 0) {
255 nfs_set_error(nfs
, "nfs_pread_async failed");
259 wait_for_nfs_reply(nfs
, &cb_data
);
261 return cb_data
.status
;
267 int nfs_read(struct nfs_context
*nfs
, struct nfsfh
*nfsfh
, size_t count
, char *buffer
)
269 return nfs_pread(nfs
, nfsfh
, nfs_get_current_offset(nfsfh
), count
, buffer
);
275 static void close_cb(int status
, struct nfs_context
*nfs
, void *data
, void *private_data
)
277 struct sync_cb_data
*cb_data
= private_data
;
278 cb_data
->is_finished
= 1;
279 cb_data
->status
= status
;
282 nfs_set_error(nfs
, "close call failed with \"%s\"", (char *)data
);
287 int nfs_close(struct nfs_context
*nfs
, struct nfsfh
*nfsfh
)
289 struct sync_cb_data cb_data
;
291 cb_data
.is_finished
= 0;
293 if (nfs_close_async(nfs
, nfsfh
, close_cb
, &cb_data
) != 0) {
294 nfs_set_error(nfs
, "nfs_close_async failed");
298 wait_for_nfs_reply(nfs
, &cb_data
);
300 return cb_data
.status
;
309 int nfs_fstat(struct nfs_context
*nfs
, struct nfsfh
*nfsfh
, struct stat
*st
)
311 struct sync_cb_data cb_data
;
313 cb_data
.is_finished
= 0;
314 cb_data
.return_data
= st
;
316 if (nfs_fstat_async(nfs
, nfsfh
, stat_cb
, &cb_data
) != 0) {
317 nfs_set_error(nfs
, "nfs_fstat_async failed");
321 wait_for_nfs_reply(nfs
, &cb_data
);
323 return cb_data
.status
;
330 static void pwrite_cb(int status
, struct nfs_context
*nfs
, void *data
, void *private_data
)
332 struct sync_cb_data
*cb_data
= private_data
;
333 cb_data
->is_finished
= 1;
334 cb_data
->status
= status
;
337 nfs_set_error(nfs
, "pwrite call failed with \"%s\"", (char *)data
);
342 int nfs_pwrite(struct nfs_context
*nfs
, struct nfsfh
*nfsfh
, off_t offset
, size_t count
, char *buf
)
344 struct sync_cb_data cb_data
;
346 cb_data
.is_finished
= 0;
348 if (nfs_pwrite_async(nfs
, nfsfh
, offset
, count
, buf
, pwrite_cb
, &cb_data
) != 0) {
349 nfs_set_error(nfs
, "nfs_pwrite_async failed");
353 wait_for_nfs_reply(nfs
, &cb_data
);
355 return cb_data
.status
;
361 int nfs_write(struct nfs_context
*nfs
, struct nfsfh
*nfsfh
, size_t count
, char *buf
)
363 return nfs_pwrite(nfs
, nfsfh
, nfs_get_current_offset(nfsfh
), count
, buf
);
370 static void fsync_cb(int status
, struct nfs_context
*nfs
, void *data
, void *private_data
)
372 struct sync_cb_data
*cb_data
= private_data
;
373 cb_data
->is_finished
= 1;
374 cb_data
->status
= status
;
377 nfs_set_error(nfs
, "fsync call failed with \"%s\"", (char *)data
);
382 int nfs_fsync(struct nfs_context
*nfs
, struct nfsfh
*nfsfh
)
384 struct sync_cb_data cb_data
;
386 cb_data
.is_finished
= 0;
388 if (nfs_fsync_async(nfs
, nfsfh
, fsync_cb
, &cb_data
) != 0) {
389 nfs_set_error(nfs
, "nfs_fsync_async failed");
393 wait_for_nfs_reply(nfs
, &cb_data
);
395 return cb_data
.status
;
404 static void ftruncate_cb(int status
, struct nfs_context
*nfs
, void *data
, void *private_data
)
406 struct sync_cb_data
*cb_data
= private_data
;
407 cb_data
->is_finished
= 1;
408 cb_data
->status
= status
;
411 nfs_set_error(nfs
, "ftruncate call failed with \"%s\"", (char *)data
);
416 int nfs_ftruncate(struct nfs_context
*nfs
, struct nfsfh
*nfsfh
, off_t length
)
418 struct sync_cb_data cb_data
;
420 cb_data
.is_finished
= 0;
422 if (nfs_ftruncate_async(nfs
, nfsfh
, length
, ftruncate_cb
, &cb_data
) != 0) {
423 nfs_set_error(nfs
, "nfs_ftruncate_async failed");
427 wait_for_nfs_reply(nfs
, &cb_data
);
429 return cb_data
.status
;
437 static void truncate_cb(int status
, struct nfs_context
*nfs
, void *data
, void *private_data
)
439 struct sync_cb_data
*cb_data
= private_data
;
440 cb_data
->is_finished
= 1;
441 cb_data
->status
= status
;
444 nfs_set_error(nfs
, "truncate call failed with \"%s\"", (char *)data
);
449 int nfs_truncate(struct nfs_context
*nfs
, const char *path
, off_t length
)
451 struct sync_cb_data cb_data
;
453 cb_data
.is_finished
= 0;
455 if (nfs_truncate_async(nfs
, path
, length
, truncate_cb
, &cb_data
) != 0) {
456 nfs_set_error(nfs
, "nfs_ftruncate_async failed");
460 wait_for_nfs_reply(nfs
, &cb_data
);
462 return cb_data
.status
;
472 static void mkdir_cb(int status
, struct nfs_context
*nfs
, void *data
, void *private_data
)
474 struct sync_cb_data
*cb_data
= private_data
;
475 cb_data
->is_finished
= 1;
476 cb_data
->status
= status
;
479 nfs_set_error(nfs
, "mkdir call failed with \"%s\"", (char *)data
);
484 int nfs_mkdir(struct nfs_context
*nfs
, const char *path
)
486 struct sync_cb_data cb_data
;
488 cb_data
.is_finished
= 0;
490 if (nfs_mkdir_async(nfs
, path
, mkdir_cb
, &cb_data
) != 0) {
491 nfs_set_error(nfs
, "nfs_mkdir_async failed");
495 wait_for_nfs_reply(nfs
, &cb_data
);
497 return cb_data
.status
;
507 static void rmdir_cb(int status
, struct nfs_context
*nfs
, void *data
, void *private_data
)
509 struct sync_cb_data
*cb_data
= private_data
;
510 cb_data
->is_finished
= 1;
511 cb_data
->status
= status
;
514 nfs_set_error(nfs
, "rmdir call failed with \"%s\"", (char *)data
);
519 int nfs_rmdir(struct nfs_context
*nfs
, const char *path
)
521 struct sync_cb_data cb_data
;
523 cb_data
.is_finished
= 0;
525 if (nfs_rmdir_async(nfs
, path
, rmdir_cb
, &cb_data
) != 0) {
526 nfs_set_error(nfs
, "nfs_rmdir_async failed");
530 wait_for_nfs_reply(nfs
, &cb_data
);
532 return cb_data
.status
;
540 static void creat_cb(int status
, struct nfs_context
*nfs
, void *data
, void *private_data
)
542 struct sync_cb_data
*cb_data
= private_data
;
543 struct nfsfh
*fh
, **nfsfh
;
545 cb_data
->is_finished
= 1;
546 cb_data
->status
= status
;
549 nfs_set_error(nfs
, "creat call failed with \"%s\"", (char *)data
);
554 nfsfh
= cb_data
->return_data
;
558 int nfs_creat(struct nfs_context
*nfs
, const char *path
, int mode
, struct nfsfh
**nfsfh
)
560 struct sync_cb_data cb_data
;
562 cb_data
.is_finished
= 0;
563 cb_data
.return_data
= nfsfh
;
565 if (nfs_creat_async(nfs
, path
, mode
, creat_cb
, &cb_data
) != 0) {
566 nfs_set_error(nfs
, "nfs_creat_async failed");
570 wait_for_nfs_reply(nfs
, &cb_data
);
572 return cb_data
.status
;
581 static void unlink_cb(int status
, struct nfs_context
*nfs
, void *data
, void *private_data
)
583 struct sync_cb_data
*cb_data
= private_data
;
585 cb_data
->is_finished
= 1;
586 cb_data
->status
= status
;
589 nfs_set_error(nfs
, "unlink call failed with \"%s\"", (char *)data
);
594 int nfs_unlink(struct nfs_context
*nfs
, const char *path
)
596 struct sync_cb_data cb_data
;
598 cb_data
.is_finished
= 0;
600 if (nfs_unlink_async(nfs
, path
, unlink_cb
, &cb_data
) != 0) {
601 nfs_set_error(nfs
, "nfs_unlink_async failed");
605 wait_for_nfs_reply(nfs
, &cb_data
);
607 return cb_data
.status
;
615 static void opendir_cb(int status
, struct nfs_context
*nfs
, void *data
, void *private_data
)
617 struct sync_cb_data
*cb_data
= private_data
;
618 struct nfsdir
*dir
, **nfsdir
;
620 cb_data
->is_finished
= 1;
621 cb_data
->status
= status
;
624 nfs_set_error(nfs
, "opendir call failed with \"%s\"", (char *)data
);
629 nfsdir
= cb_data
->return_data
;
633 int nfs_opendir(struct nfs_context
*nfs
, const char *path
, struct nfsdir
**nfsdir
)
635 struct sync_cb_data cb_data
;
637 cb_data
.is_finished
= 0;
638 cb_data
.return_data
= nfsdir
;
640 if (nfs_opendir_async(nfs
, path
, opendir_cb
, &cb_data
) != 0) {
641 nfs_set_error(nfs
, "nfs_opendir_async failed");
645 wait_for_nfs_reply(nfs
, &cb_data
);
647 return cb_data
.status
;
654 static void lseek_cb(int status
, struct nfs_context
*nfs
, void *data
, void *private_data
)
656 struct sync_cb_data
*cb_data
= private_data
;
658 cb_data
->is_finished
= 1;
659 cb_data
->status
= status
;
662 nfs_set_error(nfs
, "lseek call failed with \"%s\"", (char *)data
);
666 if (cb_data
->return_data
!= NULL
) {
667 memcpy(cb_data
->return_data
, data
, sizeof(off_t
));
671 int nfs_lseek(struct nfs_context
*nfs
, struct nfsfh
*nfsfh
, off_t offset
, int whence
, off_t
*current_offset
)
673 struct sync_cb_data cb_data
;
675 cb_data
.is_finished
= 0;
676 cb_data
.return_data
= current_offset
;
678 if (nfs_lseek_async(nfs
, nfsfh
, offset
, whence
, lseek_cb
, &cb_data
) != 0) {
679 nfs_set_error(nfs
, "nfs_lseek_async failed");
683 wait_for_nfs_reply(nfs
, &cb_data
);
685 return cb_data
.status
;
693 static void statvfs_cb(int status
, struct nfs_context
*nfs
, void *data
, void *private_data
)
695 struct sync_cb_data
*cb_data
= private_data
;
697 cb_data
->is_finished
= 1;
698 cb_data
->status
= status
;
701 nfs_set_error(nfs
, "statvfs call failed with \"%s\"", (char *)data
);
705 memcpy(cb_data
->return_data
, data
, sizeof(struct statvfs
));
708 int nfs_statvfs(struct nfs_context
*nfs
, const char *path
, struct statvfs
*svfs
)
710 struct sync_cb_data cb_data
;
712 cb_data
.is_finished
= 0;
713 cb_data
.return_data
= svfs
;
715 if (nfs_statvfs_async(nfs
, path
, statvfs_cb
, &cb_data
) != 0) {
716 nfs_set_error(nfs
, "nfs_statvfs_async failed");
720 wait_for_nfs_reply(nfs
, &cb_data
);
722 return cb_data
.status
;
732 static void readlink_cb(int status
, struct nfs_context
*nfs
, void *data
, void *private_data
)
734 struct sync_cb_data
*cb_data
= private_data
;
736 cb_data
->is_finished
= 1;
737 cb_data
->status
= status
;
740 nfs_set_error(nfs
, "readlink call failed with \"%s\"", (char *)data
);
744 if (strlen(data
) > (size_t)cb_data
->return_int
) {
745 nfs_set_error(nfs
, "Too small buffer for readlink");
746 cb_data
->status
= -ENAMETOOLONG
;
750 memcpy(cb_data
->return_data
, data
, strlen(data
)+1);
753 int nfs_readlink(struct nfs_context
*nfs
, const char *path
, char *buf
, int bufsize
)
755 struct sync_cb_data cb_data
;
757 cb_data
.is_finished
= 0;
758 cb_data
.return_data
= buf
;
759 cb_data
.return_int
= bufsize
;
761 if (nfs_readlink_async(nfs
, path
, readlink_cb
, &cb_data
) != 0) {
762 nfs_set_error(nfs
, "nfs_readlink_async failed");
766 wait_for_nfs_reply(nfs
, &cb_data
);
768 return cb_data
.status
;
776 static void chmod_cb(int status
, struct nfs_context
*nfs
, void *data
, void *private_data
)
778 struct sync_cb_data
*cb_data
= private_data
;
780 cb_data
->is_finished
= 1;
781 cb_data
->status
= status
;
784 nfs_set_error(nfs
, "chmod call failed with \"%s\"", (char *)data
);
789 int nfs_chmod(struct nfs_context
*nfs
, const char *path
, int mode
)
791 struct sync_cb_data cb_data
;
793 cb_data
.is_finished
= 0;
795 if (nfs_chmod_async(nfs
, path
, mode
, chmod_cb
, &cb_data
) != 0) {
796 nfs_set_error(nfs
, "nfs_chmod_async failed");
800 wait_for_nfs_reply(nfs
, &cb_data
);
802 return cb_data
.status
;
811 static void fchmod_cb(int status
, struct nfs_context
*nfs
, void *data
, void *private_data
)
813 struct sync_cb_data
*cb_data
= private_data
;
815 cb_data
->is_finished
= 1;
816 cb_data
->status
= status
;
819 nfs_set_error(nfs
, "fchmod call failed with \"%s\"", (char *)data
);
824 int nfs_fchmod(struct nfs_context
*nfs
, struct nfsfh
*nfsfh
, int mode
)
826 struct sync_cb_data cb_data
;
828 cb_data
.is_finished
= 0;
830 if (nfs_fchmod_async(nfs
, nfsfh
, mode
, fchmod_cb
, &cb_data
) != 0) {
831 nfs_set_error(nfs
, "nfs_fchmod_async failed");
835 wait_for_nfs_reply(nfs
, &cb_data
);
837 return cb_data
.status
;
846 static void chown_cb(int status
, struct nfs_context
*nfs
, void *data
, void *private_data
)
848 struct sync_cb_data
*cb_data
= private_data
;
850 cb_data
->is_finished
= 1;
851 cb_data
->status
= status
;
854 nfs_set_error(nfs
, "chown call failed with \"%s\"", (char *)data
);
859 int nfs_chown(struct nfs_context
*nfs
, const char *path
, int uid
, int gid
)
861 struct sync_cb_data cb_data
;
863 cb_data
.is_finished
= 0;
865 if (nfs_chown_async(nfs
, path
, uid
, gid
, chown_cb
, &cb_data
) != 0) {
866 nfs_set_error(nfs
, "nfs_chown_async failed");
870 wait_for_nfs_reply(nfs
, &cb_data
);
872 return cb_data
.status
;
878 static void fchown_cb(int status
, struct nfs_context
*nfs
, void *data
, void *private_data
)
880 struct sync_cb_data
*cb_data
= private_data
;
882 cb_data
->is_finished
= 1;
883 cb_data
->status
= status
;
886 nfs_set_error(nfs
, "fchown call failed with \"%s\"", (char *)data
);
891 int nfs_fchown(struct nfs_context
*nfs
, struct nfsfh
*nfsfh
, int uid
, int gid
)
893 struct sync_cb_data cb_data
;
895 cb_data
.is_finished
= 0;
897 if (nfs_fchown_async(nfs
, nfsfh
, uid
, gid
, fchown_cb
, &cb_data
) != 0) {
898 nfs_set_error(nfs
, "nfs_fchown_async failed");
902 wait_for_nfs_reply(nfs
, &cb_data
);
904 return cb_data
.status
;
912 static void utimes_cb(int status
, struct nfs_context
*nfs
, void *data
, void *private_data
)
914 struct sync_cb_data
*cb_data
= private_data
;
916 cb_data
->is_finished
= 1;
917 cb_data
->status
= status
;
920 nfs_set_error(nfs
, "utimes call failed with \"%s\"", (char *)data
);
925 int nfs_utimes(struct nfs_context
*nfs
, const char *path
, struct timeval
*times
)
927 struct sync_cb_data cb_data
;
929 cb_data
.is_finished
= 0;
931 if (nfs_utimes_async(nfs
, path
, times
, utimes_cb
, &cb_data
) != 0) {
932 nfs_set_error(nfs
, "nfs_utimes_async failed");
936 wait_for_nfs_reply(nfs
, &cb_data
);
938 return cb_data
.status
;
946 static void utime_cb(int status
, struct nfs_context
*nfs
, void *data
, void *private_data
)
948 struct sync_cb_data
*cb_data
= private_data
;
950 cb_data
->is_finished
= 1;
951 cb_data
->status
= status
;
954 nfs_set_error(nfs
, "utime call failed with \"%s\"", (char *)data
);
959 int nfs_utime(struct nfs_context
*nfs
, const char *path
, struct utimbuf
*times
)
961 struct sync_cb_data cb_data
;
963 cb_data
.is_finished
= 0;
965 if (nfs_utime_async(nfs
, path
, times
, utime_cb
, &cb_data
) != 0) {
966 nfs_set_error(nfs
, "nfs_utimes_async failed");
970 wait_for_nfs_reply(nfs
, &cb_data
);
972 return cb_data
.status
;
981 static void access_cb(int status
, struct nfs_context
*nfs
, void *data
, void *private_data
)
983 struct sync_cb_data
*cb_data
= private_data
;
985 cb_data
->is_finished
= 1;
986 cb_data
->status
= status
;
989 nfs_set_error(nfs
, "access call failed with \"%s\"", (char *)data
);
994 int nfs_access(struct nfs_context
*nfs
, const char *path
, int mode
)
996 struct sync_cb_data cb_data
;
998 cb_data
.is_finished
= 0;
1000 if (nfs_access_async(nfs
, path
, mode
, access_cb
, &cb_data
) != 0) {
1001 nfs_set_error(nfs
, "nfs_access_async failed");
1005 wait_for_nfs_reply(nfs
, &cb_data
);
1007 return cb_data
.status
;
1015 static void symlink_cb(int status
, struct nfs_context
*nfs
, void *data
, void *private_data
)
1017 struct sync_cb_data
*cb_data
= private_data
;
1019 cb_data
->is_finished
= 1;
1020 cb_data
->status
= status
;
1023 nfs_set_error(nfs
, "symlink call failed with \"%s\"", (char *)data
);
1028 int nfs_symlink(struct nfs_context
*nfs
, const char *oldpath
, const char *newpath
)
1030 struct sync_cb_data cb_data
;
1032 cb_data
.is_finished
= 0;
1034 if (nfs_symlink_async(nfs
, oldpath
, newpath
, symlink_cb
, &cb_data
) != 0) {
1035 nfs_set_error(nfs
, "nfs_symlink_async failed");
1039 wait_for_nfs_reply(nfs
, &cb_data
);
1041 return cb_data
.status
;
1049 static void rename_cb(int status
, struct nfs_context
*nfs
, void *data
, void *private_data
)
1051 struct sync_cb_data
*cb_data
= private_data
;
1053 cb_data
->is_finished
= 1;
1054 cb_data
->status
= status
;
1057 nfs_set_error(nfs
, "rename call failed with \"%s\"", (char *)data
);
1062 int nfs_rename(struct nfs_context
*nfs
, const char *oldpath
, const char *newpath
)
1064 struct sync_cb_data cb_data
;
1066 cb_data
.is_finished
= 0;
1068 if (nfs_rename_async(nfs
, oldpath
, newpath
, rename_cb
, &cb_data
) != 0) {
1069 nfs_set_error(nfs
, "nfs_rename_async failed");
1073 wait_for_nfs_reply(nfs
, &cb_data
);
1075 return cb_data
.status
;
1083 static void link_cb(int status
, struct nfs_context
*nfs
, void *data
, void *private_data
)
1085 struct sync_cb_data
*cb_data
= private_data
;
1087 cb_data
->is_finished
= 1;
1088 cb_data
->status
= status
;
1091 nfs_set_error(nfs
, "link call failed with \"%s\"", (char *)data
);
1096 int nfs_link(struct nfs_context
*nfs
, const char *oldpath
, const char *newpath
)
1098 struct sync_cb_data cb_data
;
1100 cb_data
.is_finished
= 0;
1102 if (nfs_link_async(nfs
, oldpath
, newpath
, link_cb
, &cb_data
) != 0) {
1103 nfs_set_error(nfs
, "nfs_link_async failed");
1107 wait_for_nfs_reply(nfs
, &cb_data
);
1109 return cb_data
.status
;
1112 void mount_getexports_cb(struct rpc_context
*mount_context
, int status
, void *data
, void *private_data
)
1114 struct sync_cb_data
*cb_data
= private_data
;
1115 exports export
= *(exports
*)data
;
1117 cb_data
->is_finished
= 1;
1118 cb_data
->status
= status
;
1119 cb_data
->return_data
= NULL
;
1122 rpc_set_error(mount_context
, "mount/export call failed with \"%s\"", (char *)data
);
1126 while (export
!= NULL
) {
1129 new_export
= malloc(sizeof(*new_export
));
1130 memset(new_export
, 0, sizeof(*new_export
));
1131 new_export
->ex_dir
= strdup(export
->ex_dir
);
1132 new_export
->ex_next
= cb_data
->return_data
;
1134 cb_data
->return_data
= new_export
;
1136 export
= export
->ex_next
;
1140 struct exportnode
*mount_getexports(const char *server
)
1142 struct sync_cb_data cb_data
;
1143 struct rpc_context
*rpc
;
1146 cb_data
.is_finished
= 0;
1147 cb_data
.return_data
= NULL
;
1149 rpc
= rpc_init_context();
1150 if (mount_getexports_async(rpc
, server
, mount_getexports_cb
, &cb_data
) != 0) {
1151 rpc_destroy_context(rpc
);
1155 wait_for_reply(rpc
, &cb_data
);
1156 rpc_destroy_context(rpc
);
1158 return cb_data
.return_data
;
1161 void mount_free_export_list(struct exportnode
*exports
)
1163 struct exportnode
*tmp
;
1165 while ((tmp
= exports
)) {
1166 exports
= exports
->ex_next
;
1175 void free_nfs_srvr_list(struct nfs_server_list
*srv
)
1177 while (srv
!= NULL
) {
1178 struct nfs_server_list
*next
= srv
->next
;
1186 struct nfs_list_data
{
1188 struct nfs_server_list
*srvrs
;
1191 void callit_cb(struct rpc_context
*rpc
, int status
, void *data _U_
, void *private_data
)
1193 struct nfs_list_data
*srv_data
= private_data
;
1194 struct sockaddr
*sin
;
1196 struct nfs_server_list
*srvr
;
1198 if (status
== RPC_STATUS_CANCEL
) {
1202 srv_data
->status
= -1;
1206 sin
= rpc_get_recv_sockaddr(rpc
);
1208 rpc_set_error(rpc
, "failed to get sockaddr in CALLIT callback");
1209 srv_data
->status
= -1;
1213 if (getnameinfo(sin
, sizeof(struct sockaddr_in
), &hostdd
[0], sizeof(hostdd
), NULL
, 0, NI_NUMERICHOST
) < 0) {
1214 rpc_set_error(rpc
, "getnameinfo failed in CALLIT callback");
1215 srv_data
->status
= -1;
1219 /* check for dupes */
1220 for (srvr
= srv_data
->srvrs
; srvr
; srvr
= srvr
->next
) {
1221 if (!strcmp(hostdd
, srvr
->addr
)) {
1226 srvr
= malloc(sizeof(struct nfs_server_list
));
1228 rpc_set_error(rpc
, "Malloc failed when allocating server structure");
1229 srv_data
->status
= -1;
1233 srvr
->addr
= strdup(hostdd
);
1234 if (srvr
->addr
== NULL
) {
1235 rpc_set_error(rpc
, "Strdup failed when allocating server structure");
1237 srv_data
->status
= -1;
1241 srvr
->next
= srv_data
->srvrs
;
1242 srv_data
->srvrs
= srvr
;
1245 static int send_nfsd_probes(struct rpc_context
*rpc
, struct ifconf
*ifc
, struct nfs_list_data
*data
)
1249 for (ptr
=(char *)(ifc
->ifc_buf
); ptr
< (char *)(ifc
->ifc_buf
) + ifc
->ifc_len
; ) {
1253 ifr
= (struct ifreq
*)ptr
;
1254 #ifdef HAVE_SOCKADDR_LEN
1255 if (ifr
->ifr_addr
.sa_len
> sizeof(struct sockaddr
)) {
1256 ptr
+= sizeof(ifr
->ifr_name
) + ifr
->ifr_addr
.sa_len
;
1258 ptr
+= sizeof(ifr
->ifr_name
) + sizeof(struct sockaddr
);
1261 ptr
+= sizeof(struct ifreq
);
1264 if (ifr
->ifr_addr
.sa_family
!= AF_INET
) {
1267 if (ioctl(rpc_get_fd(rpc
), SIOCGIFFLAGS
, ifr
) < 0) {
1270 if (!(ifr
->ifr_flags
& IFF_UP
)) {
1273 if (ifr
->ifr_flags
& IFF_LOOPBACK
) {
1276 if (!(ifr
->ifr_flags
& IFF_BROADCAST
)) {
1279 if (ioctl(rpc_get_fd(rpc
), SIOCGIFBRDADDR
, ifr
) < 0) {
1282 if (getnameinfo(&ifr
->ifr_broadaddr
, sizeof(struct sockaddr_in
), &bcdd
[0], sizeof(bcdd
), NULL
, 0, NI_NUMERICHOST
) < 0) {
1285 if (rpc_set_udp_destination(rpc
, bcdd
, 111, 1) < 0) {
1289 if (rpc_pmap_callit_async(rpc
, MOUNT_PROGRAM
, 2, 0, NULL
, 0, callit_cb
, data
) < 0) {
1297 struct nfs_server_list
*nfs_find_local_servers(void)
1299 struct rpc_context
*rpc
;
1300 struct nfs_list_data data
= {0, NULL
};
1301 struct timeval tv_start
, tv_current
;
1306 rpc
= rpc_init_udp_context();
1311 if (rpc_bind_udp(rpc
, "0.0.0.0", 0) < 0) {
1312 rpc_destroy_context(rpc
);
1317 /* get list of all interfaces */
1318 size
= sizeof(struct ifreq
);
1322 while(ifc
.ifc_len
> (size
- sizeof(struct ifreq
))) {
1327 ifc
.ifc_buf
= malloc(size
);
1328 memset(ifc
.ifc_buf
, 0, size
);
1329 if (ioctl(rpc_get_fd(rpc
), SIOCGIFCONF
, (caddr_t
)&ifc
) < 0) {
1330 rpc_destroy_context(rpc
);
1336 for (loop
=0; loop
<3; loop
++) {
1337 if (send_nfsd_probes(rpc
, &ifc
, &data
) != 0) {
1338 rpc_destroy_context(rpc
);
1343 gettimeofday(&tv_start
, NULL
);
1347 pfd
.fd
= rpc_get_fd(rpc
);
1348 pfd
.events
= rpc_which_events(rpc
);
1350 gettimeofday(&tv_current
, NULL
);
1352 - (tv_current
.tv_sec
*1000 + tv_current
.tv_usec
/ 1000)
1353 + (tv_start
.tv_sec
*1000 + tv_start
.tv_usec
/ 1000);
1355 if (poll(&pfd
, 1, mpt
) < 0) {
1356 free_nfs_srvr_list(data
.srvrs
);
1357 rpc_destroy_context(rpc
);
1360 if (pfd
.revents
== 0) {
1364 if (rpc_service(rpc
, pfd
.revents
) < 0) {
1371 rpc_destroy_context(rpc
);
1373 if (data
.status
!= 0) {
1374 free_nfs_srvr_list(data
.srvrs
);