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