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
27 #include <sys/statvfs.h>
29 #include <sys/ioctl.h>
31 #include <sys/socket.h>
42 #include <sys/types.h>
46 #ifdef HAVE_SYS_SOCKIO_H
47 #include <sys/sockio.h>
50 #include "libnfs-raw.h"
51 #include "libnfs-raw-mount.h"
52 #include "libnfs-raw-nfs.h"
53 #include "libnfs-private.h"
64 static void wait_for_reply(struct rpc_context
*rpc
, struct sync_cb_data
*cb_data
)
68 while (!cb_data
->is_finished
) {
70 pfd
.fd
= rpc_get_fd(rpc
);
71 pfd
.events
= rpc_which_events(rpc
);
72 if (poll(&pfd
, 1, -1) < 0) {
73 rpc_set_error(rpc
, "Poll failed");
74 cb_data
->status
= -EIO
;
77 if (rpc_service(rpc
, pfd
.revents
) < 0) {
78 rpc_set_error(rpc
, "rpc_service failed");
79 cb_data
->status
= -EIO
;
82 if (rpc_get_fd(rpc
) == -1) {
83 rpc_set_error(rpc
, "Socket closed\n");
89 static void wait_for_nfs_reply(struct nfs_context
*nfs
, struct sync_cb_data
*cb_data
)
93 while (!cb_data
->is_finished
) {
95 pfd
.fd
= nfs_get_fd(nfs
);
96 pfd
.events
= nfs_which_events(nfs
);
97 if (poll(&pfd
, 1, -1) < 0) {
98 nfs_set_error(nfs
, "Poll failed");
99 cb_data
->status
= -EIO
;
102 if (nfs_service(nfs
, pfd
.revents
) < 0) {
103 nfs_set_error(nfs
, "nfs_service failed");
104 cb_data
->status
= -EIO
;
107 if (nfs_get_fd(nfs
) == -1) {
108 char *server
= strdup(nfs_get_server(nfs
));
109 char *export
= strdup(nfs_get_export(nfs
));
111 if (nfs_mount(nfs
, server
, export
) != 0) {
112 nfs_set_error(nfs
, "Failed to reconnect to nfs server %s", nfs_get_error(nfs
));
129 * connect to the server and mount the export
131 static void mount_cb(int status
, struct nfs_context
*nfs
, void *data
, void *private_data
)
133 struct sync_cb_data
*cb_data
= private_data
;
135 cb_data
->is_finished
= 1;
136 cb_data
->status
= status
;
139 nfs_set_error(nfs
, "mount/mnt call failed with \"%s\"", (char *)data
);
144 int nfs_mount(struct nfs_context
*nfs
, const char *server
, const char *export
)
146 struct sync_cb_data cb_data
;
148 cb_data
.is_finished
= 0;
150 if (nfs_mount_async(nfs
, server
, export
, mount_cb
, &cb_data
) != 0) {
151 nfs_set_error(nfs
, "nfs_mount_async failed");
155 wait_for_nfs_reply(nfs
, &cb_data
);
157 return cb_data
.status
;
164 static void stat_cb(int status
, struct nfs_context
*nfs
, void *data
, void *private_data
)
166 struct sync_cb_data
*cb_data
= private_data
;
168 cb_data
->is_finished
= 1;
169 cb_data
->status
= status
;
172 nfs_set_error(nfs
, "stat call failed with \"%s\"", (char *)data
);
176 memcpy(cb_data
->return_data
, data
, sizeof(struct stat
));
179 int nfs_stat(struct nfs_context
*nfs
, const char *path
, struct stat
*st
)
181 struct sync_cb_data cb_data
;
183 cb_data
.is_finished
= 0;
184 cb_data
.return_data
= st
;
186 if (nfs_stat_async(nfs
, path
, stat_cb
, &cb_data
) != 0) {
187 nfs_set_error(nfs
, "nfs_stat_async failed");
191 wait_for_nfs_reply(nfs
, &cb_data
);
193 return cb_data
.status
;
202 static void open_cb(int status
, struct nfs_context
*nfs
, void *data
, void *private_data
)
204 struct sync_cb_data
*cb_data
= private_data
;
205 struct nfsfh
*fh
, **nfsfh
;
207 cb_data
->is_finished
= 1;
208 cb_data
->status
= status
;
211 nfs_set_error(nfs
, "open call failed with \"%s\"", (char *)data
);
216 nfsfh
= cb_data
->return_data
;
220 int nfs_open(struct nfs_context
*nfs
, const char *path
, int mode
, struct nfsfh
**nfsfh
)
222 struct sync_cb_data cb_data
;
224 cb_data
.is_finished
= 0;
225 cb_data
.return_data
= nfsfh
;
227 if (nfs_open_async(nfs
, path
, mode
, open_cb
, &cb_data
) != 0) {
228 nfs_set_error(nfs
, "nfs_open_async failed");
232 wait_for_nfs_reply(nfs
, &cb_data
);
234 return cb_data
.status
;
243 static void pread_cb(int status
, struct nfs_context
*nfs
, void *data
, void *private_data
)
245 struct sync_cb_data
*cb_data
= private_data
;
247 cb_data
->is_finished
= 1;
248 cb_data
->status
= status
;
251 nfs_set_error(nfs
, "pread call failed with \"%s\"", (char *)data
);
255 buffer
= cb_data
->return_data
;
256 memcpy(buffer
, (char *)data
, status
);
259 int nfs_pread(struct nfs_context
*nfs
, struct nfsfh
*nfsfh
, off_t offset
, size_t count
, char *buffer
)
261 struct sync_cb_data cb_data
;
263 cb_data
.is_finished
= 0;
264 cb_data
.return_data
= buffer
;
266 if (nfs_pread_async(nfs
, nfsfh
, offset
, count
, pread_cb
, &cb_data
) != 0) {
267 nfs_set_error(nfs
, "nfs_pread_async failed");
271 wait_for_nfs_reply(nfs
, &cb_data
);
273 return cb_data
.status
;
279 int nfs_read(struct nfs_context
*nfs
, struct nfsfh
*nfsfh
, size_t count
, char *buffer
)
281 return nfs_pread(nfs
, nfsfh
, nfs_get_current_offset(nfsfh
), count
, buffer
);
287 static void close_cb(int status
, struct nfs_context
*nfs
, void *data
, void *private_data
)
289 struct sync_cb_data
*cb_data
= private_data
;
290 cb_data
->is_finished
= 1;
291 cb_data
->status
= status
;
294 nfs_set_error(nfs
, "close call failed with \"%s\"", (char *)data
);
299 int nfs_close(struct nfs_context
*nfs
, struct nfsfh
*nfsfh
)
301 struct sync_cb_data cb_data
;
303 cb_data
.is_finished
= 0;
305 if (nfs_close_async(nfs
, nfsfh
, close_cb
, &cb_data
) != 0) {
306 nfs_set_error(nfs
, "nfs_close_async failed");
310 wait_for_nfs_reply(nfs
, &cb_data
);
312 return cb_data
.status
;
321 int nfs_fstat(struct nfs_context
*nfs
, struct nfsfh
*nfsfh
, struct stat
*st
)
323 struct sync_cb_data cb_data
;
325 cb_data
.is_finished
= 0;
326 cb_data
.return_data
= st
;
328 if (nfs_fstat_async(nfs
, nfsfh
, stat_cb
, &cb_data
) != 0) {
329 nfs_set_error(nfs
, "nfs_fstat_async failed");
333 wait_for_nfs_reply(nfs
, &cb_data
);
335 return cb_data
.status
;
342 static void pwrite_cb(int status
, struct nfs_context
*nfs
, void *data
, void *private_data
)
344 struct sync_cb_data
*cb_data
= private_data
;
345 cb_data
->is_finished
= 1;
346 cb_data
->status
= status
;
349 nfs_set_error(nfs
, "pwrite call failed with \"%s\"", (char *)data
);
354 int nfs_pwrite(struct nfs_context
*nfs
, struct nfsfh
*nfsfh
, off_t offset
, size_t count
, char *buf
)
356 struct sync_cb_data cb_data
;
358 cb_data
.is_finished
= 0;
360 if (nfs_pwrite_async(nfs
, nfsfh
, offset
, count
, buf
, pwrite_cb
, &cb_data
) != 0) {
361 nfs_set_error(nfs
, "nfs_pwrite_async failed");
365 wait_for_nfs_reply(nfs
, &cb_data
);
367 return cb_data
.status
;
373 int nfs_write(struct nfs_context
*nfs
, struct nfsfh
*nfsfh
, size_t count
, char *buf
)
375 return nfs_pwrite(nfs
, nfsfh
, nfs_get_current_offset(nfsfh
), count
, buf
);
382 static void fsync_cb(int status
, struct nfs_context
*nfs
, void *data
, void *private_data
)
384 struct sync_cb_data
*cb_data
= private_data
;
385 cb_data
->is_finished
= 1;
386 cb_data
->status
= status
;
389 nfs_set_error(nfs
, "fsync call failed with \"%s\"", (char *)data
);
394 int nfs_fsync(struct nfs_context
*nfs
, struct nfsfh
*nfsfh
)
396 struct sync_cb_data cb_data
;
398 cb_data
.is_finished
= 0;
400 if (nfs_fsync_async(nfs
, nfsfh
, fsync_cb
, &cb_data
) != 0) {
401 nfs_set_error(nfs
, "nfs_fsync_async failed");
405 wait_for_nfs_reply(nfs
, &cb_data
);
407 return cb_data
.status
;
416 static void ftruncate_cb(int status
, struct nfs_context
*nfs
, void *data
, void *private_data
)
418 struct sync_cb_data
*cb_data
= private_data
;
419 cb_data
->is_finished
= 1;
420 cb_data
->status
= status
;
423 nfs_set_error(nfs
, "ftruncate call failed with \"%s\"", (char *)data
);
428 int nfs_ftruncate(struct nfs_context
*nfs
, struct nfsfh
*nfsfh
, off_t length
)
430 struct sync_cb_data cb_data
;
432 cb_data
.is_finished
= 0;
434 if (nfs_ftruncate_async(nfs
, nfsfh
, length
, ftruncate_cb
, &cb_data
) != 0) {
435 nfs_set_error(nfs
, "nfs_ftruncate_async failed");
439 wait_for_nfs_reply(nfs
, &cb_data
);
441 return cb_data
.status
;
449 static void truncate_cb(int status
, struct nfs_context
*nfs
, void *data
, void *private_data
)
451 struct sync_cb_data
*cb_data
= private_data
;
452 cb_data
->is_finished
= 1;
453 cb_data
->status
= status
;
456 nfs_set_error(nfs
, "truncate call failed with \"%s\"", (char *)data
);
461 int nfs_truncate(struct nfs_context
*nfs
, const char *path
, off_t length
)
463 struct sync_cb_data cb_data
;
465 cb_data
.is_finished
= 0;
467 if (nfs_truncate_async(nfs
, path
, length
, truncate_cb
, &cb_data
) != 0) {
468 nfs_set_error(nfs
, "nfs_ftruncate_async failed");
472 wait_for_nfs_reply(nfs
, &cb_data
);
474 return cb_data
.status
;
484 static void mkdir_cb(int status
, struct nfs_context
*nfs
, void *data
, void *private_data
)
486 struct sync_cb_data
*cb_data
= private_data
;
487 cb_data
->is_finished
= 1;
488 cb_data
->status
= status
;
491 nfs_set_error(nfs
, "mkdir call failed with \"%s\"", (char *)data
);
496 int nfs_mkdir(struct nfs_context
*nfs
, const char *path
)
498 struct sync_cb_data cb_data
;
500 cb_data
.is_finished
= 0;
502 if (nfs_mkdir_async(nfs
, path
, mkdir_cb
, &cb_data
) != 0) {
503 nfs_set_error(nfs
, "nfs_mkdir_async failed");
507 wait_for_nfs_reply(nfs
, &cb_data
);
509 return cb_data
.status
;
519 static void rmdir_cb(int status
, struct nfs_context
*nfs
, void *data
, void *private_data
)
521 struct sync_cb_data
*cb_data
= private_data
;
522 cb_data
->is_finished
= 1;
523 cb_data
->status
= status
;
526 nfs_set_error(nfs
, "rmdir call failed with \"%s\"", (char *)data
);
531 int nfs_rmdir(struct nfs_context
*nfs
, const char *path
)
533 struct sync_cb_data cb_data
;
535 cb_data
.is_finished
= 0;
537 if (nfs_rmdir_async(nfs
, path
, rmdir_cb
, &cb_data
) != 0) {
538 nfs_set_error(nfs
, "nfs_rmdir_async failed");
542 wait_for_nfs_reply(nfs
, &cb_data
);
544 return cb_data
.status
;
552 static void creat_cb(int status
, struct nfs_context
*nfs
, void *data
, void *private_data
)
554 struct sync_cb_data
*cb_data
= private_data
;
555 struct nfsfh
*fh
, **nfsfh
;
557 cb_data
->is_finished
= 1;
558 cb_data
->status
= status
;
561 nfs_set_error(nfs
, "creat call failed with \"%s\"", (char *)data
);
566 nfsfh
= cb_data
->return_data
;
570 int nfs_creat(struct nfs_context
*nfs
, const char *path
, int mode
, struct nfsfh
**nfsfh
)
572 struct sync_cb_data cb_data
;
574 cb_data
.is_finished
= 0;
575 cb_data
.return_data
= nfsfh
;
577 if (nfs_creat_async(nfs
, path
, mode
, creat_cb
, &cb_data
) != 0) {
578 nfs_set_error(nfs
, "nfs_creat_async failed");
582 wait_for_nfs_reply(nfs
, &cb_data
);
584 return cb_data
.status
;
593 static void unlink_cb(int status
, struct nfs_context
*nfs
, void *data
, void *private_data
)
595 struct sync_cb_data
*cb_data
= private_data
;
597 cb_data
->is_finished
= 1;
598 cb_data
->status
= status
;
601 nfs_set_error(nfs
, "unlink call failed with \"%s\"", (char *)data
);
606 int nfs_unlink(struct nfs_context
*nfs
, const char *path
)
608 struct sync_cb_data cb_data
;
610 cb_data
.is_finished
= 0;
612 if (nfs_unlink_async(nfs
, path
, unlink_cb
, &cb_data
) != 0) {
613 nfs_set_error(nfs
, "nfs_unlink_async failed");
617 wait_for_nfs_reply(nfs
, &cb_data
);
619 return cb_data
.status
;
627 static void opendir_cb(int status
, struct nfs_context
*nfs
, void *data
, void *private_data
)
629 struct sync_cb_data
*cb_data
= private_data
;
630 struct nfsdir
*dir
, **nfsdir
;
632 cb_data
->is_finished
= 1;
633 cb_data
->status
= status
;
636 nfs_set_error(nfs
, "opendir call failed with \"%s\"", (char *)data
);
641 nfsdir
= cb_data
->return_data
;
645 int nfs_opendir(struct nfs_context
*nfs
, const char *path
, struct nfsdir
**nfsdir
)
647 struct sync_cb_data cb_data
;
649 cb_data
.is_finished
= 0;
650 cb_data
.return_data
= nfsdir
;
652 if (nfs_opendir_async(nfs
, path
, opendir_cb
, &cb_data
) != 0) {
653 nfs_set_error(nfs
, "nfs_opendir_async failed");
657 wait_for_nfs_reply(nfs
, &cb_data
);
659 return cb_data
.status
;
666 static void lseek_cb(int status
, struct nfs_context
*nfs
, void *data
, void *private_data
)
668 struct sync_cb_data
*cb_data
= private_data
;
670 cb_data
->is_finished
= 1;
671 cb_data
->status
= status
;
674 nfs_set_error(nfs
, "lseek call failed with \"%s\"", (char *)data
);
678 if (cb_data
->return_data
!= NULL
) {
679 memcpy(cb_data
->return_data
, data
, sizeof(off_t
));
683 int nfs_lseek(struct nfs_context
*nfs
, struct nfsfh
*nfsfh
, off_t offset
, int whence
, off_t
*current_offset
)
685 struct sync_cb_data cb_data
;
687 cb_data
.is_finished
= 0;
688 cb_data
.return_data
= current_offset
;
690 if (nfs_lseek_async(nfs
, nfsfh
, offset
, whence
, lseek_cb
, &cb_data
) != 0) {
691 nfs_set_error(nfs
, "nfs_lseek_async failed");
695 wait_for_nfs_reply(nfs
, &cb_data
);
697 return cb_data
.status
;
705 static void statvfs_cb(int status
, struct nfs_context
*nfs
, void *data
, void *private_data
)
707 struct sync_cb_data
*cb_data
= private_data
;
709 cb_data
->is_finished
= 1;
710 cb_data
->status
= status
;
713 nfs_set_error(nfs
, "statvfs call failed with \"%s\"", (char *)data
);
717 memcpy(cb_data
->return_data
, data
, sizeof(struct statvfs
));
720 int nfs_statvfs(struct nfs_context
*nfs
, const char *path
, struct statvfs
*svfs
)
722 struct sync_cb_data cb_data
;
724 cb_data
.is_finished
= 0;
725 cb_data
.return_data
= svfs
;
727 if (nfs_statvfs_async(nfs
, path
, statvfs_cb
, &cb_data
) != 0) {
728 nfs_set_error(nfs
, "nfs_statvfs_async failed");
732 wait_for_nfs_reply(nfs
, &cb_data
);
734 return cb_data
.status
;
744 static void readlink_cb(int status
, struct nfs_context
*nfs
, void *data
, void *private_data
)
746 struct sync_cb_data
*cb_data
= private_data
;
748 cb_data
->is_finished
= 1;
749 cb_data
->status
= status
;
752 nfs_set_error(nfs
, "readlink call failed with \"%s\"", (char *)data
);
756 if (strlen(data
) > (size_t)cb_data
->return_int
) {
757 nfs_set_error(nfs
, "Too small buffer for readlink");
758 cb_data
->status
= -ENAMETOOLONG
;
762 memcpy(cb_data
->return_data
, data
, strlen(data
)+1);
765 int nfs_readlink(struct nfs_context
*nfs
, const char *path
, char *buf
, int bufsize
)
767 struct sync_cb_data cb_data
;
769 cb_data
.is_finished
= 0;
770 cb_data
.return_data
= buf
;
771 cb_data
.return_int
= bufsize
;
773 if (nfs_readlink_async(nfs
, path
, readlink_cb
, &cb_data
) != 0) {
774 nfs_set_error(nfs
, "nfs_readlink_async failed");
778 wait_for_nfs_reply(nfs
, &cb_data
);
780 return cb_data
.status
;
788 static void chmod_cb(int status
, struct nfs_context
*nfs
, void *data
, void *private_data
)
790 struct sync_cb_data
*cb_data
= private_data
;
792 cb_data
->is_finished
= 1;
793 cb_data
->status
= status
;
796 nfs_set_error(nfs
, "chmod call failed with \"%s\"", (char *)data
);
801 int nfs_chmod(struct nfs_context
*nfs
, const char *path
, int mode
)
803 struct sync_cb_data cb_data
;
805 cb_data
.is_finished
= 0;
807 if (nfs_chmod_async(nfs
, path
, mode
, chmod_cb
, &cb_data
) != 0) {
808 nfs_set_error(nfs
, "nfs_chmod_async failed");
812 wait_for_nfs_reply(nfs
, &cb_data
);
814 return cb_data
.status
;
823 static void fchmod_cb(int status
, struct nfs_context
*nfs
, void *data
, void *private_data
)
825 struct sync_cb_data
*cb_data
= private_data
;
827 cb_data
->is_finished
= 1;
828 cb_data
->status
= status
;
831 nfs_set_error(nfs
, "fchmod call failed with \"%s\"", (char *)data
);
836 int nfs_fchmod(struct nfs_context
*nfs
, struct nfsfh
*nfsfh
, int mode
)
838 struct sync_cb_data cb_data
;
840 cb_data
.is_finished
= 0;
842 if (nfs_fchmod_async(nfs
, nfsfh
, mode
, fchmod_cb
, &cb_data
) != 0) {
843 nfs_set_error(nfs
, "nfs_fchmod_async failed");
847 wait_for_nfs_reply(nfs
, &cb_data
);
849 return cb_data
.status
;
858 static void chown_cb(int status
, struct nfs_context
*nfs
, void *data
, void *private_data
)
860 struct sync_cb_data
*cb_data
= private_data
;
862 cb_data
->is_finished
= 1;
863 cb_data
->status
= status
;
866 nfs_set_error(nfs
, "chown call failed with \"%s\"", (char *)data
);
871 int nfs_chown(struct nfs_context
*nfs
, const char *path
, int uid
, int gid
)
873 struct sync_cb_data cb_data
;
875 cb_data
.is_finished
= 0;
877 if (nfs_chown_async(nfs
, path
, uid
, gid
, chown_cb
, &cb_data
) != 0) {
878 nfs_set_error(nfs
, "nfs_chown_async failed");
882 wait_for_nfs_reply(nfs
, &cb_data
);
884 return cb_data
.status
;
890 static void fchown_cb(int status
, struct nfs_context
*nfs
, void *data
, void *private_data
)
892 struct sync_cb_data
*cb_data
= private_data
;
894 cb_data
->is_finished
= 1;
895 cb_data
->status
= status
;
898 nfs_set_error(nfs
, "fchown call failed with \"%s\"", (char *)data
);
903 int nfs_fchown(struct nfs_context
*nfs
, struct nfsfh
*nfsfh
, int uid
, int gid
)
905 struct sync_cb_data cb_data
;
907 cb_data
.is_finished
= 0;
909 if (nfs_fchown_async(nfs
, nfsfh
, uid
, gid
, fchown_cb
, &cb_data
) != 0) {
910 nfs_set_error(nfs
, "nfs_fchown_async failed");
914 wait_for_nfs_reply(nfs
, &cb_data
);
916 return cb_data
.status
;
924 static void utimes_cb(int status
, struct nfs_context
*nfs
, void *data
, void *private_data
)
926 struct sync_cb_data
*cb_data
= private_data
;
928 cb_data
->is_finished
= 1;
929 cb_data
->status
= status
;
932 nfs_set_error(nfs
, "utimes call failed with \"%s\"", (char *)data
);
937 int nfs_utimes(struct nfs_context
*nfs
, const char *path
, struct timeval
*times
)
939 struct sync_cb_data cb_data
;
941 cb_data
.is_finished
= 0;
943 if (nfs_utimes_async(nfs
, path
, times
, utimes_cb
, &cb_data
) != 0) {
944 nfs_set_error(nfs
, "nfs_utimes_async failed");
948 wait_for_nfs_reply(nfs
, &cb_data
);
950 return cb_data
.status
;
958 static void utime_cb(int status
, struct nfs_context
*nfs
, void *data
, void *private_data
)
960 struct sync_cb_data
*cb_data
= private_data
;
962 cb_data
->is_finished
= 1;
963 cb_data
->status
= status
;
966 nfs_set_error(nfs
, "utime call failed with \"%s\"", (char *)data
);
971 int nfs_utime(struct nfs_context
*nfs
, const char *path
, struct utimbuf
*times
)
973 struct sync_cb_data cb_data
;
975 cb_data
.is_finished
= 0;
977 if (nfs_utime_async(nfs
, path
, times
, utime_cb
, &cb_data
) != 0) {
978 nfs_set_error(nfs
, "nfs_utimes_async failed");
982 wait_for_nfs_reply(nfs
, &cb_data
);
984 return cb_data
.status
;
993 static void access_cb(int status
, struct nfs_context
*nfs
, void *data
, void *private_data
)
995 struct sync_cb_data
*cb_data
= private_data
;
997 cb_data
->is_finished
= 1;
998 cb_data
->status
= status
;
1001 nfs_set_error(nfs
, "access call failed with \"%s\"", (char *)data
);
1006 int nfs_access(struct nfs_context
*nfs
, const char *path
, int mode
)
1008 struct sync_cb_data cb_data
;
1010 cb_data
.is_finished
= 0;
1012 if (nfs_access_async(nfs
, path
, mode
, access_cb
, &cb_data
) != 0) {
1013 nfs_set_error(nfs
, "nfs_access_async failed");
1017 wait_for_nfs_reply(nfs
, &cb_data
);
1019 return cb_data
.status
;
1027 static void symlink_cb(int status
, struct nfs_context
*nfs
, void *data
, void *private_data
)
1029 struct sync_cb_data
*cb_data
= private_data
;
1031 cb_data
->is_finished
= 1;
1032 cb_data
->status
= status
;
1035 nfs_set_error(nfs
, "symlink call failed with \"%s\"", (char *)data
);
1040 int nfs_symlink(struct nfs_context
*nfs
, const char *oldpath
, const char *newpath
)
1042 struct sync_cb_data cb_data
;
1044 cb_data
.is_finished
= 0;
1046 if (nfs_symlink_async(nfs
, oldpath
, newpath
, symlink_cb
, &cb_data
) != 0) {
1047 nfs_set_error(nfs
, "nfs_symlink_async failed");
1051 wait_for_nfs_reply(nfs
, &cb_data
);
1053 return cb_data
.status
;
1061 static void rename_cb(int status
, struct nfs_context
*nfs
, void *data
, void *private_data
)
1063 struct sync_cb_data
*cb_data
= private_data
;
1065 cb_data
->is_finished
= 1;
1066 cb_data
->status
= status
;
1069 nfs_set_error(nfs
, "rename call failed with \"%s\"", (char *)data
);
1074 int nfs_rename(struct nfs_context
*nfs
, const char *oldpath
, const char *newpath
)
1076 struct sync_cb_data cb_data
;
1078 cb_data
.is_finished
= 0;
1080 if (nfs_rename_async(nfs
, oldpath
, newpath
, rename_cb
, &cb_data
) != 0) {
1081 nfs_set_error(nfs
, "nfs_rename_async failed");
1085 wait_for_nfs_reply(nfs
, &cb_data
);
1087 return cb_data
.status
;
1095 static void link_cb(int status
, struct nfs_context
*nfs
, void *data
, void *private_data
)
1097 struct sync_cb_data
*cb_data
= private_data
;
1099 cb_data
->is_finished
= 1;
1100 cb_data
->status
= status
;
1103 nfs_set_error(nfs
, "link call failed with \"%s\"", (char *)data
);
1108 int nfs_link(struct nfs_context
*nfs
, const char *oldpath
, const char *newpath
)
1110 struct sync_cb_data cb_data
;
1112 cb_data
.is_finished
= 0;
1114 if (nfs_link_async(nfs
, oldpath
, newpath
, link_cb
, &cb_data
) != 0) {
1115 nfs_set_error(nfs
, "nfs_link_async failed");
1119 wait_for_nfs_reply(nfs
, &cb_data
);
1121 return cb_data
.status
;
1124 void mount_getexports_cb(struct rpc_context
*mount_context
, int status
, void *data
, void *private_data
)
1126 struct sync_cb_data
*cb_data
= private_data
;
1127 exports export
= *(exports
*)data
;
1129 cb_data
->is_finished
= 1;
1130 cb_data
->status
= status
;
1131 cb_data
->return_data
= NULL
;
1134 rpc_set_error(mount_context
, "mount/export call failed with \"%s\"", (char *)data
);
1138 while (export
!= NULL
) {
1141 new_export
= malloc(sizeof(*new_export
));
1142 memset(new_export
, 0, sizeof(*new_export
));
1143 new_export
->ex_dir
= strdup(export
->ex_dir
);
1144 new_export
->ex_next
= cb_data
->return_data
;
1146 cb_data
->return_data
= new_export
;
1148 export
= export
->ex_next
;
1152 struct exportnode
*mount_getexports(const char *server
)
1154 struct sync_cb_data cb_data
;
1155 struct rpc_context
*rpc
;
1158 cb_data
.is_finished
= 0;
1159 cb_data
.return_data
= NULL
;
1161 rpc
= rpc_init_context();
1162 if (mount_getexports_async(rpc
, server
, mount_getexports_cb
, &cb_data
) != 0) {
1163 rpc_destroy_context(rpc
);
1167 wait_for_reply(rpc
, &cb_data
);
1168 rpc_destroy_context(rpc
);
1170 return cb_data
.return_data
;
1173 void mount_free_export_list(struct exportnode
*exports
)
1175 struct exportnode
*tmp
;
1177 while ((tmp
= exports
)) {
1178 exports
= exports
->ex_next
;
1187 void free_nfs_srvr_list(struct nfs_server_list
*srv
)
1189 while (srv
!= NULL
) {
1190 struct nfs_server_list
*next
= srv
->next
;
1198 struct nfs_list_data
{
1200 struct nfs_server_list
*srvrs
;
1203 void callit_cb(struct rpc_context
*rpc
, int status
, void *data _U_
, void *private_data
)
1205 struct nfs_list_data
*srv_data
= private_data
;
1206 struct sockaddr
*sin
;
1208 struct nfs_server_list
*srvr
;
1210 if (status
== RPC_STATUS_CANCEL
) {
1214 srv_data
->status
= -1;
1218 sin
= rpc_get_recv_sockaddr(rpc
);
1220 rpc_set_error(rpc
, "failed to get sockaddr in CALLIT callback");
1221 srv_data
->status
= -1;
1225 if (getnameinfo(sin
, sizeof(struct sockaddr_in
), &hostdd
[0], sizeof(hostdd
), NULL
, 0, NI_NUMERICHOST
) < 0) {
1226 rpc_set_error(rpc
, "getnameinfo failed in CALLIT callback");
1227 srv_data
->status
= -1;
1231 /* check for dupes */
1232 for (srvr
= srv_data
->srvrs
; srvr
; srvr
= srvr
->next
) {
1233 if (!strcmp(hostdd
, srvr
->addr
)) {
1238 srvr
= malloc(sizeof(struct nfs_server_list
));
1240 rpc_set_error(rpc
, "Malloc failed when allocating server structure");
1241 srv_data
->status
= -1;
1245 srvr
->addr
= strdup(hostdd
);
1246 if (srvr
->addr
== NULL
) {
1247 rpc_set_error(rpc
, "Strdup failed when allocating server structure");
1249 srv_data
->status
= -1;
1253 srvr
->next
= srv_data
->srvrs
;
1254 srv_data
->srvrs
= srvr
;
1257 static int send_nfsd_probes(struct rpc_context
*rpc
, struct ifconf
*ifc
, struct nfs_list_data
*data
)
1261 for (ptr
=(char *)(ifc
->ifc_buf
); ptr
< (char *)(ifc
->ifc_buf
) + ifc
->ifc_len
; ) {
1265 ifr
= (struct ifreq
*)ptr
;
1266 #ifdef HAVE_SOCKADDR_LEN
1267 if (ifr
->ifr_addr
.sa_len
> sizeof(struct sockaddr
)) {
1268 ptr
+= sizeof(ifr
->ifr_name
) + ifr
->ifr_addr
.sa_len
;
1270 ptr
+= sizeof(ifr
->ifr_name
) + sizeof(struct sockaddr
);
1273 ptr
+= sizeof(struct ifreq
);
1276 if (ifr
->ifr_addr
.sa_family
!= AF_INET
) {
1279 if (ioctl(rpc_get_fd(rpc
), SIOCGIFFLAGS
, ifr
) < 0) {
1282 if (!(ifr
->ifr_flags
& IFF_UP
)) {
1285 if (ifr
->ifr_flags
& IFF_LOOPBACK
) {
1288 if (!(ifr
->ifr_flags
& IFF_BROADCAST
)) {
1291 if (ioctl(rpc_get_fd(rpc
), SIOCGIFBRDADDR
, ifr
) < 0) {
1294 if (getnameinfo(&ifr
->ifr_broadaddr
, sizeof(struct sockaddr_in
), &bcdd
[0], sizeof(bcdd
), NULL
, 0, NI_NUMERICHOST
) < 0) {
1297 if (rpc_set_udp_destination(rpc
, bcdd
, 111, 1) < 0) {
1301 if (rpc_pmap_callit_async(rpc
, MOUNT_PROGRAM
, 2, 0, NULL
, 0, callit_cb
, data
) < 0) {
1309 struct nfs_server_list
*nfs_find_local_servers(void)
1311 struct rpc_context
*rpc
;
1312 struct nfs_list_data data
= {0, NULL
};
1313 struct timeval tv_start
, tv_current
;
1318 rpc
= rpc_init_udp_context();
1323 if (rpc_bind_udp(rpc
, "0.0.0.0", 0) < 0) {
1324 rpc_destroy_context(rpc
);
1329 /* get list of all interfaces */
1330 size
= sizeof(struct ifreq
);
1334 while(ifc
.ifc_len
> (size
- sizeof(struct ifreq
))) {
1339 ifc
.ifc_buf
= malloc(size
);
1340 memset(ifc
.ifc_buf
, 0, size
);
1341 if (ioctl(rpc_get_fd(rpc
), SIOCGIFCONF
, (caddr_t
)&ifc
) < 0) {
1342 rpc_destroy_context(rpc
);
1348 for (loop
=0; loop
<3; loop
++) {
1349 if (send_nfsd_probes(rpc
, &ifc
, &data
) != 0) {
1350 rpc_destroy_context(rpc
);
1355 gettimeofday(&tv_start
, NULL
);
1359 pfd
.fd
= rpc_get_fd(rpc
);
1360 pfd
.events
= rpc_which_events(rpc
);
1362 gettimeofday(&tv_current
, NULL
);
1364 - (tv_current
.tv_sec
*1000 + tv_current
.tv_usec
/ 1000)
1365 + (tv_start
.tv_sec
*1000 + tv_start
.tv_usec
/ 1000);
1367 if (poll(&pfd
, 1, mpt
) < 0) {
1368 free_nfs_srvr_list(data
.srvrs
);
1369 rpc_destroy_context(rpc
);
1372 if (pfd
.revents
== 0) {
1376 if (rpc_service(rpc
, pfd
.revents
) < 0) {
1383 rpc_destroy_context(rpc
);
1385 if (data
.status
!= 0) {
1386 free_nfs_srvr_list(data
.srvrs
);