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