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