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