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