7ba52225395fcfc10f715181030882240c672640
[deb_libnfs.git] / lib / libnfs-sync.c
1 /*
2 Copyright (C) 2010 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 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.
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 Lesser General Public License for more details.
13
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/>.
16 */
17 /*
18 * High level api to nfs filesystems
19 */
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23
24 #ifdef AROS
25 #include "aros_compat.h"
26 #endif
27
28 #ifdef WIN32
29 #include "win32_compat.h"
30 #endif
31
32 #ifdef HAVE_NET_IF_H
33 #include <net/if.h>
34 #endif
35
36 #ifdef ANDROID
37 #define statvfs statfs
38 #endif
39
40 #ifdef HAVE_SYS_VFS_H
41 #include <sys/vfs.h>
42 #endif
43
44 #ifdef HAVE_SYS_STATVFS_H
45 #include <sys/statvfs.h>
46 #endif
47
48 #ifdef HAVE_SYS_IOCTL_H
49 #include <sys/ioctl.h>
50 #endif
51
52 #ifdef HAVE_SYS_SOCKET_H
53 #include <sys/socket.h>
54 #endif
55
56 #ifdef HAVE_POLL_H
57 #include <poll.h>
58 #endif
59
60 #ifdef HAVE_NETDB_H
61 #include <netdb.h>
62 #endif
63
64 #ifdef HAVE_UNISTD_H
65 #include <unistd.h>
66 #endif
67
68 #ifdef HAVE_NETINET_IN_H
69 #include <netinet/in.h>
70 #endif
71
72 #ifdef HAVE_STRINGS_H
73 #include <strings.h>
74 #endif
75
76 #include <stdio.h>
77 #include <stdlib.h>
78 #include <string.h>
79 #include <assert.h>
80 #include <sys/types.h>
81 #include <sys/stat.h>
82 #include <fcntl.h>
83 #include <errno.h>
84
85 #ifdef HAVE_SYS_SOCKIO_H
86 #include <sys/sockio.h>
87 #endif
88
89 #include "libnfs-zdr.h"
90 #include "libnfs.h"
91 #include "libnfs-raw.h"
92 #include "libnfs-raw-mount.h"
93 #include "libnfs-raw-nfs.h"
94 #include "libnfs-private.h"
95
96 struct sync_cb_data {
97 int is_finished;
98 int status;
99 uint64_t offset;
100 void *return_data;
101 int return_int;
102 };
103
104
105 static void wait_for_reply(struct rpc_context *rpc, struct sync_cb_data *cb_data)
106 {
107 struct pollfd pfd;
108
109 assert(rpc->magic == RPC_CONTEXT_MAGIC);
110
111 while (!cb_data->is_finished) {
112
113 pfd.fd = rpc_get_fd(rpc);
114 pfd.events = rpc_which_events(rpc);
115 if (poll(&pfd, 1, -1) < 0) {
116 rpc_set_error(rpc, "Poll failed");
117 cb_data->status = -EIO;
118 break;
119 }
120 if (rpc_service(rpc, pfd.revents) < 0) {
121 rpc_set_error(rpc, "rpc_service failed");
122 cb_data->status = -EIO;
123 break;
124 }
125 if (rpc_get_fd(rpc) == -1) {
126 rpc_set_error(rpc, "Socket closed\n");
127 break;
128 }
129 }
130 }
131
132 static void wait_for_nfs_reply(struct nfs_context *nfs, struct sync_cb_data *cb_data)
133 {
134 struct pollfd pfd;
135
136 while (!cb_data->is_finished) {
137
138 pfd.fd = nfs_get_fd(nfs);
139 pfd.events = nfs_which_events(nfs);
140 if (poll(&pfd, 1, -1) < 0) {
141 nfs_set_error(nfs, "Poll failed");
142 cb_data->status = -EIO;
143 break;
144 }
145 if (nfs_service(nfs, pfd.revents) < 0) {
146 nfs_set_error(nfs, "nfs_service failed");
147 cb_data->status = -EIO;
148 break;
149 }
150 }
151 }
152
153
154
155
156
157
158 /*
159 * connect to the server and mount the export
160 */
161 static void mount_cb(int status, struct nfs_context *nfs, void *data, void *private_data)
162 {
163 struct sync_cb_data *cb_data = private_data;
164
165 cb_data->is_finished = 1;
166 cb_data->status = status;
167
168 if (status < 0) {
169 nfs_set_error(nfs, "mount/mnt call failed with \"%s\"", (char *)data);
170 return;
171 }
172 }
173
174 int nfs_mount(struct nfs_context *nfs, const char *server, const char *export)
175 {
176 struct sync_cb_data cb_data;
177 struct rpc_context *rpc = nfs_get_rpc_context(nfs);
178
179 assert(rpc->magic == RPC_CONTEXT_MAGIC);
180
181 cb_data.is_finished = 0;
182
183 if (nfs_mount_async(nfs, server, export, mount_cb, &cb_data) != 0) {
184 nfs_set_error(nfs, "nfs_mount_async failed");
185 return -1;
186 }
187
188 wait_for_nfs_reply(nfs, &cb_data);
189
190 /* Dont want any more callbacks even if the socket is closed */
191 rpc->connect_cb = NULL;
192
193 return cb_data.status;
194 }
195
196
197 /*
198 * stat()
199 */
200 static void stat_cb(int status, struct nfs_context *nfs, void *data, void *private_data)
201 {
202 struct sync_cb_data *cb_data = private_data;
203
204 cb_data->is_finished = 1;
205 cb_data->status = status;
206
207 if (status < 0) {
208 nfs_set_error(nfs, "stat call failed with \"%s\"", (char *)data);
209 return;
210 }
211 #ifdef WIN32
212 memcpy(cb_data->return_data, data, sizeof(struct __stat64));
213 #else
214 memcpy(cb_data->return_data, data, sizeof(struct stat));
215 #endif
216 }
217
218 #ifdef WIN32
219 int nfs_stat(struct nfs_context *nfs, const char *path, struct __stat64 *st)
220 #else
221 int nfs_stat(struct nfs_context *nfs, const char *path, struct stat *st)
222 #endif
223 {
224 struct sync_cb_data cb_data;
225
226 cb_data.is_finished = 0;
227 cb_data.return_data = st;
228
229 if (nfs_stat_async(nfs, path, stat_cb, &cb_data) != 0) {
230 nfs_set_error(nfs, "nfs_stat_async failed");
231 return -1;
232 }
233
234 wait_for_nfs_reply(nfs, &cb_data);
235
236 return cb_data.status;
237 }
238
239 static void stat64_cb(int status, struct nfs_context *nfs, void *data, void *private_data)
240 {
241 struct sync_cb_data *cb_data = private_data;
242
243 cb_data->is_finished = 1;
244 cb_data->status = status;
245
246 if (status < 0) {
247 nfs_set_error(nfs, "stat call failed with \"%s\"", (char *)data);
248 return;
249 }
250 memcpy(cb_data->return_data, data, sizeof(struct nfs_stat_64));
251 }
252
253 int nfs_stat64(struct nfs_context *nfs, const char *path, struct nfs_stat_64 *st)
254 {
255 struct sync_cb_data cb_data;
256
257 cb_data.is_finished = 0;
258 cb_data.return_data = st;
259
260 if (nfs_stat64_async(nfs, path, stat64_cb, &cb_data) != 0) {
261 nfs_set_error(nfs, "nfs_stat64_async failed");
262 return -1;
263 }
264
265 wait_for_nfs_reply(nfs, &cb_data);
266
267 return cb_data.status;
268 }
269
270 /*
271 * open()
272 */
273 static void open_cb(int status, struct nfs_context *nfs, void *data, void *private_data)
274 {
275 struct sync_cb_data *cb_data = private_data;
276 struct nfsfh *fh, **nfsfh;
277
278 cb_data->is_finished = 1;
279 cb_data->status = status;
280
281 if (status < 0) {
282 nfs_set_error(nfs, "open call failed with \"%s\"", (char *)data);
283 return;
284 }
285
286 fh = data;
287 nfsfh = cb_data->return_data;
288 *nfsfh = fh;
289 }
290
291 int nfs_open(struct nfs_context *nfs, const char *path, int flags, struct nfsfh **nfsfh)
292 {
293 struct sync_cb_data cb_data;
294
295 cb_data.is_finished = 0;
296 cb_data.return_data = nfsfh;
297
298 if (nfs_open_async(nfs, path, flags, open_cb, &cb_data) != 0) {
299 nfs_set_error(nfs, "nfs_open_async failed");
300 return -1;
301 }
302
303 wait_for_nfs_reply(nfs, &cb_data);
304
305 return cb_data.status;
306 }
307
308 /*
309 * chdir()
310 */
311 static void chdir_cb(int status, struct nfs_context *nfs, void *data, void *private_data)
312 {
313 struct sync_cb_data *cb_data = private_data;
314
315 cb_data->is_finished = 1;
316 cb_data->status = status;
317
318 if (status < 0) {
319 nfs_set_error(nfs, "chdir call failed with \"%s\"", (char *)data);
320 return;
321 }
322 }
323
324 int nfs_chdir(struct nfs_context *nfs, const char *path)
325 {
326 struct sync_cb_data cb_data;
327
328 cb_data.is_finished = 0;
329
330 if (nfs_chdir_async(nfs, path, chdir_cb, &cb_data) != 0) {
331 nfs_set_error(nfs, "nfs_chdir_async failed with %s",
332 nfs_get_error(nfs));
333 return -1;
334 }
335
336 wait_for_nfs_reply(nfs, &cb_data);
337
338 return cb_data.status;
339 }
340
341
342
343 /*
344 * pread()
345 */
346 static void pread_cb(int status, struct nfs_context *nfs, void *data, void *private_data)
347 {
348 struct sync_cb_data *cb_data = private_data;
349 char *buffer;
350 cb_data->is_finished = 1;
351 cb_data->status = status;
352
353 if (status < 0) {
354 nfs_set_error(nfs, "pread call failed with \"%s\"", (char *)data);
355 return;
356 }
357
358 buffer = cb_data->return_data;
359 memcpy(buffer, (char *)data, status);
360 }
361
362 int nfs_pread(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t offset, uint64_t count, char *buffer)
363 {
364 struct sync_cb_data cb_data;
365
366 cb_data.is_finished = 0;
367 cb_data.return_data = buffer;
368
369 if (nfs_pread_async(nfs, nfsfh, offset, count, pread_cb, &cb_data) != 0) {
370 nfs_set_error(nfs, "nfs_pread_async failed");
371 return -1;
372 }
373
374 wait_for_nfs_reply(nfs, &cb_data);
375
376 return cb_data.status;
377 }
378
379 /*
380 * read()
381 */
382 int nfs_read(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t count, char *buffer)
383 {
384 return nfs_pread(nfs, nfsfh, nfs_get_current_offset(nfsfh), count, buffer);
385 }
386
387 /*
388 * close()
389 */
390 static void close_cb(int status, struct nfs_context *nfs, void *data, void *private_data)
391 {
392 struct sync_cb_data *cb_data = private_data;
393 cb_data->is_finished = 1;
394 cb_data->status = status;
395
396 if (status < 0) {
397 nfs_set_error(nfs, "close call failed with \"%s\"", (char *)data);
398 return;
399 }
400 }
401
402 int nfs_close(struct nfs_context *nfs, struct nfsfh *nfsfh)
403 {
404 struct sync_cb_data cb_data;
405
406 cb_data.is_finished = 0;
407
408 if (nfs_close_async(nfs, nfsfh, close_cb, &cb_data) != 0) {
409 nfs_set_error(nfs, "nfs_close_async failed");
410 return -1;
411 }
412
413 wait_for_nfs_reply(nfs, &cb_data);
414
415 return cb_data.status;
416 }
417
418
419
420
421 /*
422 * fstat()
423 */
424 int nfs_fstat(struct nfs_context *nfs, struct nfsfh *nfsfh, struct stat *st)
425 {
426 struct sync_cb_data cb_data;
427
428 cb_data.is_finished = 0;
429 cb_data.return_data = st;
430
431 if (nfs_fstat_async(nfs, nfsfh, stat_cb, &cb_data) != 0) {
432 nfs_set_error(nfs, "nfs_fstat_async failed");
433 return -1;
434 }
435
436 wait_for_nfs_reply(nfs, &cb_data);
437
438 return cb_data.status;
439 }
440
441
442 /*
443 * pwrite()
444 */
445 static void pwrite_cb(int status, struct nfs_context *nfs, void *data, void *private_data)
446 {
447 struct sync_cb_data *cb_data = private_data;
448 cb_data->is_finished = 1;
449 cb_data->status = status;
450
451 if (status < 0) {
452 nfs_set_error(nfs, "pwrite call failed with \"%s\"", (char *)data);
453 return;
454 }
455 }
456
457 int nfs_pwrite(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t offset, uint64_t count, char *buf)
458 {
459 struct sync_cb_data cb_data;
460
461 cb_data.is_finished = 0;
462
463 if (nfs_pwrite_async(nfs, nfsfh, offset, count, buf, pwrite_cb, &cb_data) != 0) {
464 nfs_set_error(nfs, "nfs_pwrite_async failed");
465 return -1;
466 }
467
468 wait_for_nfs_reply(nfs, &cb_data);
469
470 return cb_data.status;
471 }
472
473 /*
474 * write()
475 */
476 int nfs_write(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t count, char *buf)
477 {
478 return nfs_pwrite(nfs, nfsfh, nfs_get_current_offset(nfsfh), count, buf);
479 }
480
481
482 /*
483 * fsync()
484 */
485 static void fsync_cb(int status, struct nfs_context *nfs, void *data, void *private_data)
486 {
487 struct sync_cb_data *cb_data = private_data;
488 cb_data->is_finished = 1;
489 cb_data->status = status;
490
491 if (status < 0) {
492 nfs_set_error(nfs, "fsync call failed with \"%s\"", (char *)data);
493 return;
494 }
495 }
496
497 int nfs_fsync(struct nfs_context *nfs, struct nfsfh *nfsfh)
498 {
499 struct sync_cb_data cb_data;
500
501 cb_data.is_finished = 0;
502
503 if (nfs_fsync_async(nfs, nfsfh, fsync_cb, &cb_data) != 0) {
504 nfs_set_error(nfs, "nfs_fsync_async failed");
505 return -1;
506 }
507
508 wait_for_nfs_reply(nfs, &cb_data);
509
510 return cb_data.status;
511 }
512
513
514
515
516 /*
517 * ftruncate()
518 */
519 static void ftruncate_cb(int status, struct nfs_context *nfs, void *data, void *private_data)
520 {
521 struct sync_cb_data *cb_data = private_data;
522 cb_data->is_finished = 1;
523 cb_data->status = status;
524
525 if (status < 0) {
526 nfs_set_error(nfs, "ftruncate call failed with \"%s\"", (char *)data);
527 return;
528 }
529 }
530
531 int nfs_ftruncate(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t length)
532 {
533 struct sync_cb_data cb_data;
534
535 cb_data.is_finished = 0;
536
537 if (nfs_ftruncate_async(nfs, nfsfh, length, ftruncate_cb, &cb_data) != 0) {
538 nfs_set_error(nfs, "nfs_ftruncate_async failed");
539 return -1;
540 }
541
542 wait_for_nfs_reply(nfs, &cb_data);
543
544 return cb_data.status;
545 }
546
547
548
549 /*
550 * truncate()
551 */
552 static void truncate_cb(int status, struct nfs_context *nfs, void *data, void *private_data)
553 {
554 struct sync_cb_data *cb_data = private_data;
555 cb_data->is_finished = 1;
556 cb_data->status = status;
557
558 if (status < 0) {
559 nfs_set_error(nfs, "truncate call failed with \"%s\"", (char *)data);
560 return;
561 }
562 }
563
564 int nfs_truncate(struct nfs_context *nfs, const char *path, uint64_t length)
565 {
566 struct sync_cb_data cb_data;
567
568 cb_data.is_finished = 0;
569
570 if (nfs_truncate_async(nfs, path, length, truncate_cb, &cb_data) != 0) {
571 nfs_set_error(nfs, "nfs_ftruncate_async failed");
572 return -1;
573 }
574
575 wait_for_nfs_reply(nfs, &cb_data);
576
577 return cb_data.status;
578 }
579
580
581
582
583
584 /*
585 * mkdir()
586 */
587 static void mkdir_cb(int status, struct nfs_context *nfs, void *data, void *private_data)
588 {
589 struct sync_cb_data *cb_data = private_data;
590 cb_data->is_finished = 1;
591 cb_data->status = status;
592
593 if (status < 0) {
594 nfs_set_error(nfs, "mkdir call failed with \"%s\"", (char *)data);
595 return;
596 }
597 }
598
599 int nfs_mkdir(struct nfs_context *nfs, const char *path)
600 {
601 struct sync_cb_data cb_data;
602
603 cb_data.is_finished = 0;
604
605 if (nfs_mkdir_async(nfs, path, mkdir_cb, &cb_data) != 0) {
606 nfs_set_error(nfs, "nfs_mkdir_async failed");
607 return -1;
608 }
609
610 wait_for_nfs_reply(nfs, &cb_data);
611
612 return cb_data.status;
613 }
614
615
616
617
618
619 /*
620 * rmdir()
621 */
622 static void rmdir_cb(int status, struct nfs_context *nfs, void *data, void *private_data)
623 {
624 struct sync_cb_data *cb_data = private_data;
625 cb_data->is_finished = 1;
626 cb_data->status = status;
627
628 if (status < 0) {
629 nfs_set_error(nfs, "rmdir call failed with \"%s\"", (char *)data);
630 return;
631 }
632 }
633
634 int nfs_rmdir(struct nfs_context *nfs, const char *path)
635 {
636 struct sync_cb_data cb_data;
637
638 cb_data.is_finished = 0;
639
640 if (nfs_rmdir_async(nfs, path, rmdir_cb, &cb_data) != 0) {
641 nfs_set_error(nfs, "nfs_rmdir_async failed");
642 return -1;
643 }
644
645 wait_for_nfs_reply(nfs, &cb_data);
646
647 return cb_data.status;
648 }
649
650
651
652 /*
653 * creat()
654 */
655 static void creat_cb(int status, struct nfs_context *nfs, void *data, void *private_data)
656 {
657 struct sync_cb_data *cb_data = private_data;
658 struct nfsfh *fh, **nfsfh;
659
660 cb_data->is_finished = 1;
661 cb_data->status = status;
662
663 if (status < 0) {
664 nfs_set_error(nfs, "creat call failed with \"%s\"", (char *)data);
665 return;
666 }
667
668 fh = data;
669 nfsfh = cb_data->return_data;
670 *nfsfh = fh;
671 }
672
673 int nfs_creat(struct nfs_context *nfs, const char *path, int mode, struct nfsfh **nfsfh)
674 {
675 struct sync_cb_data cb_data;
676
677 cb_data.is_finished = 0;
678 cb_data.return_data = nfsfh;
679
680 if (nfs_creat_async(nfs, path, mode, creat_cb, &cb_data) != 0) {
681 nfs_set_error(nfs, "nfs_creat_async failed");
682 return -1;
683 }
684
685 wait_for_nfs_reply(nfs, &cb_data);
686
687 return cb_data.status;
688 }
689
690 /*
691 * mknod()
692 */
693 static void mknod_cb(int status, struct nfs_context *nfs, void *data, void *private_data)
694 {
695 struct sync_cb_data *cb_data = private_data;
696
697 cb_data->is_finished = 1;
698 cb_data->status = status;
699
700 if (status < 0) {
701 nfs_set_error(nfs, "mknod call failed with \"%s\"", (char *)data);
702 return;
703 }
704 }
705
706 int nfs_mknod(struct nfs_context *nfs, const char *path, int mode, int dev)
707 {
708 struct sync_cb_data cb_data;
709
710 cb_data.is_finished = 0;
711
712 if (nfs_mknod_async(nfs, path, mode, dev, mknod_cb, &cb_data) != 0) {
713 nfs_set_error(nfs, "nfs_creat_async failed");
714 return -1;
715 }
716
717 wait_for_nfs_reply(nfs, &cb_data);
718
719 return cb_data.status;
720 }
721
722
723 /*
724 * unlink()
725 */
726 static void unlink_cb(int status, struct nfs_context *nfs, void *data, void *private_data)
727 {
728 struct sync_cb_data *cb_data = private_data;
729
730 cb_data->is_finished = 1;
731 cb_data->status = status;
732
733 if (status < 0) {
734 nfs_set_error(nfs, "unlink call failed with \"%s\"", (char *)data);
735 return;
736 }
737 }
738
739 int nfs_unlink(struct nfs_context *nfs, const char *path)
740 {
741 struct sync_cb_data cb_data;
742
743 cb_data.is_finished = 0;
744
745 if (nfs_unlink_async(nfs, path, unlink_cb, &cb_data) != 0) {
746 nfs_set_error(nfs, "nfs_unlink_async failed");
747 return -1;
748 }
749
750 wait_for_nfs_reply(nfs, &cb_data);
751
752 return cb_data.status;
753 }
754
755
756
757 /*
758 * opendir()
759 */
760 static void opendir_cb(int status, struct nfs_context *nfs, void *data, void *private_data)
761 {
762 struct sync_cb_data *cb_data = private_data;
763 struct nfsdir *dir, **nfsdir;
764
765 cb_data->is_finished = 1;
766 cb_data->status = status;
767
768 if (status < 0) {
769 nfs_set_error(nfs, "opendir call failed with \"%s\"", (char *)data);
770 return;
771 }
772
773 dir = data;
774 nfsdir = cb_data->return_data;
775 *nfsdir = dir;
776 }
777
778 int nfs_opendir(struct nfs_context *nfs, const char *path, struct nfsdir **nfsdir)
779 {
780 struct sync_cb_data cb_data;
781
782 cb_data.is_finished = 0;
783 cb_data.return_data = nfsdir;
784
785 if (nfs_opendir_async(nfs, path, opendir_cb, &cb_data) != 0) {
786 nfs_set_error(nfs, "nfs_opendir_async failed");
787 return -1;
788 }
789
790 wait_for_nfs_reply(nfs, &cb_data);
791
792 return cb_data.status;
793 }
794
795
796 /*
797 * lseek()
798 */
799 static void lseek_cb(int status, struct nfs_context *nfs, void *data, void *private_data)
800 {
801 struct sync_cb_data *cb_data = private_data;
802
803 cb_data->is_finished = 1;
804 cb_data->status = status;
805
806 if (status < 0) {
807 nfs_set_error(nfs, "lseek call failed with \"%s\"", (char *)data);
808 return;
809 }
810
811 if (cb_data->return_data != NULL) {
812 memcpy(cb_data->return_data, data, sizeof(uint64_t));
813 }
814 }
815
816 int nfs_lseek(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t offset, int whence, uint64_t *current_offset)
817 {
818 struct sync_cb_data cb_data;
819
820 cb_data.is_finished = 0;
821 cb_data.return_data = current_offset;
822
823 if (nfs_lseek_async(nfs, nfsfh, offset, whence, lseek_cb, &cb_data) != 0) {
824 nfs_set_error(nfs, "nfs_lseek_async failed");
825 return -1;
826 }
827
828 wait_for_nfs_reply(nfs, &cb_data);
829
830 return cb_data.status;
831 }
832
833
834
835 /*
836 * statvfs()
837 */
838 static void statvfs_cb(int status, struct nfs_context *nfs, void *data, void *private_data)
839 {
840 struct sync_cb_data *cb_data = private_data;
841
842 cb_data->is_finished = 1;
843 cb_data->status = status;
844
845 if (status < 0) {
846 nfs_set_error(nfs, "statvfs call failed with \"%s\"", (char *)data);
847 return;
848 }
849
850 memcpy(cb_data->return_data, data, sizeof(struct statvfs));
851 }
852
853 int nfs_statvfs(struct nfs_context *nfs, const char *path, struct statvfs *svfs)
854 {
855 struct sync_cb_data cb_data;
856
857 cb_data.is_finished = 0;
858 cb_data.return_data = svfs;
859
860 if (nfs_statvfs_async(nfs, path, statvfs_cb, &cb_data) != 0) {
861 nfs_set_error(nfs, "nfs_statvfs_async failed");
862 return -1;
863 }
864
865 wait_for_nfs_reply(nfs, &cb_data);
866
867 return cb_data.status;
868 }
869
870
871
872
873
874 /*
875 * readlink()
876 */
877 static void readlink_cb(int status, struct nfs_context *nfs, void *data, void *private_data)
878 {
879 struct sync_cb_data *cb_data = private_data;
880
881 cb_data->is_finished = 1;
882 cb_data->status = status;
883
884 if (status < 0) {
885 nfs_set_error(nfs, "readlink call failed with \"%s\"", (char *)data);
886 return;
887 }
888
889 if (strlen(data) > (size_t)cb_data->return_int) {
890 nfs_set_error(nfs, "Too small buffer for readlink");
891 cb_data->status = -ENAMETOOLONG;
892 return;
893 }
894
895 memcpy(cb_data->return_data, data, strlen(data)+1);
896 }
897
898 int nfs_readlink(struct nfs_context *nfs, const char *path, char *buf, int bufsize)
899 {
900 struct sync_cb_data cb_data;
901
902 cb_data.is_finished = 0;
903 cb_data.return_data = buf;
904 cb_data.return_int = bufsize;
905
906 if (nfs_readlink_async(nfs, path, readlink_cb, &cb_data) != 0) {
907 nfs_set_error(nfs, "nfs_readlink_async failed");
908 return -1;
909 }
910
911 wait_for_nfs_reply(nfs, &cb_data);
912
913 return cb_data.status;
914 }
915
916
917
918 /*
919 * chmod()
920 */
921 static void chmod_cb(int status, struct nfs_context *nfs, void *data, void *private_data)
922 {
923 struct sync_cb_data *cb_data = private_data;
924
925 cb_data->is_finished = 1;
926 cb_data->status = status;
927
928 if (status < 0) {
929 nfs_set_error(nfs, "chmod call failed with \"%s\"", (char *)data);
930 return;
931 }
932 }
933
934 int nfs_chmod(struct nfs_context *nfs, const char *path, int mode)
935 {
936 struct sync_cb_data cb_data;
937
938 cb_data.is_finished = 0;
939
940 if (nfs_chmod_async(nfs, path, mode, chmod_cb, &cb_data) != 0) {
941 nfs_set_error(nfs, "nfs_chmod_async failed");
942 return -1;
943 }
944
945 wait_for_nfs_reply(nfs, &cb_data);
946
947 return cb_data.status;
948 }
949
950
951
952
953 /*
954 * fchmod()
955 */
956 static void fchmod_cb(int status, struct nfs_context *nfs, void *data, void *private_data)
957 {
958 struct sync_cb_data *cb_data = private_data;
959
960 cb_data->is_finished = 1;
961 cb_data->status = status;
962
963 if (status < 0) {
964 nfs_set_error(nfs, "fchmod call failed with \"%s\"", (char *)data);
965 return;
966 }
967 }
968
969 int nfs_fchmod(struct nfs_context *nfs, struct nfsfh *nfsfh, int mode)
970 {
971 struct sync_cb_data cb_data;
972
973 cb_data.is_finished = 0;
974
975 if (nfs_fchmod_async(nfs, nfsfh, mode, fchmod_cb, &cb_data) != 0) {
976 nfs_set_error(nfs, "nfs_fchmod_async failed");
977 return -1;
978 }
979
980 wait_for_nfs_reply(nfs, &cb_data);
981
982 return cb_data.status;
983 }
984
985
986
987
988 /*
989 * chown()
990 */
991 static void chown_cb(int status, struct nfs_context *nfs, void *data, void *private_data)
992 {
993 struct sync_cb_data *cb_data = private_data;
994
995 cb_data->is_finished = 1;
996 cb_data->status = status;
997
998 if (status < 0) {
999 nfs_set_error(nfs, "chown call failed with \"%s\"", (char *)data);
1000 return;
1001 }
1002 }
1003
1004 int nfs_chown(struct nfs_context *nfs, const char *path, int uid, int gid)
1005 {
1006 struct sync_cb_data cb_data;
1007
1008 cb_data.is_finished = 0;
1009
1010 if (nfs_chown_async(nfs, path, uid, gid, chown_cb, &cb_data) != 0) {
1011 nfs_set_error(nfs, "nfs_chown_async failed");
1012 return -1;
1013 }
1014
1015 wait_for_nfs_reply(nfs, &cb_data);
1016
1017 return cb_data.status;
1018 }
1019
1020 /*
1021 * fchown()
1022 */
1023 static void fchown_cb(int status, struct nfs_context *nfs, void *data, void *private_data)
1024 {
1025 struct sync_cb_data *cb_data = private_data;
1026
1027 cb_data->is_finished = 1;
1028 cb_data->status = status;
1029
1030 if (status < 0) {
1031 nfs_set_error(nfs, "fchown call failed with \"%s\"", (char *)data);
1032 return;
1033 }
1034 }
1035
1036 int nfs_fchown(struct nfs_context *nfs, struct nfsfh *nfsfh, int uid, int gid)
1037 {
1038 struct sync_cb_data cb_data;
1039
1040 cb_data.is_finished = 0;
1041
1042 if (nfs_fchown_async(nfs, nfsfh, uid, gid, fchown_cb, &cb_data) != 0) {
1043 nfs_set_error(nfs, "nfs_fchown_async failed");
1044 return -1;
1045 }
1046
1047 wait_for_nfs_reply(nfs, &cb_data);
1048
1049 return cb_data.status;
1050 }
1051
1052
1053
1054 /*
1055 * utimes()
1056 */
1057 static void utimes_cb(int status, struct nfs_context *nfs, void *data, void *private_data)
1058 {
1059 struct sync_cb_data *cb_data = private_data;
1060
1061 cb_data->is_finished = 1;
1062 cb_data->status = status;
1063
1064 if (status < 0) {
1065 nfs_set_error(nfs, "utimes call failed with \"%s\"", (char *)data);
1066 return;
1067 }
1068 }
1069
1070 int nfs_utimes(struct nfs_context *nfs, const char *path, struct timeval *times)
1071 {
1072 struct sync_cb_data cb_data;
1073
1074 cb_data.is_finished = 0;
1075
1076 if (nfs_utimes_async(nfs, path, times, utimes_cb, &cb_data) != 0) {
1077 nfs_set_error(nfs, "nfs_utimes_async failed");
1078 return -1;
1079 }
1080
1081 wait_for_nfs_reply(nfs, &cb_data);
1082
1083 return cb_data.status;
1084 }
1085
1086
1087
1088 /*
1089 * utime()
1090 */
1091 static void utime_cb(int status, struct nfs_context *nfs, void *data, void *private_data)
1092 {
1093 struct sync_cb_data *cb_data = private_data;
1094
1095 cb_data->is_finished = 1;
1096 cb_data->status = status;
1097
1098 if (status < 0) {
1099 nfs_set_error(nfs, "utime call failed with \"%s\"", (char *)data);
1100 return;
1101 }
1102 }
1103
1104 int nfs_utime(struct nfs_context *nfs, const char *path, struct utimbuf *times)
1105 {
1106 struct sync_cb_data cb_data;
1107
1108 cb_data.is_finished = 0;
1109
1110 if (nfs_utime_async(nfs, path, times, utime_cb, &cb_data) != 0) {
1111 nfs_set_error(nfs, "nfs_utimes_async failed");
1112 return -1;
1113 }
1114
1115 wait_for_nfs_reply(nfs, &cb_data);
1116
1117 return cb_data.status;
1118 }
1119
1120
1121
1122
1123 /*
1124 * access()
1125 */
1126 static void access_cb(int status, struct nfs_context *nfs, void *data, void *private_data)
1127 {
1128 struct sync_cb_data *cb_data = private_data;
1129
1130 cb_data->is_finished = 1;
1131 cb_data->status = status;
1132
1133 if (status < 0) {
1134 nfs_set_error(nfs, "access call failed with \"%s\"", (char *)data);
1135 return;
1136 }
1137 }
1138
1139 int nfs_access(struct nfs_context *nfs, const char *path, int mode)
1140 {
1141 struct sync_cb_data cb_data;
1142
1143 cb_data.is_finished = 0;
1144
1145 if (nfs_access_async(nfs, path, mode, access_cb, &cb_data) != 0) {
1146 nfs_set_error(nfs, "nfs_access_async failed");
1147 return -1;
1148 }
1149
1150 wait_for_nfs_reply(nfs, &cb_data);
1151
1152 return cb_data.status;
1153 }
1154
1155
1156
1157 /*
1158 * symlink()
1159 */
1160 static void symlink_cb(int status, struct nfs_context *nfs, void *data, void *private_data)
1161 {
1162 struct sync_cb_data *cb_data = private_data;
1163
1164 cb_data->is_finished = 1;
1165 cb_data->status = status;
1166
1167 if (status < 0) {
1168 nfs_set_error(nfs, "symlink call failed with \"%s\"", (char *)data);
1169 return;
1170 }
1171 }
1172
1173 int nfs_symlink(struct nfs_context *nfs, const char *oldpath, const char *newpath)
1174 {
1175 struct sync_cb_data cb_data;
1176
1177 cb_data.is_finished = 0;
1178
1179 if (nfs_symlink_async(nfs, oldpath, newpath, symlink_cb, &cb_data) != 0) {
1180 nfs_set_error(nfs, "nfs_symlink_async failed");
1181 return -1;
1182 }
1183
1184 wait_for_nfs_reply(nfs, &cb_data);
1185
1186 return cb_data.status;
1187 }
1188
1189
1190
1191 /*
1192 * rename()
1193 */
1194 static void rename_cb(int status, struct nfs_context *nfs, void *data, void *private_data)
1195 {
1196 struct sync_cb_data *cb_data = private_data;
1197
1198 cb_data->is_finished = 1;
1199 cb_data->status = status;
1200
1201 if (status < 0) {
1202 nfs_set_error(nfs, "rename call failed with \"%s\"", (char *)data);
1203 return;
1204 }
1205 }
1206
1207 int nfs_rename(struct nfs_context *nfs, const char *oldpath, const char *newpath)
1208 {
1209 struct sync_cb_data cb_data;
1210
1211 cb_data.is_finished = 0;
1212
1213 if (nfs_rename_async(nfs, oldpath, newpath, rename_cb, &cb_data) != 0) {
1214 nfs_set_error(nfs, "nfs_rename_async failed");
1215 return -1;
1216 }
1217
1218 wait_for_nfs_reply(nfs, &cb_data);
1219
1220 return cb_data.status;
1221 }
1222
1223
1224
1225 /*
1226 * link()
1227 */
1228 static void link_cb(int status, struct nfs_context *nfs, void *data, void *private_data)
1229 {
1230 struct sync_cb_data *cb_data = private_data;
1231
1232 cb_data->is_finished = 1;
1233 cb_data->status = status;
1234
1235 if (status < 0) {
1236 nfs_set_error(nfs, "link call failed with \"%s\"", (char *)data);
1237 return;
1238 }
1239 }
1240
1241 int nfs_link(struct nfs_context *nfs, const char *oldpath, const char *newpath)
1242 {
1243 struct sync_cb_data cb_data;
1244
1245 cb_data.is_finished = 0;
1246
1247 if (nfs_link_async(nfs, oldpath, newpath, link_cb, &cb_data) != 0) {
1248 nfs_set_error(nfs, "nfs_link_async failed");
1249 return -1;
1250 }
1251
1252 wait_for_nfs_reply(nfs, &cb_data);
1253
1254 return cb_data.status;
1255 }
1256
1257 void mount_getexports_cb(struct rpc_context *mount_context, int status, void *data, void *private_data)
1258 {
1259 struct sync_cb_data *cb_data = private_data;
1260 exports export;
1261
1262 assert(mount_context->magic == RPC_CONTEXT_MAGIC);
1263
1264 cb_data->is_finished = 1;
1265 cb_data->status = status;
1266 cb_data->return_data = NULL;
1267
1268 if (status != 0) {
1269 rpc_set_error(mount_context, "mount/export call failed with \"%s\"", (char *)data);
1270 return;
1271 }
1272
1273 export = *(exports *)data;
1274 while (export != NULL) {
1275 exports new_export;
1276
1277 new_export = malloc(sizeof(*new_export));
1278 memset(new_export, 0, sizeof(*new_export));
1279 new_export->ex_dir = strdup(export->ex_dir);
1280 new_export->ex_next = cb_data->return_data;
1281
1282 cb_data->return_data = new_export;
1283
1284 export = export->ex_next;
1285 }
1286 }
1287
1288 struct exportnode *mount_getexports(const char *server)
1289 {
1290 struct sync_cb_data cb_data;
1291 struct rpc_context *rpc;
1292
1293
1294 cb_data.is_finished = 0;
1295 cb_data.return_data = NULL;
1296
1297 rpc = rpc_init_context();
1298 if (mount_getexports_async(rpc, server, mount_getexports_cb, &cb_data) != 0) {
1299 rpc_destroy_context(rpc);
1300 return NULL;
1301 }
1302
1303 wait_for_reply(rpc, &cb_data);
1304 rpc_destroy_context(rpc);
1305
1306 return cb_data.return_data;
1307 }
1308
1309 void mount_free_export_list(struct exportnode *exports)
1310 {
1311 struct exportnode *tmp;
1312
1313 while ((tmp = exports)) {
1314 exports = exports->ex_next;
1315 free(tmp->ex_dir);
1316 free(tmp);
1317 }
1318 }
1319
1320
1321
1322 void free_nfs_srvr_list(struct nfs_server_list *srv)
1323 {
1324 while (srv != NULL) {
1325 struct nfs_server_list *next = srv->next;
1326
1327 free(srv->addr);
1328 free(srv);
1329 srv = next;
1330 }
1331 }
1332
1333 struct nfs_list_data {
1334 int status;
1335 struct nfs_server_list *srvrs;
1336 };
1337
1338 void callit_cb(struct rpc_context *rpc, int status, void *data _U_, void *private_data)
1339 {
1340 struct nfs_list_data *srv_data = private_data;
1341 struct sockaddr *sin;
1342 char hostdd[16];
1343 struct nfs_server_list *srvr;
1344
1345 assert(rpc->magic == RPC_CONTEXT_MAGIC);
1346
1347 if (status == RPC_STATUS_CANCEL) {
1348 return;
1349 }
1350 if (status != 0) {
1351 srv_data->status = -1;
1352 return;
1353 }
1354
1355 sin = rpc_get_recv_sockaddr(rpc);
1356 if (sin == NULL) {
1357 rpc_set_error(rpc, "failed to get sockaddr in CALLIT callback");
1358 srv_data->status = -1;
1359 return;
1360 }
1361
1362 if (getnameinfo(sin, sizeof(struct sockaddr_in), &hostdd[0], sizeof(hostdd), NULL, 0, NI_NUMERICHOST) < 0) {
1363 rpc_set_error(rpc, "getnameinfo failed in CALLIT callback");
1364 srv_data->status = -1;
1365 return;
1366 }
1367
1368 /* check for dupes */
1369 for (srvr = srv_data->srvrs; srvr; srvr = srvr->next) {
1370 if (!strcmp(hostdd, srvr->addr)) {
1371 return;
1372 }
1373 }
1374
1375 srvr = malloc(sizeof(struct nfs_server_list));
1376 if (srvr == NULL) {
1377 rpc_set_error(rpc, "Malloc failed when allocating server structure");
1378 srv_data->status = -1;
1379 return;
1380 }
1381
1382 srvr->addr = strdup(hostdd);
1383 if (srvr->addr == NULL) {
1384 rpc_set_error(rpc, "Strdup failed when allocating server structure");
1385 free(srvr);
1386 srv_data->status = -1;
1387 return;
1388 }
1389
1390 srvr->next = srv_data->srvrs;
1391 srv_data->srvrs = srvr;
1392 }
1393
1394 #ifdef WIN32
1395
1396 static int send_nfsd_probes(struct rpc_context *rpc, INTERFACE_INFO *InterfaceList, int numIfs, struct nfs_list_data *data)
1397 {
1398 int i=0;
1399
1400 assert(rpc->magic == RPC_CONTEXT_MAGIC);
1401
1402 for(i = 0; i < numIfs; i++)
1403 {
1404 SOCKADDR *pAddress;
1405 char bcdd[16];
1406 unsigned long nFlags = 0;
1407
1408 pAddress = (SOCKADDR *) & (InterfaceList[i].iiBroadcastAddress);
1409
1410 if(pAddress->sa_family != AF_INET)
1411 continue;
1412
1413 nFlags = InterfaceList[i].iiFlags;
1414
1415 if (!(nFlags & IFF_UP))
1416 {
1417 continue;
1418 }
1419
1420 if (nFlags & IFF_LOOPBACK)
1421 {
1422 continue;
1423 }
1424
1425 if (!(nFlags & IFF_BROADCAST))
1426 {
1427 continue;
1428 }
1429
1430 if (getnameinfo(pAddress, sizeof(struct sockaddr_in), &bcdd[0], sizeof(bcdd), NULL, 0, NI_NUMERICHOST) < 0)
1431 {
1432 continue;
1433 }
1434
1435 if (rpc_set_udp_destination(rpc, bcdd, 111, 1) < 0)
1436 {
1437 return -1;
1438 }
1439
1440 if (rpc_pmap_callit_async(rpc, MOUNT_PROGRAM, 2, 0, NULL, 0, callit_cb, data) < 0)
1441 {
1442 return -1;
1443 }
1444 }
1445 return 0;
1446 }
1447
1448 struct nfs_server_list *nfs_find_local_servers(void)
1449 {
1450 struct rpc_context *rpc;
1451 struct nfs_list_data data = {0, NULL};
1452 struct timeval tv_start, tv_current;
1453 int loop;
1454 struct pollfd pfd;
1455 INTERFACE_INFO InterfaceList[20];
1456 unsigned long nBytesReturned;
1457 int nNumInterfaces = 0;
1458
1459 rpc = rpc_init_udp_context();
1460 if (rpc == NULL)
1461 {
1462 return NULL;
1463 }
1464
1465 if (rpc_bind_udp(rpc, "0.0.0.0", 0) < 0)
1466 {
1467 rpc_destroy_context(rpc);
1468 return NULL;
1469 }
1470
1471 if (WSAIoctl(rpc_get_fd(rpc), SIO_GET_INTERFACE_LIST, 0, 0, &InterfaceList, sizeof(InterfaceList), &nBytesReturned, 0, 0) == SOCKET_ERROR)
1472 {
1473 return NULL;
1474 }
1475
1476 nNumInterfaces = nBytesReturned / sizeof(INTERFACE_INFO);
1477
1478 for (loop=0; loop<3; loop++)
1479 {
1480 if (send_nfsd_probes(rpc, InterfaceList, nNumInterfaces, &data) != 0)
1481 {
1482 rpc_destroy_context(rpc);
1483 return NULL;
1484 }
1485
1486 win32_gettimeofday(&tv_start, NULL);
1487 for(;;)
1488 {
1489 int mpt;
1490
1491 pfd.fd = rpc_get_fd(rpc);
1492 pfd.events = rpc_which_events(rpc);
1493
1494 win32_gettimeofday(&tv_current, NULL);
1495 mpt = 1000
1496 - (tv_current.tv_sec *1000 + tv_current.tv_usec / 1000)
1497 + (tv_start.tv_sec *1000 + tv_start.tv_usec / 1000);
1498
1499 if (poll(&pfd, 1, mpt) < 0)
1500 {
1501 free_nfs_srvr_list(data.srvrs);
1502 rpc_destroy_context(rpc);
1503 return NULL;
1504 }
1505 if (pfd.revents == 0)
1506 {
1507 break;
1508 }
1509
1510 if (rpc_service(rpc, pfd.revents) < 0)
1511 {
1512 break;
1513 }
1514 }
1515 }
1516
1517 rpc_destroy_context(rpc);
1518
1519 if (data.status != 0)
1520 {
1521 free_nfs_srvr_list(data.srvrs);
1522 return NULL;
1523 }
1524 return data.srvrs;
1525 }
1526 #else
1527
1528 static int send_nfsd_probes(struct rpc_context *rpc, struct ifconf *ifc, struct nfs_list_data *data)
1529 {
1530 char *ptr;
1531
1532 assert(rpc->magic == RPC_CONTEXT_MAGIC);
1533
1534 for (ptr =(char *)(ifc->ifc_buf); ptr < (char *)(ifc->ifc_buf) + ifc->ifc_len; ) {
1535 struct ifreq *ifr;
1536 char bcdd[16];
1537
1538 ifr = (struct ifreq *)ptr;
1539 #ifdef HAVE_SOCKADDR_LEN
1540 if (ifr->ifr_addr.sa_len > sizeof(struct sockaddr)) {
1541 ptr += sizeof(ifr->ifr_name) + ifr->ifr_addr.sa_len;
1542 } else {
1543 ptr += sizeof(ifr->ifr_name) + sizeof(struct sockaddr);
1544 }
1545 #else
1546 ptr += sizeof(struct ifreq);
1547 #endif
1548
1549 if (ifr->ifr_addr.sa_family != AF_INET) {
1550 continue;
1551 }
1552 if (ioctl(rpc_get_fd(rpc), SIOCGIFFLAGS, ifr) < 0) {
1553 return -1;
1554 }
1555 if (!(ifr->ifr_flags & IFF_UP)) {
1556 continue;
1557 }
1558 if (ifr->ifr_flags & IFF_LOOPBACK) {
1559 continue;
1560 }
1561 if (!(ifr->ifr_flags & IFF_BROADCAST)) {
1562 continue;
1563 }
1564 if (ioctl(rpc_get_fd(rpc), SIOCGIFBRDADDR, ifr) < 0) {
1565 continue;
1566 }
1567 if (getnameinfo(&ifr->ifr_broadaddr, sizeof(struct sockaddr_in), &bcdd[0], sizeof(bcdd), NULL, 0, NI_NUMERICHOST) < 0) {
1568 continue;
1569 }
1570 if (rpc_set_udp_destination(rpc, bcdd, 111, 1) < 0) {
1571 return -1;
1572 }
1573
1574 if (rpc_pmap_callit_async(rpc, MOUNT_PROGRAM, 2, 0, NULL, 0, callit_cb, data) < 0) {
1575 return -1;
1576 }
1577 }
1578
1579 return 0;
1580 }
1581
1582 struct nfs_server_list *nfs_find_local_servers(void)
1583 {
1584 struct rpc_context *rpc;
1585 struct nfs_list_data data = {0, NULL};
1586 struct timeval tv_start, tv_current;
1587 struct ifconf ifc;
1588 int size, loop;
1589 struct pollfd pfd;
1590
1591 rpc = rpc_init_udp_context();
1592 if (rpc == NULL) {
1593 return NULL;
1594 }
1595
1596 if (rpc_bind_udp(rpc, "0.0.0.0", 0) < 0) {
1597 rpc_destroy_context(rpc);
1598 return NULL;
1599 }
1600
1601
1602 /* get list of all interfaces */
1603 size = sizeof(struct ifreq);
1604 ifc.ifc_buf = NULL;
1605 ifc.ifc_len = size;
1606
1607 while(ifc.ifc_len > (size - sizeof(struct ifreq))) {
1608 size *= 2;
1609
1610 free(ifc.ifc_buf);
1611 ifc.ifc_len = size;
1612 ifc.ifc_buf = malloc(size);
1613 memset(ifc.ifc_buf, 0, size);
1614 if (ioctl(rpc_get_fd(rpc), SIOCGIFCONF, (caddr_t)&ifc) < 0) {
1615 rpc_destroy_context(rpc);
1616 free(ifc.ifc_buf);
1617 return NULL;
1618 }
1619 }
1620
1621 for (loop=0; loop<3; loop++) {
1622 if (send_nfsd_probes(rpc, &ifc, &data) != 0) {
1623 rpc_destroy_context(rpc);
1624 free(ifc.ifc_buf);
1625 return NULL;
1626 }
1627
1628 gettimeofday(&tv_start, NULL);
1629 for(;;) {
1630 int mpt;
1631
1632 pfd.fd = rpc_get_fd(rpc);
1633 pfd.events = rpc_which_events(rpc);
1634
1635 gettimeofday(&tv_current, NULL);
1636 mpt = 1000
1637 - (tv_current.tv_sec *1000 + tv_current.tv_usec / 1000)
1638 + (tv_start.tv_sec *1000 + tv_start.tv_usec / 1000);
1639
1640 if (poll(&pfd, 1, mpt) < 0) {
1641 free_nfs_srvr_list(data.srvrs);
1642 rpc_destroy_context(rpc);
1643 return NULL;
1644 }
1645 if (pfd.revents == 0) {
1646 break;
1647 }
1648
1649 if (rpc_service(rpc, pfd.revents) < 0) {
1650 break;
1651 }
1652 }
1653 }
1654
1655 free(ifc.ifc_buf);
1656 rpc_destroy_context(rpc);
1657
1658 if (data.status != 0) {
1659 free_nfs_srvr_list(data.srvrs);
1660 return NULL;
1661 }
1662 return data.srvrs;
1663 }
1664 #endif//WIN32