replace index/rindex with modern equivalents
[deb_libnfs.git] / lib / libnfs-sync.c
... / ...
CommitLineData
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
43struct 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
52static 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
77static 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 */
119static 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
132int 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 */
152static 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
167int 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 */
190static 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
208int 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 */
231static 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
247int 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 */
267int 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 */
275static 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
287int 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 */
309int 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 */
330static 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
342int 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 */
361int 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 */
370static 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
382int 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 */
404static 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
416int 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 */
437static 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
449int 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 */
472static 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
484int 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 */
507static 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
519int 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 */
540static 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
558int 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 */
581static 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
594int 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 */
615static 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
633int 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 */
654static 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
671int 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 */
693static 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
708int 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 */
732static 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
753int 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 */
776static 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
789int 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 */
811static 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
824int 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 */
846static 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
859int 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 */
878static 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
891int 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 */
912static 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
925int 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 */
946static 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
959int 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 */
981static 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
994int 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 */
1015static 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
1028int 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 */
1049static 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
1062int 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 */
1083static 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
1096int 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
1112void 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
1140struct 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
1161void 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
1175void 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
1186struct nfs_list_data {
1187 int status;
1188 struct nfs_server_list *srvrs;
1189};
1190
1191void 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
1245static 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
1297struct 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}