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