All of lore.kernel.org
 help / color / mirror / Atom feed
* mount.nfs libmount support
@ 2011-02-08 13:45 Karel Zak
  2011-02-08 13:45 ` [PATCH 1/2] mount: move generic functions to utils.c and network.c Karel Zak
                   ` (2 more replies)
  0 siblings, 3 replies; 10+ messages in thread
From: Karel Zak @ 2011-02-08 13:45 UTC (permalink / raw)
  To: Chuck Lever; +Cc: linux-nfs

Hi Chuck,

this is the first version of the mount.nfs with libmount support. The code
depends on the latest util-linux code from upstream git tree, or you can 
wait few days for official 2.19 util-linux tarballs (and Fedora binary rpms).

I have tested:

	mount.nfs server://path /mountpoint
	mount.nfs server://path /mountpoint -o remount,ro
	mount.nfs server://path /mountpoint -o user

	umount.nfs server://path
	umount.nfs /mountpoint

.. works for me. For more information see the second patch.

	Karel


^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH 1/2] mount: move generic functions to utils.c and network.c
  2011-02-08 13:45 mount.nfs libmount support Karel Zak
@ 2011-02-08 13:45 ` Karel Zak
  2011-02-08 15:43   ` Chuck Lever
  2011-02-08 13:45 ` [PATCH 2/2] mount: add --enable-libmount-mount Karel Zak
  2011-02-09  5:25 ` mount.nfs libmount support NeilBrown
  2 siblings, 1 reply; 10+ messages in thread
From: Karel Zak @ 2011-02-08 13:45 UTC (permalink / raw)
  To: Chuck Lever; +Cc: linux-nfs, Karel Zak

Move generic code that could be shared between standard mount.nfs and
libmount version to utils.c and network.c.

Signed-off-by: Karel Zak <kzak@redhat.com>
---
 utils/mount/Makefile.am |    2 +-
 utils/mount/mount.c     |   83 +------------------
 utils/mount/network.c   |   28 ++++++
 utils/mount/network.h   |    2 +
 utils/mount/nfsumount.c |  119 +--------------------------
 utils/mount/utils.c     |  213 +++++++++++++++++++++++++++++++++++++++++++++++
 utils/mount/utils.h     |   36 ++++++++
 7 files changed, 283 insertions(+), 200 deletions(-)
 create mode 100644 utils/mount/utils.c
 create mode 100644 utils/mount/utils.h

diff --git a/utils/mount/Makefile.am b/utils/mount/Makefile.am
index 299384a..a9553dc 100644
--- a/utils/mount/Makefile.am
+++ b/utils/mount/Makefile.am
@@ -16,7 +16,7 @@ mount_nfs_SOURCES = mount.c error.c network.c fstab.c token.c \
 		    mount_constants.h error.h network.h fstab.h token.h \
 		    parse_opt.h parse_dev.h \
 		    nfs4_mount.h nfs_mount4.h stropts.h version.h \
-			mount_config.h
+		    mount_config.h utils.c utils.h
 
 if MOUNT_CONFIG
 mount_nfs_SOURCES += configfile.c
diff --git a/utils/mount/mount.c b/utils/mount/mount.c
index a19af53..f3f0a83 100644
--- a/utils/mount/mount.c
+++ b/utils/mount/mount.c
@@ -47,7 +47,7 @@
 #include "mount.h"
 #include "error.h"
 #include "stropts.h"
-#include "version.h"
+#include "utils.h"
 
 char *progname;
 int nfs_mount_data_version;
@@ -150,49 +150,6 @@ static const struct opt_map opt_map[] = {
 static void parse_opts(const char *options, int *flags, char **extra_opts);
 
 /*
- * Choose the version of the nfs_mount_data structure that is appropriate
- * for the kernel that is doing the mount.
- *
- * NFS_MOUNT_VERSION:		maximum version supported by these sources
- * nfs_mount_data_version:	maximum version supported by the running kernel
- */
-static void discover_nfs_mount_data_version(void)
-{
-	unsigned int kernel_version = linux_version_code();
-
-	if (kernel_version) {
-		if (kernel_version < MAKE_VERSION(2, 1, 32))
-			nfs_mount_data_version = 1;
-		else if (kernel_version < MAKE_VERSION(2, 2, 18))
-			nfs_mount_data_version = 3;
-		else if (kernel_version < MAKE_VERSION(2, 3, 0))
-			nfs_mount_data_version = 4;
-		else if (kernel_version < MAKE_VERSION(2, 3, 99))
-			nfs_mount_data_version = 3;
-		else if (kernel_version < MAKE_VERSION(2, 6, 3))
-			nfs_mount_data_version = 4;
-		else
-			nfs_mount_data_version = 6;
-	}
-	if (nfs_mount_data_version > NFS_MOUNT_VERSION)
-		nfs_mount_data_version = NFS_MOUNT_VERSION;
-	else
-		if (kernel_version > MAKE_VERSION(2, 6, 22))
-			string++;
-}
-
-static void print_one(char *spec, char *node, char *type, char *opts)
-{
-	if (!verbose)
-		return;
-
-	if (opts)
-		printf(_("%s on %s type %s (%s)\n"), spec, node, type, opts);
-	else
-		printf(_("%s on %s type %s\n"), spec, node, type);
-}
-
-/*
  * Build a canonical mount option string for /etc/mtab.
  */
 static char *fix_opts_string(int flags, const char *extra_opts)
@@ -327,22 +284,6 @@ static int add_mtab(char *spec, char *mount_point, char *fstype,
 	return result;
 }
 
-static void mount_usage(void)
-{
-	printf(_("usage: %s remotetarget dir [-rvVwfnsih] [-o nfsoptions]\n"),
-		progname);
-	printf(_("options:\n"));
-	printf(_("\t-r\t\tMount file system readonly\n"));
-	printf(_("\t-v\t\tVerbose\n"));
-	printf(_("\t-V\t\tPrint version\n"));
-	printf(_("\t-w\t\tMount file system read-write\n"));
-	printf(_("\t-f\t\tFake mount, do not actually mount\n"));
-	printf(_("\t-n\t\tDo not update /etc/mtab\n"));
-	printf(_("\t-s\t\tTolerate sloppy mount options rather than fail\n"));
-	printf(_("\t-h\t\tPrint this help\n"));
-	printf(_("\tnfsoptions\tRefer to mount.nfs(8) or nfs(5)\n\n"));
-}
-
 static void parse_opt(const char *opt, int *mask, char *extra_opts, size_t len)
 {
 	const struct opt_map *om;
@@ -403,26 +344,6 @@ static void parse_opts(const char *options, int *flags, char **extra_opts)
 	}
 }
 
-static int chk_mountpoint(char *mount_point)
-{
-	struct stat sb;
-
-	if (stat(mount_point, &sb) < 0){
-		mount_error(NULL, mount_point, errno);
-		return 1;
-	}
-	if (S_ISDIR(sb.st_mode) == 0){
-		mount_error(NULL, mount_point, ENOTDIR);
-		return 1;
-	}
-	if (access(mount_point, X_OK) < 0) {
-		mount_error(NULL, mount_point, errno);
-		return 1;
-	}
-
-	return 0;
-}
-
 static int try_mount(char *spec, char *mount_point, int flags,
 			char *fs_type, char **extra_opts, char *mount_opts,
 			int fake, int bg)
@@ -459,7 +380,7 @@ int main(int argc, char *argv[])
 
 	progname = basename(argv[0]);
 
-	discover_nfs_mount_data_version();
+	nfs_mount_data_version = discover_nfs_mount_data_version(&string);
 
 	if(!strncmp(progname, "umount", strlen("umount")))
 		exit(nfsumount(argc, argv));
diff --git a/utils/mount/network.c b/utils/mount/network.c
index 21a7a2c..c66e7a0 100644
--- a/utils/mount/network.c
+++ b/utils/mount/network.c
@@ -1491,6 +1491,34 @@ nfs_mount_version(struct mount_options *options, unsigned long *version)
 }
 
 /*
+ * 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.
+ */
+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 TRUE if @protocol contains a valid value for this option,
  * or FALSE if the option was specified with an invalid value. On
  * error, errno is set.
diff --git a/utils/mount/network.h b/utils/mount/network.h
index 2a3a110..416f4a5 100644
--- a/utils/mount/network.h
+++ b/utils/mount/network.h
@@ -62,6 +62,8 @@ int nfs_mount_proto_family(struct mount_options *options, sa_family_t *family);
 int nfs_nfs_version(struct mount_options *options, unsigned long *version);
 int  nfs_nfs_protocol(struct mount_options *options, unsigned long *protocol);
 
+char *nfs_umount_hostname(struct mount_options *options, char *hostname);
+
 int nfs_options2pmap(struct mount_options *,
 		      struct pmap *, struct pmap *);
 
diff --git a/utils/mount/nfsumount.c b/utils/mount/nfsumount.c
index 02d40ff..8cd2852 100644
--- a/utils/mount/nfsumount.c
+++ b/utils/mount/nfsumount.c
@@ -37,6 +37,7 @@
 #include "network.h"
 #include "parse_opt.h"
 #include "parse_dev.h"
+#include "utils.h"
 
 #define MOUNTSFILE	"/proc/mounts"
 #define LINELEN		(4096)
@@ -139,113 +140,6 @@ static int del_mtab(const char *spec, const char *node)
 }
 
 /*
- * 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)
-{
-	union {
-		struct sockaddr		sa;
-		struct sockaddr_in	s4;
-		struct sockaddr_in6	s6;
-	} address;
-	struct sockaddr *sap = &address.sa;
-	socklen_t salen = sizeof(address);
-	struct pmap nfs_pmap, mnt_pmap;
-	sa_family_t family;
-
-	if (!nfs_options2pmap(options, &nfs_pmap, &mnt_pmap))
-		return EX_FAIL;
-
-	/* Skip UMNT call for vers=4 mounts */
-	if (nfs_pmap.pm_vers == 4)
-		return EX_SUCCESS;
-
-	*hostname = nfs_umount_hostname(options, *hostname);
-	if (!*hostname) {
-		nfs_error(_("%s: out of memory"), progname);
-		return EX_FAIL;
-	}
-
-	if (!nfs_mount_proto_family(options, &family))
-		return 0;
-	if (!nfs_lookup(*hostname, family, sap, &salen))
-		/* nfs_lookup reports any errors */
-		return EX_FAIL;
-
-	if (nfs_advise_umount(sap, salen, &mnt_pmap, dirname) == 0)
-		/* nfs_advise_umount reports any errors */
-		return EX_FAIL;
-
-	return EX_SUCCESS;
-}
-
-/*
- * 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.
- *
- * These options might also describe the mount port, mount protocol
- * 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 nfs_umount23(const char *devname, char *string)
-{
-	char *hostname, *dirname;
-	struct mount_options *options;
-	int result = EX_FAIL;
-
-	if (!nfs_parse_devname(devname, &hostname, &dirname))
-		return EX_USAGE;
-
-	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);
-
-	free(hostname);
-	free(dirname);
-	return result;
-}
-
-/*
  * Detect NFSv4 mounts.
  *
  * Consult /proc/mounts to determine if the mount point
@@ -340,17 +234,6 @@ static struct option umount_longopts[] =
   { NULL, 0, 0, 0 }
 };
 
-static void umount_usage(void)
-{
-	printf(_("usage: %s dir [-fvnrlh]\n"), progname);
-	printf(_("options:\n\t-f\t\tforce unmount\n"));
-	printf(_("\t-v\tverbose\n"));
-	printf(_("\t-n\tDo not update /etc/mtab\n"));
-	printf(_("\t-r\tremount\n"));
-	printf(_("\t-l\tlazy unmount\n"));
-	printf(_("\t-h\tprint this help\n\n"));
-}
-
 int nfsumount(int argc, char *argv[])
 {
 	int c, ret;
diff --git a/utils/mount/utils.c b/utils/mount/utils.c
new file mode 100644
index 0000000..e82cc3e
--- /dev/null
+++ b/utils/mount/utils.c
@@ -0,0 +1,213 @@
+/*
+ * Copyright (C) 2010 Karel Zak <kzak@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "nfs_mount.h"
+#include "nls.h"
+#include "xcommon.h"
+#include "version.h"
+#include "error.h"
+#include "utils.h"
+#include "mount.h"
+#include "network.h"
+#include "parse_dev.h"
+
+extern int verbose;
+extern char *progname;
+
+/*
+ * Choose the version of the nfs_mount_data structure that is appropriate
+ * for the kernel that is doing the mount.
+ *
+ * NFS_MOUNT_VERSION:		maximum version supported by these sources
+ * nfs_mount_data_version:	maximum version supported by the running kernel
+ */
+int discover_nfs_mount_data_version(int *string_ver)
+{
+	unsigned int kernel_version = linux_version_code();
+	int ver = 0;
+
+	*string_ver = 0;
+
+	if (kernel_version) {
+		if (kernel_version < MAKE_VERSION(2, 1, 32))
+			ver = 1;
+		else if (kernel_version < MAKE_VERSION(2, 2, 18))
+			ver = 3;
+		else if (kernel_version < MAKE_VERSION(2, 3, 0))
+			ver = 4;
+		else if (kernel_version < MAKE_VERSION(2, 3, 99))
+			ver = 3;
+		else if (kernel_version < MAKE_VERSION(2, 6, 3))
+			ver = 4;
+		else
+			ver = 6;
+	}
+	if (ver > NFS_MOUNT_VERSION)
+		ver = NFS_MOUNT_VERSION;
+	else
+		if (kernel_version > MAKE_VERSION(2, 6, 22))
+			(*string_ver)++;
+
+	return ver;
+}
+
+void print_one(char *spec, char *node, char *type, char *opts)
+{
+	if (!verbose)
+		return;
+
+	if (opts)
+		printf(_("%s on %s type %s (%s)\n"), spec, node, type, opts);
+	else
+		printf(_("%s on %s type %s\n"), spec, node, type);
+}
+
+void mount_usage(void)
+{
+	printf(_("usage: %s remotetarget dir [-rvVwfnsih] [-o nfsoptions]\n"),
+		progname);
+	printf(_("options:\n"));
+	printf(_("\t-r\t\tMount file system readonly\n"));
+	printf(_("\t-v\t\tVerbose\n"));
+	printf(_("\t-V\t\tPrint version\n"));
+	printf(_("\t-w\t\tMount file system read-write\n"));
+	printf(_("\t-f\t\tFake mount, do not actually mount\n"));
+	printf(_("\t-n\t\tDo not update /etc/mtab\n"));
+	printf(_("\t-s\t\tTolerate sloppy mount options rather than fail\n"));
+	printf(_("\t-h\t\tPrint this help\n"));
+	printf(_("\tnfsoptions\tRefer to mount.nfs(8) or nfs(5)\n\n"));
+}
+
+void umount_usage(void)
+{
+	printf(_("usage: %s dir [-fvnrlh]\n"), progname);
+	printf(_("options:\n\t-f\t\tforce unmount\n"));
+	printf(_("\t-v\tverbose\n"));
+	printf(_("\t-n\tDo not update /etc/mtab\n"));
+	printf(_("\t-r\tremount\n"));
+	printf(_("\t-l\tlazy unmount\n"));
+	printf(_("\t-h\tprint this help\n\n"));
+}
+
+int chk_mountpoint(const char *mount_point)
+{
+	struct stat sb;
+
+	if (stat(mount_point, &sb) < 0){
+		mount_error(NULL, mount_point, errno);
+		return 1;
+	}
+	if (S_ISDIR(sb.st_mode) == 0){
+		mount_error(NULL, mount_point, ENOTDIR);
+		return 1;
+	}
+	if (access(mount_point, X_OK) < 0) {
+		mount_error(NULL, mount_point, errno);
+		return 1;
+	}
+
+	return 0;
+}
+
+/*
+ * 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)
+{
+	union {
+		struct sockaddr		sa;
+		struct sockaddr_in	s4;
+		struct sockaddr_in6	s6;
+	} address;
+	struct sockaddr *sap = &address.sa;
+	socklen_t salen = sizeof(address);
+	struct pmap nfs_pmap, mnt_pmap;
+	sa_family_t family;
+
+	if (!nfs_options2pmap(options, &nfs_pmap, &mnt_pmap))
+		return EX_FAIL;
+
+	/* Skip UMNT call for vers=4 mounts */
+	if (nfs_pmap.pm_vers == 4)
+		return EX_SUCCESS;
+
+	*hostname = nfs_umount_hostname(options, *hostname);
+	if (!*hostname) {
+		nfs_error(_("%s: out of memory"), progname);
+		return EX_FAIL;
+	}
+
+	if (!nfs_mount_proto_family(options, &family))
+		return 0;
+	if (!nfs_lookup(*hostname, family, sap, &salen))
+		/* nfs_lookup reports any errors */
+		return EX_FAIL;
+
+	if (nfs_advise_umount(sap, salen, &mnt_pmap, dirname) == 0)
+		/* nfs_advise_umount reports any errors */
+		return EX_FAIL;
+
+	return EX_SUCCESS;
+}
+
+/*
+ * 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.
+ *
+ * These options might also describe the mount port, mount protocol
+ * 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.
+ */
+int nfs_umount23(const char *devname, char *string)
+{
+	char *hostname = NULL, *dirname = NULL;
+	struct mount_options *options;
+	int result = EX_FAIL;
+
+	if (!nfs_parse_devname(devname, &hostname, &dirname))
+		return EX_USAGE;
+
+	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);
+
+	free(hostname);
+	free(dirname);
+	return result;
+}
+
diff --git a/utils/mount/utils.h b/utils/mount/utils.h
new file mode 100644
index 0000000..61832a3
--- /dev/null
+++ b/utils/mount/utils.h
@@ -0,0 +1,36 @@
+/*
+ * utils.h -- misc utils for mount and umount
+ *
+ * Copyright (C) 2010 Karel Zak <kzak@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 021110-1307, USA.
+ *
+ */
+
+#ifndef _NFS_UTILS_MOUNT_UTILS_H
+#define _NFS_UTILS_MOUNT_UTILS_H
+
+#include "parse_opt.h"
+
+int discover_nfs_mount_data_version(int *string_ver);
+void print_one(char *spec, char *node, char *type, char *opts);
+void mount_usage(void);
+void umount_usage(void);
+int chk_mountpoint(const char *mount_point);
+
+int nfs_umount23(const char *devname, char *string);
+
+#endif	/* _NFS_UTILS_MOUNT_UTILS_H */
-- 
1.7.3.4


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 2/2] mount: add --enable-libmount-mount
  2011-02-08 13:45 mount.nfs libmount support Karel Zak
  2011-02-08 13:45 ` [PATCH 1/2] mount: move generic functions to utils.c and network.c Karel Zak
@ 2011-02-08 13:45 ` Karel Zak
  2011-02-08 15:56   ` Chuck Lever
  2011-02-09  5:25 ` mount.nfs libmount support NeilBrown
  2 siblings, 1 reply; 10+ messages in thread
