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