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.
This commit is contained in:
parent
64d7e93081
commit
00d7d6cef6
@ -303,8 +303,8 @@ extern int set_loop(char **device, const char *file, int offset);
|
|||||||
extern int vdprintf(int d, const char *format, va_list ap);
|
extern int vdprintf(int d, const char *format, va_list ap);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int nfsmount(const char *spec, const char *node, int *flags,
|
int mount_it_now(struct mntent *mp, int vfsflags, char *filteropts);
|
||||||
char **mount_opts, int running_bg);
|
int nfsmount(struct mntent *mp, int vfsflags, char *filteropts);
|
||||||
|
|
||||||
/* Include our own copy of struct sysinfo to avoid binary compatibility
|
/* Include our own copy of struct sysinfo to avoid binary compatibility
|
||||||
* problems with Linux 2.4, which changed things. Grumble, grumble. */
|
* problems with Linux 2.4, which changed things. Grumble, grumble. */
|
||||||
|
@ -102,7 +102,7 @@ static void append_mount_options(char **oldopts, char *newopts)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Use the mount_options list to parse options into flags.
|
/* Use the mount_options list to parse options into flags.
|
||||||
* Return list of unrecognized options in *strflags if strflags!=NULL */
|
* Also return list of unrecognized options if unrecognized!=NULL */
|
||||||
static int parse_mount_options(char *options, char **unrecognized)
|
static int parse_mount_options(char *options, char **unrecognized)
|
||||||
{
|
{
|
||||||
int flags = MS_SILENT;
|
int flags = MS_SILENT;
|
||||||
@ -188,7 +188,7 @@ void delete_block_backed_filesystems(void);
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if ENABLE_FEATURE_MTAB_SUPPORT
|
#if ENABLE_FEATURE_MTAB_SUPPORT
|
||||||
static int useMtab;
|
static int useMtab = 1;
|
||||||
static int fakeIt;
|
static int fakeIt;
|
||||||
#else
|
#else
|
||||||
#define useMtab 0
|
#define useMtab 0
|
||||||
@ -196,8 +196,7 @@ static int fakeIt;
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Perform actual mount of specific filesystem at specific location.
|
// Perform actual mount of specific filesystem at specific location.
|
||||||
|
int mount_it_now(struct mntent *mp, int vfsflags, char *filteropts)
|
||||||
static int mount_it_now(struct mntent *mp, int vfsflags, char *filteropts)
|
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
@ -228,7 +227,7 @@ static int mount_it_now(struct mntent *mp, int vfsflags, char *filteropts)
|
|||||||
int i;
|
int i;
|
||||||
|
|
||||||
if(!mountTable)
|
if(!mountTable)
|
||||||
bb_error_msg("No %s",bb_path_mtab_file);
|
bb_error_msg("no %s",bb_path_mtab_file);
|
||||||
|
|
||||||
// Add vfs string flags
|
// Add vfs string flags
|
||||||
|
|
||||||
@ -244,7 +243,13 @@ static int mount_it_now(struct mntent *mp, int vfsflags, char *filteropts)
|
|||||||
// Write and close.
|
// Write and close.
|
||||||
|
|
||||||
if(!mp->mnt_type || !*mp->mnt_type) mp->mnt_type="--bind";
|
if(!mp->mnt_type || !*mp->mnt_type) mp->mnt_type="--bind";
|
||||||
addmntent(mountTable, mp);
|
// addmntent(mountTable, mp);
|
||||||
|
if(0) bb_error_msg("buggy: addmntent(fsname='%s' dir='%s' type='%s' opts='%s')",
|
||||||
|
mp->mnt_fsname,
|
||||||
|
mp->mnt_dir,
|
||||||
|
mp->mnt_type,
|
||||||
|
mp->mnt_opts
|
||||||
|
);
|
||||||
endmntent(mountTable);
|
endmntent(mountTable);
|
||||||
if (ENABLE_FEATURE_CLEAN_UP)
|
if (ENABLE_FEATURE_CLEAN_UP)
|
||||||
if(strcmp(mp->mnt_type,"--bind")) mp->mnt_type = 0;
|
if(strcmp(mp->mnt_type,"--bind")) mp->mnt_type = 0;
|
||||||
@ -319,13 +324,7 @@ static int singlemount(struct mntent *mp, int ignore_busy)
|
|||||||
(!mp->mnt_type || !strcmp(mp->mnt_type,"nfs")) &&
|
(!mp->mnt_type || !strcmp(mp->mnt_type,"nfs")) &&
|
||||||
strchr(mp->mnt_fsname, ':') != NULL)
|
strchr(mp->mnt_fsname, ':') != NULL)
|
||||||
{
|
{
|
||||||
if (nfsmount(mp->mnt_fsname, mp->mnt_dir, &vfsflags, &filteropts, 1)) {
|
rc = nfsmount(mp, vfsflags, filteropts);
|
||||||
bb_perror_msg("nfsmount failed");
|
|
||||||
} else {
|
|
||||||
// Strangely enough, nfsmount() doesn't actually mount() anything.
|
|
||||||
mp->mnt_type = "nfs";
|
|
||||||
rc = mount_it_now(mp, vfsflags, filteropts);
|
|
||||||
}
|
|
||||||
goto report_error;
|
goto report_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -400,7 +399,8 @@ report_error:
|
|||||||
|
|
||||||
if (rc && errno == EBUSY && ignore_busy) rc = 0;
|
if (rc && errno == EBUSY && ignore_busy) rc = 0;
|
||||||
if (rc < 0)
|
if (rc < 0)
|
||||||
bb_perror_msg("mounting %s on %s failed", mp->mnt_fsname, mp->mnt_dir);
|
/* perror here sometimes says "mounting ... on ... failed: Success" */
|
||||||
|
bb_error_msg("mounting %s on %s failed", mp->mnt_fsname, mp->mnt_dir);
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
@ -22,6 +22,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "busybox.h"
|
#include "busybox.h"
|
||||||
|
#include <syslog.h>
|
||||||
|
#include <mntent.h>
|
||||||
#include <sys/utsname.h>
|
#include <sys/utsname.h>
|
||||||
#undef TRUE
|
#undef TRUE
|
||||||
#undef FALSE
|
#undef FALSE
|
||||||
@ -332,15 +334,8 @@ static bool_t xdr_mountres3(XDR *xdrs, mountres3 *objp)
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#define MAX_NFSPROT ((nfs_mount_version >= 4) ? 3 : 2)
|
#define MAX_NFSPROT ((nfs_mount_version >= 4) ? 3 : 2)
|
||||||
|
|
||||||
enum {
|
|
||||||
EX_FAIL = 32, /* mount failure */
|
|
||||||
EX_BG = 256 /* retry in background (internal only) */
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* nfs_mount_version according to the sources seen at compile time.
|
* nfs_mount_version according to the sources seen at compile time.
|
||||||
*/
|
*/
|
||||||
@ -426,50 +421,62 @@ next:
|
|||||||
return &p;
|
return &p;
|
||||||
}
|
}
|
||||||
|
|
||||||
int nfsmount(const char *spec, const char *node, int *flags,
|
static int daemonize(void)
|
||||||
char **mount_opts, int running_bg)
|
|
||||||
{
|
{
|
||||||
/* prev_bg_host is a -o bg support:
|
int fd;
|
||||||
* "bg: if the first NFS mount attempt times out,
|
int pid = fork();
|
||||||
* retry the mount in the background.
|
if (pid < 0) /* error */
|
||||||
* After a mount operation is backgrounded,
|
return -errno;
|
||||||
* all subsequent mounts on the same NFS server
|
if (pid > 0) /* parent */
|
||||||
* will be backgrounded immediately, without first
|
return 0;
|
||||||
* attempting the mount. A missing mount point is treated
|
/* child */
|
||||||
* as a timeout, to allow for nested NFS mounts."
|
fd = xopen(bb_dev_null, O_RDWR);
|
||||||
*
|
dup2(fd, 0);
|
||||||
* But current implementation is a dirty hack -
|
dup2(fd, 1);
|
||||||
* it works only if all mounts are to one host!
|
dup2(fd, 2);
|
||||||
* IOW: think what will happen if you have this sequence:
|
if (fd > 2) close(fd);
|
||||||
* mount a.a.a.a:/dir /mnt/a -o bg
|
setsid();
|
||||||
* mount b.b.b.b:/dir /mnt/b -o bg
|
openlog(bb_applet_name, LOG_PID, LOG_DAEMON);
|
||||||
* mount a.a.a.a:/dir /mnt/a -o bg
|
logmode = LOGMODE_SYSLOG;
|
||||||
* mount b.b.b.b:/dir /mnt/b -o bg
|
return 1;
|
||||||
*/
|
}
|
||||||
|
|
||||||
static char *prev_bg_host;
|
// TODO
|
||||||
char *hostdir;
|
static inline int we_saw_this_host_before(const char *hostname)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* RPC strerror analogs are terminally idiotic:
|
||||||
|
* *mandatory* prefix and \n at end.
|
||||||
|
* This hopefully helps. Usage:
|
||||||
|
* error_msg_rpc(clnt_*error*(" ")) */
|
||||||
|
static void error_msg_rpc(const char *msg)
|
||||||
|
{
|
||||||
|
size_t len;
|
||||||
|
while (msg[0] == ' ' || msg[0] == ':') msg++;
|
||||||
|
len = strlen(msg);
|
||||||
|
while (len && msg[len-1] == '\n') len--;
|
||||||
|
bb_error_msg("%.*s", len, msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
int nfsmount(struct mntent *mp, int vfsflags, char *filteropts)
|
||||||
|
{
|
||||||
CLIENT *mclient;
|
CLIENT *mclient;
|
||||||
char *hostname;
|
char *hostname;
|
||||||
char *pathname;
|
char *pathname;
|
||||||
char *old_opts;
|
|
||||||
char *mounthost;
|
char *mounthost;
|
||||||
struct timeval total_timeout;
|
|
||||||
enum clnt_stat clnt_stat;
|
|
||||||
struct nfs_mount_data data;
|
struct nfs_mount_data data;
|
||||||
char *opt, *opteq;
|
char *opt;
|
||||||
int val;
|
|
||||||
struct hostent *hp;
|
struct hostent *hp;
|
||||||
struct sockaddr_in server_addr;
|
struct sockaddr_in server_addr;
|
||||||
struct sockaddr_in mount_server_addr;
|
struct sockaddr_in mount_server_addr;
|
||||||
struct pmap* pm_mnt;
|
|
||||||
int msock, fsock;
|
int msock, fsock;
|
||||||
struct timeval retry_timeout;
|
|
||||||
union {
|
union {
|
||||||
struct fhstatus nfsv2;
|
struct fhstatus nfsv2;
|
||||||
struct mountres3 nfsv3;
|
struct mountres3 nfsv3;
|
||||||
} status;
|
} status;
|
||||||
struct stat statbuf;
|
int daemonized;
|
||||||
char *s;
|
char *s;
|
||||||
int port;
|
int port;
|
||||||
int mountport;
|
int mountport;
|
||||||
@ -488,29 +495,27 @@ int nfsmount(const char *spec, const char *node, int *flags,
|
|||||||
int nfsprog;
|
int nfsprog;
|
||||||
int nfsvers;
|
int nfsvers;
|
||||||
int retval;
|
int retval;
|
||||||
time_t t;
|
|
||||||
time_t prevt;
|
|
||||||
time_t timeout;
|
|
||||||
|
|
||||||
find_kernel_nfs_mount_version();
|
find_kernel_nfs_mount_version();
|
||||||
|
|
||||||
/* NB: old_opts and hostdir must be free()d prior to return! */
|
daemonized = 0;
|
||||||
|
|
||||||
old_opts = NULL;
|
|
||||||
mounthost = NULL;
|
mounthost = NULL;
|
||||||
retval = EX_FAIL;
|
retval = ETIMEDOUT;
|
||||||
msock = fsock = -1;
|
msock = fsock = -1;
|
||||||
mclient = NULL;
|
mclient = NULL;
|
||||||
|
|
||||||
hostdir = xstrdup(spec);
|
/* NB: hostname, mounthost, filteropts must be free()d prior to return */
|
||||||
|
|
||||||
|
filteropts = xstrdup(filteropts); /* going to trash it later... */
|
||||||
|
|
||||||
|
hostname = xstrdup(mp->mnt_fsname);
|
||||||
/* mount_main() guarantees that ':' is there */
|
/* mount_main() guarantees that ':' is there */
|
||||||
s = strchr(hostdir, ':');
|
s = strchr(hostname, ':');
|
||||||
hostname = hostdir;
|
|
||||||
pathname = s + 1;
|
pathname = s + 1;
|
||||||
*s = '\0';
|
*s = '\0';
|
||||||
/* Ignore all but first hostname in replicated mounts
|
/* Ignore all but first hostname in replicated mounts
|
||||||
until they can be fully supported. (mack@sgi.com) */
|
until they can be fully supported. (mack@sgi.com) */
|
||||||
s = strchr(hostdir, ',');
|
s = strchr(hostname, ',');
|
||||||
if (s) {
|
if (s) {
|
||||||
*s = '\0';
|
*s = '\0';
|
||||||
bb_error_msg("warning: multiple hostnames not supported");
|
bb_error_msg("warning: multiple hostnames not supported");
|
||||||
@ -538,12 +543,15 @@ int nfsmount(const char *spec, const char *node, int *flags,
|
|||||||
|
|
||||||
/* add IP address to mtab options for use when unmounting */
|
/* add IP address to mtab options for use when unmounting */
|
||||||
|
|
||||||
s = inet_ntoa(server_addr.sin_addr);
|
if (!mp->mnt_opts) { /* TODO: actually mp->mnt_opts is never NULL */
|
||||||
old_opts = *mount_opts;
|
mp->mnt_opts = xasprintf("addr=%s", inet_ntoa(server_addr.sin_addr));
|
||||||
if (!old_opts)
|
} else {
|
||||||
old_opts = xstrdup("");
|
char *tmp = xasprintf("%s%saddr=%s", mp->mnt_opts,
|
||||||
*mount_opts = xasprintf("%s%saddr=%s",
|
mp->mnt_opts[0] ? "," : "",
|
||||||
old_opts, *old_opts ? "," : "", s);
|
inet_ntoa(server_addr.sin_addr));
|
||||||
|
free(mp->mnt_opts);
|
||||||
|
mp->mnt_opts = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
/* Set default options.
|
/* Set default options.
|
||||||
* rsize/wsize (and bsize, for ver >= 3) are left 0 in order to
|
* 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,
|
|||||||
|
|
||||||
/* parse options */
|
/* parse options */
|
||||||
|
|
||||||
for (opt = strtok(old_opts, ","); opt; opt = strtok(NULL, ",")) {
|
for (opt = strtok(filteropts, ","); opt; opt = strtok(NULL, ",")) {
|
||||||
opteq = strchr(opt, '=');
|
char *opteq = strchr(opt, '=');
|
||||||
if (opteq) {
|
if (opteq) {
|
||||||
val = atoi(opteq + 1);
|
int val = atoi(opteq + 1);
|
||||||
*opteq = '\0';
|
*opteq = '\0';
|
||||||
if (!strcmp(opt, "rsize"))
|
if (!strcmp(opt, "rsize"))
|
||||||
data.rsize = val;
|
data.rsize = val;
|
||||||
@ -641,7 +649,7 @@ int nfsmount(const char *spec, const char *node, int *flags,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
val = 1;
|
int val = 1;
|
||||||
if (!strncmp(opt, "no", 2)) {
|
if (!strncmp(opt, "no", 2)) {
|
||||||
val = 0;
|
val = 0;
|
||||||
opt += 2;
|
opt += 2;
|
||||||
@ -723,19 +731,20 @@ int nfsmount(const char *spec, const char *node, int *flags,
|
|||||||
|
|
||||||
data.version = nfs_mount_version;
|
data.version = nfs_mount_version;
|
||||||
|
|
||||||
if (*flags & MS_REMOUNT)
|
if (vfsflags & MS_REMOUNT)
|
||||||
goto copy_data_and_return;
|
goto do_mount;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If the previous mount operation on the same host was
|
* If the previous mount operation on the same host was
|
||||||
* backgrounded, and the "bg" for this mount is also set,
|
* backgrounded, and the "bg" for this mount is also set,
|
||||||
* give up immediately, to avoid the initial timeout.
|
* give up immediately, to avoid the initial timeout.
|
||||||
*/
|
*/
|
||||||
if (bg && !running_bg &&
|
if (bg && we_saw_this_host_before(hostname)) {
|
||||||
prev_bg_host && strcmp(hostname, prev_bg_host) == 0) {
|
daemonized = daemonize(); /* parent or error */
|
||||||
if (retry > 0)
|
if (daemonized <= 0) { /* parent or error */
|
||||||
retval = EX_BG;
|
retval = -daemonized;
|
||||||
goto ret;
|
goto ret;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* create mount daemon client */
|
/* create mount daemon client */
|
||||||
@ -745,7 +754,8 @@ int nfsmount(const char *spec, const char *node, int *flags,
|
|||||||
mount_server_addr.sin_family = AF_INET;
|
mount_server_addr.sin_family = AF_INET;
|
||||||
mount_server_addr.sin_addr.s_addr = inet_addr(hostname);
|
mount_server_addr.sin_addr.s_addr = inet_addr(hostname);
|
||||||
} else {
|
} else {
|
||||||
if ((hp = gethostbyname(mounthost)) == NULL) {
|
hp = gethostbyname(mounthost);
|
||||||
|
if (hp == NULL) {
|
||||||
bb_herror_msg("%s", mounthost);
|
bb_herror_msg("%s", mounthost);
|
||||||
goto fail;
|
goto fail;
|
||||||
} else {
|
} else {
|
||||||
@ -761,11 +771,9 @@ int nfsmount(const char *spec, const char *node, int *flags,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The following loop implements the mount retries. On the first
|
* The following loop implements the mount retries. When the mount
|
||||||
* call, "running_bg" is 0. When the mount times out, and the
|
* times out, and the "bg" option is set, we background ourself
|
||||||
* "bg" option is set, the exit status EX_BG will be returned.
|
* and continue trying.
|
||||||
* 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"
|
* The case where the mount point is not present and the "bg"
|
||||||
* option is set, is treated as a timeout. This is done to
|
* 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,
|
|||||||
*
|
*
|
||||||
* The "retry" count specified by the user is the number of
|
* The "retry" count specified by the user is the number of
|
||||||
* minutes to retry before giving up.
|
* minutes to retry before giving up.
|
||||||
*
|
|
||||||
* Only the first error message will be displayed.
|
|
||||||
*/
|
*/
|
||||||
retry_timeout.tv_sec = 3;
|
{
|
||||||
retry_timeout.tv_usec = 0;
|
struct timeval total_timeout;
|
||||||
total_timeout.tv_sec = 20;
|
struct timeval retry_timeout;
|
||||||
total_timeout.tv_usec = 0;
|
struct pmap* pm_mnt;
|
||||||
timeout = time(NULL) + 60 * retry;
|
time_t t;
|
||||||
prevt = 0;
|
time_t prevt;
|
||||||
t = 30;
|
time_t timeout;
|
||||||
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);
|
|
||||||
|
|
||||||
pm_mnt = get_mountport(&mount_server_addr,
|
retry_timeout.tv_sec = 3;
|
||||||
mountprog,
|
retry_timeout.tv_usec = 0;
|
||||||
mountvers,
|
total_timeout.tv_sec = 20;
|
||||||
proto,
|
total_timeout.tv_usec = 0;
|
||||||
mountport);
|
timeout = time(NULL) + 60 * retry;
|
||||||
|
prevt = 0;
|
||||||
|
t = 30;
|
||||||
|
retry:
|
||||||
|
/* be careful not to use too many CPU cycles */
|
||||||
|
if (t - prevt < 30)
|
||||||
|
sleep(30);
|
||||||
|
|
||||||
/* contact the mount daemon via TCP */
|
pm_mnt = get_mountport(&mount_server_addr,
|
||||||
mount_server_addr.sin_port = htons(pm_mnt->pm_port);
|
mountprog,
|
||||||
msock = RPC_ANYSOCK;
|
mountvers,
|
||||||
|
proto,
|
||||||
|
mountport);
|
||||||
|
nfsvers = (pm_mnt->pm_vers < 2) ? 2 : pm_mnt->pm_vers;
|
||||||
|
|
||||||
switch (pm_mnt->pm_prot) {
|
/* contact the mount daemon via TCP */
|
||||||
case IPPROTO_UDP:
|
mount_server_addr.sin_port = htons(pm_mnt->pm_port);
|
||||||
mclient = clntudp_create(&mount_server_addr,
|
msock = RPC_ANYSOCK;
|
||||||
|
|
||||||
|
switch (pm_mnt->pm_prot) {
|
||||||
|
case IPPROTO_UDP:
|
||||||
|
mclient = clntudp_create(&mount_server_addr,
|
||||||
pm_mnt->pm_prog,
|
pm_mnt->pm_prog,
|
||||||
pm_mnt->pm_vers,
|
pm_mnt->pm_vers,
|
||||||
retry_timeout,
|
retry_timeout,
|
||||||
&msock);
|
&msock);
|
||||||
if (mclient)
|
if (mclient)
|
||||||
break;
|
break;
|
||||||
mount_server_addr.sin_port = htons(pm_mnt->pm_port);
|
mount_server_addr.sin_port = htons(pm_mnt->pm_port);
|
||||||
msock = RPC_ANYSOCK;
|
msock = RPC_ANYSOCK;
|
||||||
case IPPROTO_TCP:
|
case IPPROTO_TCP:
|
||||||
mclient = clnttcp_create(&mount_server_addr,
|
mclient = clnttcp_create(&mount_server_addr,
|
||||||
pm_mnt->pm_prog,
|
pm_mnt->pm_prog,
|
||||||
pm_mnt->pm_vers,
|
pm_mnt->pm_vers,
|
||||||
&msock, 0, 0);
|
&msock, 0, 0);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
mclient = 0;
|
mclient = 0;
|
||||||
}
|
|
||||||
if (mclient) {
|
|
||||||
/* try to mount hostname:pathname */
|
|
||||||
mclient->cl_auth = authunix_create_default();
|
|
||||||
|
|
||||||
/* make pointers in xdr_mountres3 NULL so
|
|
||||||
* that xdr_array allocates memory for us
|
|
||||||
*/
|
|
||||||
memset(&status, 0, sizeof(status));
|
|
||||||
|
|
||||||
if (pm_mnt->pm_vers == 3)
|
|
||||||
clnt_stat = clnt_call(mclient, MOUNTPROC3_MNT,
|
|
||||||
(xdrproc_t) xdr_dirpath,
|
|
||||||
(caddr_t) &pathname,
|
|
||||||
(xdrproc_t) xdr_mountres3,
|
|
||||||
(caddr_t) &status,
|
|
||||||
total_timeout);
|
|
||||||
else
|
|
||||||
clnt_stat = clnt_call(mclient, MOUNTPROC_MNT,
|
|
||||||
(xdrproc_t) xdr_dirpath,
|
|
||||||
(caddr_t) &pathname,
|
|
||||||
(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 (!mclient) {
|
||||||
|
if (!daemonized && prevt == 0)
|
||||||
|
error_msg_rpc(clnt_spcreateerror(" "));
|
||||||
|
} else {
|
||||||
|
enum clnt_stat clnt_stat;
|
||||||
|
/* try to mount hostname:pathname */
|
||||||
|
mclient->cl_auth = authunix_create_default();
|
||||||
|
|
||||||
|
/* make pointers in xdr_mountres3 NULL so
|
||||||
|
* that xdr_array allocates memory for us
|
||||||
|
*/
|
||||||
|
memset(&status, 0, sizeof(status));
|
||||||
|
|
||||||
|
if (pm_mnt->pm_vers == 3)
|
||||||
|
clnt_stat = clnt_call(mclient, MOUNTPROC3_MNT,
|
||||||
|
(xdrproc_t) xdr_dirpath,
|
||||||
|
(caddr_t) &pathname,
|
||||||
|
(xdrproc_t) xdr_mountres3,
|
||||||
|
(caddr_t) &status,
|
||||||
|
total_timeout);
|
||||||
|
else
|
||||||
|
clnt_stat = clnt_call(mclient, MOUNTPROC_MNT,
|
||||||
|
(xdrproc_t) xdr_dirpath,
|
||||||
|
(caddr_t) &pathname,
|
||||||
|
(xdrproc_t) xdr_fhstatus,
|
||||||
|
(caddr_t) &status,
|
||||||
|
total_timeout);
|
||||||
|
|
||||||
|
if (clnt_stat == RPC_SUCCESS)
|
||||||
|
goto prepare_kernel_data; /* we're done */
|
||||||
|
if (errno != ECONNREFUSED) {
|
||||||
|
error_msg_rpc(clnt_sperror(mclient, " "));
|
||||||
|
goto fail; /* don't retry */
|
||||||
|
}
|
||||||
|
/* Connection refused */
|
||||||
|
if (!daemonized && prevt == 0) /* print just once */
|
||||||
|
error_msg_rpc(clnt_sperror(mclient, " "));
|
||||||
|
auth_destroy(mclient->cl_auth);
|
||||||
|
clnt_destroy(mclient);
|
||||||
|
mclient = 0;
|
||||||
|
close(msock);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Timeout. We are going to retry... maybe */
|
||||||
|
|
||||||
if (!bg)
|
if (!bg)
|
||||||
goto fail;
|
goto fail;
|
||||||
if (!running_bg) {
|
if (!daemonized) {
|
||||||
prev_bg_host = xstrdup(hostname);
|
daemonized = daemonize();
|
||||||
if (retry > 0)
|
if (daemonized <= 0) { /* parent or error */
|
||||||
retval = EX_BG;
|
retval = -daemonized;
|
||||||
goto fail;
|
goto ret;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
prevt = t;
|
||||||
t = time(NULL);
|
t = time(NULL);
|
||||||
if (t >= timeout)
|
if (t >= timeout)
|
||||||
|
/* TODO error message */
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
|
goto retry;
|
||||||
}
|
}
|
||||||
nfsvers = (pm_mnt->pm_vers < 2) ? 2 : pm_mnt->pm_vers;
|
|
||||||
|
prepare_kernel_data:
|
||||||
|
|
||||||
if (nfsvers == 2) {
|
if (nfsvers == 2) {
|
||||||
if (status.nfsv2.fhs_status != 0) {
|
if (status.nfsv2.fhs_status != 0) {
|
||||||
@ -927,17 +942,17 @@ int nfsmount(const char *spec, const char *node, int *flags,
|
|||||||
} else
|
} else
|
||||||
fsock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
fsock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
||||||
if (fsock < 0) {
|
if (fsock < 0) {
|
||||||
perror("nfs socket");
|
bb_perror_msg("nfs socket");
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
if (bindresvport(fsock, 0) < 0) {
|
if (bindresvport(fsock, 0) < 0) {
|
||||||
perror("nfs bindresvport");
|
bb_perror_msg("nfs bindresvport");
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
if (port == 0) {
|
if (port == 0) {
|
||||||
server_addr.sin_port = PMAPPORT;
|
server_addr.sin_port = PMAPPORT;
|
||||||
port = pmap_getport(&server_addr, nfsprog, nfsvers,
|
port = pmap_getport(&server_addr, nfsprog, nfsvers,
|
||||||
tcp ? IPPROTO_TCP : IPPROTO_UDP);
|
tcp ? IPPROTO_TCP : IPPROTO_UDP);
|
||||||
if (port == 0)
|
if (port == 0)
|
||||||
port = NFS_PORT;
|
port = NFS_PORT;
|
||||||
#ifdef NFS_MOUNT_DEBUG
|
#ifdef NFS_MOUNT_DEBUG
|
||||||
@ -961,16 +976,34 @@ int nfsmount(const char *spec, const char *node, int *flags,
|
|||||||
auth_destroy(mclient->cl_auth);
|
auth_destroy(mclient->cl_auth);
|
||||||
clnt_destroy(mclient);
|
clnt_destroy(mclient);
|
||||||
close(msock);
|
close(msock);
|
||||||
copy_data_and_return:
|
|
||||||
*mount_opts = xrealloc(*mount_opts, sizeof(data));
|
|
||||||
memcpy(*mount_opts, &data, sizeof(data));
|
|
||||||
|
|
||||||
retval = 0;
|
if (bg) {
|
||||||
|
/* We must wait until mount directory is available */
|
||||||
|
struct stat statbuf;
|
||||||
|
int delay = 1;
|
||||||
|
while (stat(mp->mnt_dir, &statbuf) == -1) {
|
||||||
|
if (!daemonized) {
|
||||||
|
daemonized = daemonize();
|
||||||
|
if (daemonized <= 0) { /* parent or error */
|
||||||
|
retval = -daemonized;
|
||||||
|
goto ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sleep(delay); /* 1, 2, 4, 8, 16, 30, ... */
|
||||||
|
delay *= 2;
|
||||||
|
if (delay > 30)
|
||||||
|
delay = 30;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
do_mount: /* perform actual mount */
|
||||||
|
|
||||||
|
mp->mnt_type = "nfs";
|
||||||
|
retval = mount_it_now(mp, vfsflags, (char*)&data);
|
||||||
goto ret;
|
goto ret;
|
||||||
|
|
||||||
/* abort */
|
fail: /* abort */
|
||||||
|
|
||||||
fail:
|
|
||||||
if (msock != -1) {
|
if (msock != -1) {
|
||||||
if (mclient) {
|
if (mclient) {
|
||||||
auth_destroy(mclient->cl_auth);
|
auth_destroy(mclient->cl_auth);
|
||||||
@ -982,7 +1015,8 @@ fail:
|
|||||||
close(fsock);
|
close(fsock);
|
||||||
|
|
||||||
ret:
|
ret:
|
||||||
free(hostdir);
|
free(hostname);
|
||||||
free(old_opts);
|
free(mounthost);
|
||||||
|
free(filteropts);
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user