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