diff options
author | Denis Vlasenko <vda.linux@googlemail.com> | 2006-09-11 17:42:44 +0000 |
---|---|---|
committer | Denis Vlasenko <vda.linux@googlemail.com> | 2006-09-11 17:42:44 +0000 |
commit | 00d7d6cef6419654071ccc77d9b2f212198dab3d (patch) | |
tree | dd597506d203700ee8bdab93e5467cac0e2a1712 | |
parent | 64d7e93081141cb6f1668436a5629a2304047f38 (diff) | |
download | busybox-w32-00d7d6cef6419654071ccc77d9b2f212198dab3d.tar.gz busybox-w32-00d7d6cef6419654071ccc77d9b2f212198dab3d.tar.bz2 busybox-w32-00d7d6cef6419654071ccc77d9b2f212198dab3d.zip |
nfsmount: sanitize it. It had a rather peculiar idea of implementing "bg"
option - it was going to return a special flag back to caller and
expecting caller to call it again with special parameter! Also
caller was charged with calling mount() syscall...
mount: mtab support was non-functional. Enabling it revealed serious bug
which is not fixed yet.
-rw-r--r-- | include/libbb.h | 4 | ||||
-rw-r--r-- | util-linux/mount.c | 28 | ||||
-rw-r--r-- | util-linux/nfsmount.c | 380 |
3 files changed, 223 insertions, 189 deletions
diff --git a/include/libbb.h b/include/libbb.h index 6e136ab7b..cb39e7b3f 100644 --- a/include/libbb.h +++ b/include/libbb.h | |||
@@ -303,8 +303,8 @@ extern int set_loop(char **device, const char *file, int offset); | |||
303 | extern int vdprintf(int d, const char *format, va_list ap); | 303 | extern int vdprintf(int d, const char *format, va_list ap); |
304 | #endif | 304 | #endif |
305 | 305 | ||
306 | int nfsmount(const char *spec, const char *node, int *flags, | 306 | int mount_it_now(struct mntent *mp, int vfsflags, char *filteropts); |
307 | char **mount_opts, int running_bg); | 307 | int nfsmount(struct mntent *mp, int vfsflags, char *filteropts); |
308 | 308 | ||
309 | /* Include our own copy of struct sysinfo to avoid binary compatibility | 309 | /* Include our own copy of struct sysinfo to avoid binary compatibility |
310 | * problems with Linux 2.4, which changed things. Grumble, grumble. */ | 310 | * problems with Linux 2.4, which changed things. Grumble, grumble. */ |
diff --git a/util-linux/mount.c b/util-linux/mount.c index b1d9e287d..bd2a62d64 100644 --- a/util-linux/mount.c +++ b/util-linux/mount.c | |||
@@ -102,7 +102,7 @@ static void append_mount_options(char **oldopts, char *newopts) | |||
102 | } | 102 | } |
103 | 103 | ||
104 | /* Use the mount_options list to parse options into flags. | 104 | /* Use the mount_options list to parse options into flags. |
105 | * Return list of unrecognized options in *strflags if strflags!=NULL */ | 105 | * Also return list of unrecognized options if unrecognized!=NULL */ |
106 | static int parse_mount_options(char *options, char **unrecognized) | 106 | static int parse_mount_options(char *options, char **unrecognized) |
107 | { | 107 | { |
108 | int flags = MS_SILENT; | 108 | int flags = MS_SILENT; |
@@ -188,7 +188,7 @@ void delete_block_backed_filesystems(void); | |||
188 | #endif | 188 | #endif |
189 | 189 | ||
190 | #if ENABLE_FEATURE_MTAB_SUPPORT | 190 | #if ENABLE_FEATURE_MTAB_SUPPORT |
191 | static int useMtab; | 191 | static int useMtab = 1; |
192 | static int fakeIt; | 192 | static int fakeIt; |
193 | #else | 193 | #else |
194 | #define useMtab 0 | 194 | #define useMtab 0 |
@@ -196,8 +196,7 @@ static int fakeIt; | |||
196 | #endif | 196 | #endif |
197 | 197 | ||
198 | // Perform actual mount of specific filesystem at specific location. | 198 | // Perform actual mount of specific filesystem at specific location. |
199 | 199 | int mount_it_now(struct mntent *mp, int vfsflags, char *filteropts) | |
200 | static int mount_it_now(struct mntent *mp, int vfsflags, char *filteropts) | ||
201 | { | 200 | { |
202 | int rc; | 201 | int rc; |
203 | 202 | ||
@@ -228,7 +227,7 @@ static int mount_it_now(struct mntent *mp, int vfsflags, char *filteropts) | |||
228 | int i; | 227 | int i; |
229 | 228 | ||
230 | if(!mountTable) | 229 | if(!mountTable) |
231 | bb_error_msg("No %s",bb_path_mtab_file); | 230 | bb_error_msg("no %s",bb_path_mtab_file); |
232 | 231 | ||
233 | // Add vfs string flags | 232 | // Add vfs string flags |
234 | 233 | ||
@@ -244,7 +243,13 @@ static int mount_it_now(struct mntent *mp, int vfsflags, char *filteropts) | |||
244 | // Write and close. | 243 | // Write and close. |
245 | 244 | ||
246 | if(!mp->mnt_type || !*mp->mnt_type) mp->mnt_type="--bind"; | 245 | if(!mp->mnt_type || !*mp->mnt_type) mp->mnt_type="--bind"; |
247 | addmntent(mountTable, mp); | 246 | // addmntent(mountTable, mp); |
247 | if(0) bb_error_msg("buggy: addmntent(fsname='%s' dir='%s' type='%s' opts='%s')", | ||
248 | mp->mnt_fsname, | ||
249 | mp->mnt_dir, | ||
250 | mp->mnt_type, | ||
251 | mp->mnt_opts | ||
252 | ); | ||
248 | endmntent(mountTable); | 253 | endmntent(mountTable); |
249 | if (ENABLE_FEATURE_CLEAN_UP) | 254 | if (ENABLE_FEATURE_CLEAN_UP) |
250 | if(strcmp(mp->mnt_type,"--bind")) mp->mnt_type = 0; | 255 | if(strcmp(mp->mnt_type,"--bind")) mp->mnt_type = 0; |
@@ -319,13 +324,7 @@ static int singlemount(struct mntent *mp, int ignore_busy) | |||
319 | (!mp->mnt_type || !strcmp(mp->mnt_type,"nfs")) && | 324 | (!mp->mnt_type || !strcmp(mp->mnt_type,"nfs")) && |
320 | strchr(mp->mnt_fsname, ':') != NULL) | 325 | strchr(mp->mnt_fsname, ':') != NULL) |
321 | { | 326 | { |
322 | if (nfsmount(mp->mnt_fsname, mp->mnt_dir, &vfsflags, &filteropts, 1)) { | 327 | rc = nfsmount(mp, vfsflags, filteropts); |
323 | bb_perror_msg("nfsmount failed"); | ||
324 | } else { | ||
325 | // Strangely enough, nfsmount() doesn't actually mount() anything. | ||
326 | mp->mnt_type = "nfs"; | ||
327 | rc = mount_it_now(mp, vfsflags, filteropts); | ||
328 | } | ||
329 | goto report_error; | 328 | goto report_error; |
330 | } | 329 | } |
331 | 330 | ||
@@ -400,7 +399,8 @@ report_error: | |||
400 | 399 | ||
401 | if (rc && errno == EBUSY && ignore_busy) rc = 0; | 400 | if (rc && errno == EBUSY && ignore_busy) rc = 0; |
402 | if (rc < 0) | 401 | if (rc < 0) |
403 | bb_perror_msg("mounting %s on %s failed", mp->mnt_fsname, mp->mnt_dir); | 402 | /* perror here sometimes says "mounting ... on ... failed: Success" */ |
403 | bb_error_msg("mounting %s on %s failed", mp->mnt_fsname, mp->mnt_dir); | ||
404 | 404 | ||
405 | return rc; | 405 | return rc; |
406 | } | 406 | } |
diff --git a/util-linux/nfsmount.c b/util-linux/nfsmount.c index d43bc3e3c..4e523b5f3 100644 --- a/util-linux/nfsmount.c +++ b/util-linux/nfsmount.c | |||
@@ -22,6 +22,8 @@ | |||
22 | */ | 22 | */ |
23 | 23 | ||
24 | #include "busybox.h" | 24 | #include "busybox.h" |
25 | #include <syslog.h> | ||
26 | #include <mntent.h> | ||
25 | #include <sys/utsname.h> | 27 | #include <sys/utsname.h> |
26 | #undef TRUE | 28 | #undef TRUE |
27 | #undef FALSE | 29 | #undef FALSE |
@@ -332,15 +334,8 @@ static bool_t xdr_mountres3(XDR *xdrs, mountres3 *objp) | |||
332 | return TRUE; | 334 | return TRUE; |
333 | } | 335 | } |
334 | 336 | ||
335 | |||
336 | #define MAX_NFSPROT ((nfs_mount_version >= 4) ? 3 : 2) | 337 | #define MAX_NFSPROT ((nfs_mount_version >= 4) ? 3 : 2) |
337 | 338 | ||
338 | enum { | ||
339 | EX_FAIL = 32, /* mount failure */ | ||
340 | EX_BG = 256 /* retry in background (internal only) */ | ||
341 | }; | ||
342 | |||
343 | |||
344 | /* | 339 | /* |
345 | * nfs_mount_version according to the sources seen at compile time. | 340 | * nfs_mount_version according to the sources seen at compile time. |
346 | */ | 341 | */ |
@@ -426,50 +421,62 @@ next: | |||
426 | return &p; | 421 | return &p; |
427 | } | 422 | } |
428 | 423 | ||
429 | int nfsmount(const char *spec, const char *node, int *flags, | 424 | static int daemonize(void) |
430 | char **mount_opts, int running_bg) | ||
431 | { | 425 | { |
432 | /* prev_bg_host is a -o bg support: | 426 | int fd; |
433 | * "bg: if the first NFS mount attempt times out, | 427 | int pid = fork(); |
434 | * retry the mount in the background. | 428 | if (pid < 0) /* error */ |
435 | * After a mount operation is backgrounded, | 429 | return -errno; |
436 | * all subsequent mounts on the same NFS server | 430 | if (pid > 0) /* parent */ |
437 | * will be backgrounded immediately, without first | 431 | return 0; |
438 | * attempting the mount. A missing mount point is treated | 432 | /* child */ |
439 | * as a timeout, to allow for nested NFS mounts." | 433 | fd = xopen(bb_dev_null, O_RDWR); |
440 | * | 434 | dup2(fd, 0); |
441 | * But current implementation is a dirty hack - | 435 | dup2(fd, 1); |
442 | * it works only if all mounts are to one host! | 436 | dup2(fd, 2); |
443 | * IOW: think what will happen if you have this sequence: | 437 | if (fd > 2) close(fd); |
444 | * mount a.a.a.a:/dir /mnt/a -o bg | 438 | setsid(); |
445 | * mount b.b.b.b:/dir /mnt/b -o bg | 439 | openlog(bb_applet_name, LOG_PID, LOG_DAEMON); |
446 | * mount a.a.a.a:/dir /mnt/a -o bg | 440 | logmode = LOGMODE_SYSLOG; |
447 | * mount b.b.b.b:/dir /mnt/b -o bg | 441 | return 1; |
448 | */ | 442 | } |
443 | |||
444 | // TODO | ||
445 | static inline int we_saw_this_host_before(const char *hostname) | ||
446 | { | ||
447 | return 0; | ||
448 | } | ||
449 | |||
450 | /* RPC strerror analogs are terminally idiotic: | ||
451 | * *mandatory* prefix and \n at end. | ||
452 | * This hopefully helps. Usage: | ||
453 | * error_msg_rpc(clnt_*error*(" ")) */ | ||
454 | static void error_msg_rpc(const char *msg) | ||
455 | { | ||
456 | size_t len; | ||
457 | while (msg[0] == ' ' || msg[0] == ':') msg++; | ||
458 | len = strlen(msg); | ||
459 | while (len && msg[len-1] == '\n') len--; | ||
460 | bb_error_msg("%.*s", len, msg); | ||
461 | } | ||
449 | 462 | ||
450 | static char *prev_bg_host; | 463 | int nfsmount(struct mntent *mp, int vfsflags, char *filteropts) |
451 | char *hostdir; | 464 | { |
452 | CLIENT *mclient; | 465 | CLIENT *mclient; |
453 | char *hostname; | 466 | char *hostname; |
454 | char *pathname; | 467 | char *pathname; |
455 | char *old_opts; | ||
456 | char *mounthost; | 468 | char *mounthost; |
457 | struct timeval total_timeout; | ||
458 | enum clnt_stat clnt_stat; | ||
459 | struct nfs_mount_data data; | 469 | struct nfs_mount_data data; |
460 | char *opt, *opteq; | 470 | char *opt; |
461 | int val; | ||
462 | struct hostent *hp; | 471 | struct hostent *hp; |
463 | struct sockaddr_in server_addr; | 472 | struct sockaddr_in server_addr; |
464 | struct sockaddr_in mount_server_addr; | 473 | struct sockaddr_in mount_server_addr; |
465 | struct pmap* pm_mnt; | ||
466 | int msock, fsock; | 474 | int msock, fsock; |
467 | struct timeval retry_timeout; | ||
468 | union { | 475 | union { |
469 | struct fhstatus nfsv2; | 476 | struct fhstatus nfsv2; |
470 | struct mountres3 nfsv3; | 477 | struct mountres3 nfsv3; |
471 | } status; | 478 | } status; |
472 | struct stat statbuf; | 479 | int daemonized; |
473 | char *s; | 480 | char *s; |
474 | int port; | 481 | int port; |
475 | int mountport; | 482 | int mountport; |
@@ -488,29 +495,27 @@ int nfsmount(const char *spec, const char *node, int *flags, | |||
488 | int nfsprog; | 495 | int nfsprog; |
489 | int nfsvers; | 496 | int nfsvers; |
490 | int retval; | 497 | int retval; |
491 | time_t t; | ||
492 | time_t prevt; | ||
493 | time_t timeout; | ||
494 | 498 | ||
495 | find_kernel_nfs_mount_version(); | 499 | find_kernel_nfs_mount_version(); |
496 | 500 | ||
497 | /* NB: old_opts and hostdir must be free()d prior to return! */ | 501 | daemonized = 0; |
498 | |||
499 | old_opts = NULL; | ||
500 | mounthost = NULL; | 502 | mounthost = NULL; |
501 | retval = EX_FAIL; | 503 | retval = ETIMEDOUT; |
502 | msock = fsock = -1; | 504 | msock = fsock = -1; |
503 | mclient = NULL; | 505 | mclient = NULL; |
504 | 506 | ||
505 | hostdir = xstrdup(spec); | 507 | /* NB: hostname, mounthost, filteropts must be free()d prior to return */ |
508 | |||
509 | filteropts = xstrdup(filteropts); /* going to trash it later... */ | ||
510 | |||
511 | hostname = xstrdup(mp->mnt_fsname); | ||
506 | /* mount_main() guarantees that ':' is there */ | 512 | /* mount_main() guarantees that ':' is there */ |
507 | s = strchr(hostdir, ':'); | 513 | s = strchr(hostname, ':'); |
508 | hostname = hostdir; | ||
509 | pathname = s + 1; | 514 | pathname = s + 1; |
510 | *s = '\0'; | 515 | *s = '\0'; |
511 | /* Ignore all but first hostname in replicated mounts | 516 | /* Ignore all but first hostname in replicated mounts |
512 | until they can be fully supported. (mack@sgi.com) */ | 517 | until they can be fully supported. (mack@sgi.com) */ |
513 | s = strchr(hostdir, ','); | 518 | s = strchr(hostname, ','); |
514 | if (s) { | 519 | if (s) { |
515 | *s = '\0'; | 520 | *s = '\0'; |
516 | bb_error_msg("warning: multiple hostnames not supported"); | 521 | bb_error_msg("warning: multiple hostnames not supported"); |
@@ -538,12 +543,15 @@ int nfsmount(const char *spec, const char *node, int *flags, | |||
538 | 543 | ||
539 | /* add IP address to mtab options for use when unmounting */ | 544 | /* add IP address to mtab options for use when unmounting */ |
540 | 545 | ||
541 | s = inet_ntoa(server_addr.sin_addr); | 546 | if (!mp->mnt_opts) { /* TODO: actually mp->mnt_opts is never NULL */ |
542 | old_opts = *mount_opts; | 547 | mp->mnt_opts = xasprintf("addr=%s", inet_ntoa(server_addr.sin_addr)); |
543 | if (!old_opts) | 548 | } else { |
544 | old_opts = xstrdup(""); | 549 | char *tmp = xasprintf("%s%saddr=%s", mp->mnt_opts, |
545 | *mount_opts = xasprintf("%s%saddr=%s", | 550 | mp->mnt_opts[0] ? "," : "", |
546 | old_opts, *old_opts ? "," : "", s); | 551 | inet_ntoa(server_addr.sin_addr)); |
552 | free(mp->mnt_opts); | ||
553 | mp->mnt_opts = tmp; | ||
554 | } | ||
547 | 555 | ||
548 | /* Set default options. | 556 | /* Set default options. |
549 | * rsize/wsize (and bsize, for ver >= 3) are left 0 in order to | 557 | * rsize/wsize (and bsize, for ver >= 3) are left 0 in order to |
@@ -576,10 +584,10 @@ int nfsmount(const char *spec, const char *node, int *flags, | |||
576 | 584 | ||
577 | /* parse options */ | 585 | /* parse options */ |
578 | 586 | ||
579 | for (opt = strtok(old_opts, ","); opt; opt = strtok(NULL, ",")) { | 587 | for (opt = strtok(filteropts, ","); opt; opt = strtok(NULL, ",")) { |
580 | opteq = strchr(opt, '='); | 588 | char *opteq = strchr(opt, '='); |
581 | if (opteq) { | 589 | if (opteq) { |
582 | val = atoi(opteq + 1); | 590 | int val = atoi(opteq + 1); |
583 | *opteq = '\0'; | 591 | *opteq = '\0'; |
584 | if (!strcmp(opt, "rsize")) | 592 | if (!strcmp(opt, "rsize")) |
585 | data.rsize = val; | 593 | data.rsize = val; |
@@ -641,7 +649,7 @@ int nfsmount(const char *spec, const char *node, int *flags, | |||
641 | } | 649 | } |
642 | } | 650 | } |
643 | else { | 651 | else { |
644 | val = 1; | 652 | int val = 1; |
645 | if (!strncmp(opt, "no", 2)) { | 653 | if (!strncmp(opt, "no", 2)) { |
646 | val = 0; | 654 | val = 0; |
647 | opt += 2; | 655 | opt += 2; |
@@ -723,19 +731,20 @@ int nfsmount(const char *spec, const char *node, int *flags, | |||
723 | 731 | ||
724 | data.version = nfs_mount_version; | 732 | data.version = nfs_mount_version; |
725 | 733 | ||
726 | if (*flags & MS_REMOUNT) | 734 | if (vfsflags & MS_REMOUNT) |
727 | goto copy_data_and_return; | 735 | goto do_mount; |
728 | 736 | ||
729 | /* | 737 | /* |
730 | * If the previous mount operation on the same host was | 738 | * If the previous mount operation on the same host was |
731 | * backgrounded, and the "bg" for this mount is also set, | 739 | * backgrounded, and the "bg" for this mount is also set, |
732 | * give up immediately, to avoid the initial timeout. | 740 | * give up immediately, to avoid the initial timeout. |
733 | */ | 741 | */ |
734 | if (bg && !running_bg && | 742 | if (bg && we_saw_this_host_before(hostname)) { |
735 | prev_bg_host && strcmp(hostname, prev_bg_host) == 0) { | 743 | daemonized = daemonize(); /* parent or error */ |
736 | if (retry > 0) | 744 | if (daemonized <= 0) { /* parent or error */ |
737 | retval = EX_BG; | 745 | retval = -daemonized; |
738 | goto ret; | 746 | goto ret; |
747 | } | ||
739 | } | 748 | } |
740 | 749 | ||
741 | /* create mount daemon client */ | 750 | /* create mount daemon client */ |
@@ -745,7 +754,8 @@ int nfsmount(const char *spec, const char *node, int *flags, | |||
745 | mount_server_addr.sin_family = AF_INET; | 754 | mount_server_addr.sin_family = AF_INET; |
746 | mount_server_addr.sin_addr.s_addr = inet_addr(hostname); | 755 | mount_server_addr.sin_addr.s_addr = inet_addr(hostname); |
747 | } else { | 756 | } else { |
748 | if ((hp = gethostbyname(mounthost)) == NULL) { | 757 | hp = gethostbyname(mounthost); |
758 | if (hp == NULL) { | ||
749 | bb_herror_msg("%s", mounthost); | 759 | bb_herror_msg("%s", mounthost); |
750 | goto fail; | 760 | goto fail; |
751 | } else { | 761 | } else { |
@@ -761,11 +771,9 @@ int nfsmount(const char *spec, const char *node, int *flags, | |||
761 | } | 771 | } |
762 | 772 | ||
763 | /* | 773 | /* |
764 | * The following loop implements the mount retries. On the first | 774 | * The following loop implements the mount retries. When the mount |
765 | * call, "running_bg" is 0. When the mount times out, and the | 775 | * times out, and the "bg" option is set, we background ourself |
766 | * "bg" option is set, the exit status EX_BG will be returned. | 776 | * and continue trying. |
767 | * For a backgrounded mount, there will be a second call by the | ||
768 | * child process with "running_bg" set to 1. | ||
769 | * | 777 | * |
770 | * The case where the mount point is not present and the "bg" | 778 | * The case where the mount point is not present and the "bg" |
771 | * option is set, is treated as a timeout. This is done to | 779 | * option is set, is treated as a timeout. This is done to |
@@ -773,115 +781,122 @@ int nfsmount(const char *spec, const char *node, int *flags, | |||
773 | * | 781 | * |
774 | * The "retry" count specified by the user is the number of | 782 | * The "retry" count specified by the user is the number of |
775 | * minutes to retry before giving up. | 783 | * minutes to retry before giving up. |
776 | * | ||
777 | * Only the first error message will be displayed. | ||
778 | */ | 784 | */ |
779 | retry_timeout.tv_sec = 3; | 785 | { |
780 | retry_timeout.tv_usec = 0; | 786 | struct timeval total_timeout; |
781 | total_timeout.tv_sec = 20; | 787 | struct timeval retry_timeout; |
782 | total_timeout.tv_usec = 0; | 788 | struct pmap* pm_mnt; |
783 | timeout = time(NULL) + 60 * retry; | 789 | time_t t; |
784 | prevt = 0; | 790 | time_t prevt; |
785 | t = 30; | 791 | time_t timeout; |
786 | val = 1; | 792 | |
787 | for (;;) { | 793 | retry_timeout.tv_sec = 3; |
788 | if (bg && stat(node, &statbuf) == -1) { | 794 | retry_timeout.tv_usec = 0; |
789 | if (running_bg) { | 795 | total_timeout.tv_sec = 20; |
790 | sleep(val); /* 1, 2, 4, 8, 16, 30, ... */ | 796 | total_timeout.tv_usec = 0; |
791 | val *= 2; | 797 | timeout = time(NULL) + 60 * retry; |
792 | if (val > 30) | 798 | prevt = 0; |
793 | val = 30; | 799 | t = 30; |
794 | } | 800 | retry: |
795 | } else { | 801 | /* be careful not to use too many CPU cycles */ |
796 | /* be careful not to use too many CPU cycles */ | 802 | if (t - prevt < 30) |
797 | if (t - prevt < 30) | 803 | sleep(30); |
798 | sleep(30); | 804 | |
799 | 805 | pm_mnt = get_mountport(&mount_server_addr, | |
800 | pm_mnt = get_mountport(&mount_server_addr, | 806 | mountprog, |
801 | mountprog, | 807 | mountvers, |
802 | mountvers, | 808 | proto, |
803 | proto, | 809 | mountport); |
804 | mountport); | 810 | nfsvers = (pm_mnt->pm_vers < 2) ? 2 : pm_mnt->pm_vers; |
805 | 811 | ||
806 | /* contact the mount daemon via TCP */ | 812 | /* contact the mount daemon via TCP */ |
807 | mount_server_addr.sin_port = htons(pm_mnt->pm_port); | 813 | mount_server_addr.sin_port = htons(pm_mnt->pm_port); |
808 | msock = RPC_ANYSOCK; | 814 | msock = RPC_ANYSOCK; |
809 | 815 | ||
810 | switch (pm_mnt->pm_prot) { | 816 | switch (pm_mnt->pm_prot) { |
811 | case IPPROTO_UDP: | 817 | case IPPROTO_UDP: |
812 | mclient = clntudp_create(&mount_server_addr, | 818 | mclient = clntudp_create(&mount_server_addr, |
813 | pm_mnt->pm_prog, | 819 | pm_mnt->pm_prog, |
814 | pm_mnt->pm_vers, | 820 | pm_mnt->pm_vers, |
815 | retry_timeout, | 821 | retry_timeout, |
816 | &msock); | 822 | &msock); |
817 | if (mclient) | 823 | if (mclient) |
818 | break; | 824 | break; |
819 | mount_server_addr.sin_port = htons(pm_mnt->pm_port); | 825 | mount_server_addr.sin_port = htons(pm_mnt->pm_port); |
820 | msock = RPC_ANYSOCK; | 826 | msock = RPC_ANYSOCK; |
821 | case IPPROTO_TCP: | 827 | case IPPROTO_TCP: |
822 | mclient = clnttcp_create(&mount_server_addr, | 828 | mclient = clnttcp_create(&mount_server_addr, |
823 | pm_mnt->pm_prog, | 829 | pm_mnt->pm_prog, |
824 | pm_mnt->pm_vers, | 830 | pm_mnt->pm_vers, |
825 | &msock, 0, 0); | 831 | &msock, 0, 0); |
826 | break; | 832 | break; |
827 | default: | 833 | default: |
828 | mclient = 0; | 834 | mclient = 0; |
829 | } | 835 | } |
830 | if (mclient) { | 836 | if (!mclient) { |
831 | /* try to mount hostname:pathname */ | 837 | if (!daemonized && prevt == 0) |
832 | mclient->cl_auth = authunix_create_default(); | 838 | error_msg_rpc(clnt_spcreateerror(" ")); |
833 | 839 | } else { | |
834 | /* make pointers in xdr_mountres3 NULL so | 840 | enum clnt_stat clnt_stat; |
835 | * that xdr_array allocates memory for us | 841 | /* try to mount hostname:pathname */ |
836 | */ | 842 | mclient->cl_auth = authunix_create_default(); |
837 | memset(&status, 0, sizeof(status)); | 843 | |
838 | 844 | /* make pointers in xdr_mountres3 NULL so | |
839 | if (pm_mnt->pm_vers == 3) | 845 | * that xdr_array allocates memory for us |
840 | clnt_stat = clnt_call(mclient, MOUNTPROC3_MNT, | 846 | */ |
841 | (xdrproc_t) xdr_dirpath, | 847 | memset(&status, 0, sizeof(status)); |
842 | (caddr_t) &pathname, | 848 | |
843 | (xdrproc_t) xdr_mountres3, | 849 | if (pm_mnt->pm_vers == 3) |
844 | (caddr_t) &status, | 850 | clnt_stat = clnt_call(mclient, MOUNTPROC3_MNT, |
845 | total_timeout); | 851 | (xdrproc_t) xdr_dirpath, |
846 | else | 852 | (caddr_t) &pathname, |
847 | clnt_stat = clnt_call(mclient, MOUNTPROC_MNT, | 853 | (xdrproc_t) xdr_mountres3, |
848 | (xdrproc_t) xdr_dirpath, | 854 | (caddr_t) &status, |
849 | (caddr_t) &pathname, | 855 | total_timeout); |
850 | (xdrproc_t) xdr_fhstatus, | 856 | else |
851 | (caddr_t) &status, | 857 | clnt_stat = clnt_call(mclient, MOUNTPROC_MNT, |
852 | total_timeout); | 858 | (xdrproc_t) xdr_dirpath, |
853 | 859 | (caddr_t) &pathname, | |
854 | if (clnt_stat == RPC_SUCCESS) | 860 | (xdrproc_t) xdr_fhstatus, |
855 | break; /* we're done */ | 861 | (caddr_t) &status, |
856 | if (errno != ECONNREFUSED) { | 862 | total_timeout); |
857 | clnt_perror(mclient, "mount"); | 863 | |
858 | goto fail; /* don't retry */ | 864 | if (clnt_stat == RPC_SUCCESS) |
859 | } | 865 | goto prepare_kernel_data; /* we're done */ |
860 | if (!running_bg && prevt == 0) | 866 | if (errno != ECONNREFUSED) { |
861 | clnt_perror(mclient, "mount"); | 867 | error_msg_rpc(clnt_sperror(mclient, " ")); |
862 | auth_destroy(mclient->cl_auth); | 868 | goto fail; /* don't retry */ |
863 | clnt_destroy(mclient); | ||
864 | mclient = 0; | ||
865 | close(msock); | ||
866 | } else { | ||
867 | if (!running_bg && prevt == 0) | ||
868 | clnt_pcreateerror("mount"); | ||
869 | } | 869 | } |
870 | prevt = t; | 870 | /* Connection refused */ |
871 | if (!daemonized && prevt == 0) /* print just once */ | ||
872 | error_msg_rpc(clnt_sperror(mclient, " ")); | ||
873 | auth_destroy(mclient->cl_auth); | ||
874 | clnt_destroy(mclient); | ||
875 | mclient = 0; | ||
876 | close(msock); | ||
871 | } | 877 | } |
878 | |||
879 | /* Timeout. We are going to retry... maybe */ | ||
880 | |||
872 | if (!bg) | 881 | if (!bg) |
873 | goto fail; | 882 | goto fail; |
874 | if (!running_bg) { | 883 | if (!daemonized) { |
875 | prev_bg_host = xstrdup(hostname); | 884 | daemonized = daemonize(); |
876 | if (retry > 0) | 885 | if (daemonized <= 0) { /* parent or error */ |
877 | retval = EX_BG; | 886 | retval = -daemonized; |
878 | goto fail; | 887 | goto ret; |
888 | } | ||
879 | } | 889 | } |
890 | prevt = t; | ||
880 | t = time(NULL); | 891 | t = time(NULL); |
881 | if (t >= timeout) | 892 | if (t >= timeout) |
893 | /* TODO error message */ | ||
882 | goto fail; | 894 | goto fail; |
895 | |||
896 | goto retry; | ||
883 | } | 897 | } |
884 | nfsvers = (pm_mnt->pm_vers < 2) ? 2 : pm_mnt->pm_vers; | 898 | |
899 | prepare_kernel_data: | ||
885 | 900 | ||
886 | if (nfsvers == 2) { | 901 | if (nfsvers == 2) { |
887 | if (status.nfsv2.fhs_status != 0) { | 902 | if (status.nfsv2.fhs_status != 0) { |
@@ -927,17 +942,17 @@ int nfsmount(const char *spec, const char *node, int *flags, | |||
927 | } else | 942 | } else |
928 | fsock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); | 943 | fsock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); |
929 | if (fsock < 0) { | 944 | if (fsock < 0) { |
930 | perror("nfs socket"); | 945 | bb_perror_msg("nfs socket"); |
931 | goto fail; | 946 | goto fail; |
932 | } | 947 | } |
933 | if (bindresvport(fsock, 0) < 0) { | 948 | if (bindresvport(fsock, 0) < 0) { |
934 | perror("nfs bindresvport"); | 949 | bb_perror_msg("nfs bindresvport"); |
935 | goto fail; | 950 | goto fail; |
936 | } | 951 | } |
937 | if (port == 0) { | 952 | if (port == 0) { |
938 | server_addr.sin_port = PMAPPORT; | 953 | server_addr.sin_port = PMAPPORT; |
939 | port = pmap_getport(&server_addr, nfsprog, nfsvers, | 954 | port = pmap_getport(&server_addr, nfsprog, nfsvers, |
940 | tcp ? IPPROTO_TCP : IPPROTO_UDP); | 955 | tcp ? IPPROTO_TCP : IPPROTO_UDP); |
941 | if (port == 0) | 956 | if (port == 0) |
942 | port = NFS_PORT; | 957 | port = NFS_PORT; |
943 | #ifdef NFS_MOUNT_DEBUG | 958 | #ifdef NFS_MOUNT_DEBUG |
@@ -961,16 +976,34 @@ int nfsmount(const char *spec, const char *node, int *flags, | |||
961 | auth_destroy(mclient->cl_auth); | 976 | auth_destroy(mclient->cl_auth); |
962 | clnt_destroy(mclient); | 977 | clnt_destroy(mclient); |
963 | close(msock); | 978 | close(msock); |
964 | copy_data_and_return: | ||
965 | *mount_opts = xrealloc(*mount_opts, sizeof(data)); | ||
966 | memcpy(*mount_opts, &data, sizeof(data)); | ||
967 | 979 | ||
968 | retval = 0; | 980 | if (bg) { |
981 | /* We must wait until mount directory is available */ | ||
982 | struct stat statbuf; | ||
983 | int delay = 1; | ||
984 | while (stat(mp->mnt_dir, &statbuf) == -1) { | ||
985 | if (!daemonized) { | ||
986 | daemonized = daemonize(); | ||
987 | if (daemonized <= 0) { /* parent or error */ | ||
988 | retval = -daemonized; | ||
989 | goto ret; | ||
990 | } | ||
991 | } | ||
992 | sleep(delay); /* 1, 2, 4, 8, 16, 30, ... */ | ||
993 | delay *= 2; | ||
994 | if (delay > 30) | ||
995 | delay = 30; | ||
996 | } | ||
997 | } | ||
998 | |||
999 | do_mount: /* perform actual mount */ | ||
1000 | |||
1001 | mp->mnt_type = "nfs"; | ||
1002 | retval = mount_it_now(mp, vfsflags, (char*)&data); | ||
969 | goto ret; | 1003 | goto ret; |
970 | 1004 | ||
971 | /* abort */ | 1005 | fail: /* abort */ |
972 | 1006 | ||
973 | fail: | ||
974 | if (msock != -1) { | 1007 | if (msock != -1) { |
975 | if (mclient) { | 1008 | if (mclient) { |
976 | auth_destroy(mclient->cl_auth); | 1009 | auth_destroy(mclient->cl_auth); |
@@ -982,7 +1015,8 @@ fail: | |||
982 | close(fsock); | 1015 | close(fsock); |
983 | 1016 | ||
984 | ret: | 1017 | ret: |
985 | free(hostdir); | 1018 | free(hostname); |
986 | free(old_opts); | 1019 | free(mounthost); |
1020 | free(filteropts); | ||
987 | return retval; | 1021 | return retval; |
988 | } | 1022 | } |