From: Karel Zak @ 2011-02-08 13:45 UTC (permalink / raw)
  To: Chuck Lever; +Cc: linux-nfs, Karel Zak

This patch allows to link mount.nfs with libmount from util-linux >=
v2.19. The new libmount based code is enabled by CONFIG_LIBMOUNT and
is stored in mount_libmount.c. The old code is not affected by this
change.

The libmount does not have officially stable API yet, so the
--enable-libmount-mount is marked as experimental in the configure
help output.

The ./configure option is the same as we use in util-linux to enable
support for libmount in mount(8).

The addr= (and some other options necessary for remount/umount) are
stored to /etc/mtab or to /dev/.mount/utab. The utab file is *private*
libmount file. It's possible that some mount options (for example
user=) will be moved to kernel, so the utab will not be necessary.

About libmount:

  * supports systems without and with regular /etc/mtab
  * does not store VFS and FS mount options in userspace
  * manages user= option and evaluate permissions
  * parses VFS mount options and generate MS_* flags
  * parses /etc/{fstab,mtab}, /proc/mounts or /proc/self/mountinfo
  * long-term goal is to use the same code in all mount.<type> helpers

Note, use

   LIBMOUNT_DEBUG=0xffff mount.nfs foo:/path /path

to debug the library.

On systems with util-linux v2.19 the findmnt(8) command uses libmount
to list all/selected mount points:

   $ findmnt /path
   $ findmnt --mtab /path

the --mtab appends userspace mount options (e.g. user=) to the output.

Signed-off-by: Karel Zak <kzak@redhat.com>
---
 configure.ac                 |   16 ++
 utils/mount/Makefile.am      |   13 ++-
 utils/mount/mount_libmount.c |  398 ++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 425 insertions(+), 2 deletions(-)
 create mode 100644 utils/mount/mount_libmount.c

diff --git a/configure.ac b/configure.ac
index 2e074d9..9c384d8 100644
--- a/configure.ac
+++ b/configure.ac
@@ -132,6 +132,15 @@ AC_ARG_ENABLE(mount,
 	enable_mount=$enableval,
 	enable_mount=yes)
 	AM_CONDITIONAL(CONFIG_MOUNT, [test "$enable_mount" = "yes"])
