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