X-Git-Url: https://git.decadent.org.uk/gitweb/?p=nfs-utils.git;a=blobdiff_plain;f=utils%2Fmount%2Fstropts.c;h=319be71aac195ca020ee01cd69f47ba419a81752;hp=e2e72a7c552cdce84eb6d68e99b617fb1df6bac2;hb=3163dabcf0a6b992859508368baf67c918d2c091;hpb=586a66451679e25c47cb8cd65a0c6a0c44148920 diff --git a/utils/mount/stropts.c b/utils/mount/stropts.c index e2e72a7..319be71 100644 --- a/utils/mount/stropts.c +++ b/utils/mount/stropts.c @@ -25,11 +25,7 @@ #include #endif -#include #include -#include -#include -#include #include #include #include @@ -42,23 +38,20 @@ #include "xcommon.h" #include "mount.h" #include "nls.h" -#include "nfs_mount.h" #include "mount_constants.h" #include "stropts.h" #include "error.h" #include "network.h" #include "parse_opt.h" #include "version.h" +#include "parse_dev.h" -#ifdef HAVE_RPCSVC_NFS_PROT_H -#include -#else -#include -#define nfsstat nfs_stat +#ifndef NFS_PROGRAM +#define NFS_PROGRAM (100003) #endif #ifndef NFS_PORT -#define NFS_PORT 2049 +#define NFS_PORT (2049) #endif #ifndef NFS_MAXHOSTNAME @@ -98,78 +91,6 @@ struct nfsmount_info { sa_family_t family; /* supported address family */ }; -static int nfs_parse_devname(struct nfsmount_info *mi) -{ - int ret = 0; - char *dev, *pathname, *s; - - dev = xstrdup(mi->spec); - - if (!(pathname = strchr(dev, ':'))) { - nfs_error(_("%s: remote share not in 'host:dir' format"), - progname); - goto out; - } - *pathname = '\0'; - pathname++; - - /* - * We don't need a copy of the pathname, but let's - * sanity check it anyway. - */ - if (strlen(pathname) > NFS_MAXPATHNAME) { - nfs_error(_("%s: export pathname is too long"), - progname); - goto out; - } - - /* - * Ignore all but first hostname in replicated mounts - * until they can be fully supported. (mack@sgi.com) - */ - if ((s = strchr(dev, ','))) { - *s = '\0'; - nfs_error(_("%s: warning: multiple hostnames not supported"), - progname); - nfs_error(_("%s: ignoring hostnames that follow the first one"), - progname); - } - mi->hostname = xstrdup(dev); - if (strlen(mi->hostname) > NFS_MAXHOSTNAME) { - nfs_error(_("%s: server hostname is too long"), - progname); - free(mi->hostname); - mi->hostname = NULL; - goto out; - } - - ret = 1; - -out: - free(dev); - return ret; -} - -static int fill_ipv4_sockaddr(const char *hostname, struct sockaddr_in *addr) -{ - struct hostent *hp; - addr->sin_family = AF_INET; - - if (inet_aton(hostname, &addr->sin_addr)) - return 1; - if ((hp = gethostbyname(hostname)) == NULL) { - nfs_error(_("%s: can't get address for %s\n"), - progname, hostname); - return 0; - } - if (hp->h_length > sizeof(struct in_addr)) { - nfs_error(_("%s: got bad hp->h_length"), progname); - hp->h_length = sizeof(struct in_addr); - } - memcpy(&addr->sin_addr, hp->h_addr, hp->h_length); - return 1; -} - /* * Obtain a retry timeout value based on the value of the "retry=" option. * @@ -178,19 +99,21 @@ static int fill_ipv4_sockaddr(const char *hostname, struct sockaddr_in *addr) static time_t nfs_parse_retry_option(struct mount_options *options, unsigned int timeout_minutes) { - char *retry_option, *endptr; + long tmp; - retry_option = po_get(options, "retry"); - if (retry_option) { - long tmp; - - errno = 0; - tmp = strtol(retry_option, &endptr, 10); - if (errno == 0 && endptr != retry_option && tmp >= 0) + switch (po_get_numeric(options, "retry", &tmp)) { + case PO_NOT_FOUND: + break; + case PO_FOUND: + if (tmp >= 0) { timeout_minutes = tmp; - else if (verbose) + break; + } + case PO_BAD_VALUE: + if (verbose) nfs_error(_("%s: invalid retry timeout was specified; " "using default timeout"), progname); + break; } return time(NULL) + (time_t)(timeout_minutes * 60); @@ -301,9 +224,15 @@ static int nfs_fix_mounthost_option(const sa_family_t family, * Returns zero if the "lock" option is in effect, but statd * can't be started. Otherwise, returns 1. */ -static int verify_lock_option(struct mount_options *options) +static const char *nfs_lock_opttbl[] = { + "nolock", + "lock", + NULL, +}; + +static int nfs_verify_lock_option(struct mount_options *options) { - if (po_rightmost(options, "nolock", "lock") == PO_KEY1_RIGHTMOST) + if (po_rightmost(options, nfs_lock_opttbl) == 1) return 1; if (!start_statd()) { @@ -334,27 +263,30 @@ static int nfs_append_sloppy_option(struct mount_options *options) */ static int nfs_validate_options(struct nfsmount_info *mi) { - struct sockaddr_in saddr; + struct sockaddr_storage dummy; + struct sockaddr *sap = (struct sockaddr *)&dummy; + socklen_t salen = sizeof(dummy); + + if (!nfs_parse_devname(mi->spec, &mi->hostname, NULL)) + return 0; - if (!fill_ipv4_sockaddr(mi->hostname, &saddr)) + if (!nfs_name_to_address(mi->hostname, mi->family, sap, &salen)) return 0; if (strncmp(mi->type, "nfs4", 4) == 0) { - if (!nfs_append_clientaddr_option((struct sockaddr *)&saddr, - sizeof(saddr), mi->options)) + if (!nfs_append_clientaddr_option(sap, salen, mi->options)) return 0; } else { if (!nfs_fix_mounthost_option(mi->family, mi->options)) return 0; - if (!mi->fake && !verify_lock_option(mi->options)) + if (!mi->fake && !nfs_verify_lock_option(mi->options)) return 0; } if (!nfs_append_sloppy_option(mi->options)) return 0; - return nfs_append_addr_option((struct sockaddr *)&saddr, - sizeof(saddr), mi->options); + return nfs_append_addr_option(sap, salen, mi->options); } /* @@ -365,7 +297,7 @@ static int nfs_validate_options(struct nfsmount_info *mi) * passed-in error is permanent, thus the mount system call * should not be retried. */ -static int is_permanent_error(int error) +static int nfs_is_permanent_error(int error) { switch (error) { case ESTALE: @@ -377,6 +309,81 @@ static int is_permanent_error(int error) } } +static int nfs_construct_new_options(struct mount_options *options, + struct pmap *nfs_pmap, + struct pmap *mnt_pmap) +{ + char new_option[64]; + + po_remove_all(options, "nfsprog"); + po_remove_all(options, "mountprog"); + + po_remove_all(options, "v2"); + po_remove_all(options, "v3"); + po_remove_all(options, "vers"); + po_remove_all(options, "nfsvers"); + snprintf(new_option, sizeof(new_option) - 1, + "vers=%lu", nfs_pmap->pm_vers); + if (po_append(options, new_option) == PO_FAILED) + return 0; + + po_remove_all(options, "proto"); + po_remove_all(options, "udp"); + po_remove_all(options, "tcp"); + switch (nfs_pmap->pm_prot) { + case IPPROTO_TCP: + snprintf(new_option, sizeof(new_option) - 1, + "proto=tcp"); + if (po_append(options, new_option) == PO_FAILED) + return 0; + break; + case IPPROTO_UDP: + snprintf(new_option, sizeof(new_option) - 1, + "proto=udp"); + if (po_append(options, new_option) == PO_FAILED) + return 0; + break; + } + + po_remove_all(options, "port"); + if (nfs_pmap->pm_port != NFS_PORT) { + snprintf(new_option, sizeof(new_option) - 1, + "port=%lu", nfs_pmap->pm_port); + if (po_append(options, new_option) == PO_FAILED) + return 0; + } + + po_remove_all(options, "mountvers"); + snprintf(new_option, sizeof(new_option) - 1, + "mountvers=%lu", mnt_pmap->pm_vers); + if (po_append(options, new_option) == PO_FAILED) + return 0; + + po_remove_all(options, "mountproto"); + switch (mnt_pmap->pm_prot) { + case IPPROTO_TCP: + snprintf(new_option, sizeof(new_option) - 1, + "mountproto=tcp"); + if (po_append(options, new_option) == PO_FAILED) + return 0; + break; + case IPPROTO_UDP: + snprintf(new_option, sizeof(new_option) - 1, + "mountproto=udp"); + if (po_append(options, new_option) == PO_FAILED) + return 0; + break; + } + + po_remove_all(options, "mountport"); + snprintf(new_option, sizeof(new_option) - 1, + "mountport=%lu", mnt_pmap->pm_port); + if (po_append(options, new_option) == PO_FAILED) + return 0; + + return 1; +} + /* * Reconstruct the mount option string based on a portmapper probe * of the server. Returns one if the server's portmapper returned @@ -384,19 +391,18 @@ static int is_permanent_error(int error) * * To handle version and transport protocol fallback properly, we * need to parse some of the mount options in order to set up a - * portmap probe. Mount options that rewrite_mount_options() + * portmap probe. Mount options that nfs_rewrite_mount_options() * doesn't recognize are left alone. * * Returns a new group of mount options if successful; otherwise * NULL is returned if some failure occurred. */ -static struct mount_options *rewrite_mount_options(char *str) +static struct mount_options *nfs_rewrite_mount_options(char *str) { struct mount_options *options; - char *option, new_option[64]; + char *option; clnt_addr_t mnt_server = { }; clnt_addr_t nfs_server = { }; - int p; options = po_split(str); if (!options) { @@ -422,79 +428,23 @@ static struct mount_options *rewrite_mount_options(char *str) memcpy(&mnt_server.saddr, &nfs_server.saddr, sizeof(mnt_server.saddr)); - option = po_get(options, "mountport"); - if (option) - mnt_server.pmap.pm_port = atoi(option); - mnt_server.pmap.pm_prog = MOUNTPROG; - option = po_get(options, "mountvers"); - if (option) - mnt_server.pmap.pm_vers = atoi(option); + nfs_options2pmap(options, &nfs_server.pmap, &mnt_server.pmap); - option = po_get(options, "port"); - if (option) { - nfs_server.pmap.pm_port = atoi(option); - po_remove_all(options, "port"); - } + /* The kernel NFS client doesn't support changing the RPC program + * number for these services, so reset these fields before probing + * the server's ports. */ nfs_server.pmap.pm_prog = NFS_PROGRAM; - - option = po_get(options, "nfsvers"); - if (option) { - nfs_server.pmap.pm_vers = atoi(option); - po_remove_all(options, "nfsvers"); - } - option = po_get(options, "vers"); - if (option) { - nfs_server.pmap.pm_vers = atoi(option); - po_remove_all(options, "vers"); - } - option = po_get(options, "proto"); - if (option) { - if (strcmp(option, "tcp") == 0) { - nfs_server.pmap.pm_prot = IPPROTO_TCP; - po_remove_all(options, "proto"); - } - if (strcmp(option, "udp") == 0) { - nfs_server.pmap.pm_prot = IPPROTO_UDP; - po_remove_all(options, "proto"); - } - } - p = po_rightmost(options, "tcp", "udp"); - switch (p) { - case PO_KEY2_RIGHTMOST: - nfs_server.pmap.pm_prot = IPPROTO_UDP; - break; - case PO_KEY1_RIGHTMOST: - nfs_server.pmap.pm_prot = IPPROTO_TCP; - break; - } - po_remove_all(options, "tcp"); - po_remove_all(options, "udp"); + mnt_server.pmap.pm_prog = MOUNTPROG; if (!probe_bothports(&mnt_server, &nfs_server)) { errno = ESPIPE; goto err; } - snprintf(new_option, sizeof(new_option) - 1, - "nfsvers=%lu", nfs_server.pmap.pm_vers); - if (po_append(options, new_option) == PO_FAILED) + if (!nfs_construct_new_options(options, + &nfs_server.pmap, &mnt_server.pmap)) { + errno = EINVAL; goto err; - - if (nfs_server.pmap.pm_prot == IPPROTO_TCP) - snprintf(new_option, sizeof(new_option) - 1, - "proto=tcp"); - else - snprintf(new_option, sizeof(new_option) - 1, - "proto=udp"); - if (po_append(options, new_option) == PO_FAILED) - goto err; - - if (nfs_server.pmap.pm_port != NFS_PORT) { - snprintf(new_option, sizeof(new_option) - 1, - "port=%lu", nfs_server.pmap.pm_port); - if (po_append(options, new_option) == PO_FAILED) - goto err; - } errno = 0; @@ -543,7 +493,7 @@ static int nfs_retry_nfs23mount(struct nfsmount_info *mi) char *retry_str = NULL; char **extra_opts = mi->extra_opts; - retry_options = rewrite_mount_options(*extra_opts); + retry_options = nfs_rewrite_mount_options(*extra_opts); if (!retry_options) return 0; @@ -672,7 +622,7 @@ static int nfsmount_fg(struct nfsmount_info *mi) if (nfs_try_mount(mi)) return EX_SUCCESS; - if (is_permanent_error(errno)) + if (nfs_is_permanent_error(errno)) break; if (time(NULL) > timeout) { @@ -705,7 +655,7 @@ static int nfsmount_parent(struct nfsmount_info *mi) if (nfs_try_mount(mi)) return EX_SUCCESS; - if (is_permanent_error(errno)) { + if (nfs_is_permanent_error(errno)) { mount_error(mi->spec, mi->node, errno); return EX_FAIL; } @@ -740,7 +690,7 @@ static int nfsmount_child(struct nfsmount_info *mi) if (nfs_try_mount(mi)) return EX_SUCCESS; - if (is_permanent_error(errno)) + if (nfs_is_permanent_error(errno)) break; if (time(NULL) > timeout) @@ -771,12 +721,18 @@ static int nfsmount_bg(struct nfsmount_info *mi) * * Returns a valid mount command exit code. */ +static const char *nfs_background_opttbl[] = { + "bg", + "fg", + NULL, +}; + static int nfsmount_start(struct nfsmount_info *mi) { if (!nfs_validate_options(mi)) return EX_FAIL; - if (po_rightmost(mi->options, "bg", "fg") == PO_KEY1_RIGHTMOST) + if (po_rightmost(mi->options, nfs_background_opttbl) == 1) return nfsmount_bg(mi); else return nfsmount_fg(mi); @@ -812,9 +768,6 @@ int nfsmount_string(const char *spec, const char *node, const char *type, }; int retval = EX_FAIL; - if (!nfs_parse_devname(&mi)) - return retval; - mi.options = po_split(*extra_opts); if (mi.options) { retval = nfsmount_start(&mi);