+
+if test "$enable_mount" = yes; then
+	AC_ARG_ENABLE(libmount-mount,
+		[AC_HELP_STRING([--enable-libmount-mount],
+				[Link mount.nfs with libmount (EXPERIMENTAL)])],
+		enable_libmount=yes,
+		enable_libmount=no)
+fi
+
 AC_ARG_ENABLE(tirpc,
 	[AC_HELP_STRING([--enable-tirpc],
 			[enable use of TI-RPC @<:@default=yes@:>@])],
@@ -285,6 +294,13 @@ AC_SUBST(LIBCRYPT)
 AC_SUBST(LIBBSD)
 AC_SUBST(LIBBLKID)
 
+if test "$enable_libmount" != no; then
+   AC_CHECK_LIB(mount, mnt_context_do_mount, [LIBMOUNT="-lmount"], AC_MSG_ERROR([libmount needed]))
+   AC_CHECK_HEADER(libmount/libmount.h, , AC_MSG_ERROR([Cannot find libmount header file libmount/libmount.h]))
+fi
+AM_CONDITIONAL(CONFIG_LIBMOUNT, [test "$enable_libmount" = "yes"])
+AC_SUBST(LIBMOUNT)
+
 if test "$enable_gss" = yes; then
   dnl 'gss' requires getnameinfo - at least for gssd_proc.c
   AC_CHECK_FUNC([getnameinfo], , [AC_MSG_ERROR([GSSAPI support requires 'getnameinfo' function])])
diff --git a/utils/mount/Makefile.am b/utils/mount/Makefile.am
index a9553dc..056293c 100644
--- a/utils/mount/Makefile.am
+++ b/utils/mount/Makefile.am
@@ -9,7 +9,7 @@ man5_MANS	= nfs.man
 
 sbin_PROGRAMS	= mount.nfs
 EXTRA_DIST = nfsmount.x $(man8_MANS) $(man5_MANS)
-mount_nfs_SOURCES = mount.c error.c network.c fstab.c token.c \
+mount_common = error.c network.c fstab.c token.c \
 		    parse_opt.c parse_dev.c \
 		    nfsmount.c nfs4mount.c stropts.c\
 		    nfsumount.c \
@@ -19,7 +19,7 @@ mount_nfs_SOURCES = mount.c error.c network.c fstab.c token.c \
 		    mount_config.h utils.c utils.h
 
 if MOUNT_CONFIG
-mount_nfs_SOURCES += configfile.c
+mount_common += configfile.c
 man5_MANS += nfsmount.conf.man
 EXTRA_DIST += nfsmount.conf
 endif
@@ -27,6 +27,15 @@ endif
 mount_nfs_LDADD = ../../support/nfs/libnfs.a \
 		  ../../support/export/libexport.a
 
+mount_nfs_SOURCES = $(mount_common)
+
+if CONFIG_LIBMOUNT
+mount_nfs_SOURCES += mount_libmount.c
+mount_nfs_LDADD += $(LIBMOUNT)
+else
+mount_nfs_SOURCES += mount.c
+endif
+
 MAINTAINERCLEANFILES = Makefile.in
 
 install-exec-hook:
diff --git a/utils/mount/mount_libmount.c b/utils/mount/mount_libmount.c
new file mode 100644
index 0000000..3d499c0
--- /dev/null
+++ b/utils/mount/mount_libmount.c
@@ -0,0 +1,398 @@
+/*
+ * mount_libmount.c -- Linux NFS [u]mount based on libmount
+ *
+ * Copyright (C) 2011 Karel Zak <kzak@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <getopt.h>
+
+#include <libmount/libmount.h>
+
+#include "nls.h"
+#include "mount_config.h"
+
+#include "nfs_mount.h"
+#include "nfs4_mount.h"
+#include "stropts.h"
+#include "version.h"
+#include "xcommon.h"
+
+#include "error.h"
+#include "utils.h"
+
+char *progname;
+int nfs_mount_data_version;
+int verbose;
+int sloppy;
+int string;
+int nomtab;
+
+#define FOREGROUND	(0)
+#define BACKGROUND	(1)
+
+static int try_mount(struct libmnt_context *cxt, int bg)
+{
+	struct libmnt_fs *fs;
+	const char *p;
+	char *src = NULL, *tgt = NULL, *type = NULL, *opts = NULL;
+	unsigned long flags = 0;
+	int fake, ret = 0;
+
+	fs = mnt_context_get_fs(cxt);
+
+	/* libmount returns read-only pointers (const char)
+	 * so, reallocate for nfsmount() functions.
+	 */
+	if ((p = mnt_fs_get_source(fs)))		/* spec */
+		src = strdup(p);
+	if ((p = mnt_fs_get_target(fs)))		/* mountpoint */
+		tgt = strdup(p);
+	if ((p = mnt_fs_get_fstype(fs)))
+		type = strdup(p);
+	if ((p = mnt_fs_get_fs_options(fs)))
+		opts = strdup(p);
+
+	mnt_context_get_mflags(cxt, &flags);	/* mount(2) flags */
+	fake = mnt_context_is_fake(cxt);
+
+	if (string)
+		ret = nfsmount_string(src, tgt, type, flags, &opts, fake, bg);
+
+	else if (strcmp(type, "nfs4") == 0)
+		ret = nfs4mount(src, tgt, flags, &opts, fake, bg);
+	else
+		ret = nfsmount(src, tgt, flags, &opts, fake, bg);
+
+	if (!ret && !mnt_context_is_nomtab(cxt)) {
+		/* it's possible that mount options was modified by nfsmount()
+		 * functions -- update info in libmount as well
+		 *
+		 * Note that on systems without /etc/mtab the fs-specific
+		 * options are not managed by libmount at all. We have to use
+		 * "mount attributes" that are private for mount.<type> helpers.
+		 * The umount.nfs reads the attributes.
+		 */
+		mnt_fs_set_attributes(fs, opts);	/* for non-mtab systems */
+		mnt_fs_set_fs_options(fs, opts);	/* for mtab */
+	}
+
+	free(src);
+	free(tgt);
+	free(type);
+	free(opts);
+
+	return ret;
+}
+
+/* returns: error = -1, success = 0 , unknown = 1 */
+static int is_vers4(struct libmnt_context *cxt)
+{
+	struct libmnt_fs *fs = mnt_context_get_fs(cxt);
+	struct libmnt_table *tb = NULL;
+	const char *src = mnt_context_get_source(cxt),
+		   *tgt = mnt_context_get_target(cxt);
+	int rc = 1;
+
+	if (!src || !tgt)
+		return -1;
+
+	if (!mnt_fs_is_kernel(fs)) {
+		struct libmnt_table *tb = mnt_new_table_from_file("/proc/mounts");
+
+		if (!tb)
+			return -1;
+		fs = mnt_table_find_pair(tb, src, tgt, MNT_ITER_BACKWARD);
+	}
+
+	if (fs) {
+		const char *type = mnt_fs_get_fstype(fs);
+		if (type && strcmp(type, "nfs4") == 0)
+			rc = 0;
+	}
+	mnt_free_table(tb);
+	return rc;
+}
+
+static int umount_main(struct libmnt_context *cxt, int argc, char **argv)
+{
+	int rc, c;
+	struct libmnt_fs *fs;
+	char *spec = NULL, *opts = NULL;
+
+	struct option longopts[] = {
+		{ "force", 0, 0, 'f' },
+		{ "help", 0, 0, 'h' },
+		{ "no-mtab", 0, 0, 'n' },
+		{ "verbose", 0, 0, 'v' },
+		{ "read-only", 0, 0, 'r' },
+		{ "lazy", 0, 0, 'l' },
+		{ "types", 1, 0, 't' },
+		{ NULL, 0, 0, 0 }
+	};
+
+	mnt_context_init_helper(cxt, MNT_ACT_UMOUNT, 0);
+
+	while ((c = getopt_long (argc, argv, "fvnrlh", longopts, NULL)) != -1) {
+
+		rc = mnt_context_helper_setopt(cxt, c, optarg);
+		if (rc == 0)		/* valid option */
+			continue;
+		if (rc < 0)		/* error (probably ENOMEM) */
+			goto err;
+					/* rc==1 means unknow option */
+		umount_usage();
+		return EX_USAGE;
+	}
+
+	if (optind < argc)
+		spec = argv[optind++];
+
+	if (!spec || (*spec != '/' && strchr(spec,':') == NULL)) {
+		nfs_error(_("%s: no mount point provided"), progname);
+		return EX_USAGE;
+	}
+
+	if (mnt_context_set_target(cxt, spec))
+		goto err;
+	if (mnt_context_set_fstype_pattern(cxt, "nfs,nfs4"))	/* restrict filesystems */
+		goto err;
+
+	/* read mtab/fstab, evaluate permissions, etc. */
+	rc = mnt_context_prepare_umount(cxt);
+	if (rc) {
+		nfs_error(_("%s: failed to prepare umount: %s\n"),
+					progname, strerror(-rc));
+		goto err;
+	}
+
+	/* NFS stores some mount options in userspace, in mtab or in libmount
+	 * private mount table.
+	 */
+	fs = mnt_context_get_fs(cxt);
+	if (fs) {
+		opts = (char *) mnt_fs_get_attributes(fs);	/* /dev/.mount/utab */
+		if (opts) {
+			opts = strdup(opts);
+			if (!opts)
+				goto err;
+		}
+		else
+			opts = mnt_fs_strdup_options(fs);	/* /etc/mtab */
+	}
+
+	if (!mnt_context_is_lazy(cxt)) {
+		if (opts) {
+			/* we have full FS description (e.g. from mtab or /proc) */
+			switch (is_vers4(cxt)) {
+			case 0:
+				/* 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!
+				 */
+				nfs_umount23(mnt_context_get_source(cxt), opts);
+				break;
+			case 1:			/* unknown */
+				break;
+			default:		/* error */
+				goto err;
+			}
+		} else
+			/* strange, no entry in mtab or /proc not mounted */
+			nfs_umount23(spec, "tcp,v3");
+	}
+
+	rc = mnt_context_do_umount(cxt);	/* call umount(2) syscall */
+	mnt_context_finalize_mount(cxt);	/* mtab update */
+
+	if (!rc)
+		goto err;
+
+	free(opts);
+	return EX_SUCCESS;
+err:
+	free(opts);
+	return EX_FAIL;
+}
+
+static int mount_main(struct libmnt_context *cxt, int argc, char **argv)
+{
+	int rc, c;
+	struct libmnt_fs *fs;
+	char *spec = NULL, *mount_point = NULL, *opts = NULL;
+
+	struct option longopts[] = {
+	  { "fake", 0, 0, 'f' },
+	  { "help", 0, 0, 'h' },
+	  { "no-mtab", 0, 0, 'n' },
+	  { "read-only", 0, 0, 'r' },
+	  { "ro", 0, 0, 'r' },
+	  { "verbose", 0, 0, 'v' },
+	  { "version", 0, 0, 'V' },
+	  { "read-write", 0, 0, 'w' },
+	  { "rw", 0, 0, 'w' },
+	  { "options", 1, 0, 'o' },
+	  { "sloppy", 0, 0, 's' },
+	  { NULL, 0, 0, 0 }
+	};
+
+	mount_config_init(progname);
+	mnt_context_init_helper(cxt, MNT_ACT_MOUNT, 0);
+
+	while ((c = getopt_long(argc, argv, "fhnrVvwo:s", longopts, NULL)) != -1) {
+
+		rc = mnt_context_helper_setopt(cxt, c, optarg);
+		if (rc == 0)		/* valid option */
+			continue;
+		if (rc < 0)		/* error (probably ENOMEM) */
+			goto err;
+					/* rc==1 means unknow option */
+		switch (c) {
+		case 'V':
+			printf("%s: ("PACKAGE_STRING")\n", progname);
+			return EX_SUCCESS;
+		case 'h':
+		default:
+			mount_usage();
+			return EX_USAGE;
+		}
+	}
+
+	if (optind < argc)
+		spec = argv[optind++];
+	if (optind < argc)
+		mount_point = argv[optind++];
+
+	if (!mount_point) {
+		nfs_error(_("%s: no mount point provided"), progname);
+		goto err;
+	}
+	if (!spec) {
+		nfs_error(_("%s: no mount spec provided"), progname);
+		goto err;
+	}
+
+	if (geteuid() != 0) {
+		nfs_error(_("%s: not installed setuid - "
+			    "\"user\" NFS mounts not supported."), progname);
+		goto err;
+	}
+
+	verbose = mnt_context_is_verbose(cxt);
+	sloppy = mnt_context_is_sloppy(cxt);
+	nomtab = mnt_context_is_nomtab(cxt);
+
+	if (strcmp(progname, "mount.nfs4") == 0)
+		mnt_context_set_fstype(cxt, "nfs4");
+	else
+		mnt_context_set_fstype(cxt, "nfs");	/* default */
+
+	rc = mnt_context_set_source(cxt, spec);
+	if (!rc)
+		mnt_context_set_target(cxt, mount_point);
+	if (rc) {
+		nfs_error(_("%s: failed to set spec or mountpoint: %s"),
+				progname, strerror(errno));
+		goto err;
+	}
+
+	mount_point = mnt_resolve_path(mount_point,
+				       mnt_context_get_cache(cxt));
+
+	if (chk_mountpoint(mount_point))
+		goto err;
+	/*
+	 * Concatenate mount options from the configuration file
+	 */
+	fs = mnt_context_get_fs(cxt);
+	if (fs) {
+		opts = mnt_fs_strdup_options(fs);
+
+		opts = mount_config_opts(spec, mount_point, opts);
+		mnt_fs_set_options(fs, opts);
+	}
+
+	rc = mnt_context_prepare_mount(cxt);
+	if (rc) {
+		nfs_error(_("%s: failed to prepare mount: %s\n"),
+					progname, strerror(-rc));
+		goto err;
+	}
+
+	rc = try_mount(cxt, FOREGROUND);
+
+	if (rc == EX_BG) {
+		printf(_("%s: backgrounding \"%s\"\n"),
+			progname, mnt_context_get_source(cxt));
+		printf(_("%s: mount options: \"%s\"\n"),
+			progname, opts);
+
+		fflush(stdout);
+
+		if (daemon(0, 0)) {
+			nfs_error(_("%s: failed to start "
+					"background process: %s\n"),
+					progname, strerror(errno));
+			exit(EX_FAIL);
+		}
+
+		rc = try_mount(cxt, BACKGROUND);
+
+		if (verbose && rc)
+			printf(_("%s: giving up \"%s\"\n"),
+				progname, mnt_context_get_source(cxt));
+	}
+
+	mnt_context_set_syscall_status(cxt, rc);
+	mnt_context_finalize_mount(cxt);	/* mtab update */
+
+	return rc;
+err:
+	return EX_FAIL;
+}
+
+int main(int argc, char *argv[])
+{
+	struct libmnt_context *cxt;
+	int rc;
+
+	mnt_init_debug(0);
+	cxt = mnt_new_context();
+	if (!cxt) {
+		nfs_error(_("Can't initilize libmount: %s"),
+					strerror(errno));
+		rc = EX_FAIL;
+		goto done;
+	}
+
+	progname = basename(argv[0]);
+	nfs_mount_data_version = discover_nfs_mount_data_version(&string);
+
+	if(!strncmp(progname, "umount", 6))
+		rc = umount_main(cxt, argc, argv);
+	else
+		rc = mount_main(cxt, argc, argv);
+done:
+	mnt_free_context(cxt);
+	return rc;
+}
+
-- 
1.7.3.4


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: [PATCH 1/2] mount: move generic functions to utils.c and network.c
  2011-02-08 13:45 ` [PATCH 1/2] mount: move generic functions to utils.c and network.c Karel Zak
@ 2011-02-08 15:43   ` Chuck Lever
  2011-02-08 16:08     ` Karel Zak
  0 siblings, 1 reply; 10+ messages in thread
From: Chuck Lever @ 2011-02-08 15:43 UTC (permalink / raw)
  To: Karel Zak; +Cc: linux-nfs

Nice work, just a few nits so far.  I'll wait for utils-linux 2.19... and we have NFS Connectathon (http://www.connectathon.org) in a couple of weeks, so it will be March before I can spend some quality time with this.

Also, I'm cleaning up a version of parse_opt.c and token.c for you, if you want to include these in libmount at some point.

It's really too bad that we have to maintain yet another version of mount.nfs for backwards compatibility (for building on systems without libmount).  Possibly the nfs-utils maintainer can make an executive decision about requiring libmount going forward, so we can keep things simpler.


On Feb 8, 2011, at 8:45 AM, Karel Zak wrote:

> Move generic code that could be shared between standard mount.nfs and
> libmount version to utils.c and network.c.
> 
> Signed-off-by: Karel Zak <kzak@redhat.com>
> ---
> utils/mount/Makefile.am |    2 +-
> utils/mount/mount.c     |   83 +------------------
> utils/mount/network.c   |   28 ++++++
> utils/mount/network.h   |    2 +
> utils/mount/nfsumount.c |  119 +--------------------------
> utils/mount/utils.c     |  213 +++++++++++++++++++++++++++++++++++++++++++++++
> utils/mount/utils.h     |   36 ++++++++
> 7 files changed, 283 insertions(+), 200 deletions(-)
> create mode 100644 utils/mount/utils.c
> create mode 100644 utils/mount/utils.h
> 
> diff --git a/utils/mount/Makefile.am b/utils/mount/Makefile.am
> index 299384a..a9553dc 100644
> --- a/utils/mount/Makefile.am
> +++ b/utils/mount/Makefile.am
> @@ -16,7 +16,7 @@ mount_nfs_SOURCES = mount.c error.c network.c fstab.c token.c \
> 		    mount_constants.h error.h network.h fstab.h token.h \
> 		    parse_opt.h parse_dev.h \
> 		    nfs4_mount.h nfs_mount4.h stropts.h version.h \
> -			mount_config.h
> +		    mount_config.h utils.c utils.h
> 
> if MOUNT_CONFIG
> mount_nfs_SOURCES += configfile.c
> diff --git a/utils/mount/mount.c b/utils/mount/mount.c
> index a19af53..f3f0a83 100644
> --- a/utils/mount/mount.c
> +++ b/utils/mount/mount.c
> @@ -47,7 +47,7 @@
> #include "mount.h"
> #include "error.h"
> #include "stropts.h"
> -#include "version.h"
> +#include "utils.h"
> 
> char *progname;
> int nfs_mount_data_version;
> @@ -150,49 +150,6 @@ static const struct opt_map opt_map[] = {
> static void parse_opts(const char *options, int *flags, char **extra_opts);
> 
> /*
> - * Choose the version of the nfs_mount_data structure that is appropriate
> - * for the kernel that is doing the mount.
> - *
> - * NFS_MOUNT_VERSION:		maximum version supported by these sources
> - * nfs_mount_data_version:	maximum version supported by the running kernel
> - */
> -static void discover_nfs_mount_data_version(void)
> -{
> -	unsigned int kernel_version = linux_version_code();
> -
> -	if (kernel_version) {
> -		if (kernel_version < MAKE_VERSION(2, 1, 32))
> -			nfs_mount_data_version = 1;
> -		else if (kernel_version < MAKE_VERSION(2, 2, 18))
> -			nfs_mount_data_version = 3;
> -		else if (kernel_version < MAKE_VERSION(2, 3, 0))
> -			nfs_mount_data_version = 4;
> -		else if (kernel_version < MAKE_VERSION(2, 3, 99))
> -			nfs_mount_data_version = 3;
> -		else if (kernel_version < MAKE_VERSION(2, 6, 3))
> -			nfs_mount_data_version = 4;
> -		else
> -			nfs_mount_data_version = 6;
> -	}
> -	if (nfs_mount_data_version > NFS_MOUNT_VERSION)
> -		nfs_mount_data_version = NFS_MOUNT_VERSION;
> -	else
> -		if (kernel_version > MAKE_VERSION(2, 6, 22))
> -			string++;
> -}
> -
> -static void print_one(char *spec, char *node, char *type, char *opts)
> -{
> -	if (!verbose)
> -		return;
> -
> -	if (opts)
> -		printf(_("%s on %s type %s (%s)\n"), spec, node, type, opts);
> -	else
> -		printf(_("%s on %s type %s\n"), spec, node, type);
> -}
> -
> -/*
>  * Build a canonical mount option string for /etc/mtab.
>  */
> static char *fix_opts_string(int flags, const char *extra_opts)
> @@ -327,22 +284,6 @@ static int add_mtab(char *spec, char *mount_point, char *fstype,
> 	return result;
> }
> 
> -static void mount_usage(void)
> -{
> -	printf(_("usage: %s remotetarget dir [-rvVwfnsih] [-o nfsoptions]\n"),
> -		progname);
> -	printf(_("options:\n"));
> -	printf(_("\t-r\t\tMount file system readonly\n"));
> -	printf(_("\t-v\t\tVerbose\n"));
> -	printf(_("\t-V\t\tPrint version\n"));
> -	printf(_("\t-w\t\tMount file system read-write\n"));
> -	printf(_("\t-f\t\tFake mount, do not actually mount\n"));
> -	printf(_("\t-n\t\tDo not update /etc/mtab\n"));
> -	printf(_("\t-s\t\tTolerate sloppy mount options rather than fail\n"));
> -	printf(_("\t-h\t\tPrint this help\n"));
> -	printf(_("\tnfsoptions\tRefer to mount.nfs(8) or nfs(5)\n\n"));
> -}
> -
> static void parse_opt(const char *opt, int *mask, char *extra_opts, size_t len)
> {
> 	const struct opt_map *om;
> @@ -403,26 +344,6 @@ static void parse_opts(const char *options, int *flags, char **extra_opts)
> 	}
> }
> 
> -static int chk_mountpoint(char *mount_point)
> -{
> -	struct stat sb;
> -
> -	if (stat(mount_point, &sb) < 0){
> -		mount_error(NULL, mount_point, errno);
> -		return 1;
> -	}
> -	if (S_ISDIR(sb.st_mode) == 0){
> -		mount_error(NULL, mount_point, ENOTDIR);
> -		return 1;
> -	}
> -	if (access(mount_point, X_OK) < 0) {
> -		mount_error(NULL, mount_point, errno);
> -		return 1;
> -	}
> -
> -	return 0;
> -}
> -
> static int try_mount(char *spec, char *mount_point, int flags,
> 			char *fs_type, char **extra_opts, char *mount_opts,
> 			int fake, int bg)
> @@ -459,7 +380,7 @@ int main(int argc, char *argv[])
> 
> 	progname = basename(argv[0]);
> 
> -	discover_nfs_mount_data_version();
> +	nfs_mount_data_version = discover_nfs_mount_data_version(&string);
> 
> 	if(!strncmp(progname, "umount", strlen("umount")))
> 		exit(nfsumount(argc, argv));
> diff --git a/utils/mount/network.c b/utils/mount/network.c
> index 21a7a2c..c66e7a0 100644
> --- a/utils/mount/network.c
> +++ b/utils/mount/network.c
> @@ -1491,6 +1491,34 @@ nfs_mount_version(struct mount_options *options, unsigned long *version)
> }
> 
> /*
> + * 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.
> + */
> +char *nfs_umount_hostname(struct mount_options *options,
> +				 char *hostname)

IMO this function belongs in utils.c, unless you also move nfs_umount_do_umnt() to network.c.

> +{
> +	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 TRUE if @protocol contains a valid value for this option,
>  * or FALSE if the option was specified with an invalid value. On
>  * error, errno is set.
> diff --git a/utils/mount/network.h b/utils/mount/network.h
> index 2a3a110..416f4a5 100644
> --- a/utils/mount/network.h
> +++ b/utils/mount/network.h
> @@ -62,6 +62,8 @@ int nfs_mount_proto_family(struct mount_options *options, sa_family_t *family);
> int nfs_nfs_version(struct mount_options *options, unsigned long *version);
> int  nfs_nfs_protocol(struct mount_options *options, unsigned long *protocol);
> 
> +char *nfs_umount_hostname(struct mount_options *options, char *hostname);
> +
> int nfs_options2pmap(struct mount_options *,
> 		      struct pmap *, struct pmap *);
> 
> diff --git a/utils/mount/nfsumount.c b/utils/mount/nfsumount.c
> index 02d40ff..8cd2852 100644
> --- a/utils/mount/nfsumount.c
> +++ b/utils/mount/nfsumount.c
> @@ -37,6 +37,7 @@
> #include "network.h"
> #include "parse_opt.h"
> #include "parse_dev.h"
> +#include "utils.h"
> 
> #define MOUNTSFILE	"/proc/mounts"
> #define LINELEN		(4096)
> @@ -139,113 +140,6 @@ static int del_mtab(const char *spec, const char *node)
> }
> 
> /*
> - * 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)
> -{
> -	union {
> -		struct sockaddr		sa;
> -		struct sockaddr_in	s4;
> -		struct sockaddr_in6	s6;
> -	} address;

I think we have nfs_sockaddr for this now.  Karel, can you make this minor change in the new copy of this function?

> -	struct sockaddr *sap = &address.sa;
> -	socklen_t salen = sizeof(address);
> -	struct pmap nfs_pmap, mnt_pmap;
> -	sa_family_t family;
> -
> -	if (!nfs_options2pmap(options, &nfs_pmap, &mnt_pmap))
> -		return EX_FAIL;
> -
> -	/* Skip UMNT call for vers=4 mounts */
> -	if (nfs_pmap.pm_vers == 4)
> -		return EX_SUCCESS;
> -
> -	*hostname = nfs_umount_hostname(options, *hostname);
> -	if (!*hostname) {
> -		nfs_error(_("%s: out of memory"), progname);
> -		return EX_FAIL;
> -	}
> -
> -	if (!nfs_mount_proto_family(options, &family))
> -		return 0;
> -	if (!nfs_lookup(*hostname, family, sap, &salen))
> -		/* nfs_lookup reports any errors */
> -		return EX_FAIL;
> -
> -	if (nfs_advise_umount(sap, salen, &mnt_pmap, dirname) == 0)
> -		/* nfs_advise_umount reports any errors */
> -		return EX_FAIL;
> -
> -	return EX_SUCCESS;
> -}
> -
> -/*
> - * 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.
> - *
> - * These options might also describe the mount port, mount protocol
> - * 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 nfs_umount23(const char *devname, char *string)
> -{
> -	char *hostname, *dirname;
> -	struct mount_options *options;
> -	int result = EX_FAIL;
> -
> -	if (!nfs_parse_devname(devname, &hostname, &dirname))
> -		return EX_USAGE;
> -
> -	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);
> -
> -	free(hostname);
> -	free(dirname);
> -	return result;
> -}
> -
> -/*
>  * Detect NFSv4 mounts.
>  *
>  * Consult /proc/mounts to determine if the mount point
> @@ -340,17 +234,6 @@ static struct option umount_longopts[] =
>   { NULL, 0, 0, 0 }
> };
> 
> -static void umount_usage(void)
> -{
> -	printf(_("usage: %s dir [-fvnrlh]\n"), progname);
> -	printf(_("options:\n\t-f\t\tforce unmount\n"));
> -	printf(_("\t-v\tverbose\n"));
> -	printf(_("\t-n\tDo not update /etc/mtab\n"));
> -	printf(_("\t-r\tremount\n"));
> -	printf(_("\t-l\tlazy unmount\n"));
> -	printf(_("\t-h\tprint this help\n\n"));
> -}
> -
> int nfsumount(int argc, char *argv[])
> {
> 	int c, ret;
> diff --git a/utils/mount/utils.c b/utils/mount/utils.c
> new file mode 100644
> index 0000000..e82cc3e
> --- /dev/null
> +++ b/utils/mount/utils.c
> @@ -0,0 +1,213 @@
> +/*
> + * Copyright (C) 2010 Karel Zak <kzak@redhat.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2, or (at your option)
> + * any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + */
> +
> +#ifdef HAVE_CONFIG_H
> +#include <config.h>
> +#endif
> +
> +#include <stdio.h>
> +#include <string.h>
> +#include <errno.h>
> +#include <unistd.h>
> +#include <sys/types.h>
> +#include <sys/stat.h>
> +
> +#include "nfs_mount.h"
> +#include "nls.h"
> +#include "xcommon.h"
> +#include "version.h"
> +#include "error.h"
> +#include "utils.h"
> +#include "mount.h"
> +#include "network.h"
> +#include "parse_dev.h"
> +
> +extern int verbose;
> +extern char *progname;
> +
> +/*
> + * Choose the version of the nfs_mount_data structure that is appropriate
> + * for the kernel that is doing the mount.
> + *
> + * NFS_MOUNT_VERSION:		maximum version supported by these sources
> + * nfs_mount_data_version:	maximum version supported by the running kernel
> + */
> +int discover_nfs_mount_data_version(int *string_ver)
> +{
> +	unsigned int kernel_version = linux_version_code();
> +	int ver = 0;
> +
> +	*string_ver = 0;
> +
> +	if (kernel_version) {
> +		if (kernel_version < MAKE_VERSION(2, 1, 32))
> +			ver = 1;
> +		else if (kernel_version < MAKE_VERSION(2, 2, 18))
> +			ver = 3;
> +		else if (kernel_version < MAKE_VERSION(2, 3, 0))
> +			ver = 4;
> +		else if (kernel_version < MAKE_VERSION(2, 3, 99))
> +			ver = 3;
> +		else if (kernel_version < MAKE_VERSION(2, 6, 3))
> +			ver = 4;
> +		else
> +			ver = 6;
> +	}
> +	if (ver > NFS_MOUNT_VERSION)
> +		ver = NFS_MOUNT_VERSION;
> +	else
> +		if (kernel_version > MAKE_VERSION(2, 6, 22))
> +			(*string_ver)++;
> +
> +	return ver;
> +}
> +
> +void print_one(char *spec, char *node, char *type, char *opts)
> +{
> +	if (!verbose)
> +		return;
> +
> +	if (opts)
> +		printf(_("%s on %s type %s (%s)\n"), spec, node, type, opts);
> +	else
> +		printf(_("%s on %s type %s\n"), spec, node, type);
> +}
> +
> +void mount_usage(void)
> +{
> +	printf(_("usage: %s remotetarget dir [-rvVwfnsih] [-o nfsoptions]\n"),
> +		progname);
> +	printf(_("options:\n"));
> +	printf(_("\t-r\t\tMount file system readonly\n"));
> +	printf(_("\t-v\t\tVerbose\n"));
> +	printf(_("\t-V\t\tPrint version\n"));
> +	printf(_("\t-w\t\tMount file system read-write\n"));
> +	printf(_("\t-f\t\tFake mount, do not actually mount\n"));
> +	printf(_("\t-n\t\tDo not update /etc/mtab\n"));
> +	printf(_("\t-s\t\tTolerate sloppy mount options rather than fail\n"));
> +	printf(_("\t-h\t\tPrint this help\n"));
> +	printf(_("\tnfsoptions\tRefer to mount.nfs(8) or nfs(5)\n\n"));
> +}
> +
> +void umount_usage(void)
> +{
> +	printf(_("usage: %s dir [-fvnrlh]\n"), progname);
> +	printf(_("options:\n\t-f\t\tforce unmount\n"));
> +	printf(_("\t-v\tverbose\n"));
> +	printf(_("\t-n\tDo not update /etc/mtab\n"));
> +	printf(_("\t-r\tremount\n"));
> +	printf(_("\t-l\tlazy unmount\n"));
> +	printf(_("\t-h\tprint this help\n\n"));
> +}
> +
> +int chk_mountpoint(const char *mount_point)
> +{
> +	struct stat sb;
> +
> +	if (stat(mount_point, &sb) < 0){
> +		mount_error(NULL, mount_point, errno);
> +		return 1;
> +	}
> +	if (S_ISDIR(sb.st_mode) == 0){
> +		mount_error(NULL, mount_point, ENOTDIR);
> +		return 1;
> +	}
> +	if (access(mount_point, X_OK) < 0) {
> +		mount_error(NULL, mount_point, errno);
> +		return 1;
> +	}
> +
> +	return 0;
> +}
> +
> +/*
> + * 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)
> +{
> +	union {
> +		struct sockaddr		sa;
> +		struct sockaddr_in	s4;
> +		struct sockaddr_in6	s6;
> +	} address;

See above re: nfs_sockaddr.

If any of these functions belong in network.c, I think this function does.  Look at the functions it calls: all of these are already in network.c.  In any event, this function deals directly with making the RPC calls and doing DNS lookups, which is what the functions in network.c are for.

> +	struct sockaddr *sap = &address.sa;
> +	socklen_t salen = sizeof(address);
> +	struct pmap nfs_pmap, mnt_pmap;
> +	sa_family_t family;
> +
> +	if (!nfs_options2pmap(options, &nfs_pmap, &mnt_pmap))
> +		return EX_FAIL;
> +
> +	/* Skip UMNT call for vers=4 mounts */
> +	if (nfs_pmap.pm_vers == 4)
> +		return EX_SUCCESS;
> +
> +	*hostname = nfs_umount_hostname(options, *hostname);
> +	if (!*hostname) {
> +		nfs_error(_("%s: out of memory"), progname);
> +		return EX_FAIL;
> +	}
> +
> +	if (!nfs_mount_proto_family(options, &family))
> +		return 0;
> +	if (!nfs_lookup(*hostname, family, sap, &salen))
> +		/* nfs_lookup reports any errors */
> +		return EX_FAIL;
> +
> +	if (nfs_advise_umount(sap, salen, &mnt_pmap, dirname) == 0)
> +		/* nfs_advise_umount reports any errors */
> +		return EX_FAIL;
> +
> +	return EX_SUCCESS;
> +}
> +
> +/*
> + * 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.
> + *
> + * These options might also describe the mount port, mount protocol
> + * 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.
> + */
> +int nfs_umount23(const char *devname, char *string)
> +{
> +	char *hostname = NULL, *dirname = NULL;
> +	struct mount_options *options;
> +	int result = EX_FAIL;
> +
> +	if (!nfs_parse_devname(devname, &hostname, &dirname))
> +		return EX_USAGE;
> +
> +	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);
> +
> +	free(hostname);
> +	free(dirname);
> +	return result;
> +}
> +
> diff --git a/utils/mount/utils.h b/utils/mount/utils.h
> new file mode 100644
> index 0000000..61832a3
> --- /dev/null
> +++ b/utils/mount/utils.h
> @@ -0,0 +1,36 @@
> +/*
> + * utils.h -- misc utils for mount and umount
> + *
> + * Copyright (C) 2010 Karel Zak <kzak@redhat.com>
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public
> + * License as published by the Free Software Foundation; either
> + * version 2 of the License, or (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public
> + * License along with this program; if not, write to the
> + * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
> + * Boston, MA 021110-1307, USA.

Nit: You include the address paragraph in this boilerplate, but not in utils.c.

> + *
> + */
> +
> +#ifndef _NFS_UTILS_MOUNT_UTILS_H
> +#define _NFS_UTILS_MOUNT_UTILS_H
> +
> +#include "parse_opt.h"
> +
> +int discover_nfs_mount_data_version(int *string_ver);
> +void print_one(char *spec, char *node, char *type, char *opts);
> +void mount_usage(void);
> +void umount_usage(void);
> +int chk_mountpoint(const char *mount_point);
> +
> +int nfs_umount23(const char *devname, char *string);
> +
> +#endif	/* _NFS_UTILS_MOUNT_UTILS_H */

Nit: Ideally this should be /* !_NFS_UTILS_MOUNT_UTILS_H */ (note the exclamation mark).  Most of these are incorrect in nfs-utils.

> -- 
> 1.7.3.4
> 

-- 
Chuck Lever
chuck[dot]lever[at]oracle[dot]com





^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 2/2] mount: add --enable-libmount-mount
  2011-02-08 13:45 ` [PATCH 2/2] mount: add --enable-libmount-mount Karel Zak
