summaryrefslogtreecommitdiffstats
path: root/mount/nfsmount.c
diff options
context:
space:
mode:
Diffstat (limited to 'mount/nfsmount.c')
-rw-r--r--mount/nfsmount.c246
1 files changed, 183 insertions, 63 deletions
diff --git a/mount/nfsmount.c b/mount/nfsmount.c
index ee869dc44..fd9364669 100644
--- a/mount/nfsmount.c
+++ b/mount/nfsmount.c
@@ -17,6 +17,9 @@
*
* Fri, 8 Mar 1996 18:01:39, Swen Thuemmler <swen@uni-paderborn.de>:
* Omit the call to connect() for Linux version 1.3.11 or later.
+ *
+ * Wed Oct 1 23:55:28 1997: Dick Streefland <dick_streefland@tasking.com>
+ * Implemented the "bg", "fg" and "retry" mount options for NFS.
*/
/*
@@ -34,17 +37,14 @@
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/utsname.h>
+#include <sys/stat.h>
#include <arpa/inet.h>
#include "sundries.h"
#include "nfsmount.h"
-#if defined(__GLIBC__)
-#define _LINUX_SOCKET_H
-#endif /* __GLIBC__ */
-#define _I386_BITOPS_H
-#include <linux/fs.h>
#include <linux/nfs.h>
+#include "mount_constants.h"
#include "nfs_mount3.h"
static char *nfs_strerror(int stat);
@@ -96,8 +96,9 @@ find_kernel_nfs_mount_version(void) {
}
int nfsmount(const char *spec, const char *node, int *flags,
- char **extra_opts, char **mount_opts)
+ char **extra_opts, char **mount_opts, int running_bg)
{
+ static char *prev_bg_host;
char hostdir[1024];
CLIENT *mclient;
char *hostname;
@@ -115,8 +116,9 @@ int nfsmount(const char *spec, const char *node, int *flags,
struct sockaddr_in server_addr;
struct sockaddr_in mount_server_addr;
int msock, fsock;
- struct timeval pertry_timeout;
+ struct timeval retry_timeout;
struct fhstatus status;
+ struct stat statbuf;
char *s;
int port;
int mountport;
@@ -133,9 +135,14 @@ int nfsmount(const char *spec, const char *node, int *flags,
int mountvers;
int nfsprog;
int nfsvers;
+ int retval;
+ time_t t;
+ time_t prevt;
+ time_t timeout;
find_kernel_nfs_mount_version();
+ retval = EX_FAIL;
msock = fsock = -1;
mclient = NULL;
if (strlen(spec) >= sizeof(hostdir)) {
@@ -148,21 +155,30 @@ int nfsmount(const char *spec, const char *node, int *flags,
hostname = hostdir;
dirname = s + 1;
*s = '\0';
- }
- else {
+ } else {
fprintf(stderr, "mount: "
"directory to mount not in host:dir format\n");
goto fail;
}
server_addr.sin_family = AF_INET;
- if (!inet_aton(hostname, &server_addr.sin_addr)) {
+#if 1 /* old libc's do not have inet_aton() -- change 1 to 0 */
+ if (!inet_aton(hostname, &server_addr.sin_addr))
+#endif
+ {
if ((hp = gethostbyname(hostname)) == NULL) {
fprintf(stderr, "mount: can't get address for %s\n",
hostname);
goto fail;
- } else
- memcpy(&server_addr.sin_addr, hp->h_addr, hp->h_length);
+ } else {
+ if (hp->h_length > sizeof(struct in_addr)) {
+ fprintf(stderr,
+ "mount: got bad hp->h_length\n");
+ hp->h_length = sizeof(struct in_addr);
+ }
+ memcpy(&server_addr.sin_addr,
+ hp->h_addr, hp->h_length);
+ }
}
memcpy (&mount_server_addr, &server_addr, sizeof (mount_server_addr));
@@ -203,7 +219,7 @@ int nfsmount(const char *spec, const char *node, int *flags,
nocto = 0;
nolock = 0;
noac = 0;
- retry = 10000;
+ retry = 10000; /* 10000 minutes ~ 1 week */
tcp = 0;
mountprog = MOUNTPROG;
@@ -306,9 +322,11 @@ int nfsmount(const char *spec, const char *node, int *flags,
else
printf("Warning: option nolock is not supported.\n");
} else {
- printf("unknown nfs mount option: "
- "%s%s\n", val ? "" : "no", opt);
- goto fail;
+ if (!sloppy) {
+ printf("unknown nfs mount option: "
+ "%s%s\n", val ? "" : "no", opt);
+ goto fail;
+ }
}
}
}
@@ -349,9 +367,6 @@ int nfsmount(const char *spec, const char *node, int *flags,
printf("tcp = %d\n",
(data.flags & NFS_MOUNT_TCP) != 0);
#endif
-#if 0
- goto fail;
-#endif
#endif
data.version = nfs_mount_version;
@@ -360,58 +375,132 @@ int nfsmount(const char *spec, const char *node, int *flags,
if (*flags & MS_REMOUNT)
return 0;
+ /*
+ * If the previous mount operation on the same host was
+ * backgrounded, and the "bg" for this mount is also set,
+ * give up immediately, to avoid the initial timeout.
+ */
+ if (bg && !running_bg &&
+ prev_bg_host && strcmp(hostname, prev_bg_host) == 0) {
+ if (retry > 0)
+ retval = EX_BG;
+ return retval;
+ }
+
/* create mount deamon client */
/* See if the nfs host = mount host. */
if (mounthost) {
if (mounthost[0] >= '0' && mounthost[0] <= '9') {
mount_server_addr.sin_family = AF_INET;
mount_server_addr.sin_addr.s_addr = inet_addr(hostname);
- }
- else if ((hp = gethostbyname(mounthost)) == NULL) {
- fprintf(stderr, "mount: can't get address for %s\n", hostname);
- goto fail;
- }
- else {
- mount_server_addr.sin_family = AF_INET;
- memcpy(&mount_server_addr.sin_addr, hp->h_addr, hp->h_length);
+ } else {
+ if ((hp = gethostbyname(mounthost)) == NULL) {
+ fprintf(stderr, "mount: can't get address for %s\n",
+ hostname);
+ goto fail;
+ } else {
+ if (hp->h_length > sizeof(struct in_addr)) {
+ fprintf(stderr,
+ "mount: got bad hp->h_length?\n");
+ hp->h_length = sizeof(struct in_addr);
+ }
+ mount_server_addr.sin_family = AF_INET;
+ memcpy(&mount_server_addr.sin_addr,
+ hp->h_addr, hp->h_length);
+ }
}
}
- mount_server_addr.sin_port = htons(mountport);
- msock = RPC_ANYSOCK;
- if ((mclient = clnttcp_create(&mount_server_addr,
- mountprog, mountvers, &msock, 0, 0)) == NULL) {
- mount_server_addr.sin_port = htons(mountport);
- msock = RPC_ANYSOCK;
- pertry_timeout.tv_sec = 3;
- pertry_timeout.tv_usec = 0;
- if ((mclient = clntudp_create(&mount_server_addr,
- mountprog, mountvers, pertry_timeout, &msock)) == NULL) {
- clnt_pcreateerror("mount clntudp_create");
+ /*
+ * The following loop implements the mount retries. On the first
+ * call, "running_bg" is 0. When the mount times out, and the
+ * "bg" option is set, the exit status EX_BG will be returned.
+ * For a backgrounded mount, there will be a second call by the
+ * child process with "running_bg" set to 1.
+ *
+ * The case where the mount point is not present and the "bg"
+ * option is set, is treated as a timeout. This is done to
+ * support nested mounts.
+ *
+ * The "retry" count specified by the user is the number of
+ * minutes to retry before giving up.
+ *
+ * Only the first error message will be displayed.
+ */
+ retry_timeout.tv_sec = 3;
+ retry_timeout.tv_usec = 0;
+ total_timeout.tv_sec = 20;
+ total_timeout.tv_usec = 0;
+ timeout = time(NULL) + 60 * retry;
+ prevt = 0;
+ t = 30;
+ val = 1;
+ for (;;) {
+ if (bg && stat(node, &statbuf) == -1) {
+ if (running_bg) {
+ sleep(val); /* 1, 2, 4, 8, 16, 30, ... */
+ val *= 2;
+ if (val > 30)
+ val = 30;
+ }
+ } else {
+ /* be careful not to use too many CPU cycles */
+ if (t - prevt < 30)
+ sleep(30);
+
+ /* contact the mount daemon via TCP */
+ mount_server_addr.sin_port = htons(mountport);
+ msock = RPC_ANYSOCK;
+ mclient = clnttcp_create(&mount_server_addr,
+ mountprog, mountvers,
+ &msock, 0, 0);
+
+ /* if this fails, contact the mount daemon via UDP */
+ if (!mclient) {
+ mount_server_addr.sin_port = htons(mountport);
+ msock = RPC_ANYSOCK;
+ mclient = clntudp_create(&mount_server_addr,
+ mountprog, mountvers,
+ retry_timeout, &msock);
+ }
+ if (mclient) {
+ /* try to mount hostname:dirname */
+ mclient->cl_auth = authunix_create_default();
+ clnt_stat = clnt_call(mclient, MOUNTPROC_MNT,
+ (xdrproc_t) xdr_dirpath, (caddr_t) &dirname,
+ (xdrproc_t) xdr_fhstatus, (caddr_t) &status,
+ total_timeout);
+ if (clnt_stat == RPC_SUCCESS)
+ break; /* we're done */
+ if (errno != ECONNREFUSED) {
+ clnt_perror(mclient, "mount");
+ goto fail; /* don't retry */
+ }
+ if (!running_bg && prevt == 0)
+ clnt_perror(mclient, "mount");
+ auth_destroy(mclient->cl_auth);
+ clnt_destroy(mclient);
+ mclient = 0;
+ close(msock);
+ } else {
+ if (!running_bg && prevt == 0)
+ clnt_pcreateerror("mount");
+ }
+ prevt = t;
+ }
+ if (!bg)
+ goto fail;
+ if (!running_bg) {
+ prev_bg_host = xstrdup(hostname);
+ if (retry > 0)
+ retval = EX_BG;
goto fail;
}
-#ifdef NFS_MOUNT_DEBUG
- printf("using UDP for mount deamon\n");
-#endif
+ t = time(NULL);
+ if (t >= timeout)
+ goto fail;
}
-#ifdef NFS_MOUNT_DEBUG
- else
- printf("using TCP for mount deamon\n");
-#endif
- mclient->cl_auth = authunix_create_default();
- total_timeout.tv_sec = 20;
- total_timeout.tv_usec = 0;
- /* try to mount hostname:dirname */
-
- clnt_stat = clnt_call(mclient, MOUNTPROC_MNT,
- (xdrproc_t) xdr_dirpath, &dirname,
- (xdrproc_t) xdr_fhstatus, &status,
- total_timeout);
- if (clnt_stat != RPC_SUCCESS) {
- clnt_perror(mclient, "rpc mount");
- goto fail;
- }
if (status.fhs_status != 0) {
fprintf(stderr,
"mount: %s:%s failed, reason given by server: %s\n",
@@ -485,15 +574,16 @@ int nfsmount(const char *spec, const char *node, int *flags,
fail:
if (msock != -1) {
- auth_destroy(mclient->cl_auth);
- clnt_destroy(mclient);
+ if (mclient) {
+ auth_destroy(mclient->cl_auth);
+ clnt_destroy(mclient);
+ }
close(msock);
}
if (fsock != -1)
close(fsock);
- return 1;
-}
-
+ return retval;
+}
/*
* We need to translate between nfs status return values and
@@ -554,3 +644,33 @@ static char *nfs_strerror(int stat)
return buf;
}
+#if 0
+int
+my_getport(struct in_addr server, struct timeval *timeo, ...)
+{
+ struct sockaddr_in sin;
+ struct pmap pmap;
+ CLIENT *clnt;
+ int sock = RPC_ANYSOCK, port;
+
+ pmap.pm_prog = prog;
+ pmap.pm_vers = vers;
+ pmap.pm_prot = prot;
+ pmap.pm_port = 0;
+ sin.sin_family = AF_INET;
+ sin.sin_addr = server;
+ sin.sin_port = htons(111);
+ clnt = clntudp_create(&sin, 100000, 2, *timeo, &sock);
+ status = clnt_call(clnt, PMAP_GETPORT,
+ &pmap, (xdrproc_t) xdr_pmap,
+ &port, (xdrproc_t) xdr_uint);
+ if (status != SUCCESS) {
+ /* natter */
+ port = 0;
+ }
+
+ clnt_destroy(clnt);
+ close(sock);
+ return port;
+}
+#endif