aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2006-09-11 17:42:44 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2006-09-11 17:42:44 +0000
commit00d7d6cef6419654071ccc77d9b2f212198dab3d (patch)
treedd597506d203700ee8bdab93e5467cac0e2a1712
parent64d7e93081141cb6f1668436a5629a2304047f38 (diff)
downloadbusybox-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.h4
-rw-r--r--util-linux/mount.c28
-rw-r--r--util-linux/nfsmount.c380
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);
303extern int vdprintf(int d, const char *format, va_list ap); 303extern int vdprintf(int d, const char *format, va_list ap);
304#endif 304#endif
305 305
306int nfsmount(const char *spec, const char *node, int *flags, 306int mount_it_now(struct mntent *mp, int vfsflags, char *filteropts);
307 char **mount_opts, int running_bg); 307int 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 */
106static int parse_mount_options(char *options, char **unrecognized) 106static 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
191static int useMtab; 191static int useMtab = 1;
192static int fakeIt; 192static 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 199int mount_it_now(struct mntent *mp, int vfsflags, char *filteropts)
200static 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);
247if(0) bb_error_msg("buggy: addmntent(fsname='%s' dir='%s' type='%s' opts='%s')",
248mp->mnt_fsname,
249mp->mnt_dir,
250mp->mnt_type,
251mp->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
338enum {
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
429int nfsmount(const char *spec, const char *node, int *flags, 424static 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
445static 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*(" ")) */
454static 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; 463int 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 } 800retry:
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
899prepare_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);
964copy_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
999do_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 */ 1005fail: /* abort */
972 1006
973fail:
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
984ret: 1017ret:
985 free(hostdir); 1018 free(hostname);
986 free(old_opts); 1019 free(mounthost);
1020 free(filteropts);
987 return retval; 1021 return retval;
988} 1022}