@ 2011-02-08 15:56   ` Chuck Lever
  0 siblings, 0 replies; 10+ messages in thread
From: Chuck Lever @ 2011-02-08 15:56 UTC (permalink / raw)
  To: Karel Zak; +Cc: linux-nfs

A few initial comments.

On Feb 8, 2011, at 8:45 AM, Karel Zak wrote:

> This patch allows to link mount.nfs with libmount from util-linux >=
> v2.19. The new libmount based code is enabled by CONFIG_LIBMOUNT and
> is stored in mount_libmount.c. The old code is not affected by this
> change.
> 
> The libmount does not have officially stable API yet, so the
> --enable-libmount-mount is marked as experimental in the configure
> help output.
> 
> The ./configure option is the same as we use in util-linux to enable
> support for libmount in mount(8).
> 
> The addr= (and some other options necessary for remount/umount) are
> stored to /etc/mtab or to /dev/.mount/utab. The utab file is *private*
> libmount file. It's possible that some mount options (for example
> user=) will be moved to kernel, so the utab will not be necessary.
> 
> About libmount:
> 
>  * supports systems without and with regular /etc/mtab
>  * does not store VFS and FS mount options in userspace
>  * manages user= option and evaluate permissions
>  * parses VFS mount options and generate MS_* flags
>  * parses /etc/{fstab,mtab}, /proc/mounts or /proc/self/mountinfo
>  * long-term goal is to use the same code in all mount.<type> helpers
> 
> Note, use
> 
>   LIBMOUNT_DEBUG=0xffff mount.nfs foo:/path /path
> 
> to debug the library.
> 
> On systems with util-linux v2.19 the findmnt(8) command uses libmount
> to list all/selected mount points:
> 
>   $ findmnt /path
>   $ findmnt --mtab /path
> 
> the --mtab appends userspace mount options (e.g. user=) to the output.

I like the long patch description.

> 
> Signed-off-by: Karel Zak <kzak@redhat.com>
> ---
> configure.ac                 |   16 ++
> utils/mount/Makefile.am      |   13 ++-
> utils/mount/mount_libmount.c |  398 ++++++++++++++++++++++++++++++++++++++++++
> 3 files changed, 425 insertions(+), 2 deletions(-)
> create mode 100644 utils/mount/mount_libmount.c
> 
> diff --git a/configure.ac b/configure.ac
> index 2e074d9..9c384d8 100644
> --- a/configure.ac
> +++ b/configure.ac
> @@ -132,6 +132,15 @@ AC_ARG_ENABLE(mount,
> 	enable_mount=$enableval,
> 	enable_mount=yes)
> 	AM_CONDITIONAL(CONFIG_MOUNT, [test "$enable_mount" = "yes"])
> +
> +if test "$enable_mount" = yes; then
> +	AC_ARG_ENABLE(libmount-mount,
> +		[AC_HELP_STRING([--enable-libmount-mount],
> +				[Link mount.nfs with libmount (EXPERIMENTAL)])],
> +		enable_libmount=yes,
> +		enable_libmount=no)
> +fi
> +
> AC_ARG_ENABLE(tirpc,
> 	[AC_HELP_STRING([--enable-tirpc],
> 			[enable use of TI-RPC @<:@default=yes@:>@])],
> @@ -285,6 +294,13 @@ AC_SUBST(LIBCRYPT)
> AC_SUBST(LIBBSD)
> AC_SUBST(LIBBLKID)
> 
> +if test "$enable_libmount" != no; then
> +   AC_CHECK_LIB(mount, mnt_context_do_mount, [LIBMOUNT="-lmount"], AC_MSG_ERROR([libmount needed]))
> +   AC_CHECK_HEADER(libmount/libmount.h, , AC_MSG_ERROR([Cannot find libmount header file libmount/libmount.h]))
> +fi
> +AM_CONDITIONAL(CONFIG_LIBMOUNT, [test "$enable_libmount" = "yes"])
> +AC_SUBST(LIBMOUNT)
> +
> if test "$enable_gss" = yes; then
>   dnl 'gss' requires getnameinfo - at least for gssd_proc.c
>   AC_CHECK_FUNC([getnameinfo], , [AC_MSG_ERROR([GSSAPI support requires 'getnameinfo' function])])
> diff --git a/utils/mount/Makefile.am b/utils/mount/Makefile.am
> index a9553dc..056293c 100644
> --- a/utils/mount/Makefile.am
> +++ b/utils/mount/Makefile.am
> @@ -9,7 +9,7 @@ man5_MANS	= nfs.man
> 
> sbin_PROGRAMS	= mount.nfs
> EXTRA_DIST = nfsmount.x $(man8_MANS) $(man5_MANS)
> -mount_nfs_SOURCES = mount.c error.c network.c fstab.c token.c \
> +mount_common = error.c network.c fstab.c token.c \
> 		    parse_opt.c parse_dev.c \
> 		    nfsmount.c nfs4mount.c stropts.c\
> 		    nfsumount.c \
> @@ -19,7 +19,7 @@ mount_nfs_SOURCES = mount.c error.c network.c fstab.c token.c \
> 		    mount_config.h utils.c utils.h
> 
> if MOUNT_CONFIG
> -mount_nfs_SOURCES += configfile.c
> +mount_common += configfile.c
> man5_MANS += nfsmount.conf.man
> EXTRA_DIST += nfsmount.conf
> endif
> @@ -27,6 +27,15 @@ endif
> mount_nfs_LDADD = ../../support/nfs/libnfs.a \
> 		  ../../support/export/libexport.a
> 
> +mount_nfs_SOURCES = $(mount_common)
> +
> +if CONFIG_LIBMOUNT
> +mount_nfs_SOURCES += mount_libmount.c
> +mount_nfs_LDADD += $(LIBMOUNT)
> +else
> +mount_nfs_SOURCES += mount.c
> +endif
> +
> MAINTAINERCLEANFILES = Makefile.in
> 
> install-exec-hook:
> diff --git a/utils/mount/mount_libmount.c b/utils/mount/mount_libmount.c
> new file mode 100644
> index 0000000..3d499c0
> --- /dev/null
> +++ b/utils/mount/mount_libmount.c
> @@ -0,0 +1,398 @@
> +/*
> + * mount_libmount.c -- Linux NFS [u]mount based on libmount
> + *
> + * Copyright (C) 2011 Karel Zak <kzak@redhat.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2, or (at your option)
> + * any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.

Nit: boilerplate here is also minus the address paragraph.

> + *
> + */
> +
> +#ifdef HAVE_CONFIG_H
> +#include <config.h>
> +#endif
> +
> +#include <unistd.h>
> +#include <stdio.h>
> +#include <string.h>
> +#include <errno.h>
> +#include <getopt.h>
> +
> +#include <libmount/libmount.h>
> +
> +#include "nls.h"
> +#include "mount_config.h"
> +
> +#include "nfs_mount.h"
> +#include "nfs4_mount.h"
> +#include "stropts.h"
> +#include "version.h"
> +#include "xcommon.h"
> +
> +#include "error.h"
> +#include "utils.h"
> +
> +char *progname;
> +int nfs_mount_data_version;
> +int verbose;
> +int sloppy;
> +int string;
> +int nomtab;
> +
> +#define FOREGROUND	(0)
> +#define BACKGROUND	(1)
> +
> +static int try_mount(struct libmnt_context *cxt, int bg)
> +{
> +	struct libmnt_fs *fs;
> +	const char *p;
> +	char *src = NULL, *tgt = NULL, *type = NULL, *opts = NULL;
> +	unsigned long flags = 0;
> +	int fake, ret = 0;
> +
> +	fs = mnt_context_get_fs(cxt);
> +
> +	/* libmount returns read-only pointers (const char)
> +	 * so, reallocate for nfsmount() functions.
> +	 */
> +	if ((p = mnt_fs_get_source(fs)))		/* spec */
> +		src = strdup(p);
> +	if ((p = mnt_fs_get_target(fs)))		/* mountpoint */
> +		tgt = strdup(p);
> +	if ((p = mnt_fs_get_fstype(fs)))
> +		type = strdup(p);
> +	if ((p = mnt_fs_get_fs_options(fs)))
> +		opts = strdup(p);
> +
> +	mnt_context_get_mflags(cxt, &flags);	/* mount(2) flags */
> +	fake = mnt_context_is_fake(cxt);
> +
> +	if (string)
> +		ret = nfsmount_string(src, tgt, type, flags, &opts, fake, bg);
> +
> +	else if (strcmp(type, "nfs4") == 0)
> +		ret = nfs4mount(src, tgt, flags, &opts, fake, bg);
> +	else
> +		ret = nfsmount(src, tgt, flags, &opts, fake, bg);
> +
> +	if (!ret && !mnt_context_is_nomtab(cxt)) {
> +		/* it's possible that mount options was modified by nfsmount()
> +		 * functions -- update info in libmount as well
> +		 *
> +		 * Note that on systems without /etc/mtab the fs-specific
> +		 * options are not managed by libmount at all. We have to use
> +		 * "mount attributes" that are private for mount.<type> helpers.
> +		 * The umount.nfs reads the attributes.
> +		 */
> +		mnt_fs_set_attributes(fs, opts);	/* for non-mtab systems */
> +		mnt_fs_set_fs_options(fs, opts);	/* for mtab */
> +	}
> +
> +	free(src);
> +	free(tgt);
> +	free(type);
> +	free(opts);
> +
> +	return ret;
> +}
> +
> +/* returns: error = -1, success = 0 , unknown = 1 */
> +static int is_vers4(struct libmnt_context *cxt)
> +{
> +	struct libmnt_fs *fs = mnt_context_get_fs(cxt);
> +	struct libmnt_table *tb = NULL;
> +	const char *src = mnt_context_get_source(cxt),
> +		   *tgt = mnt_context_get_target(cxt);
> +	int rc = 1;
> +
> +	if (!src || !tgt)
> +		return -1;
> +
> +	if (!mnt_fs_is_kernel(fs)) {
> +		struct libmnt_table *tb = mnt_new_table_from_file("/proc/mounts");
> +
> +		if (!tb)
> +			return -1;
> +		fs = mnt_table_find_pair(tb, src, tgt, MNT_ITER_BACKWARD);
> +	}
> +
> +	if (fs) {
> +		const char *type = mnt_fs_get_fstype(fs);
> +		if (type && strcmp(type, "nfs4") == 0)
> +			rc = 0;
> +	}
> +	mnt_free_table(tb);
> +	return rc;
> +}
> +
> +static int umount_main(struct libmnt_context *cxt, int argc, char **argv)
> +{
> +	int rc, c;
> +	struct libmnt_fs *fs;
> +	char *spec = NULL, *opts = NULL;
> +
> +	struct option longopts[] = {
> +		{ "force", 0, 0, 'f' },
> +		{ "help", 0, 0, 'h' },
> +		{ "no-mtab", 0, 0, 'n' },
> +		{ "verbose", 0, 0, 'v' },
> +		{ "read-only", 0, 0, 'r' },
> +		{ "lazy", 0, 0, 'l' },
> +		{ "types", 1, 0, 't' },
> +		{ NULL, 0, 0, 0 }
> +	};
> +
> +	mnt_context_init_helper(cxt, MNT_ACT_UMOUNT, 0);
> +
> +	while ((c = getopt_long (argc, argv, "fvnrlh", longopts, NULL)) != -1) {
> +
> +		rc = mnt_context_helper_setopt(cxt, c, optarg);
> +		if (rc == 0)		/* valid option */
> +			continue;
> +		if (rc < 0)		/* error (probably ENOMEM) */
> +			goto err;
> +					/* rc==1 means unknow option */
> +		umount_usage();
> +		return EX_USAGE;
> +	}
> +
> +	if (optind < argc)
> +		spec = argv[optind++];
> +
> +	if (!spec || (*spec != '/' && strchr(spec,':') == NULL)) {
> +		nfs_error(_("%s: no mount point provided"), progname);
> +		return EX_USAGE;
> +	}
> +
> +	if (mnt_context_set_target(cxt, spec))
> +		goto err;
> +	if (mnt_context_set_fstype_pattern(cxt, "nfs,nfs4"))	/* restrict filesystems */
> +		goto err;
> +
> +	/* read mtab/fstab, evaluate permissions, etc. */
> +	rc = mnt_context_prepare_umount(cxt);
> +	if (rc) {
> +		nfs_error(_("%s: failed to prepare umount: %s\n"),
> +					progname, strerror(-rc));
> +		goto err;
> +	}
> +
> +	/* NFS stores some mount options in userspace, in mtab or in libmount
> +	 * private mount table.
> +	 */

It might help to abstract the storing and retrieval of these special mount options into separate named functions (here in mount_libmount.c, of course) so a casual reader of this code gets a sense of the pairing between mount.nfs and umount.nfs.  It would be a place to clearly document this important behavior.

> +	fs = mnt_context_get_fs(cxt);
> +	if (fs) {
> +		opts = (char *) mnt_fs_get_attributes(fs);	/* /dev/.mount/utab */
> +		if (opts) {
> +			opts = strdup(opts);
> +			if (!opts)
> +				goto err;
> +		}
> +		else
> +			opts = mnt_fs_strdup_options(fs);	/* /etc/mtab */
> +	}
> +
> +	if (!mnt_context_is_lazy(cxt)) {
> +		if (opts) {
> +			/* we have full FS description (e.g. from mtab or /proc) */
> +			switch (is_vers4(cxt)) {
> +			case 0:
> +				/* 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!
> +				 */
> +				nfs_umount23(mnt_context_get_source(cxt), opts);
> +				break;
> +			case 1:			/* unknown */
> +				break;
> +			default:		/* error */
> +				goto err;
> +			}
> +		} else
> +			/* strange, no entry in mtab or /proc not mounted */
> +			nfs_umount23(spec, "tcp,v3");
> +	}
> +
> +	rc = mnt_context_do_umount(cxt);	/* call umount(2) syscall */
> +	mnt_context_finalize_mount(cxt);	/* mtab update */
> +
> +	if (!rc)
> +		goto err;
> +
> +	free(opts);
> +	return EX_SUCCESS;
> +err:
> +	free(opts);
> +	return EX_FAIL;
> +}
> +
> +static int mount_main(struct libmnt_context *cxt, int argc, char **argv)
> +{
> +	int rc, c;
> +	struct libmnt_fs *fs;
> +	char *spec = NULL, *mount_point = NULL, *opts = NULL;
> +
> +	struct option longopts[] = {
> +	  { "fake", 0, 0, 'f' },
> +	  { "help", 0, 0, 'h' },
> +	  { "no-mtab", 0, 0, 'n' },
> +	  { "read-only", 0, 0, 'r' },
> +	  { "ro", 0, 0, 'r' },
> +	  { "verbose", 0, 0, 'v' },
> +	  { "version", 0, 0, 'V' },
> +	  { "read-write", 0, 0, 'w' },
> +	  { "rw", 0, 0, 'w' },
> +	  { "options", 1, 0, 'o' },
> +	  { "sloppy", 0, 0, 's' },
> +	  { NULL, 0, 0, 0 }
> +	};

Should these be declared "const static" ?  The current declaration would seem to put this big array of strings on the stack.

> +
> +	mount_config_init(progname);
> +	mnt_context_init_helper(cxt, MNT_ACT_MOUNT, 0);
> +
> +	while ((c = getopt_long(argc, argv, "fhnrVvwo:s", longopts, NULL)) != -1) {
> +
> +		rc = mnt_context_helper_setopt(cxt, c, optarg);
> +		if (rc == 0)		/* valid option */
> +			continue;
> +		if (rc < 0)		/* error (probably ENOMEM) */
> +			goto err;
> +					/* rc==1 means unknow option */
> +		switch (c) {
> +		case 'V':
> +			printf("%s: ("PACKAGE_STRING")\n", progname);
> +			return EX_SUCCESS;
> +		case 'h':
> +		default:
> +			mount_usage();
> +			return EX_USAGE;
> +		}
> +	}
> +
> +	if (optind < argc)
> +		spec = argv[optind++];
> +	if (optind < argc)
> +		mount_point = argv[optind++];
> +
> +	if (!mount_point) {
> +		nfs_error(_("%s: no mount point provided"), progname);
> +		goto err;
> +	}
> +	if (!spec) {
> +		nfs_error(_("%s: no mount spec provided"), progname);
> +		goto err;
> +	}
> +
> +	if (geteuid() != 0) {
> +		nfs_error(_("%s: not installed setuid - "
> +			    "\"user\" NFS mounts not supported."), progname);
> +		goto err;
> +	}
> +
> +	verbose = mnt_context_is_verbose(cxt);
> +	sloppy = mnt_context_is_sloppy(cxt);
> +	nomtab = mnt_context_is_nomtab(cxt);
> +
> +	if (strcmp(progname, "mount.nfs4") == 0)
> +		mnt_context_set_fstype(cxt, "nfs4");
> +	else
> +		mnt_context_set_fstype(cxt, "nfs");	/* default */
> +
> +	rc = mnt_context_set_source(cxt, spec);
> +	if (!rc)
> +		mnt_context_set_target(cxt, mount_point);
> +	if (rc) {
> +		nfs_error(_("%s: failed to set spec or mountpoint: %s"),
> +				progname, strerror(errno));
> +		goto err;
> +	}
> +
> +	mount_point = mnt_resolve_path(mount_point,
> +				       mnt_context_get_cache(cxt));
> +
> +	if (chk_mountpoint(mount_point))
> +		goto err;
> +	/*
> +	 * Concatenate mount options from the configuration file
> +	 */
> +	fs = mnt_context_get_fs(cxt);
> +	if (fs) {
> +		opts = mnt_fs_strdup_options(fs);
> +
> +		opts = mount_config_opts(spec, mount_point, opts);
> +		mnt_fs_set_options(fs, opts);
> +	}
> +
> +	rc = mnt_context_prepare_mount(cxt);
> +	if (rc) {
> +		nfs_error(_("%s: failed to prepare mount: %s\n"),
> +					progname, strerror(-rc));
> +		goto err;
> +	}
> +
> +	rc = try_mount(cxt, FOREGROUND);
> +
> +	if (rc == EX_BG) {
> +		printf(_("%s: backgrounding \"%s\"\n"),
> +			progname, mnt_context_get_source(cxt));
> +		printf(_("%s: mount options: \"%s\"\n"),
> +			progname, opts);
> +
> +		fflush(stdout);
> +
> +		if (daemon(0, 0)) {
> +			nfs_error(_("%s: failed to start "
> +					"background process: %s\n"),
> +					progname, strerror(errno));
> +			exit(EX_FAIL);
> +		}
> +
> +		rc = try_mount(cxt, BACKGROUND);
> +
> +		if (verbose && rc)
> +			printf(_("%s: giving up \"%s\"\n"),
> +				progname, mnt_context_get_source(cxt));
> +	}
> +
> +	mnt_context_set_syscall_status(cxt, rc);
> +	mnt_context_finalize_mount(cxt);	/* mtab update */
> +
> +	return rc;
> +err:
> +	return EX_FAIL;
> +}
> +
> +int main(int argc, char *argv[])
> +{
> +	struct libmnt_context *cxt;
> +	int rc;
> +
> +	mnt_init_debug(0);
> +	cxt = mnt_new_context();
> +	if (!cxt) {
> +		nfs_error(_("Can't initilize libmount: %s"),
> +					strerror(errno));
> +		rc = EX_FAIL;
> +		goto done;
> +	}

How is localization handled?

> +
> +	progname = basename(argv[0]);
> +	nfs_mount_data_version = discover_nfs_mount_data_version(&string);
> +
> +	if(!strncmp(progname, "umount", 6))

Nit: we tend to like "strncmp() == 0" since it's less likely to be misread.  "!strncmp" can easily be misread as "not equal".

> +		rc = umount_main(cxt, argc, argv);
> +	else
> +		rc = mount_main(cxt, argc, argv);
> +done:
> +	mnt_free_context(cxt);
> +	return rc;
> +}
> +
> -- 
> 1.7.3.4
> 

-- 
Chuck Lever
chuck[dot]lever[at]oracle[dot]com





^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 1/2] mount: move generic functions to utils.c and network.c
  2011-02-08 15:43   ` Chuck Lever
