Author: Chuck Lever Date: Tue Feb 17 16:27:43 2009 -0500 umount command: remove do_nfs_umount23 function Remove do_nfs_umount23() now that it is unused. Signed-off-by: Chuck Lever Signed-off-by: Steve Dickson commit c735a8331b082038a0e83ec4187c2656b0804eea Author: Chuck Lever Date: Tue Feb 17 16:26:31 2009 -0500 umount.nfs command: Support AF_INET6 server addresses Replace existing mount option parser in nfsumount.c with the new pmap stuffer function nfs_options2pmap(). Mount option parsing for umount.nfs now works the same as it does for mount option rewriting in the text-based mount.nfs command. This adds a number of new features: 1. The new logic supports resolving AF_INET6 server addresses 2. Support is added for the recently introduced "mountaddr" option. 3. Parsing numeric option values is much more careful 4. Option parsing no longer uses xmalloc/xstrdup, so it won't fail silently if memory can't be allocated 5. Mount program number set in /etc/rpc is respected 6. Mount doesn't exit with EX_USAGE if the hostname lookup fails Signed-off-by: Chuck Lever Signed-off-by: Steve Dickson commit 97de03f8c866b9d3e790d64f4e9ac24011aaa5b1 Author: Chuck Lever Date: Tue Feb 17 16:25:27 2009 -0500 umount.nfs command: Add an AF_INET6-capable version of nfs_call_unmount() We need an AF_INET6-capable version of nfs_call_unmount() to allow the umount.nfs command to support unmounting NFS servers over IPv6. The legacy mount.nfs command still likes to use nfs_call_umount(), so we leave it in place and introduce a new API that can take a "struct sockaddr *". The umount.nfs command will invoke this new API, but we'll leave the legacy mount.nfs command and the umount.nfs4 command alone. The umount.nfs4 command does not need this support because NFSv4 unmount operations are entirely local. Signed-off-by: Chuck Lever Signed-off-by: Steve Dickson diff -up nfs-utils-1.1.4/utils/mount/network.c.save nfs-utils-1.1.4/utils/mount/network.c --- nfs-utils-1.1.4/utils/mount/network.c.save 2009-02-17 16:37:18.000000000 -0500 +++ nfs-utils-1.1.4/utils/mount/network.c 2009-02-17 16:38:10.000000000 -0500 @@ -838,6 +838,59 @@ int start_statd(void) } /** + * nfs_advise_umount - ask the server to remove a share from it's rmtab + * @sap: pointer to IP address of server to call + * @salen: length of server address + * @pmap: partially filled-in mountd RPC service tuple + * @argp: directory path of share to "unmount" + * + * Returns one if the unmount call succeeded; zero if the unmount + * failed for any reason; rpccreateerr.cf_stat is set to reflect + * the nature of the error. + * + * We use a fast timeout since this call is advisory only. + */ +int nfs_advise_umount(const struct sockaddr *sap, const socklen_t salen, + const struct pmap *pmap, const dirpath *argp) +{ + struct sockaddr_storage address; + struct sockaddr *saddr = (struct sockaddr *)&address; + struct pmap mnt_pmap = *pmap; + struct timeval timeout = { + .tv_sec = MOUNT_TIMEOUT >> 3, + }; + CLIENT *client; + enum clnt_stat res = 0; + + if (nfs_probe_mntport(sap, salen, &mnt_pmap) == 0) + return 0; + + memcpy(saddr, sap, salen); + nfs_set_port(saddr, mnt_pmap.pm_port); + + client = nfs_get_rpcclient(saddr, salen, mnt_pmap.pm_prot, + mnt_pmap.pm_prog, mnt_pmap.pm_vers, + &timeout); + if (client == NULL) + return 0; + + client->cl_auth = authunix_create_default(); + + res = CLNT_CALL(client, MOUNTPROC_UMNT, + (xdrproc_t)xdr_dirpath, (caddr_t)argp, + (xdrproc_t)xdr_void, NULL, + timeout); + + auth_destroy(client->cl_auth); + CLNT_DESTROY(client); + + if (res != RPC_SUCCESS) + return 0; + + return 1; +} + +/** * nfs_call_umount - ask the server to remove a share from it's rmtab * @mnt_server: address of RPC MNT program server * @argp: directory path of share to "unmount" diff -up nfs-utils-1.1.4/utils/mount/network.h.save nfs-utils-1.1.4/utils/mount/network.h --- nfs-utils-1.1.4/utils/mount/network.h.save 2009-02-17 16:37:26.000000000 -0500 +++ nfs-utils-1.1.4/utils/mount/network.h 2009-02-17 16:38:10.000000000 -0500 @@ -52,7 +52,6 @@ int nfs_present_sockaddr(const struct so const socklen_t, char *, const size_t); int nfs_callback_address(const struct sockaddr *, const socklen_t, struct sockaddr *, socklen_t *); -int nfs_call_umount(clnt_addr_t *, dirpath *); int clnt_ping(struct sockaddr_in *, const unsigned long, const unsigned long, const unsigned int, struct sockaddr_in *); @@ -66,6 +65,9 @@ int start_statd(void); unsigned long nfsvers_to_mnt(const unsigned long); +int nfs_call_umount(clnt_addr_t *, dirpath *); +int nfs_advise_umount(const struct sockaddr *, const socklen_t, + const struct pmap *, const dirpath *); CLIENT *mnt_openclnt(clnt_addr_t *, int *); void mnt_closeclnt(CLIENT *, int); diff -up nfs-utils-1.1.4/utils/mount/nfsumount.c.save nfs-utils-1.1.4/utils/mount/nfsumount.c --- nfs-utils-1.1.4/utils/mount/nfsumount.c.save 2009-02-17 16:37:42.000000000 -0500 +++ nfs-utils-1.1.4/utils/mount/nfsumount.c 2009-02-17 16:38:29.000000000 -0500 @@ -34,6 +34,7 @@ #include "mount.h" #include "error.h" #include "network.h" +#include "parse_opt.h" #include "parse_dev.h" #if !defined(MNT_FORCE) @@ -134,6 +135,64 @@ static int del_mtab(const char *spec, co } /* + * Discover mount server's hostname/address by examining mount options + * + * Returns a pointer to a string that the caller must free, on + * success; otherwise NULL is returned. + */ +static char *nfs_umount_hostname(struct mount_options *options, + char *hostname) +{ + char *option; + + option = po_get(options, "mountaddr"); + if (option) + goto out; + option = po_get(options, "mounthost"); + if (option) + goto out; + option = po_get(options, "addr"); + if (option) + goto out; + + return hostname; + +out: + free(hostname); + return strdup(option); +} + +/* + * Returns EX_SUCCESS if mount options and device name have been + * parsed successfully; otherwise EX_FAIL. + */ +static int nfs_umount_do_umnt(struct mount_options *options, + char **hostname, char **dirname) +{ + struct sockaddr_storage address; + struct sockaddr *sap = (struct sockaddr *)&address; + socklen_t salen = sizeof(address); + struct pmap nfs_pmap, mnt_pmap; + + nfs_options2pmap(options, &nfs_pmap, &mnt_pmap); + + *hostname = nfs_umount_hostname(options, *hostname); + if (!*hostname) { + nfs_error(_("%s: out of memory"), progname); + return EX_FAIL; + } + + if (nfs_name_to_address(*hostname, AF_UNSPEC, sap, &salen)) { + if (nfs_advise_umount(sap, salen, &mnt_pmap, dirname) != 0) + return EX_SUCCESS; + else + nfs_error(_("%s: Server failed to unmount '%s:%s'"), + progname, *hostname, *dirname); + } + return EX_FAIL; +} + +/* * Pick up certain mount options used during the original mount * from /etc/mtab. The basics include the server's IP address and * the server pathname of the share to unregister. @@ -142,85 +201,28 @@ static int del_mtab(const char *spec, co * version, and transport protocol used to punch through a firewall. * We will need this information to get through the firewall again * to do the umount. + * + * Note that option parsing failures won't necessarily cause the + * umount request to fail. Those values will be left zero in the + * pmap tuple. If the GETPORT call later fails to disambiguate them, + * then we fail. */ -static int do_nfs_umount23(const char *spec, char *opts) +static int nfs_umount23(const char *devname, char *string) { - char *hostname; - char *dirname; - clnt_addr_t mnt_server = { &hostname, }; - struct mntent mnt = { .mnt_opts = opts }; - struct pmap *pmap = &mnt_server.pmap; - char *p; - int result = EX_USAGE; - - if (!nfs_parse_devname(spec, &hostname, &dirname)) - return result; - -#ifdef NFS_MOUNT_DEBUG - printf(_("host: %s, directory: %s\n"), hostname, dirname); -#endif - - if (opts && (p = strstr(opts, "addr="))) { - char *q; + char *hostname, *dirname; + struct mount_options *options; + int result = EX_FAIL; - free(hostname); - p += 5; - q = p; - while (*q && *q != ',') q++; - hostname = xstrndup(p,q-p); - } - - if (opts && (p = strstr(opts, "mounthost="))) { - char *q; - - free(hostname); - p += 10; - q = p; - while (*q && *q != ',') q++; - hostname = xstrndup(p,q-p); - } - - pmap->pm_prog = MOUNTPROG; - pmap->pm_vers = 0; /* unknown */ - if (opts && (p = strstr(opts, "mountprog=")) && isdigit(*(p+10))) - pmap->pm_prog = atoi(p+10); - if (opts && (p = strstr(opts, "mountport=")) && isdigit(*(p+10))) - pmap->pm_port = atoi(p+10); - if (opts && hasmntopt(&mnt, "v2")) - pmap->pm_vers = nfsvers_to_mnt(2); - if (opts && hasmntopt(&mnt, "v3")) - pmap->pm_vers = nfsvers_to_mnt(3); - if (opts && (p = strstr(opts, "vers=")) && isdigit(*(p+5))) - pmap->pm_vers = nfsvers_to_mnt(atoi(p+5)); - if (opts && (p = strstr(opts, "mountvers=")) && isdigit(*(p+10))) - pmap->pm_vers = atoi(p+10); - if (opts && (hasmntopt(&mnt, "udp") - || hasmntopt(&mnt, "proto=udp") - || hasmntopt(&mnt, "mountproto=udp") - )) - pmap->pm_prot = IPPROTO_UDP; - if (opts && (hasmntopt(&mnt, "tcp") - || hasmntopt(&mnt, "proto=tcp") - || hasmntopt(&mnt, "mountproto=tcp") - )) - pmap->pm_prot = IPPROTO_TCP; - - if (!nfs_gethostbyname(hostname, &mnt_server.saddr)) { - nfs_error(_("%s: DNS resolution of '%s' failed"), - progname, hostname); - goto out; - } - - if (!nfs_call_umount(&mnt_server, &dirname)) { - nfs_error(_("%s: Server failed to unmount '%s'"), - progname, spec); - result = EX_FAIL; - goto out; - } + if (!nfs_parse_devname(devname, &hostname, &dirname)) + return EX_USAGE; - result = EX_SUCCESS; + options = po_split(string); + if (options) { + result = nfs_umount_do_umnt(options, &hostname, &dirname); + po_destroy(options); + } else + nfs_error(_("%s: option parsing error"), progname); -out: free(hostname); free(dirname); return result; @@ -350,16 +352,16 @@ int nfsumount(int argc, char *argv[]) ret = 0; if (mc) { if (!lazy && strcmp(mc->m.mnt_type, "nfs4") != 0) - /* We ignore the error from do_nfs_umount23. + /* We ignore the error from nfs_umount23. * If the actual umount succeeds (in del_mtab), * we don't want to signal an error, as that * could cause /sbin/mount to retry! */ - do_nfs_umount23(mc->m.mnt_fsname, mc->m.mnt_opts); - ret = del_mtab(mc->m.mnt_fsname, mc->m.mnt_dir); + nfs_umount23(mc->m.mnt_fsname, mc->m.mnt_opts); + ret = del_mtab(mc->m.mnt_fsname, mc->m.mnt_dir) ?: ret; } else if (*spec != '/') { if (!lazy) - ret = do_nfs_umount23(spec, "tcp,v3"); + ret = nfs_umount23(spec, "tcp,v3"); } else ret = del_mtab(NULL, spec);