510772fa1efe6f7e889ac7af2e7b1277157475a7
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>
37 #ifdef HAVE_SYS_SOCKIO_H
38 #include <sys/sockio.h>
41 #include "libnfs-raw.h"
42 #include "libnfs-raw-mount.h"
43 #include "libnfs-raw-nfs.h"
44 #include "libnfs-private.h"
55 static void wait_for_reply(struct rpc_context
*rpc
, struct sync_cb_data
*cb_data
)
59 while (!cb_data
->is_finished
) {
61 pfd
.fd
= rpc_get_fd(rpc
);
62 pfd
.events
= rpc_which_events(rpc
);
63 if (poll(&pfd
, 1, -1) < 0) {
64 rpc_set_error(rpc
, "Poll failed");
65 cb_data
->status
= -EIO
;
68 if (rpc_service(rpc
, pfd
.revents
) < 0) {
69 rpc_set_error(rpc
, "rpc_service failed");
70 cb_data
->status
= -EIO
;
73 if (rpc_get_fd(rpc
) == -1) {
74 rpc_set_error(rpc
, "Socket closed\n");
80 static void wait_for_nfs_reply(struct nfs_context
*nfs
, struct sync_cb_data
*cb_data
)
84 while (!cb_data
->is_finished
) {
86 pfd
.fd
= nfs_get_fd(nfs
);
87 pfd
.events
= nfs_which_events(nfs
);
88 if (poll(&pfd
, 1, -1) < 0) {
89 nfs_set_error(nfs
, "Poll failed");
90 cb_data
->status
= -EIO
;
93 if (nfs_service(nfs
, pfd
.revents
) < 0) {
94 nfs_set_error(nfs
, "nfs_service failed");
95 cb_data
->status
= -EIO
;
98 if (nfs_get_fd(nfs
) == -1) {
99 char *server
= strdup(nfs_get_server(nfs
));
100 char *export
= strdup(nfs_get_export(nfs
));
102 if (nfs_mount(nfs
, server
, export
) != 0) {
103 nfs_set_error(nfs
, "Failed to reconnect to nfs server %s", nfs_get_error(nfs
));
120 * connect to the server and mount the export
122 static void mount_cb(int status
, struct nfs_context
*nfs
, void *data
, void *private_data
)
124 struct sync_cb_data
*cb_data
= private_data
;
126 cb_data
->is_finished
= 1;
127 cb_data
->status
= status
;
130 nfs_set_error(nfs
, "mount/mnt call failed with \"%s\"", (char *)data
);
135 int nfs_mount(struct nfs_context
*nfs
, const char *server
, const char *export
)
137 struct sync_cb_data cb_data
;
139 cb_data
.is_finished
= 0;
141 if (nfs_mount_async(nfs
, server
, export
, mount_cb
, &cb_data
) != 0) {
142 nfs_set_error(nfs
, "nfs_mount_async failed");
146 wait_for_nfs_reply(nfs
, &cb_data
);
148 return cb_data
.status
;
155 static void stat_cb(int status
, struct nfs_context
*nfs
, void *data
, void *private_data
)
157 struct sync_cb_data
*cb_data
= private_data
;
159 cb_data
->is_finished
= 1;
160 cb_data
->status
= status
;
163 nfs_set_error(nfs
, "stat call failed with \"%s\"", (char *)data
);
167 memcpy(cb_data
->return_data
, data
, sizeof(struct stat
));
170 int nfs_stat(struct nfs_context
*nfs
, const char *path
, struct stat
*st
)
172 struct sync_cb_data cb_data
;
174 cb_data
.is_finished
= 0;
175 cb_data
.return_data
= st
;
177 if (nfs_stat_async(nfs
, path
, stat_cb
, &cb_data
) != 0) {
178 nfs_set_error(nfs
, "nfs_stat_async failed");
182 wait_for_nfs_reply(nfs
, &cb_data
);
184 return cb_data
.status
;
193 static void open_cb(int status
, struct nfs_context
*nfs
, void *data
, void *private_data
)
195 struct sync_cb_data
*cb_data
= private_data
;
196 struct nfsfh
*fh
, **nfsfh
;
198 cb_data
->is_finished
= 1;
199 cb_data
->status
= status
;
202 nfs_set_error(nfs
, "open call failed with \"%s\"", (char *)data
);
207 nfsfh
= cb_data
->return_data
;
211 int nfs_open(struct nfs_context
*nfs
, const char *path
, int mode
, struct nfsfh
**nfsfh
)
213 struct sync_cb_data cb_data
;
215 cb_data
.is_finished
= 0;
216 cb_data
.return_data
= nfsfh
;
218 if (nfs_open_async(nfs
, path
, mode
, open_cb
, &cb_data
) != 0) {
219 nfs_set_error(nfs
, "nfs_open_async failed");
223 wait_for_nfs_reply(nfs
, &cb_data
);
225 return cb_data
.status
;
234 static void pread_cb(int status
, struct nfs_context
*nfs
, void *data
, void *private_data
)
236 struct sync_cb_data
*cb_data
= private_data
;
238 cb_data
->is_finished
= 1;
239 cb_data
->status
= status
;
242 nfs_set_error(nfs
, "pread call failed with \"%s\"", (char *)data
);
246 buffer
= cb_data
->return_data
;
247 memcpy(buffer
, (char *)data
, status
);
250 int nfs_pread(struct nfs_context
*nfs
, struct nfsfh
*nfsfh
, off_t offset
, size_t count
, char *buffer
)
252 struct sync_cb_data cb_data
;
254 cb_data
.is_finished
= 0;
255 cb_data
.return_data
= buffer
;
257 if (nfs_pread_async(nfs
, nfsfh
, offset
, count
, pread_cb
, &cb_data
) != 0) {
258 nfs_set_error(nfs
, "nfs_pread_async failed");
262 wait_for_nfs_reply(nfs
, &cb_data
);
264 return cb_data
.status
;
270 int nfs_read(struct nfs_context
*nfs
, struct nfsfh
*nfsfh
, size_t count
, char *buffer
)
272 return nfs_pread(nfs
, nfsfh
, nfs_get_current_offset(nfsfh
), count
, buffer
);
278 static void close_cb(int status
, struct nfs_context
*nfs
, void *data
, void *private_data
)
280 struct sync_cb_data
*cb_data
= private_data
;
281 cb_data
->is_finished
= 1;
282 cb_data
->status
= status
;
285 nfs_set_error(nfs
, "close call failed with \"%s\"", (char *)data
);
290 int nfs_close(struct nfs_context
*nfs
, struct nfsfh
*nfsfh
)
292 struct sync_cb_data cb_data
;
294 cb_data
.is_finished
= 0;
296 if (nfs_close_async(nfs
, nfsfh
, close_cb
, &cb_data
) != 0) {
297 nfs_set_error(nfs
, "nfs_close_async failed");
301 wait_for_nfs_reply(nfs
, &cb_data
);
303 return cb_data
.status
;
312 int nfs_fstat(struct nfs_context
*nfs
, struct nfsfh
*nfsfh
, struct stat
*st
)
314 struct sync_cb_data cb_data
;
316 cb_data
.is_finished
= 0;
317 cb_data
.return_data
= st
;
319 if (nfs_fstat_async(nfs
, nfsfh
, stat_cb
, &cb_data
) != 0) {
320 nfs_set_error(nfs
, "nfs_fstat_async failed");
324 wait_for_nfs_reply(nfs
, &cb_data
);
326 return cb_data
.status
;
333 static void pwrite_cb(int status
, struct nfs_context
*nfs
, void *data
, void *private_data
)
335 struct sync_cb_data
*cb_data
= private_data
;
336 cb_data
->is_finished
= 1;
337 cb_data
->status
= status
;
340 nfs_set_error(nfs
, "pwrite call failed with \"%s\"", (char *)data
);
345 int nfs_pwrite(struct nfs_context
*nfs
, struct nfsfh
*nfsfh
, off_t offset
, size_t count
, char *buf
)
347 struct sync_cb_data cb_data
;
349 cb_data
.is_finished
= 0;
351 if (nfs_pwrite_async(nfs
, nfsfh
, offset
, count
, buf
, pwrite_cb
, &cb_data
) != 0) {
352 nfs_set_error(nfs
, "nfs_pwrite_async failed");
356 wait_for_nfs_reply(nfs
, &cb_data
);
358 return cb_data
.status
;
364 int nfs_write(struct nfs_context
*nfs
, struct nfsfh
*nfsfh
, size_t count
, char *buf
)
366 return nfs_pwrite(nfs
, nfsfh
, nfs_get_current_offset(nfsfh
), count
, buf
);
373 static void fsync_cb(int status
, struct nfs_context
*nfs
, void *data
, void *private_data
)
375 struct sync_cb_data
*cb_data
= private_data
;
376 cb_data
->is_finished
= 1;
377 cb_data
->status
= status
;
380 nfs_set_error(nfs
, "fsync call failed with \"%s\"", (char *)data
);
385 int nfs_fsync(struct nfs_context
*nfs
, struct nfsfh
*nfsfh
)
387 struct sync_cb_data cb_data
;
389 cb_data
.is_finished
= 0;
391 if (nfs_fsync_async(nfs
, nfsfh
, fsync_cb
, &cb_data
) != 0) {
392 nfs_set_error(nfs
, "nfs_fsync_async failed");
396 wait_for_nfs_reply(nfs
, &cb_data
);
398 return cb_data
.status
;
407 static void ftruncate_cb(int status
, struct nfs_context
*nfs
, void *data
, void *private_data
)
409 struct sync_cb_data
*cb_data
= private_data
;
410 cb_data
->is_finished
= 1;
411 cb_data
->status
= status
;
414 nfs_set_error(nfs
, "ftruncate call failed with \"%s\"", (char *)data
);
419 int nfs_ftruncate(struct nfs_context
*nfs
, struct nfsfh
*nfsfh
, off_t length
)
421 struct sync_cb_data cb_data
;
423 cb_data
.is_finished
= 0;
425 if (nfs_ftruncate_async(nfs
, nfsfh
, length
, ftruncate_cb
, &cb_data
) != 0) {
426 nfs_set_error(nfs
, "nfs_ftruncate_async failed");
430 wait_for_nfs_reply(nfs
, &cb_data
);
432 return cb_data
.status
;
440 static void truncate_cb(int status
, struct nfs_context
*nfs
, void *data
, void *private_data
)
442 struct sync_cb_data
*cb_data
= private_data
;
443 cb_data
->is_finished
= 1;
444 cb_data
->status
= status
;
447 nfs_set_error(nfs
, "truncate call failed with \"%s\"", (char *)data
);
452 int nfs_truncate(struct nfs_context
*nfs
, const char *path
, off_t length
)
454 struct sync_cb_data cb_data
;
456 cb_data
.is_finished
= 0;
458 if (nfs_truncate_async(nfs
, path
, length
, truncate_cb
, &cb_data
) != 0) {
459 nfs_set_error(nfs
, "nfs_ftruncate_async failed");
463 wait_for_nfs_reply(nfs
, &cb_data
);
465 return cb_data
.status
;
475 static void mkdir_cb(int status
, struct nfs_context
*nfs
, void *data
, void *private_data
)
477 struct sync_cb_data
*cb_data
= private_data
;
478 cb_data
->is_finished
= 1;
479 cb_data
->status
= status
;
482 nfs_set_error(nfs
, "mkdir call failed with \"%s\"", (char *)data
);
487 int nfs_mkdir(struct nfs_context
*nfs
, const char *path
)
489 struct sync_cb_data cb_data
;
491 cb_data
.is_finished
= 0;
493 if (nfs_mkdir_async(nfs
, path
, mkdir_cb
, &cb_data
) != 0) {
494 nfs_set_error(nfs
, "nfs_mkdir_async failed");
498 wait_for_nfs_reply(nfs
, &cb_data
);
500 return cb_data
.status
;
510 static void rmdir_cb(int status
, struct nfs_context
*nfs
, void *data
, void *private_data
)
512 struct sync_cb_data
*cb_data
= private_data
;
513 cb_data
->is_finished
= 1;
514 cb_data
->status
= status
;
517 nfs_set_error(nfs
, "rmdir call failed with \"%s\"", (char *)data
);
522 int nfs_rmdir(struct nfs_context
*nfs
, const char *path
)
524 struct sync_cb_data cb_data
;
526 cb_data
.is_finished
= 0;
528 if (nfs_rmdir_async(nfs
, path
, rmdir_cb
, &cb_data
) != 0) {
529 nfs_set_error(nfs
, "nfs_rmdir_async failed");
533 wait_for_nfs_reply(nfs
, &cb_data
);
535 return cb_data
.status
;
543 static void creat_cb(int status
, struct nfs_context
*nfs
, void *data
, void *private_data
)
545 struct sync_cb_data
*cb_data
= private_data
;
546 struct nfsfh
*fh
, **nfsfh
;
548 cb_data
->is_finished
= 1;
549 cb_data
->status
= status
;
552 nfs_set_error(nfs
, "creat call failed with \"%s\"", (char *)data
);
557 nfsfh
= cb_data
->return_data
;
561 int nfs_creat(struct nfs_context
*nfs
, const char *path
, int mode
, struct nfsfh
**nfsfh
)
563 struct sync_cb_data cb_data
;
565 cb_data
.is_finished
= 0;
566 cb_data
.return_data
= nfsfh
;
568 if (nfs_creat_async(nfs
, path
, mode
, creat_cb
, &cb_data
) != 0) {
569 nfs_set_error(nfs
, "nfs_creat_async failed");
573 wait_for_nfs_reply(nfs
, &cb_data
);
575 return cb_data
.status
;
584 static void unlink_cb(int status
, struct nfs_context
*nfs
, void *data
, void *private_data
)
586 struct sync_cb_data
*cb_data
= private_data
;
588 cb_data
->is_finished
= 1;
589 cb_data
->status
= status
;
592 nfs_set_error(nfs
, "unlink call failed with \"%s\"", (char *)data
);
597 int nfs_unlink(struct nfs_context
*nfs
, const char *path
)
599 struct sync_cb_data cb_data
;
601 cb_data
.is_finished
= 0;
603 if (nfs_unlink_async(nfs
, path
, unlink_cb
, &cb_data
) != 0) {
604 nfs_set_error(nfs
, "nfs_unlink_async failed");
608 wait_for_nfs_reply(nfs
, &cb_data
);
610 return cb_data
.status
;
618 static void opendir_cb(int status
, struct nfs_context
*nfs
, void *data
, void *private_data
)
620 struct sync_cb_data
*cb_data
= private_data
;
621 struct nfsdir
*dir
, **nfsdir
;
623 cb_data
->is_finished
= 1;
624 cb_data
->status
= status
;
627 nfs_set_error(nfs
, "opendir call failed with \"%s\"", (char *)data
);
632 nfsdir
= cb_data
->return_data
;
636 int nfs_opendir(struct nfs_context
*nfs
, const char *path
, struct nfsdir
**nfsdir
)
638 struct sync_cb_data cb_data
;
640 cb_data
.is_finished
= 0;
641 cb_data
.return_data
= nfsdir
;
643 if (nfs_opendir_async(nfs
, path
, opendir_cb
, &cb_data
) != 0) {
644 nfs_set_error(nfs
, "nfs_opendir_async failed");
648 wait_for_nfs_reply(nfs
, &cb_data
);
650 return cb_data
.status
;
657 static void lseek_cb(int status
, struct nfs_context
*nfs
, void *data
, void *private_data
)
659 struct sync_cb_data
*cb_data
= private_data
;
661 cb_data
->is_finished
= 1;
662 cb_data
->status
= status
;
665 nfs_set_error(nfs
, "lseek call failed with \"%s\"", (char *)data
);
669 if (cb_data
->return_data
!= NULL
) {
670 memcpy(cb_data
->return_data
, data
, sizeof(off_t
));
674 int nfs_lseek(struct nfs_context
*nfs
, struct nfsfh
*nfsfh
, off_t offset
, int whence
, off_t
*current_offset
)
676 struct sync_cb_data cb_data
;
678 cb_data
.is_finished
= 0;
679 cb_data
.return_data
= current_offset
;
681 if (nfs_lseek_async(nfs
, nfsfh
, offset
, whence
, lseek_cb
, &cb_data
) != 0) {
682 nfs_set_error(nfs
, "nfs_lseek_async failed");
686 wait_for_nfs_reply(nfs
, &cb_data
);
688 return cb_data
.status
;
696 static void statvfs_cb(int status
, struct nfs_context
*nfs
, void *data
, void *private_data
)
698 struct sync_cb_data
*cb_data
= private_data
;
700 cb_data
->is_finished
= 1;
701 cb_data
->status
= status
;
704 nfs_set_error(nfs
, "statvfs call failed with \"%s\"", (char *)data
);
708 memcpy(cb_data
->return_data
, data
, sizeof(struct statvfs
));
711 int nfs_statvfs(struct nfs_context
*nfs
, const char *path
, struct statvfs
*svfs
)
713 struct sync_cb_data cb_data
;
715 cb_data
.is_finished
= 0;
716 cb_data
.return_data
= svfs
;
718 if (nfs_statvfs_async(nfs
, path
, statvfs_cb
, &cb_data
) != 0) {
719 nfs_set_error(nfs
, "nfs_statvfs_async failed");
723 wait_for_nfs_reply(nfs
, &cb_data
);
725 return cb_data
.status
;
735 static void readlink_cb(int status
, struct nfs_context
*nfs
, void *data
, void *private_data
)
737 struct sync_cb_data
*cb_data
= private_data
;
739 cb_data
->is_finished
= 1;
740 cb_data
->status
= status
;
743 nfs_set_error(nfs
, "readlink call failed with \"%s\"", (char *)data
);
747 if (strlen(data
) > (size_t)cb_data
->return_int
) {
748 nfs_set_error(nfs
, "Too small buffer for readlink");
749 cb_data
->status
= -ENAMETOOLONG
;
753 memcpy(cb_data
->return_data
, data
, strlen(data
)+1);
756 int nfs_readlink(struct nfs_context
*nfs
, const char *path
, char *buf
, int bufsize
)
758 struct sync_cb_data cb_data
;
760 cb_data
.is_finished
= 0;
761 cb_data
.return_data
= buf
;
762 cb_data
.return_int
= bufsize
;
764 if (nfs_readlink_async(nfs
, path
, readlink_cb
, &cb_data
) != 0) {
765 nfs_set_error(nfs
, "nfs_readlink_async failed");
769 wait_for_nfs_reply(nfs
, &cb_data
);
771 return cb_data
.status
;
779 static void chmod_cb(int status
, struct nfs_context
*nfs
, void *data
, void *private_data
)
781 struct sync_cb_data
*cb_data
= private_data
;
783 cb_data
->is_finished
= 1;
784 cb_data
->status
= status
;
787 nfs_set_error(nfs
, "chmod call failed with \"%s\"", (char *)data
);
792 int nfs_chmod(struct nfs_context
*nfs
, const char *path
, int mode
)
794 struct sync_cb_data cb_data
;
796 cb_data
.is_finished
= 0;
798 if (nfs_chmod_async(nfs
, path
, mode
, chmod_cb
, &cb_data
) != 0) {
799 nfs_set_error(nfs
, "nfs_chmod_async failed");
803 wait_for_nfs_reply(nfs
, &cb_data
);
805 return cb_data
.status
;
814 static void fchmod_cb(int status
, struct nfs_context
*nfs
, void *data
, void *private_data
)
816 struct sync_cb_data
*cb_data
= private_data
;
818 cb_data
->is_finished
= 1;
819 cb_data
->status
= status
;
822 nfs_set_error(nfs
, "fchmod call failed with \"%s\"", (char *)data
);
827 int nfs_fchmod(struct nfs_context
*nfs
, struct nfsfh
*nfsfh
, int mode
)
829 struct sync_cb_data cb_data
;
831 cb_data
.is_finished
= 0;
833 if (nfs_fchmod_async(nfs
, nfsfh
, mode
, fchmod_cb
, &cb_data
) != 0) {
834 nfs_set_error(nfs
, "nfs_fchmod_async failed");
838 wait_for_nfs_reply(nfs
, &cb_data
);
840 return cb_data
.status
;
849 static void chown_cb(int status
, struct nfs_context
*nfs
, void *data
, void *private_data
)
851 struct sync_cb_data
*cb_data
= private_data
;
853 cb_data
->is_finished
= 1;
854 cb_data
->status
= status
;
857 nfs_set_error(nfs
, "chown call failed with \"%s\"", (char *)data
);
862 int nfs_chown(struct nfs_context
*nfs
, const char *path
, int uid
, int gid
)
864 struct sync_cb_data cb_data
;
866 cb_data
.is_finished
= 0;
868 if (nfs_chown_async(nfs
, path
, uid
, gid
, chown_cb
, &cb_data
) != 0) {
869 nfs_set_error(nfs
, "nfs_chown_async failed");
873 wait_for_nfs_reply(nfs
, &cb_data
);
875 return cb_data
.status
;
881 static void fchown_cb(int status
, struct nfs_context
*nfs
, void *data
, void *private_data
)
883 struct sync_cb_data
*cb_data
= private_data
;
885 cb_data
->is_finished
= 1;
886 cb_data
->status
= status
;
889 nfs_set_error(nfs
, "fchown call failed with \"%s\"", (char *)data
);
894 int nfs_fchown(struct nfs_context
*nfs
, struct nfsfh
*nfsfh
, int uid
, int gid
)
896 struct sync_cb_data cb_data
;
898 cb_data
.is_finished
= 0;
900 if (nfs_fchown_async(nfs
, nfsfh
, uid
, gid
, fchown_cb
, &cb_data
) != 0) {
901 nfs_set_error(nfs
, "nfs_fchown_async failed");
905 wait_for_nfs_reply(nfs
, &cb_data
);
907 return cb_data
.status
;
915 static void utimes_cb(int status
, struct nfs_context
*nfs
, void *data
, void *private_data
)
917 struct sync_cb_data
*cb_data
= private_data
;
919 cb_data
->is_finished
= 1;
920 cb_data
->status
= status
;
923 nfs_set_error(nfs
, "utimes call failed with \"%s\"", (char *)data
);
928 int nfs_utimes(struct nfs_context
*nfs
, const char *path
, struct timeval
*times
)
930 struct sync_cb_data cb_data
;
932 cb_data
.is_finished
= 0;
934 if (nfs_utimes_async(nfs
, path
, times
, utimes_cb
, &cb_data
) != 0) {
935 nfs_set_error(nfs
, "nfs_utimes_async failed");
939 wait_for_nfs_reply(nfs
, &cb_data
);
941 return cb_data
.status
;
949 static void utime_cb(int status
, struct nfs_context
*nfs
, void *data
, void *private_data
)
951 struct sync_cb_data
*cb_data
= private_data
;
953 cb_data
->is_finished
= 1;
954 cb_data
->status
= status
;
957 nfs_set_error(nfs
, "utime call failed with \"%s\"", (char *)data
);
962 int nfs_utime(struct nfs_context
*nfs
, const char *path
, struct utimbuf
*times
)
964 struct sync_cb_data cb_data
;
966 cb_data
.is_finished
= 0;
968 if (nfs_utime_async(nfs
, path
, times
, utime_cb
, &cb_data
) != 0) {
969 nfs_set_error(nfs
, "nfs_utimes_async failed");
973 wait_for_nfs_reply(nfs
, &cb_data
);
975 return cb_data
.status
;
984 static void access_cb(int status
, struct nfs_context
*nfs
, void *data
, void *private_data
)
986 struct sync_cb_data
*cb_data
= private_data
;
988 cb_data
->is_finished
= 1;
989 cb_data
->status
= status
;
992 nfs_set_error(nfs
, "access call failed with \"%s\"", (char *)data
);
997 int nfs_access(struct nfs_context
*nfs
, const char *path
, int mode
)
999 struct sync_cb_data cb_data
;
1001 cb_data
.is_finished
= 0;
1003 if (nfs_access_async(nfs
, path
, mode
, access_cb
, &cb_data
) != 0) {
1004 nfs_set_error(nfs
, "nfs_access_async failed");
1008 wait_for_nfs_reply(nfs
, &cb_data
);
1010 return cb_data
.status
;
1018 static void symlink_cb(int status
, struct nfs_context
*nfs
, void *data
, void *private_data
)
1020 struct sync_cb_data
*cb_data
= private_data
;
1022 cb_data
->is_finished
= 1;
1023 cb_data
->status
= status
;
1026 nfs_set_error(nfs
, "symlink call failed with \"%s\"", (char *)data
);
1031 int nfs_symlink(struct nfs_context
*nfs
, const char *oldpath
, const char *newpath
)
1033 struct sync_cb_data cb_data
;
1035 cb_data
.is_finished
= 0;
1037 if (nfs_symlink_async(nfs
, oldpath
, newpath
, symlink_cb
, &cb_data
) != 0) {
1038 nfs_set_error(nfs
, "nfs_symlink_async failed");
1042 wait_for_nfs_reply(nfs
, &cb_data
);
1044 return cb_data
.status
;
1052 static void rename_cb(int status
, struct nfs_context
*nfs
, void *data
, void *private_data
)
1054 struct sync_cb_data
*cb_data
= private_data
;
1056 cb_data
->is_finished
= 1;
1057 cb_data
->status
= status
;
1060 nfs_set_error(nfs
, "rename call failed with \"%s\"", (char *)data
);
1065 int nfs_rename(struct nfs_context
*nfs
, const char *oldpath
, const char *newpath
)
1067 struct sync_cb_data cb_data
;
1069 cb_data
.is_finished
= 0;
1071 if (nfs_rename_async(nfs
, oldpath
, newpath
, rename_cb
, &cb_data
) != 0) {
1072 nfs_set_error(nfs
, "nfs_rename_async failed");
1076 wait_for_nfs_reply(nfs
, &cb_data
);
1078 return cb_data
.status
;
1086 static void link_cb(int status
, struct nfs_context
*nfs
, void *data
, void *private_data
)
1088 struct sync_cb_data
*cb_data
= private_data
;
1090 cb_data
->is_finished
= 1;
1091 cb_data
->status
= status
;
1094 nfs_set_error(nfs
, "link call failed with \"%s\"", (char *)data
);
1099 int nfs_link(struct nfs_context
*nfs
, const char *oldpath
, const char *newpath
)
1101 struct sync_cb_data cb_data
;
1103 cb_data
.is_finished
= 0;
1105 if (nfs_link_async(nfs
, oldpath
, newpath
, link_cb
, &cb_data
) != 0) {
1106 nfs_set_error(nfs
, "nfs_link_async failed");
1110 wait_for_nfs_reply(nfs
, &cb_data
);
1112 return cb_data
.status
;
1115 void mount_getexports_cb(struct rpc_context
*mount_context
, int status
, void *data
, void *private_data
)
1117 struct sync_cb_data
*cb_data
= private_data
;
1118 exports export
= *(exports
*)data
;
1120 cb_data
->is_finished
= 1;
1121 cb_data
->status
= status
;
1122 cb_data
->return_data
= NULL
;
1125 rpc_set_error(mount_context
, "mount/export call failed with \"%s\"", (char *)data
);
1129 while (export
!= NULL
) {
1132 new_export
= malloc(sizeof(*new_export
));
1133 memset(new_export
, 0, sizeof(*new_export
));
1134 new_export
->ex_dir
= strdup(export
->ex_dir
);
1135 new_export
->ex_next
= cb_data
->return_data
;
1137 cb_data
->return_data
= new_export
;
1139 export
= export
->ex_next
;
1143 struct exportnode
*mount_getexports(const char *server
)
1145 struct sync_cb_data cb_data
;
1146 struct rpc_context
*rpc
;
1149 cb_data
.is_finished
= 0;
1150 cb_data
.return_data
= NULL
;
1152 rpc
= rpc_init_context();
1153 if (mount_getexports_async(rpc
, server
, mount_getexports_cb
, &cb_data
) != 0) {
1154 rpc_destroy_context(rpc
);
1158 wait_for_reply(rpc
, &cb_data
);
1159 rpc_destroy_context(rpc
);
1161 return cb_data
.return_data
;
1164 void mount_free_export_list(struct exportnode
*exports
)
1166 struct exportnode
*tmp
;
1168 while ((tmp
= exports
)) {
1169 exports
= exports
->ex_next
;
1178 void free_nfs_srvr_list(struct nfs_server_list
*srv
)
1180 while (srv
!= NULL
) {
1181 struct nfs_server_list
*next
= srv
->next
;
1189 struct nfs_list_data
{
1191 struct nfs_server_list
*srvrs
;
1194 void callit_cb(struct rpc_context
*rpc
, int status
, void *data _U_
, void *private_data
)
1196 struct nfs_list_data
*srv_data
= private_data
;
1197 struct sockaddr
*sin
;
1199 struct nfs_server_list
*srvr
;
1201 if (status
== RPC_STATUS_CANCEL
) {
1205 srv_data
->status
= -1;
1209 sin
= rpc_get_recv_sockaddr(rpc
);
1211 rpc_set_error(rpc
, "failed to get sockaddr in CALLIT callback");
1212 srv_data
->status
= -1;
1216 if (getnameinfo(sin
, sizeof(struct sockaddr_in
), &hostdd
[0], sizeof(hostdd
), NULL
, 0, NI_NUMERICHOST
) < 0) {
1217 rpc_set_error(rpc
, "getnameinfo failed in CALLIT callback");
1218 srv_data
->status
= -1;
1222 /* check for dupes */
1223 for (srvr
= srv_data
->srvrs
; srvr
; srvr
= srvr
->next
) {
1224 if (!strcmp(hostdd
, srvr
->addr
)) {
1229 srvr
= malloc(sizeof(struct nfs_server_list
));
1231 rpc_set_error(rpc
, "Malloc failed when allocating server structure");
1232 srv_data
->status
= -1;
1236 srvr
->addr
= strdup(hostdd
);
1237 if (srvr
->addr
== NULL
) {
1238 rpc_set_error(rpc
, "Strdup failed when allocating server structure");
1240 srv_data
->status
= -1;
1244 srvr
->next
= srv_data
->srvrs
;
1245 srv_data
->srvrs
= srvr
;
1248 static int send_nfsd_probes(struct rpc_context
*rpc
, struct ifconf
*ifc
, struct nfs_list_data
*data
)
1252 for (ptr
=(char *)(ifc
->ifc_buf
); ptr
< (char *)(ifc
->ifc_buf
) + ifc
->ifc_len
; ) {
1256 ifr
= (struct ifreq
*)ptr
;
1257 #ifdef HAVE_SOCKADDR_LEN
1258 if (ifr
->ifr_addr
.sa_len
> sizeof(struct sockaddr
)) {
1259 ptr
+= sizeof(ifr
->ifr_name
) + ifr
->ifr_addr
.sa_len
;
1261 ptr
+= sizeof(ifr
->ifr_name
) + sizeof(struct sockaddr
);
1264 ptr
+= sizeof(struct ifreq
);
1267 if (ifr
->ifr_addr
.sa_family
!= AF_INET
) {
1270 if (ioctl(rpc_get_fd(rpc
), SIOCGIFFLAGS
, ifr
) < 0) {
1273 if (!(ifr
->ifr_flags
& IFF_UP
)) {
1276 if (ifr
->ifr_flags
& IFF_LOOPBACK
) {
1279 if (!(ifr
->ifr_flags
& IFF_BROADCAST
)) {
1282 if (ioctl(rpc_get_fd(rpc
), SIOCGIFBRDADDR
, ifr
) < 0) {
1285 if (getnameinfo(&ifr
->ifr_broadaddr
, sizeof(struct sockaddr_in
), &bcdd
[0], sizeof(bcdd
), NULL
, 0, NI_NUMERICHOST
) < 0) {
1288 if (rpc_set_udp_destination(rpc
, bcdd
, 111, 1) < 0) {
1292 if (rpc_pmap_callit_async(rpc
, MOUNT_PROGRAM
, 2, 0, NULL
, 0, callit_cb
, data
) < 0) {
1300 struct nfs_server_list
*nfs_find_local_servers(void)
1302 struct rpc_context
*rpc
;
1303 struct nfs_list_data data
= {0, NULL
};
1304 struct timeval tv_start
, tv_current
;
1309 rpc
= rpc_init_udp_context();
1314 if (rpc_bind_udp(rpc
, "0.0.0.0", 0) < 0) {
1315 rpc_destroy_context(rpc
);
1320 /* get list of all interfaces */
1321 size
= sizeof(struct ifreq
);
1325 while(ifc
.ifc_len
> (size
- sizeof(struct ifreq
))) {
1330 ifc
.ifc_buf
= malloc(size
);
1331 memset(ifc
.ifc_buf
, 0, size
);
1332 if (ioctl(rpc_get_fd(rpc
), SIOCGIFCONF
, (caddr_t
)&ifc
) < 0) {
1333 rpc_destroy_context(rpc
);
1339 for (loop
=0; loop
<3; loop
++) {
1340 if (send_nfsd_probes(rpc
, &ifc
, &data
) != 0) {
1341 rpc_destroy_context(rpc
);
1346 gettimeofday(&tv_start
, NULL
);
1350 pfd
.fd
= rpc_get_fd(rpc
);
1351 pfd
.events
= rpc_which_events(rpc
);
1353 gettimeofday(&tv_current
, NULL
);
1355 - (tv_current
.tv_sec
*1000 + tv_current
.tv_usec
/ 1000)
1356 + (tv_start
.tv_sec
*1000 + tv_start
.tv_usec
/ 1000);
1358 if (poll(&pfd
, 1, mpt
) < 0) {
1359 free_nfs_srvr_list(data
.srvrs
);
1360 rpc_destroy_context(rpc
);
1363 if (pfd
.revents
== 0) {
1367 if (rpc_service(rpc
, pfd
.revents
) < 0) {
1374 rpc_destroy_context(rpc
);
1376 if (data
.status
!= 0) {
1377 free_nfs_srvr_list(data
.srvrs
);