@ 2011-02-08 16:08     ` Karel Zak
  2011-02-15  0:08       ` Chuck Lever
  0 siblings, 1 reply; 10+ messages in thread
From: Karel Zak @ 2011-02-08 16:08 UTC (permalink / raw)
  To: Chuck Lever; +Cc: linux-nfs

On Tue, Feb 08, 2011 at 10:43:23AM -0500, Chuck Lever wrote:
> Nice work, just a few nits so far.

I'll send updated version later. Thanks for your feedback.

> I'll wait for utils-linux
> 2.19... and we have NFS Connectathon (http://www.connectathon.org)
> in a couple of weeks, so it will be March before I can spend some
> quality time with this.
> 
> Also, I'm cleaning up a version of parse_opt.c and token.c for you,
> if you want to include these in libmount at some point.

The library already has some code for mount options parsing, but there
is not code to create a list from parsed mount options. The library 
already uses struct list_head (originally probably from e2fsprogs
and Linux kernel, see include/list.h in util-linux), so maybe we can
use it for mount options too.

    Karel

-- 
 Karel Zak  <kzak@redhat.com>
 http://karelzak.blogspot.com

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: mount.nfs libmount support
  2011-02-08 13:45 mount.nfs libmount support Karel Zak
  2011-02-08 13:45 ` [PATCH 1/2] mount: move generic functions to utils.c and network.c Karel Zak
  2011-02-08 13:45 ` [PATCH 2/2] mount: add --enable-libmount-mount Karel Zak
@ 2011-02-09  5:25 ` NeilBrown
  2 siblings, 0 replies; 10+ messages in thread
From: NeilBrown @ 2011-02-09  5:25 UTC (permalink / raw)
  To: Karel Zak; +Cc: Chuck Lever, linux-nfs

On Tue,  8 Feb 2011 14:45:15 +0100 Karel Zak <kzak@redhat.com> wrote:

> Hi Chuck,
> 
> this is the first version of the mount.nfs with libmount support. The code
> depends on the latest util-linux code from upstream git tree, or you can 
> wait few days for official 2.19 util-linux tarballs (and Fedora binary rpms).
> 
> I have tested:
> 
> 	mount.nfs server://path /mountpoint
> 	mount.nfs server://path /mountpoint -o remount,ro
> 	mount.nfs server://path /mountpoint -o user

Probably a small point but.... you do know that isn't the standard syntax for
NFS mounts, don't you?  NFS uses a single slash.

        mount.nfs server:/path /mountpoint ...

NeilBrown


> 
> 	umount.nfs server://path
> 	umount.nfs /mountpoint
> 
> .. works for me. For more information see the second patch.
> 
> 	Karel
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-nfs" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 1/2] mount: move generic functions to utils.c and network.c
  2011-02-08 16:08     ` Karel Zak
@ 2011-02-15  0:08       ` Chuck Lever
  0 siblings, 0 replies; 10+ messages in thread
From: Chuck Lever @ 2011-02-15  0:08 UTC (permalink / raw)
  To: Karel Zak; +Cc: linux-nfs


On Feb 8, 2011, at 11:08 AM, Karel Zak wrote:

> On Tue, Feb 08, 2011 at 10:43:23AM -0500, Chuck Lever wrote:
>> Nice work, just a few nits so far.
> 
> I'll send updated version later. Thanks for your feedback.
> 
>> I'll wait for utils-linux
>> 2.19... and we have NFS Connectathon (http://www.connectathon.org)
>> in a couple of weeks, so it will be March before I can spend some
>> quality time with this.
>> 
>> Also, I'm cleaning up a version of parse_opt.c and token.c for you,
>> if you want to include these in libmount at some point.
> 
> The library already has some code for mount options parsing, but there
> is not code to create a list from parsed mount options. The library 
> already uses struct list_head (originally probably from e2fsprogs
> and Linux kernel, see include/list.h in util-linux), so maybe we can
> use it for mount options too.

"struct mount_options" is meant to be opaque to callers.  Originally I expected there would be more than just a list in it.  As it turned out, a doubly-linked list is all that is needed.

I can experiment with replacing "struct mount_options" with "struct list_head."  I rather prefer the opacity, as that discourages callers from tinkering with the option lists themselves.  It's a nit, I suppose.

-- 
Chuck Lever
chuck[dot]lever[at]oracle[dot]com





^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH 1/2] mount: move generic functions to utils.c and network.c
  2011-03-14 13:58 mount.nfs libmount support (v3) Karel Zak
@ 2011-03-14 13:58 ` Karel Zak
  0 siblings, 0 replies; 10+ messages in thread
From: Karel Zak @ 2011-03-14 13:58 UTC (permalink / raw)
  To: Chuck Lever, Steve Dickson; +Cc: linux-nfs, Karel Zak, Steve Dickson

Move generic code that could be shared between standard mount.nfs and
libmount version to utils.c and network.c.

CC: Chuck Lever <chuck.lever@oracle.com>
CC: Steve Dickson <steved@redhat.com>
Signed-off-by: Karel Zak <kzak@redhat.com>
---
 utils/mount/Makefile.am |    2 +-
 utils/mount/mount.c     |   83 +----------------------
 utils/mount/network.c   |   68 ++++++++++++++++++
 utils/mount/network.h   |    3 +
 utils/mount/nfsumount.c |  119 +-------------------------------
 utils/mount/utils.c     |  175 +++++++++++++++++++++++++++++++++++++++++++++++
 utils/mount/utils.h     |   36 ++++++++++
 7 files changed, 286 insertions(+), 200 deletions(-)
 create mode 100644 utils/mount/utils.c
 create mode 100644 utils/mount/utils.h

diff --git a/utils/mount/Makefile.am b/utils/mount/Makefile.am
index 299384a..a9553dc 100644
--- a/utils/mount/Makefile.am
+++ b/utils/mount/Makefile.am
@@ -16,7 +16,7 @@ mount_nfs_SOURCES = mount.c error.c network.c fstab.c token.c \
 		    mount_constants.h error.h network.h fstab.h token.h \
 		    parse_opt.h parse_dev.h \
 		    nfs4_mount.h nfs_mount4.h stropts.h version.h \
-			mount_config.h
+		    mount_config.h utils.c utils.h
 
 if MOUNT_CONFIG
 mount_nfs_SOURCES += configfile.c
diff --git a/utils/mount/mount.c b/utils/mount/mount.c
index a19af53..f3f0a83 100644
--- a/utils/mount/mount.c
+++ b/utils/mount/mount.c
@@ -47,7 +47,7 @@
 #include "mount.h"
 #include "error.h"
 #include "stropts.h"
-#include "version.h"
+#include "utils.h"
 
 char *progname;
 int nfs_mount_data_version;
@@ -150,49 +150,6 @@ static const struct opt_map opt_map[] = {
 static void parse_opts(const char *options, int *flags, char **extra_opts);
 
 /*
- * Choose the version of the nfs_mount_data structure that is appropriate
- * for the kernel that is doing the mount.
- *
- * NFS_MOUNT_VERSION:		maximum version supported by these sources
- * nfs_mount_data_version:	maximum version supported by the running kernel
- */
-static void discover_nfs_mount_data_version(void)
-{
-	unsigned int kernel_version = linux_version_code();
-
-	if (kernel_version) {
-		if (kernel_version < MAKE_VERSION(2, 1, 32))
-			nfs_mount_data_version = 1;
-		else if (kernel_version < MAKE_VERSION(2, 2, 18))
-			nfs_mount_data_version = 3;
-		else if (kernel_version < MAKE_VERSION(2, 3, 0))
-			nfs_mount_data_version = 4;
-		else if (kernel_version < MAKE_VERSION(2, 3, 99))
-			nfs_mount_data_version = 3;
-		else if (kernel_version < MAKE_VERSION(2, 6, 3))
-			nfs_mount_data_version = 4;
-		else
-			nfs_mount_data_version = 6;
-	}
-	if (nfs_mount_data_version > NFS_MOUNT_VERSION)
-		nfs_mount_data_version = NFS_MOUNT_VERSION;
-	else
-		if (kernel_version > MAKE_VERSION(2, 6, 22))
-			string++;
-}
-
-static void print_one(char *spec, char *node, char *type, char *opts)
-{
-	if (!verbose)
-		return;
-
-	if (opts)
-		printf(_("%s on %s type %s (%s)\n"), spec, node, type, opts);
-	else
-		printf(_("%s on %s type %s\n"), spec, node, type);
-}
-
-/*
  * Build a canonical mount option string for /etc/mtab.
  */
 static char *fix_opts_string(int flags, const char *extra_opts)
@@ -327,22 +284,6 @@ static int add_mtab(char *spec, char *mount_point, char *fstype,
 	return result;
 }
 
-static void mount_usage(void)
-{
-	printf(_("usage: %s remotetarget dir [-rvVwfnsih] [-o nfsoptions]\n"),
-		progname);
-	printf(_("options:\n"));
-	printf(_("\t-r\t\tMount file system readonly\n"));
-	printf(_("\t-v\t\tVerbose\n"));
-	printf(_("\t-V\t\tPrint version\n"));
-	printf(_("\t-w\t\tMount file system read-write\n"));
-	printf(_("\t-f\t\tFake mount, do not actually mount\n"));
-	printf(_("\t-n\t\tDo not update /etc/mtab\n"));
-	printf(_("\t-s\t\tTolerate sloppy mount options rather than fail\n"));
-	printf(_("\t-h\t\tPrint this help\n"));
-	printf(_("\tnfsoptions\tRefer to mount.nfs(8) or nfs(5)\n\n"));
-}
-
 static void parse_opt(const char *opt, int *mask, char *extra_opts, size_t len)
 {
 	const struct opt_map *om;
@@ -403,26 +344,6 @@ static void parse_opts(const char *options, int *flags, char **extra_opts)
 	}
 }
 
-static int chk_mountpoint(char *mount_point)
-{
-	struct stat sb;
-
-	if (stat(mount_point, &sb) < 0){
-		mount_error(NULL, mount_point, errno);
-		return 1;
-	}
-	if (S_ISDIR(sb.st_mode) == 0){
-		mount_error(NULL, mount_point, ENOTDIR);
-		return 1;
-	}
-	if (access(mount_point, X_OK) < 0) {
-		mount_error(NULL, mount_point, errno);
-		return 1;
-	}
-
-	return 0;
-}
-
 static int try_mount(char *spec, char *mount_point, int flags,
 			char *fs_type, char **extra_opts, char *mount_opts,
 			int fake, int bg)
@@ -459,7 +380,7 @@ int main(int argc, char *argv[])
 
 	progname = basename(argv[0]);
 
-	discover_nfs_mount_data_version();
+	nfs_mount_data_version = discover_nfs_mount_data_version(&string);
 
 	if(!strncmp(progname, "umount", strlen("umount")))
 		exit(nfsumount(argc, argv));
diff --git a/utils/mount/network.c b/utils/mount/network.c
index 9b6504d..3dec3b5 100644
--- a/utils/mount/network.c
+++ b/utils/mount/network.c
@@ -1626,3 +1626,71 @@ int nfs_options2pmap(struct mount_options *options,
 
 	return 1;
 }
+
+/*
+ * 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.
+ */
+int nfs_umount_do_umnt(struct mount_options *options,
+		       char **hostname, char **dirname)
+{
+	union nfs_sockaddr address;
+	struct sockaddr *sap = &address.sa;
+	socklen_t salen = sizeof(address);
+	struct pmap nfs_pmap, mnt_pmap;
+	sa_family_t family;
+
+	if (!nfs_options2pmap(options, &nfs_pmap, &mnt_pmap))
+		return EX_FAIL;
+
+	/* Skip UMNT call for vers=4 mounts */
+	if (nfs_pmap.pm_vers == 4)
+		return EX_SUCCESS;
+
+	*hostname = nfs_umount_hostname(options, *hostname);
+	if (!*hostname) {
+		nfs_error(_("%s: out of memory"), progname);
+		return EX_FAIL;
+	}
+
+	if (!nfs_mount_proto_family(options, &family))
+		return 0;
+	if (!nfs_lookup(*hostname, family, sap, &salen))
+		/* nfs_lookup reports any errors */
+		return EX_FAIL;
+
+	if (nfs_advise_umount(sap, salen, &mnt_pmap, dirname) == 0)
+		/* nfs_advise_umount reports any errors */
+		return EX_FAIL;
+
+	return EX_SUCCESS;
+}
diff --git a/utils/mount/network.h b/utils/mount/network.h
index 2a3a110..81c6f22 100644
--- a/utils/mount/network.h
+++ b/utils/mount/network.h
@@ -75,4 +75,7 @@ int nfs_advise_umount(const struct sockaddr *, const socklen_t,
 CLIENT *mnt_openclnt(clnt_addr_t *, int *);
 void mnt_closeclnt(CLIENT *, int);
 
+int nfs_umount_do_umnt(struct mount_options *options,
+		       char **hostname, char **dirname);
+
 #endif	/* _NFS_UTILS_MOUNT_NETWORK_H */
diff --git a/utils/mount/nfsumount.c b/utils/mount/nfsumount.c
index 02d40ff..8cd2852 100644
--- a/utils/mount/nfsumount.c
+++ b/utils/mount/nfsumount.c
@@ -37,6 +37,7 @@
 #include "network.h"
 #include "parse_opt.h"
 #include "parse_dev.h"
+#include "utils.h"
 
 #define MOUNTSFILE	"/proc/mounts"
 #define LINELEN		(4096)
@@ -139,113 +140,6 @@ static int del_mtab(const char *spec, const char *node)
 }
 
 /*
- * 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)
-{
-	union {
-		struct sockaddr		sa;
-		struct sockaddr_in	s4;
-		struct sockaddr_in6	s6;
-	} address;
-	struct sockaddr *sap = &address.sa;
-	socklen_t salen = sizeof(address);
-	struct pmap nfs_pmap, mnt_pmap;
-	sa_family_t family;
-
-	if (!nfs_options2pmap(options, &nfs_pmap, &mnt_pmap))
-		return EX_FAIL;
-
-	/* Skip UMNT call for vers=4 mounts */
-	if (nfs_pmap.pm_vers == 4)
-		return EX_SUCCESS;
-
-	*hostname = nfs_umount_hostname(options, *hostname);
-	if (!*hostname) {
-		nfs_error(_("%s: out of memory"), progname);
-		return EX_FAIL;
-	}
-
-	if (!nfs_mount_proto_family(options, &family))
-		return 0;
-	if (!nfs_lookup(*hostname, family, sap, &salen))
-		/* nfs_lookup reports any errors */
-		return EX_FAIL;
-
-	if (nfs_advise_umount(sap, salen, &mnt_pmap, dirname) == 0)
-		/* nfs_advise_umount reports any errors */
-		return EX_FAIL;
-
-	return EX_SUCCESS;
-}
-
-/*
- * 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.
- *
- * These options might also describe the mount port, mount protocol
- * 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 nfs_umount23(const char *devname, char *string)
-{
-	char *hostname, *dirname;
-	struct mount_options *options;
-	int result = EX_FAIL;
-
-	if (!nfs_parse_devname(devname, &hostname, &dirname))
-		return EX_USAGE;
-
-	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);
-
-	free(hostname);
-	free(dirname);
-	return result;
-}
-
-/*
  * Detect NFSv4 mounts.
  *
  * Consult /proc/mounts to determine if the mount point
@@ -340,17 +234,6 @@ static struct option umount_longopts[] =
   { NULL, 0, 0, 0 }
 };
 
-static void umount_usage(void)
-{
-	printf(_("usage: %s dir [-fvnrlh]\n"), progname);
-	printf(_("options:\n\t-f\t\tforce unmount\n"));
-	printf(_("\t-v\tverbose\n"));
-	printf(_("\t-n\tDo not update /etc/mtab\n"));
-	printf(_("\t-r\tremount\n"));
-	printf(_("\t-l\tlazy unmount\n"));
-	printf(_("\t-h\tprint this help\n\n"));
-}
-
 int nfsumount(int argc, char *argv[])
 {
 	int c, ret;
diff --git a/utils/mount/utils.c b/utils/mount/utils.c
new file mode 100644
index 0000000..298db39
--- /dev/null
+++ b/utils/mount/utils.c
@@ -0,0 +1,175 @@
+/*
+ * Copyright (C) 2010 Karel Zak <kzak@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 021110-1307, USA.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "sockaddr.h"
+#include "nfs_mount.h"
+#include "nls.h"
+#include "xcommon.h"
+#include "version.h"
+#include "error.h"
+#include "utils.h"
+#include "mount.h"
+#include "network.h"
+#include "parse_dev.h"
+
+extern int verbose;
+extern char *progname;
+
+/*
+ * Choose the version of the nfs_mount_data structure that is appropriate
+ * for the kernel that is doing the mount.
+ *
+ * NFS_MOUNT_VERSION:		maximum version supported by these sources
+ * nfs_mount_data_version:	maximum version supported by the running kernel
+ */
+int discover_nfs_mount_data_version(int *string_ver)
+{
+	unsigned int kernel_version = linux_version_code();
+	int ver = 0;
+
+	*string_ver = 0;
+
+	if (kernel_version) {
+		if (kernel_version < MAKE_VERSION(2, 1, 32))
+			ver = 1;
+		else if (kernel_version < MAKE_VERSION(2, 2, 18))
+			ver = 3;
+		else if (kernel_version < MAKE_VERSION(2, 3, 0))
+			ver = 4;
+		else if (kernel_version < MAKE_VERSION(2, 3, 99))
+			ver = 3;
+		else if (kernel_version < MAKE_VERSION(2, 6, 3))
+			ver = 4;
+		else
+			ver = 6;
+	}
+	if (ver > NFS_MOUNT_VERSION)
+		ver = NFS_MOUNT_VERSION;
+	else
+		if (kernel_version > MAKE_VERSION(2, 6, 22))
+			(*string_ver)++;
+
+	return ver;
+}
+
+void print_one(char *spec, char *node, char *type, char *opts)
+{
+	if (!verbose)
+		return;
+
+	if (opts)
+		printf(_("%s on %s type %s (%s)\n"), spec, node, type, opts);
+	else
+		printf(_("%s on %s type %s\n"), spec, node, type);
+}
+
+void mount_usage(void)
+{
+	printf(_("usage: %s remotetarget dir [-rvVwfnsih] [-o nfsoptions]\n"),
+		progname);
+	printf(_("options:\n"));
+	printf(_("\t-r\t\tMount file system readonly\n"));
+	printf(_("\t-v\t\tVerbose\n"));
+	printf(_("\t-V\t\tPrint version\n"));
+	printf(_("\t-w\t\tMount file system read-write\n"));
+	printf(_("\t-f\t\tFake mount, do not actually mount\n"));
+	printf(_("\t-n\t\tDo not update /etc/mtab\n"));
+	printf(_("\t-s\t\tTolerate sloppy mount options rather than fail\n"));
+	printf(_("\t-h\t\tPrint this help\n"));
+	printf(_("\tnfsoptions\tRefer to mount.nfs(8) or nfs(5)\n\n"));
+}
+
+void umount_usage(void)
+{
+	printf(_("usage: %s dir [-fvnrlh]\n"), progname);
+	printf(_("options:\n\t-f\t\tforce unmount\n"));
+	printf(_("\t-v\tverbose\n"));
+	printf(_("\t-n\tDo not update /etc/mtab\n"));
+	printf(_("\t-r\tremount\n"));
+	printf(_("\t-l\tlazy unmount\n"));
+	printf(_("\t-h\tprint this help\n\n"));
+}
+
+int chk_mountpoint(const char *mount_point)
+{
+	struct stat sb;
+
+	if (stat(mount_point, &sb) < 0){
+		mount_error(NULL, mount_point, errno);
+		return 1;
+	}
+	if (S_ISDIR(sb.st_mode) == 0){
+		mount_error(NULL, mount_point, ENOTDIR);
+		return 1;
+	}
+	if (access(mount_point, X_OK) < 0) {
+		mount_error(NULL, mount_point, errno);
+		return 1;
+	}
+
+	return 0;
+}
+
+/*
+ * 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.
+ *
+ * These options might also describe the mount port, mount protocol
+ * 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.
+ */
+int nfs_umount23(const char *devname, char *string)
+{
+	char *hostname = NULL, *dirname = NULL;
+	struct mount_options *options;
+	int result = EX_FAIL;
+
+	if (!nfs_parse_devname(devname, &hostname, &dirname))
+		return EX_USAGE;
+
+	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);
+
+	free(hostname);
+	free(dirname);
+	return result;
+}
diff --git a/utils/mount/utils.h b/utils/mount/utils.h
new file mode 100644
index 0000000..3fcd504
--- /dev/null
+++ b/utils/mount/utils.h
@@ -0,0 +1,36 @@
+/*
+ * utils.h -- misc utils for mount and umount
+ *
+ * Copyright (C) 2010 Karel Zak <kzak@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 021110-1307, USA.
+ *
+ */
+
+#ifndef _NFS_UTILS_MOUNT_UTILS_H
+#define _NFS_UTILS_MOUNT_UTILS_H
+
+#include "parse_opt.h"
+
+int discover_nfs_mount_data_version(int *string_ver);
+void print_one(char *spec, char *node, char *type, char *opts);
+void mount_usage(void);
+void umount_usage(void);
+int chk_mountpoint(const char *mount_point);
+
+int nfs_umount23(const char *devname, char *string);
+
+#endif	/* !_NFS_UTILS_MOUNT_UTILS_H */
-- 
1.7.3.4


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 1/2] mount: move generic functions to utils.c and network.c
  2011-03-03 13:43 mount.nfs libmount support (v2) Karel Zak
