add example for sync interface to probe for all local servers
[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 */
20
21#include <stdio.h>
22#include <stdlib.h>
23#include <string.h>
24#include <strings.h>
25#include <sys/types.h>
26#include <sys/stat.h>
27#include <sys/statvfs.h>
552c7665 28#include <sys/ioctl.h>
84004dbf
RS
29#include <unistd.h>
30#include <fcntl.h>
31#include <errno.h>
32#include <poll.h>
552c7665
RS
33#include <net/if.h>
34#include <netdb.h>
84004dbf
RS
35#include "libnfs.h"
36#include "libnfs-raw.h"
37#include "libnfs-raw-mount.h"
38#include "libnfs-raw-nfs.h"
1896d37b 39#include "libnfs-private.h"
84004dbf
RS
40
41struct sync_cb_data {
42 int is_finished;
43 int status;
44 off_t offset;
45 void *return_data;
46 int return_int;
47};
48
49
df5af25f 50static void wait_for_reply(struct rpc_context *rpc, struct sync_cb_data *cb_data)
84004dbf
RS
51{
52 struct pollfd pfd;
53
54 for (;;) {
55 if (cb_data->is_finished) {
56 break;
57 }
df5af25f
RS
58 pfd.fd = rpc_get_fd(rpc);
59 pfd.events = rpc_which_events(rpc);
84004dbf
RS
60
61 if (poll(&pfd, 1, -1) < 0) {
df5af25f 62 rpc_set_error(rpc, "Poll failed");
84004dbf
RS
63 cb_data->status = -EIO;
64 break;
65 }
df5af25f
RS
66 if (rpc_service(rpc, pfd.revents) < 0) {
67 rpc_set_error(rpc, "rpc_service failed");
84004dbf
RS
68 cb_data->status = -EIO;
69 break;
70 }
71 }
72}
73
74
75
76
77
78
79/*
80 * connect to the server and mount the export
81 */
1896d37b 82static void mount_cb(int status, struct nfs_context *nfs, void *data, void *private_data)
84004dbf
RS
83{
84 struct sync_cb_data *cb_data = private_data;
85
86 cb_data->is_finished = 1;
87 cb_data->status = status;
88
89 if (status < 0) {
1896d37b 90 nfs_set_error(nfs, "mount/mnt call failed with \"%s\"", (char *)data);
84004dbf
RS
91 return;
92 }
93}
94
e2ba5764 95int nfs_mount(struct nfs_context *nfs, const char *server, const char *export)
84004dbf
RS
96{
97 struct sync_cb_data cb_data;
98
99 cb_data.is_finished = 0;
100
101 if (nfs_mount_async(nfs, server, export, mount_cb, &cb_data) != 0) {
1896d37b 102 nfs_set_error(nfs, "nfs_mount_async failed");
84004dbf
RS
103 return -1;
104 }
105
df5af25f 106 wait_for_reply(nfs_get_rpc_context(nfs), &cb_data);
84004dbf
RS
107
108 return cb_data.status;
109}
110
111
112/*
113 * stat()
114 */
1896d37b 115static void stat_cb(int status, struct nfs_context *nfs, void *data, void *private_data)
84004dbf
RS
116{
117 struct sync_cb_data *cb_data = private_data;
118
119 cb_data->is_finished = 1;
120 cb_data->status = status;
121
122 if (status < 0) {
1896d37b 123 nfs_set_error(nfs, "stat call failed with \"%s\"", (char *)data);
84004dbf
RS
124 return;
125 }
126
127 memcpy(cb_data->return_data, data, sizeof(struct stat));
128}
129
e2ba5764 130int nfs_stat(struct nfs_context *nfs, const char *path, struct stat *st)
84004dbf
RS
131{
132 struct sync_cb_data cb_data;
133
134 cb_data.is_finished = 0;
135 cb_data.return_data = st;
136
137 if (nfs_stat_async(nfs, path, stat_cb, &cb_data) != 0) {
1896d37b 138 nfs_set_error(nfs, "nfs_stat_async failed");
84004dbf
RS
139 return -1;
140 }
141
df5af25f 142 wait_for_reply(nfs_get_rpc_context(nfs), &cb_data);
84004dbf
RS
143
144 return cb_data.status;
145}
146
147
148
149
150/*
151 * open()
152 */
1896d37b 153static void open_cb(int status, struct nfs_context *nfs, void *data, void *private_data)
84004dbf
RS
154{
155 struct sync_cb_data *cb_data = private_data;
156 struct nfsfh *fh, **nfsfh;
157
158 cb_data->is_finished = 1;
159 cb_data->status = status;
160
161 if (status < 0) {
1896d37b 162 nfs_set_error(nfs, "open call failed with \"%s\"", (char *)data);
84004dbf
RS
163 return;
164 }
165
166 fh = data;
167 nfsfh = cb_data->return_data;
168 *nfsfh = fh;
169}
170
e2ba5764 171int nfs_open(struct nfs_context *nfs, const char *path, int mode, struct nfsfh **nfsfh)
84004dbf
RS
172{
173 struct sync_cb_data cb_data;
174
175 cb_data.is_finished = 0;
176 cb_data.return_data = nfsfh;
177
178 if (nfs_open_async(nfs, path, mode, open_cb, &cb_data) != 0) {
1896d37b 179 nfs_set_error(nfs, "nfs_open_async failed");
84004dbf
RS
180 return -1;
181 }
182
df5af25f 183 wait_for_reply(nfs_get_rpc_context(nfs), &cb_data);
84004dbf
RS
184
185 return cb_data.status;
186}
187
188
189
190
191/*
192 * pread()
193 */
1896d37b 194static void pread_cb(int status, struct nfs_context *nfs, void *data, void *private_data)
84004dbf
RS
195{
196 struct sync_cb_data *cb_data = private_data;
197 char *buffer;
198 cb_data->is_finished = 1;
199 cb_data->status = status;
200
201 if (status < 0) {
1896d37b 202 nfs_set_error(nfs, "pread call failed with \"%s\"", (char *)data);
84004dbf
RS
203 return;
204 }
205
206 buffer = cb_data->return_data;
207 memcpy(buffer, (char *)data, status);
208}
209
e2ba5764 210int nfs_pread(struct nfs_context *nfs, struct nfsfh *nfsfh, off_t offset, size_t count, char *buffer)
84004dbf
RS
211{
212 struct sync_cb_data cb_data;
213
214 cb_data.is_finished = 0;
215 cb_data.return_data = buffer;
216
217 if (nfs_pread_async(nfs, nfsfh, offset, count, pread_cb, &cb_data) != 0) {
1896d37b 218 nfs_set_error(nfs, "nfs_pread_async failed");
84004dbf
RS
219 return -1;
220 }
221
df5af25f 222 wait_for_reply(nfs_get_rpc_context(nfs), &cb_data);
84004dbf
RS
223
224 return cb_data.status;
225}
226
227/*
228 * read()
229 */
e2ba5764 230int nfs_read(struct nfs_context *nfs, struct nfsfh *nfsfh, size_t count, char *buffer)
84004dbf 231{
e2ba5764 232 return nfs_pread(nfs, nfsfh, nfs_get_current_offset(nfsfh), count, buffer);
84004dbf
RS
233}
234
235/*
236 * close()
237 */
1896d37b 238static void close_cb(int status, struct nfs_context *nfs, void *data, void *private_data)
84004dbf
RS
239{
240 struct sync_cb_data *cb_data = private_data;
241 cb_data->is_finished = 1;
242 cb_data->status = status;
243
244 if (status < 0) {
1896d37b 245 nfs_set_error(nfs, "close call failed with \"%s\"", (char *)data);
84004dbf
RS
246 return;
247 }
248}
249
e2ba5764 250int nfs_close(struct nfs_context *nfs, struct nfsfh *nfsfh)
84004dbf
RS
251{
252 struct sync_cb_data cb_data;
253
254 cb_data.is_finished = 0;
255
256 if (nfs_close_async(nfs, nfsfh, close_cb, &cb_data) != 0) {
1896d37b 257 nfs_set_error(nfs, "nfs_close_async failed");
84004dbf
RS
258 return -1;
259 }
260
df5af25f 261 wait_for_reply(nfs_get_rpc_context(nfs), &cb_data);
84004dbf
RS
262
263 return cb_data.status;
264}
265
266
267
268
269/*
270 * fstat()
271 */
e2ba5764 272int nfs_fstat(struct nfs_context *nfs, struct nfsfh *nfsfh, struct stat *st)
84004dbf
RS
273{
274 struct sync_cb_data cb_data;
275
276 cb_data.is_finished = 0;
277 cb_data.return_data = st;
278
279 if (nfs_fstat_async(nfs, nfsfh, stat_cb, &cb_data) != 0) {
1896d37b 280 nfs_set_error(nfs, "nfs_fstat_async failed");
84004dbf
RS
281 return -1;
282 }
283
df5af25f 284 wait_for_reply(nfs_get_rpc_context(nfs), &cb_data);
84004dbf
RS
285
286 return cb_data.status;
287}
288
289
290/*
291 * pwrite()
292 */
1896d37b 293static void pwrite_cb(int status, struct nfs_context *nfs, void *data, void *private_data)
84004dbf
RS
294{
295 struct sync_cb_data *cb_data = private_data;
296 cb_data->is_finished = 1;
297 cb_data->status = status;
298
299 if (status < 0) {
1896d37b 300 nfs_set_error(nfs, "pwrite call failed with \"%s\"", (char *)data);
84004dbf
RS
301 return;
302 }
303}
304
e2ba5764 305int nfs_pwrite(struct nfs_context *nfs, struct nfsfh *nfsfh, off_t offset, size_t count, char *buf)
84004dbf
RS
306{
307 struct sync_cb_data cb_data;
308
309 cb_data.is_finished = 0;
310
311 if (nfs_pwrite_async(nfs, nfsfh, offset, count, buf, pwrite_cb, &cb_data) != 0) {
1896d37b 312 nfs_set_error(nfs, "nfs_pwrite_async failed");
84004dbf
RS
313 return -1;
314 }
315
df5af25f 316 wait_for_reply(nfs_get_rpc_context(nfs), &cb_data);
84004dbf
RS
317
318 return cb_data.status;
319}
320
321/*
322 * write()
323 */
e2ba5764 324int nfs_write(struct nfs_context *nfs, struct nfsfh *nfsfh, size_t count, char *buf)
84004dbf 325{
e2ba5764 326 return nfs_pwrite(nfs, nfsfh, nfs_get_current_offset(nfsfh), count, buf);
84004dbf
RS
327}
328
329
330/*
331 * fsync()
332 */
1896d37b 333static void fsync_cb(int status, struct nfs_context *nfs, void *data, void *private_data)
84004dbf
RS
334{
335 struct sync_cb_data *cb_data = private_data;
336 cb_data->is_finished = 1;
337 cb_data->status = status;
338
339 if (status < 0) {
1896d37b 340 nfs_set_error(nfs, "fsync call failed with \"%s\"", (char *)data);
84004dbf
RS
341 return;
342 }
343}
344
e2ba5764 345int nfs_fsync(struct nfs_context *nfs, struct nfsfh *nfsfh)
84004dbf
RS
346{
347 struct sync_cb_data cb_data;
348
349 cb_data.is_finished = 0;
350
351 if (nfs_fsync_async(nfs, nfsfh, fsync_cb, &cb_data) != 0) {
1896d37b 352 nfs_set_error(nfs, "nfs_fsync_async failed");
84004dbf
RS
353 return -1;
354 }
355
df5af25f 356 wait_for_reply(nfs_get_rpc_context(nfs), &cb_data);
84004dbf
RS
357
358 return cb_data.status;
359}
360
361
362
363
364/*
365 * ftruncate()
366 */
1896d37b 367static void ftruncate_cb(int status, struct nfs_context *nfs, void *data, void *private_data)
84004dbf
RS
368{
369 struct sync_cb_data *cb_data = private_data;
370 cb_data->is_finished = 1;
371 cb_data->status = status;
372
373 if (status < 0) {
1896d37b 374 nfs_set_error(nfs, "ftruncate call failed with \"%s\"", (char *)data);
84004dbf
RS
375 return;
376 }
377}
378
e2ba5764 379int nfs_ftruncate(struct nfs_context *nfs, struct nfsfh *nfsfh, off_t length)
84004dbf
RS
380{
381 struct sync_cb_data cb_data;
382
383 cb_data.is_finished = 0;
384
385 if (nfs_ftruncate_async(nfs, nfsfh, length, ftruncate_cb, &cb_data) != 0) {
1896d37b 386 nfs_set_error(nfs, "nfs_ftruncate_async failed");
84004dbf
RS
387 return -1;
388 }
389
df5af25f 390 wait_for_reply(nfs_get_rpc_context(nfs), &cb_data);
84004dbf
RS
391
392 return cb_data.status;
393}
394
395
396
397/*
398 * truncate()
399 */
1896d37b 400static void truncate_cb(int status, struct nfs_context *nfs, void *data, void *private_data)
84004dbf
RS
401{
402 struct sync_cb_data *cb_data = private_data;
403 cb_data->is_finished = 1;
404 cb_data->status = status;
405
406 if (status < 0) {
1896d37b 407 nfs_set_error(nfs, "truncate call failed with \"%s\"", (char *)data);
84004dbf
RS
408 return;
409 }
410}
411
e2ba5764 412int nfs_truncate(struct nfs_context *nfs, const char *path, off_t length)
84004dbf
RS
413{
414 struct sync_cb_data cb_data;
415
416 cb_data.is_finished = 0;
417
418 if (nfs_truncate_async(nfs, path, length, truncate_cb, &cb_data) != 0) {
1896d37b 419 nfs_set_error(nfs, "nfs_ftruncate_async failed");
84004dbf
RS
420 return -1;
421 }
422
df5af25f 423 wait_for_reply(nfs_get_rpc_context(nfs), &cb_data);
84004dbf
RS
424
425 return cb_data.status;
426}
427
428
429
430
431
432/*
433 * mkdir()
434 */
1896d37b 435static void mkdir_cb(int status, struct nfs_context *nfs, void *data, void *private_data)
84004dbf
RS
436{
437 struct sync_cb_data *cb_data = private_data;
438 cb_data->is_finished = 1;
439 cb_data->status = status;
440
441 if (status < 0) {
1896d37b 442 nfs_set_error(nfs, "mkdir call failed with \"%s\"", (char *)data);
84004dbf
RS
443 return;
444 }
445}
446
e2ba5764 447int nfs_mkdir(struct nfs_context *nfs, const char *path)
84004dbf
RS
448{
449 struct sync_cb_data cb_data;
450
451 cb_data.is_finished = 0;
452
453 if (nfs_mkdir_async(nfs, path, mkdir_cb, &cb_data) != 0) {
1896d37b 454 nfs_set_error(nfs, "nfs_mkdir_async failed");
84004dbf
RS
455 return -1;
456 }
457
df5af25f 458 wait_for_reply(nfs_get_rpc_context(nfs), &cb_data);
84004dbf
RS
459
460 return cb_data.status;
461}
462
463
464
465
466
467/*
468 * rmdir()
469 */
1896d37b 470static void rmdir_cb(int status, struct nfs_context *nfs, void *data, void *private_data)
84004dbf
RS
471{
472 struct sync_cb_data *cb_data = private_data;
473 cb_data->is_finished = 1;
474 cb_data->status = status;
475
476 if (status < 0) {
1896d37b 477 nfs_set_error(nfs, "rmdir call failed with \"%s\"", (char *)data);
84004dbf
RS
478 return;
479 }
480}
481
e2ba5764 482int nfs_rmdir(struct nfs_context *nfs, const char *path)
84004dbf
RS
483{
484 struct sync_cb_data cb_data;
485
486 cb_data.is_finished = 0;
487
488 if (nfs_rmdir_async(nfs, path, rmdir_cb, &cb_data) != 0) {
1896d37b 489 nfs_set_error(nfs, "nfs_rmdir_async failed");
84004dbf
RS
490 return -1;
491 }
492
df5af25f 493 wait_for_reply(nfs_get_rpc_context(nfs), &cb_data);
84004dbf
RS
494
495 return cb_data.status;
496}
497
498
499
500/*
501 * creat()
502 */
1896d37b 503static void creat_cb(int status, struct nfs_context *nfs, void *data, void *private_data)
84004dbf
RS
504{
505 struct sync_cb_data *cb_data = private_data;
506 struct nfsfh *fh, **nfsfh;
507
508 cb_data->is_finished = 1;
509 cb_data->status = status;
510
511 if (status < 0) {
1896d37b 512 nfs_set_error(nfs, "creat call failed with \"%s\"", (char *)data);
84004dbf
RS
513 return;
514 }
515
516 fh = data;
517 nfsfh = cb_data->return_data;
518 *nfsfh = fh;
519}
520
e2ba5764 521int nfs_creat(struct nfs_context *nfs, const char *path, int mode, struct nfsfh **nfsfh)
84004dbf
RS
522{
523 struct sync_cb_data cb_data;
524
525 cb_data.is_finished = 0;
526 cb_data.return_data = nfsfh;
527
528 if (nfs_creat_async(nfs, path, mode, creat_cb, &cb_data) != 0) {
1896d37b 529 nfs_set_error(nfs, "nfs_creat_async failed");
84004dbf
RS
530 return -1;
531 }
532
df5af25f 533 wait_for_reply(nfs_get_rpc_context(nfs), &cb_data);
84004dbf
RS
534
535 return cb_data.status;
536}
537
538
539
540
541/*
542 * unlink()
543 */
1896d37b 544static void unlink_cb(int status, struct nfs_context *nfs, void *data, void *private_data)
84004dbf
RS
545{
546 struct sync_cb_data *cb_data = private_data;
547
548 cb_data->is_finished = 1;
549 cb_data->status = status;
550
551 if (status < 0) {
1896d37b 552 nfs_set_error(nfs, "unlink call failed with \"%s\"", (char *)data);
84004dbf
RS
553 return;
554 }
555}
556
e2ba5764 557int nfs_unlink(struct nfs_context *nfs, const char *path)
84004dbf
RS
558{
559 struct sync_cb_data cb_data;
560
561 cb_data.is_finished = 0;
562
563 if (nfs_unlink_async(nfs, path, unlink_cb, &cb_data) != 0) {
1896d37b 564 nfs_set_error(nfs, "nfs_unlink_async failed");
84004dbf
RS
565 return -1;
566 }
567
df5af25f 568 wait_for_reply(nfs_get_rpc_context(nfs), &cb_data);
84004dbf
RS
569
570 return cb_data.status;
571}
572
573
574
575/*
576 * opendir()
577 */
1896d37b 578static void opendir_cb(int status, struct nfs_context *nfs, void *data, void *private_data)
84004dbf
RS
579{
580 struct sync_cb_data *cb_data = private_data;
581 struct nfsdir *dir, **nfsdir;
582
583 cb_data->is_finished = 1;
584 cb_data->status = status;
585
586 if (status < 0) {
1896d37b 587 nfs_set_error(nfs, "opendir call failed with \"%s\"", (char *)data);
84004dbf
RS
588 return;
589 }
590
591 dir = data;
592 nfsdir = cb_data->return_data;
593 *nfsdir = dir;
594}
595
e2ba5764 596int nfs_opendir(struct nfs_context *nfs, const char *path, struct nfsdir **nfsdir)
84004dbf
RS
597{
598 struct sync_cb_data cb_data;
599
600 cb_data.is_finished = 0;
601 cb_data.return_data = nfsdir;
602
603 if (nfs_opendir_async(nfs, path, opendir_cb, &cb_data) != 0) {
1896d37b 604 nfs_set_error(nfs, "nfs_opendir_async failed");
84004dbf
RS
605 return -1;
606 }
607
df5af25f 608 wait_for_reply(nfs_get_rpc_context(nfs), &cb_data);
84004dbf
RS
609
610 return cb_data.status;
611}
612
613
614/*
615 * lseek()
616 */
1896d37b 617static void lseek_cb(int status, struct nfs_context *nfs, void *data, void *private_data)
84004dbf
RS
618{
619 struct sync_cb_data *cb_data = private_data;
620
621 cb_data->is_finished = 1;
622 cb_data->status = status;
623
624 if (status < 0) {
1896d37b 625 nfs_set_error(nfs, "lseek call failed with \"%s\"", (char *)data);
84004dbf
RS
626 return;
627 }
628
629 if (cb_data->return_data != NULL) {
630 memcpy(cb_data->return_data, data, sizeof(off_t));
631 }
632}
633
e2ba5764 634int nfs_lseek(struct nfs_context *nfs, struct nfsfh *nfsfh, off_t offset, int whence, off_t *current_offset)
84004dbf
RS
635{
636 struct sync_cb_data cb_data;
637
638 cb_data.is_finished = 0;
639 cb_data.return_data = current_offset;
640
641 if (nfs_lseek_async(nfs, nfsfh, offset, whence, lseek_cb, &cb_data) != 0) {
1896d37b 642 nfs_set_error(nfs, "nfs_lseek_async failed");
84004dbf
RS
643 return -1;
644 }
645
df5af25f 646 wait_for_reply(nfs_get_rpc_context(nfs), &cb_data);
84004dbf
RS
647
648 return cb_data.status;
649}
650
651
652
653/*
654 * statvfs()
655 */
1896d37b 656static void statvfs_cb(int status, struct nfs_context *nfs, void *data, void *private_data)
84004dbf
RS
657{
658 struct sync_cb_data *cb_data = private_data;
659
660 cb_data->is_finished = 1;
661 cb_data->status = status;
662
663 if (status < 0) {
1896d37b 664 nfs_set_error(nfs, "statvfs call failed with \"%s\"", (char *)data);
84004dbf
RS
665 return;
666 }
667
668 memcpy(cb_data->return_data, data, sizeof(struct statvfs));
669}
670
e2ba5764 671int nfs_statvfs(struct nfs_context *nfs, const char *path, struct statvfs *svfs)
84004dbf
RS
672{
673 struct sync_cb_data cb_data;
674
675 cb_data.is_finished = 0;
676 cb_data.return_data = svfs;
677
678 if (nfs_statvfs_async(nfs, path, statvfs_cb, &cb_data) != 0) {
1896d37b 679 nfs_set_error(nfs, "nfs_statvfs_async failed");
84004dbf
RS
680 return -1;
681 }
682
df5af25f 683 wait_for_reply(nfs_get_rpc_context(nfs), &cb_data);
84004dbf
RS
684
685 return cb_data.status;
686}
687
688
689
690
691
692/*
693 * readlink()
694 */
1896d37b 695static void readlink_cb(int status, struct nfs_context *nfs, void *data, void *private_data)
84004dbf
RS
696{
697 struct sync_cb_data *cb_data = private_data;
698
699 cb_data->is_finished = 1;
700 cb_data->status = status;
701
702 if (status < 0) {
1896d37b 703 nfs_set_error(nfs, "readlink call failed with \"%s\"", (char *)data);
84004dbf
RS
704 return;
705 }
706
707 if (strlen(data) > (size_t)cb_data->return_int) {
1896d37b 708 nfs_set_error(nfs, "Too small buffer for readlink");
84004dbf
RS
709 cb_data->status = -ENAMETOOLONG;
710 return;
711 }
712
713 memcpy(cb_data->return_data, data, strlen(data)+1);
714}
715
e2ba5764 716int nfs_readlink(struct nfs_context *nfs, const char *path, char *buf, int bufsize)
84004dbf
RS
717{
718 struct sync_cb_data cb_data;
719
720 cb_data.is_finished = 0;
721 cb_data.return_data = buf;
722 cb_data.return_int = bufsize;
723
724 if (nfs_readlink_async(nfs, path, readlink_cb, &cb_data) != 0) {
1896d37b 725 nfs_set_error(nfs, "nfs_readlink_async failed");
84004dbf
RS
726 return -1;
727 }
728
df5af25f 729 wait_for_reply(nfs_get_rpc_context(nfs), &cb_data);
84004dbf
RS
730
731 return cb_data.status;
732}
733
734
735
736/*
737 * chmod()
738 */
1896d37b 739static void chmod_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, "chmod call failed with \"%s\"", (char *)data);
84004dbf
RS
748 return;
749 }
750}
751
e2ba5764 752int nfs_chmod(struct nfs_context *nfs, const char *path, int mode)
84004dbf
RS
753{
754 struct sync_cb_data cb_data;
755
756 cb_data.is_finished = 0;
757
758 if (nfs_chmod_async(nfs, path, mode, chmod_cb, &cb_data) != 0) {
1896d37b 759 nfs_set_error(nfs, "nfs_chmod_async failed");
84004dbf
RS
760 return -1;
761 }
762
df5af25f 763 wait_for_reply(nfs_get_rpc_context(nfs), &cb_data);
84004dbf
RS
764
765 return cb_data.status;
766}
767
768
769
770
771/*
772 * fchmod()
773 */
1896d37b 774static void fchmod_cb(int status, struct nfs_context *nfs, void *data, void *private_data)
84004dbf
RS
775{
776 struct sync_cb_data *cb_data = private_data;
777
778 cb_data->is_finished = 1;
779 cb_data->status = status;
780
781 if (status < 0) {
1896d37b 782 nfs_set_error(nfs, "fchmod call failed with \"%s\"", (char *)data);
84004dbf
RS
783 return;
784 }
785}
786
e2ba5764 787int nfs_fchmod(struct nfs_context *nfs, struct nfsfh *nfsfh, int mode)
84004dbf
RS
788{
789 struct sync_cb_data cb_data;
790
791 cb_data.is_finished = 0;
792
793 if (nfs_fchmod_async(nfs, nfsfh, mode, fchmod_cb, &cb_data) != 0) {
1896d37b 794 nfs_set_error(nfs, "nfs_fchmod_async failed");
84004dbf
RS
795 return -1;
796 }
797
df5af25f 798 wait_for_reply(nfs_get_rpc_context(nfs), &cb_data);
84004dbf
RS
799
800 return cb_data.status;
801}
802
803
804
805
806/*
807 * chown()
808 */
1896d37b 809static void chown_cb(int status, struct nfs_context *nfs, void *data, void *private_data)
84004dbf
RS
810{
811 struct sync_cb_data *cb_data = private_data;
812
813 cb_data->is_finished = 1;
814 cb_data->status = status;
815
816 if (status < 0) {
1896d37b 817 nfs_set_error(nfs, "chown call failed with \"%s\"", (char *)data);
84004dbf
RS
818 return;
819 }
820}
821
e2ba5764 822int nfs_chown(struct nfs_context *nfs, const char *path, int uid, int gid)
84004dbf
RS
823{
824 struct sync_cb_data cb_data;
825
826 cb_data.is_finished = 0;
827
828 if (nfs_chown_async(nfs, path, uid, gid, chown_cb, &cb_data) != 0) {
1896d37b 829 nfs_set_error(nfs, "nfs_chown_async failed");
84004dbf
RS
830 return -1;
831 }
832
df5af25f 833 wait_for_reply(nfs_get_rpc_context(nfs), &cb_data);
84004dbf
RS
834
835 return cb_data.status;
836}
837
838/*
839 * fchown()
840 */
1896d37b 841static void fchown_cb(int status, struct nfs_context *nfs, void *data, void *private_data)
84004dbf
RS
842{
843 struct sync_cb_data *cb_data = private_data;
844
845 cb_data->is_finished = 1;
846 cb_data->status = status;
847
848 if (status < 0) {
1896d37b 849 nfs_set_error(nfs, "fchown call failed with \"%s\"", (char *)data);
84004dbf
RS
850 return;
851 }
852}
853
e2ba5764 854int nfs_fchown(struct nfs_context *nfs, struct nfsfh *nfsfh, int uid, int gid)
84004dbf
RS
855{
856 struct sync_cb_data cb_data;
857
858 cb_data.is_finished = 0;
859
860 if (nfs_fchown_async(nfs, nfsfh, uid, gid, fchown_cb, &cb_data) != 0) {
1896d37b 861 nfs_set_error(nfs, "nfs_fchown_async failed");
84004dbf
RS
862 return -1;
863 }
864
df5af25f 865 wait_for_reply(nfs_get_rpc_context(nfs), &cb_data);
84004dbf
RS
866
867 return cb_data.status;
868}
869
870
871
872/*
873 * utimes()
874 */
1896d37b 875static void utimes_cb(int status, struct nfs_context *nfs, void *data, void *private_data)
84004dbf
RS
876{
877 struct sync_cb_data *cb_data = private_data;
878
879 cb_data->is_finished = 1;
880 cb_data->status = status;
881
882 if (status < 0) {
1896d37b 883 nfs_set_error(nfs, "utimes call failed with \"%s\"", (char *)data);
84004dbf
RS
884 return;
885 }
886}
887
e2ba5764 888int nfs_utimes(struct nfs_context *nfs, const char *path, struct timeval *times)
84004dbf
RS
889{
890 struct sync_cb_data cb_data;
891
892 cb_data.is_finished = 0;
893
894 if (nfs_utimes_async(nfs, path, times, utimes_cb, &cb_data) != 0) {
1896d37b 895 nfs_set_error(nfs, "nfs_utimes_async failed");
84004dbf
RS
896 return -1;
897 }
898
df5af25f 899 wait_for_reply(nfs_get_rpc_context(nfs), &cb_data);
84004dbf
RS
900
901 return cb_data.status;
902}
903
904
905
906/*
907 * utime()
908 */
1896d37b 909static void utime_cb(int status, struct nfs_context *nfs, void *data, void *private_data)
84004dbf
RS
910{
911 struct sync_cb_data *cb_data = private_data;
912
913 cb_data->is_finished = 1;
914 cb_data->status = status;
915
916 if (status < 0) {
1896d37b 917 nfs_set_error(nfs, "utime call failed with \"%s\"", (char *)data);
84004dbf
RS
918 return;
919 }
920}
921
e2ba5764 922int nfs_utime(struct nfs_context *nfs, const char *path, struct utimbuf *times)
84004dbf
RS
923{
924 struct sync_cb_data cb_data;
925
926 cb_data.is_finished = 0;
927
928 if (nfs_utime_async(nfs, path, times, utime_cb, &cb_data) != 0) {
1896d37b 929 nfs_set_error(nfs, "nfs_utimes_async failed");
84004dbf
RS
930 return -1;
931 }
932
df5af25f 933 wait_for_reply(nfs_get_rpc_context(nfs), &cb_data);
84004dbf
RS
934
935 return cb_data.status;
936}
937
938
939
940
941/*
942 * access()
943 */
1896d37b 944static void access_cb(int status, struct nfs_context *nfs, void *data, void *private_data)
84004dbf
RS
945{
946 struct sync_cb_data *cb_data = private_data;
947
948 cb_data->is_finished = 1;
949 cb_data->status = status;
950
951 if (status < 0) {
1896d37b 952 nfs_set_error(nfs, "access call failed with \"%s\"", (char *)data);
84004dbf
RS
953 return;
954 }
955}
956
e2ba5764 957int nfs_access(struct nfs_context *nfs, const char *path, int mode)
84004dbf
RS
958{
959 struct sync_cb_data cb_data;
960
961 cb_data.is_finished = 0;
962
963 if (nfs_access_async(nfs, path, mode, access_cb, &cb_data) != 0) {
1896d37b 964 nfs_set_error(nfs, "nfs_access_async failed");
84004dbf
RS
965 return -1;
966 }
967
df5af25f 968 wait_for_reply(nfs_get_rpc_context(nfs), &cb_data);
84004dbf
RS
969
970 return cb_data.status;
971}
972
973
974
975/*
976 * symlink()
977 */
1896d37b 978static void symlink_cb(int status, struct nfs_context *nfs, void *data, void *private_data)
84004dbf
RS
979{
980 struct sync_cb_data *cb_data = private_data;
981
982 cb_data->is_finished = 1;
983 cb_data->status = status;
984
985 if (status < 0) {
1896d37b 986 nfs_set_error(nfs, "symlink call failed with \"%s\"", (char *)data);
84004dbf
RS
987 return;
988 }
989}
990
e2ba5764 991int nfs_symlink(struct nfs_context *nfs, const char *oldpath, const char *newpath)
84004dbf
RS
992{
993 struct sync_cb_data cb_data;
994
995 cb_data.is_finished = 0;
996
997 if (nfs_symlink_async(nfs, oldpath, newpath, symlink_cb, &cb_data) != 0) {
1896d37b 998 nfs_set_error(nfs, "nfs_symlink_async failed");
84004dbf
RS
999 return -1;
1000 }
1001
df5af25f 1002 wait_for_reply(nfs_get_rpc_context(nfs), &cb_data);
84004dbf
RS
1003
1004 return cb_data.status;
1005}
1006
1007
1008
1009/*
1010 * rename()
1011 */
1896d37b 1012static void rename_cb(int status, struct nfs_context *nfs, void *data, void *private_data)
84004dbf
RS
1013{
1014 struct sync_cb_data *cb_data = private_data;
1015
1016 cb_data->is_finished = 1;
1017 cb_data->status = status;
1018
1019 if (status < 0) {
1896d37b 1020 nfs_set_error(nfs, "rename call failed with \"%s\"", (char *)data);
84004dbf
RS
1021 return;
1022 }
1023}
1024
e2ba5764 1025int nfs_rename(struct nfs_context *nfs, const char *oldpath, const char *newpath)
84004dbf
RS
1026{
1027 struct sync_cb_data cb_data;
1028
1029 cb_data.is_finished = 0;
1030
1031 if (nfs_rename_async(nfs, oldpath, newpath, rename_cb, &cb_data) != 0) {
1896d37b 1032 nfs_set_error(nfs, "nfs_rename_async failed");
84004dbf
RS
1033 return -1;
1034 }
1035
df5af25f 1036 wait_for_reply(nfs_get_rpc_context(nfs), &cb_data);
84004dbf
RS
1037
1038 return cb_data.status;
1039}
1040
1041
1042
1043/*
1044 * link()
1045 */
1896d37b 1046static void link_cb(int status, struct nfs_context *nfs, void *data, void *private_data)
84004dbf
RS
1047{
1048 struct sync_cb_data *cb_data = private_data;
1049
1050 cb_data->is_finished = 1;
1051 cb_data->status = status;
1052
1053 if (status < 0) {
1896d37b 1054 nfs_set_error(nfs, "link call failed with \"%s\"", (char *)data);
84004dbf
RS
1055 return;
1056 }
1057}
1058
e2ba5764 1059int nfs_link(struct nfs_context *nfs, const char *oldpath, const char *newpath)
84004dbf
RS
1060{
1061 struct sync_cb_data cb_data;
1062
1063 cb_data.is_finished = 0;
1064
1065 if (nfs_link_async(nfs, oldpath, newpath, link_cb, &cb_data) != 0) {
1896d37b 1066 nfs_set_error(nfs, "nfs_link_async failed");
84004dbf
RS
1067 return -1;
1068 }
1069
df5af25f 1070 wait_for_reply(nfs_get_rpc_context(nfs), &cb_data);
84004dbf
RS
1071
1072 return cb_data.status;
1073}
df5af25f 1074
739df145 1075void mount_getexports_cb(struct rpc_context *mount_context, int status, void *data, void *private_data)
df5af25f
RS
1076{
1077 struct sync_cb_data *cb_data = private_data;
1078 exports export = *(exports *)data;
1079
df5af25f
RS
1080 cb_data->is_finished = 1;
1081 cb_data->status = status;
1082 cb_data->return_data = NULL;
1083
739df145
RS
1084 if (status != 0) {
1085 rpc_set_error(mount_context, "mount/export call failed with \"%s\"", (char *)data);
1086 return;
1087 }
1088
df5af25f
RS
1089 while (export != NULL) {
1090 exports new_export;
1091
1092 new_export = malloc(sizeof(*new_export));
1093 memset(new_export, 0, sizeof(*new_export));
1094 new_export->ex_dir = strdup(export->ex_dir);
1095 new_export->ex_next = cb_data->return_data;
1096
1097 cb_data->return_data = new_export;
1098
1099 export = export->ex_next;
1100 }
1101}
1102
e210bd2a 1103struct exportnode *mount_getexports(const char *server)
df5af25f
RS
1104{
1105 struct sync_cb_data cb_data;
e210bd2a
RS
1106 struct rpc_context *rpc;
1107
df5af25f
RS
1108
1109 cb_data.is_finished = 0;
1110 cb_data.return_data = NULL;
1111
e210bd2a 1112 rpc = rpc_init_context();
df5af25f 1113 if (mount_getexports_async(rpc, server, mount_getexports_cb, &cb_data) != 0) {
e210bd2a 1114 rpc_destroy_context(rpc);
df5af25f
RS
1115 return NULL;
1116 }
1117
1118 wait_for_reply(rpc, &cb_data);
e210bd2a 1119 rpc_destroy_context(rpc);
df5af25f
RS
1120
1121 return cb_data.return_data;
1122}
1123
1124void mount_free_export_list(struct exportnode *exports)
1125{
1126 struct exportnode *tmp;
1127
1128 while ((tmp = exports)) {
1129 exports = exports->ex_next;
1130 free(tmp->ex_dir);
1131 free(tmp);
1132 }
1133}
1134
552c7665
RS
1135
1136
1137
1138void free_nfs_srvr_list(struct nfs_server_list *srv)
1139{
1140 while (srv != NULL) {
1141 struct nfs_server_list *next = srv->next;
1142
1143 free(srv->addr);
1144 free(srv);
1145 srv = next;
1146 }
1147}
1148
1149struct nfs_list_data {
1150 int status;
1151 struct nfs_server_list *srvrs;
1152};
1153
1154void callit_cb(struct rpc_context *rpc, int status, void *data _U_, void *private_data)
1155{
1156 struct nfs_list_data *srv_data = private_data;
1157 struct sockaddr *sin;
1158 char hostdd[16];
1159 struct nfs_server_list *srvr;
1160
1161 if (status == RPC_STATUS_CANCEL) {
1162 return;
1163 }
1164 if (status != 0) {
1165 srv_data->status = -1;
1166 return;
1167 }
1168
1169 sin = rpc_get_recv_sockaddr(rpc);
1170 if (sin == NULL) {
1171 rpc_set_error(rpc, "failed to get sockaddr in CALLIT callback");
1172 srv_data->status = -1;
1173 return;
1174 }
1175
1176 if (getnameinfo(sin, sizeof(struct sockaddr_in), &hostdd[0], sizeof(hostdd), NULL, 0, NI_NUMERICHOST) < 0) {
1177 rpc_set_error(rpc, "getnameinfo failed in CALLIT callback");
1178 srv_data->status = -1;
1179 return;
1180 }
1181
1182
1183 srvr = malloc(sizeof(struct nfs_server_list));
1184 if (srvr == NULL) {
1185 rpc_set_error(rpc, "Malloc failed when allocating server structure");
1186 srv_data->status = -1;
1187 return;
1188 }
1189
1190 srvr->addr = strdup(hostdd);
1191 if (srvr->addr == NULL) {
1192 rpc_set_error(rpc, "Strdup failed when allocating server structure");
1193 free(srvr);
1194 srv_data->status = -1;
1195 return;
1196 }
1197
1198 srvr->next = srv_data->srvrs;
1199 srv_data->srvrs = srvr;
1200}
1201
1202struct nfs_server_list *nfs_find_local_servers(void)
1203{
1204 struct rpc_context *rpc;
1205 struct nfs_list_data data = {0, NULL};
1206 struct timeval tv_start, tv_current;
1207 struct ifconf ifc;
1208 int i, size;
1209 struct pollfd pfd;
1210
1211 rpc = rpc_init_udp_context();
1212 if (rpc == NULL) {
1213 return NULL;
1214 }
1215
1216 if (rpc_bind_udp(rpc, "0.0.0.0", 0) < 0) {
1217 rpc_destroy_context(rpc);
1218 return NULL;
1219 }
1220
1221
1222 /* get list of all interfaces */
1223 size = sizeof(struct ifreq);
1224 ifc.ifc_buf = NULL;
1225 ifc.ifc_len = size;
1226
1227 while (ifc.ifc_len == size) {
1228 size *= 2;
1229
1230 free(ifc.ifc_buf);
1231 ifc.ifc_len = size;
1232 ifc.ifc_buf = malloc(size);
1233 if (ioctl(rpc_get_fd(rpc), SIOCGIFCONF, (caddr_t)&ifc) < 0) {
1234 rpc_destroy_context(rpc);
1235 free(ifc.ifc_buf);
1236 return NULL;
1237 }
1238 }
1239
1240 for (i = 0; (unsigned)i < ifc.ifc_len / sizeof(struct ifconf); i++) {
1241 char bcdd[16];
1242
1243 if (ifc.ifc_req[i].ifr_addr.sa_family != AF_INET) {
1244 continue;
1245 }
1246 if (ioctl(rpc_get_fd(rpc), SIOCGIFFLAGS, &ifc.ifc_req[i]) < 0) {
1247 rpc_destroy_context(rpc);
1248 free(ifc.ifc_buf);
1249 return NULL;
1250 }
1251 if (!(ifc.ifc_req[i].ifr_flags & IFF_UP)) {
1252 continue;
1253 }
1254 if (ifc.ifc_req[i].ifr_flags & IFF_LOOPBACK) {
1255 continue;
1256 }
1257 if (!(ifc.ifc_req[i].ifr_flags & IFF_BROADCAST)) {
1258 continue;
1259 }
1260 if (ioctl(rpc_get_fd(rpc), SIOCGIFBRDADDR, &ifc.ifc_req[i]) < 0) {
1261 rpc_destroy_context(rpc);
1262 free(ifc.ifc_buf);
1263 return NULL;
1264 }
1265 if (getnameinfo(&ifc.ifc_req[i].ifr_broadaddr, sizeof(struct sockaddr_in), &bcdd[0], sizeof(bcdd), NULL, 0, NI_NUMERICHOST) < 0) {
1266 rpc_destroy_context(rpc);
1267 free(ifc.ifc_buf);
1268 return NULL;
1269 }
1270 if (rpc_set_udp_destination(rpc, bcdd, 111, 1) < 0) {
1271 rpc_destroy_context(rpc);
1272 free(ifc.ifc_buf);
1273 return NULL;
1274 }
1275
1276 if (rpc_pmap_callit_async(rpc, MOUNT_PROGRAM, 2, 0, NULL, 0, callit_cb, &data) < 0) {
1277 rpc_destroy_context(rpc);
1278 free(ifc.ifc_buf);
1279 return NULL;
1280 }
1281 }
1282 free(ifc.ifc_buf);
1283
1284 gettimeofday(&tv_start, NULL);
1285 for(;;) {
1286 int mpt;
1287
1288 pfd.fd = rpc_get_fd(rpc);
1289 pfd.events = rpc_which_events(rpc);
1290
1291 gettimeofday(&tv_current, NULL);
1292 mpt = 1000
1293 - (tv_current.tv_sec *1000 + tv_current.tv_usec / 1000)
1294 + (tv_start.tv_sec *1000 + tv_start.tv_usec / 1000);
1295
1296 if (poll(&pfd, 1, mpt) < 0) {
1297 free_nfs_srvr_list(data.srvrs);
1298 rpc_destroy_context(rpc);
1299 return NULL;
1300 }
1301 if (pfd.revents == 0) {
1302 break;
1303 }
1304
1305 if (rpc_service(rpc, pfd.revents) < 0) {
1306 break;
1307 }
1308 }
1309
1310 rpc_destroy_context(rpc);
1311
1312 if (data.status != 0) {
1313 free_nfs_srvr_list(data.srvrs);
1314 return NULL;
1315 }
1316
1317 return data.srvrs;
1318}