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