@ 2011-03-03 13:43 ` Karel Zak
  0 siblings, 0 replies; 10+ messages in thread
From: Karel Zak @ 2011-03-03 13:43 UTC (permalink / raw)
  To: Chuck Lever; +Cc: linux-nfs, Karel Zak, Steve Dickson

Move generic code that could be shared between standard mount.nfs and
libmount version to utils.c and network.c.

CC: Chuck Lever <chuck.lever@oracle.com>
CC: Steve Dickson <steved@redhat.com>
Signed-off-by: Karel Zak <kzak@redhat.com>
---
 utils/mount/Makefile.am |    2 +-
 utils/mount/mount.c     |   83 +----------------------
 utils/mount/network.c   |   68 ++++++++++++++++++
 utils/mount/network.h   |    3 +
 utils/mount/nfsumount.c |  119 +-------------------------------
 utils/mount/utils.c     |  175 +++++++++++++++++++++++++++++++++++++++++++++++
 utils/mount/utils.h     |   36 ++++++++++
 7 files changed, 286 insertions(+), 200 deletions(-)
 create mode 100644 utils/mount/utils.c
 create mode 100644 utils/mount/utils.h

diff --git a/utils/mount/Makefile.am b/utils/mount/Makefile.am
index 299384a..a9553dc 100644
--- a/utils/mount/Makefile.am
+++ b/utils/mount/Makefile.am
@@ -16,7 +16,7 @@ mount_nfs_SOURCES = mount.c error.c network.c fstab.c token.c \
 		    mount_constants.h error.h network.h fstab.h token.h \
 		    parse_opt.h parse_dev.h \
 		    nfs4_mount.h nfs_mount4.h stropts.h version.h \
-			mount_config.h
+		    mount_config.h utils.c utils.h
 
 if MOUNT_CONFIG
 mount_nfs_SOURCES += configfile.c
diff --git a/utils/mount/mount.c b/utils/mount/mount.c
index a19af53..f3f0a83 100644
--- a/utils/mount/mount.c
+++ b/utils/mount/mount.c
@@ -47,7 +47,7 @@
 #include "mount.h"
 #include "error.h"
 #include "stropts.h"
-#include "version.h"
+#include "utils.h"
 
 char *progname;
 int nfs_mount_data_version;
@@ -150,49 +150,6 @@ static const struct opt_map opt_map[] = {
 static void parse_opts(const char *options, int *flags, char **extra_opts);
 
 /*
- * Choose the version of the nfs_mount_data structure that is appropriate
- * for the kernel that is doing the mount.
- *
- * NFS_MOUNT_VERSION:		maximum version supported by these sources
- * nfs_mount_data_version:	maximum version supported by the running kernel
- */
-static void discover_nfs_mount_data_version(void)
-{
-	unsigned int kernel_version = linux_version_code();
-
-	if (kernel_version) {
-		if (kernel_version < MAKE_VERSION(2, 1, 32))
-			nfs_mount_data_version = 1;
-		else if (kernel_version < MAKE_VERSION(2, 2, 18))
-			nfs_mount_data_version = 3;
-		else if (kernel_version < MAKE_VERSION(2, 3, 0))
-			nfs_mount_data_version = 4;
-		else if (kernel_version < MAKE_VERSION(2, 3, 99))
-			nfs_mount_data_version = 3;
-		else if (kernel_version < MAKE_VERSION(2, 6, 3))
-			nfs_mount_data_version = 4;
-		else
-			nfs_mount_data_version = 6;
-	}
-	if (nfs_mount_data_version > NFS_MOUNT_VERSION)
-		nfs_mount_data_version = NFS_MOUNT_VERSION;
-	else
-		if (kernel_version > MAKE_VERSION(2, 6, 22))
-			string++;
-}
-
-static void print_one(char *spec, char *node, char *type, char *opts)
-{
-	if (!verbose)
-		return;
-
-	if (opts)
-		printf(_("%s on %s type %s (%s)\n"), spec, node, type, opts);
-	else
-		printf(_("%s on %s type %s\n"), spec, node, type);
-}
-
-/*
  * Build a canonical mount option string for /etc/mtab.
  */
 static char *fix_opts_string(int flags, const char *extra_opts)
@@ -327,22 +284,6 @@ static int add_mtab(char *spec, char *mount_point, char *fstype,
 	return result;
 }
 
-static void mount_usage(void)
-{
-	printf(_("usage: %s remotetarget dir [-rvVwfnsih] [-o nfsoptions]\n"),
-		progname);
-	printf(_("options:\n"));
-	printf(_("\t-r\t\tMount file system readonly\n"));
-	printf(_("\t-v\t\tVerbose\n"));
-	printf(_("\t-V\t\tPrint version\n"));
-	printf(_("\t-w\t\tMount file system read-write\n"));
-	printf(_("\t-f\t\tFake mount, do not actually mount\n"));
-	printf(_("\t-n\t\tDo not update /etc/mtab\n"));
-	printf(_("\t-s\t\tTolerate sloppy mount options rather than fail\n"));
-	printf(_("\t-h\t\tPrint this help\n"));
-	printf(_("\tnfsoptions\tRefer to mount.nfs(8) or nfs(5)\n\n"));
-}
-
 static void parse_opt(const char *opt, int *mask, char *extra_opts, size_t len)
 {
 	const struct opt_map *om;
@@ -403,26 +344,6 @@ static void parse_opts(const char *options, int *flags, char **extra_opts)
 	}
 }
 
-static int chk_mountpoint(char *mount_point)
-{
-	struct stat sb;
-
-	if (stat(mount_point, &sb) < 0){
-		mount_error(NULL, mount_point, errno);
-		return 1;
-	}
-	if (S_ISDIR(sb.st_mode) == 0){
-		mount_error(NULL, mount_point, ENOTDIR);
-		return 1;
-	}
-	if (access(mount_point, X_OK) < 0) {
-		mount_error(NULL, mount_point, errno);
-		return 1;
-	}
-
-	return 0;
-}
-
 static int try_mount(char *spec, char *mount_point, int flags,
 			char *fs_type, char **extra_opts, char *mount_opts,
 			int fake, int bg)
@@ -459,7 +380,7 @@ int main(int argc, char *argv[])
 
 	progname = basename(argv[0]);
 
-	discover_nfs_mount_data_version();
+	nfs_mount_data_version = discover_nfs_mount_data_version(&string);
 
 	if(!strncmp(progname, "umount", strlen("umount")))
 		exit(nfsumount(argc, argv));
diff --git a/utils/mount/network.c b/utils/mount/network.c
index 21a7a2c..8049c1a 100644
--- a/utils/mount/network.c
+++ b/utils/mount/network.c
@@ -1626,3 +1626,71 @@ int nfs_options2pmap(struct mount_options *options,
 
 	return 1;
 }
+
+/*
+ * 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.
+ */
+int nfs_umount_do_umnt(struct mount_options *options,
+		       char **hostname, char **dirname)
+{
+	union nfs_sockaddr address;
+	struct sockaddr *sap = &address.sa;
+	socklen_t salen = sizeof(address);
+	struct pmap nfs_pmap, mnt_pmap;
+	sa_family_t family;
+
+	if (!nfs_options2pmap(options, &nfs_pmap, &mnt_pmap))
+		return EX_FAIL;
+
+	/* Skip UMNT call for vers=4 mounts */
+	if (nfs_pmap.pm_vers == 4)
+		return EX_SUCCESS;
+
+	*hostname = nfs_umount_hostname(options, *hostname);
+	if (!*hostname) {
+		nfs_error(_("%s: out of memory"), progname);
+		return EX_FAIL;
+	}
+
+	if (!nfs_mount_proto_family(options, &family))
+		return 0;
+	if (!nfs_lookup(*hostname, family, sap, &salen))
+		/* nfs_lookup reports any errors */
+		return EX_FAIL;
+
+	if (nfs_advise_umount(sap, salen, &mnt_pmap, dirname) == 0)
+		/* nfs_advise_umount reports any errors */
+		return EX_FAIL;
+
+	return EX_SUCCESS;
+}
diff --git a/utils/mount/network.h b/utils/mount/network.h
index 2a3a110..81c6f22 100644
--- a/utils/mount/network.h
+++ b/utils/mount/network.h
@@ -75,4 +75,7 @@ int nfs_advise_umount(const struct sockaddr *, const socklen_t,
 CLIENT *mnt_openclnt(clnt_addr_t *, int *);
 void mnt_closeclnt(CLIENT *, int);
 
+int nfs_umount_do_umnt(struct mount_options *options,
+		       char **hostname, char **dirname);
+
 #endif	/* _NFS_UTILS_MOUNT_NETWORK_H */
diff --git a/utils/mount/nfsumount.c b/utils/mount/nfsumount.c
index 02d40ff..8cd2852 100644
--- a/utils/mount/nfsumount.c
+++ b/utils/mount/nfsumount.c
@@ -37,6 +37,7 @@
 #include "network.h"
 #include "parse_opt.h"
 #include "parse_dev.h"
+#include "utils.h"
 
 #define MOUNTSFILE	"/proc/mounts"
 #define LINELEN		(4096)
@@ -139,113 +140,6 @@ static int del_mtab(const char *spec, const char *node)
 }
 
 /*
- * 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)
-{
-	union {
-		struct sockaddr		sa;
-		struct sockaddr_in	s4;
-		struct sockaddr_in6	s6;
-	} address;
-	struct sockaddr *sap = &address.sa;
-	socklen_t salen = sizeof(address);
-	struct pmap nfs_pmap, mnt_pmap;
-	sa_family_t family;
-
-	if (!nfs_options2pmap(options, &nfs_pmap, &mnt_pmap))
-		return EX_FAIL;
-
-	/* Skip UMNT call for vers=4 mounts */
-	if (nfs_pmap.pm_vers == 4)
-		return EX_SUCCESS;
-
-	*hostname = nfs_umount_hostname(options, *hostname);
-	if (!*hostname) {
-		nfs_error(_("%s: out of memory"), progname);
-		return EX_FAIL;
-	}
-
-	if (!nfs_mount_proto_family(options, &family))
-		return 0;
-	if (!nfs_lookup(*hostname, family, sap, &salen))
-		/* nfs_lookup reports any errors */
-		return EX_FAIL;
-
-	if (nfs_advise_umount(sap, salen, &mnt_pmap, dirname) == 0)
-		/* nfs_advise_umount reports any errors */
-		return EX_FAIL;
-
-	return EX_SUCCESS;
-}
-
-/*
- * 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.
- *
- * These options might also describe the mount port, mount protocol
- * 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 nfs_umount23(const char *devname, char *string)
-{
-	char *hostname, *dirname;
-	struct mount_options *options;
-	int result = EX_FAIL;
-
-	if (!nfs_parse_devname(devname, &hostname, &dirname))
-		return EX_USAGE;
-
-	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);
-
-	free(hostname);
-	free(dirname);
-	return result;
-}
-
-/*
  * Detect NFSv4 mounts.
  *
  * Consult /proc/mounts to determine if the mount point
@@ -340,17 +234,6 @@ static struct option umount_longopts[] =
   { NULL, 0, 0, 0 }
 };
 
-static void umount_usage(void)
-{
-	printf(_("usage: %s dir [-fvnrlh]\n"), progname);
-	printf(_("options:\n\t-f\t\tforce unmount\n"));
-	printf(_("\t-v\tverbose\n"));
-	printf(_("\t-n\tDo not update /etc/mtab\n"));
-	printf(_("\t-r\tremount\n"));
-	printf(_("\t-l\tlazy unmount\n"));
-	printf(_("\t-h\tprint this help\n\n"));
-}
-
 int nfsumount(int argc, char *argv[])
 {
 	int c, ret;
diff --git a/utils/mount/utils.c b/utils/mount/utils.c
new file mode 100644
index 0000000..298db39
--- /dev/null
+++ b/utils/mount/utils.c
@@ -0,0 +1,175 @@
+/*
+ * Copyright (C) 2010 Karel Zak <kzak@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 021110-1307, USA.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "sockaddr.h"
+#include "nfs_mount.h"
+#include "nls.h"
+#include "xcommon.h"
+#include "version.h"
+#include "error.h"
+#include "utils.h"
+#include "mount.h"
+#include "network.h"
+#include "parse_dev.h"
+
+extern int verbose;
+extern char *progname;
+
+/*
+ * Choose the version of the nfs_mount_data structure that is appropriate
+ * for the kernel that is doing the mount.
+ *
+ * NFS_MOUNT_VERSION:		maximum version supported by these sources
+ * nfs_mount_data_version:	maximum version supported by the running kernel
+ */
+int discover_nfs_mount_data_version(int *string_ver)
+{
+	unsigned int kernel_version = linux_version_code();
+	int ver = 0;
+
+	*string_ver = 0;
+
+	if (kernel_version) {
+		if (kernel_version < MAKE_VERSION(2, 1, 32))
+			ver = 1;
+		else if (kernel_version < MAKE_VERSION(2, 2, 18))
+			ver = 3;
+		else if (kernel_version < MAKE_VERSION(2, 3, 0))
+			ver = 4;
+		else if (kernel_version < MAKE_VERSION(2, 3, 99))
+			ver = 3;
+		else if (kernel_version < MAKE_VERSION(2, 6, 3))
+			ver = 4;
+		else
+			ver = 6;
+	}
+	if (ver > NFS_MOUNT_VERSION)
+		ver = NFS_MOUNT_VERSION;
+	else
+		if (kernel_version > MAKE_VERSION(2, 6, 22))
+			(*string_ver)++;
+
+	return ver;
+}
+
+void print_one(char *spec, char *node, char *type, char *opts)
+{
+	if (!verbose)
+		return;
+
+	if (opts)
+		printf(_("%s on %s type %s (%s)\n"), spec, node, type, opts);
+	else
+		printf(_("%s on %s type %s\n"), spec, node, type);
+}
+
+void mount_usage(void)
+{
+	printf(_("usage: %s remotetarget dir [-rvVwfnsih] [-o nfsoptions]\n"),
+		progname);
+	printf(_("options:\n"));
+	printf(_("\t-r\t\tMount file system readonly\n"));
+	printf(_("\t-v\t\tVerbose\n"));
+	printf(_("\t-V\t\tPrint version\n"));
+	printf(_("\t-w\t\tMount file system read-write\n"));
+	printf(_("\t-f\t\tFake mount, do not actually mount\n"));
+	printf(_("\t-n\t\tDo not update /etc/mtab\n"));
+	printf(_("\t-s\t\tTolerate sloppy mount options rather than fail\n"));
+	printf(_("\t-h\t\tPrint this help\n"));
+	printf(_("\tnfsoptions\tRefer to mount.nfs(8) or nfs(5)\n\n"));
+}
+
+void umount_usage(void)
+{
+	printf(_("usage: %s dir [-fvnrlh]\n"), progname);
+	printf(_("options:\n\t-f\t\tforce unmount\n"));
+	printf(_("\t-v\tverbose\n"));
+	printf(_("\t-n\tDo not update /etc/mtab\n"));
+	printf(_("\t-r\tremount\n"));
+	printf(_("\t-l\tlazy unmount\n"));
+	printf(_("\t-h\tprint this help\n\n"));
+}
+
+int chk_mountpoint(const char *mount_point)
+{
+	struct stat sb;
+
+	if (stat(mount_point, &sb) < 0){
+		mount_error(NULL, mount_point, errno);
+		return 1;
+	}
+	if (S_ISDIR(sb.st_mode) == 0){
+		mount_error(NULL, mount_point, ENOTDIR);
+		return 1;
+	}
+	if (access(mount_point, X_OK) < 0) {
+		mount_error(NULL, mount_point, errno);
+		return 1;
+	}
+
+	return 0;
+}
+
+/*
+ * 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.
+ *
+ * These options might also describe the mount port, mount protocol
+ * 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.
+ */
+int nfs_umount23(const char *devname, char *string)
+{
+	char *hostname = NULL, *dirname = NULL;
+	struct mount_options *options;
+	int result = EX_FAIL;
+
+	if (!nfs_parse_devname(devname, &hostname, &dirname))
+		return EX_USAGE;
+
+	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);
+
+	free(hostname);
+	free(dirname);
+	return result;
+}
diff --git a/utils/mount/utils.h b/utils/mount/utils.h
new file mode 100644
index 0000000..3fcd504
--- /dev/null
+++ b/utils/mount/utils.h
@@ -0,0 +1,36 @@
+/*
+ * utils.h -- misc utils for mount and umount
+ *
+ * Copyright (C) 2010 Karel Zak <kzak@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 021110-1307, USA.
+ *
+ */
+
+#ifndef _NFS_UTILS_MOUNT_UTILS_H
+#define _NFS_UTILS_MOUNT_UTILS_H
+
+#include "parse_opt.h"
+
+int discover_nfs_mount_data_version(int *string_ver);
+void print_one(char *spec, char *node, char *type, char *opts);
+void mount_usage(void);
+void umount_usage(void);
+int chk_mountpoint(const char *mount_point);
+
+int nfs_umount23(const char *devname, char *string);
+
+#endif	/* !_NFS_UTILS_MOUNT_UTILS_H */
-- 
1.7.3.4


^ permalink raw reply related	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2011-03-14 13:58 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-02-08 13:45 mount.nfs libmount support Karel Zak
2011-02-08 13:45 ` [PATCH 1/2] mount: move generic functions to utils.c and network.c Karel Zak
2011-02-08 15:43   ` Chuck Lever
2011-02-08 16:08     ` Karel Zak
2011-02-15  0:08       ` Chuck Lever
2011-02-08 13:45 ` [PATCH 2/2] mount: add --enable-libmount-mount Karel Zak
2011-02-08 15:56   ` Chuck Lever
2011-02-09  5:25 ` mount.nfs libmount support NeilBrown
2011-03-03 13:43 mount.nfs libmount support (v2) Karel Zak
2011-03-03 13:43 ` [PATCH 1/2] mount: move generic functions to utils.c and network.c Karel Zak
2011-03-14 13:58 mount.nfs libmount support (v3) Karel Zak
2011-03-14 13:58 ` [PATCH 1/2] mount: move generic functions to utils.c and network.c Karel Zak

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.