All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 1 / 2] Move NFS mount code from util-linux to nfs-utils
@ 2006-06-08 19:10 Amit Gud
  2006-06-09  6:14 ` Neil Brown
  0 siblings, 1 reply; 2+ messages in thread
From: Amit Gud @ 2006-06-08 19:10 UTC (permalink / raw)
  To: Neil Brown; +Cc: nfs, Steve Dickson

[-- Attachment #1: Type: text/plain, Size: 66 bytes --]



AG
-- 
May the source be with you.
http://www.cis.ksu.edu/~gud


[-- Attachment #2: nfsmount-migration-to-nfsutils-v2.patch --]
[-- Type: text/plain, Size: 114635 bytes --]

Adds the mount directory and the code to mount and umount the NFS file system.


Signed-off-by: Amit Gud <agud@redhat.com>
Signed-off-by: Steve Dickson <steved@redhat.com>

---
diff -uprN nfs-utils-1.0.8/utils/Makefile.am nfs-utils-1.0.8-ag/utils/Makefile.am
--- nfs-utils-1.0.8/utils/Makefile.am	2006-03-26 19:30:08.000000000 -0500
+++ nfs-utils-1.0.8-ag/utils/Makefile.am	2006-06-08 11:22:22.096815000 -0400
@@ -17,6 +17,7 @@ endif
 SUBDIRS = \
 	exportfs \
 	lockd \
+	mount \
 	mountd \
 	nfsd \
 	nfsstat \
diff -uprN nfs-utils-1.0.8/utils/mount/Makefile.am nfs-utils-1.0.8-ag/utils/mount/Makefile.am
--- nfs-utils-1.0.8/utils/mount/Makefile.am	1969-12-31 19:00:00.000000000 -0500
+++ nfs-utils-1.0.8-ag/utils/mount/Makefile.am	2006-06-08 11:37:04.260840000 -0400
@@ -0,0 +1,41 @@
+## Process this file with automake to produce Makefile.in
+
+man8_MANS	= mount.nfs.man umount.nfs.man
+
+sbin_PROGRAMS	= mount.nfs
+EXTRA_DIST = nfsmount.x $(man8_MANS)
+mount_nfs_SOURCES = mount.c nfsmount.c nfs4mount.c nfsumount.c \
+		  nfsmount_xdr.c mount_constants.h nfs4_mount.h nfsmount.h \
+		  nfs_mount4.h
+
+mount_nfs_LDADD = ../../support/nfs/libnfs.a
+
+MAINTAINERCLEANFILES = Makefile.in
+
+install-exec-hook:
+	(cd $(DESTDIR)$(sbindir) && \
+	  ln -sf $(sbin_PROGRAMS) mount.nfs4 && \
+	  ln -sf $(sbin_PROGRAMS) umount.nfs && \
+	  ln -sf $(sbin_PROGRAMS) umount.nfs4)
+uninstall-hook:
+	(cd $(DESTDIR)$(sbindir) && \
+	    rm -f mount.nfs4 umount.nfs umount.nfs4)
+
+
+install-man-links:
+	(cd $(DESTDIR)$(man8dir) && \
+	  for m in $(man8_MANS) $(dist_man8_MANS) $(nodist_man8_MANS); do \
+	    inst=`echo $$m | sed -e 's/man$$/8/'`; \
+	    rm -f $(RPCPREFIX)$$inst ; \
+	    $(LN_S) $$inst $(RPCPREFIX)$$inst ; \
+	  ln -sf mount.nfs.8 mount.nfs4.8
+	  ln -sf umount.nfs.8 umount.nfs4.8
+	  done)
+
+uninstall-man-links:
+	(cd $(DESTDIR)$(man8dir) && \
+	  for m in $(man8_MANS) $(dist_man8_MANS) $(nodist_man8_MANS); do \
+	    inst=`echo $$m | sed -e 's/man$$/8/'`; \
+	    rm -f $(RPCPREFIX)$$inst ; \
+	  done)
+
diff -uprN nfs-utils-1.0.8/utils/mount/mount.c nfs-utils-1.0.8-ag/utils/mount/mount.c
--- nfs-utils-1.0.8/utils/mount/mount.c	1969-12-31 19:00:00.000000000 -0500
+++ nfs-utils-1.0.8-ag/utils/mount/mount.c	2006-06-08 11:22:22.107815000 -0400
@@ -0,0 +1,357 @@
+/*
+ * mount.c -- Linux NFS mount
+ *
+ * Copyright (C) 2006 Amit Gud <agud@redhat.com>
+ *
+ * - Basic code and wrapper around mount and umount code of NFS.
+ *   Based on util-linux/mount/mount.c.
+ *
+ * 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.
+ *
+ */
+
+#include <unistd.h>
+#include <sys/types.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/mount.h>
+#include <getopt.h>
+#include <mntent.h>
+
+#include "fstab.h"
+#include "xcommon.h"
+#include "mount_constants.h"
+#include "nfs_paths.h"
+
+#define MTAB_FILE "/etc/mtab"
+
+extern int nfsumount(int, char **);
+extern int nfs4mount(const char *, const char *, int *, char **,
+		char **, int);
+extern int nfsmount(const char *, const char *, int *, char **,
+		char **, int *, int);
+
+char *progname;
+int nomtab;
+int verbose;
+int mounttype;
+
+extern void umount_usage();
+
+static struct option longopts[] = {
+  { "fake", 0, 0, 'f' },
+  { "fork", 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' },
+  { "nfsvers", 1, 0, 't' },
+  { "bind", 0, 0, 128 },
+  { "replace", 0, 0, 129 },
+  { "after", 0, 0, 130 },
+  { "before", 0, 0, 131 },
+  { "over", 0, 0, 132 },
+  { "move", 0, 0, 133 },
+  { "guess-fstype", 1, 0, 134 },
+  { NULL, 0, 0, 0 }
+};
+
+/* Map from -o and fstab option strings to the flag argument to mount(2).  */
+struct opt_map {
+  const char *opt;              /* option name */
+  int  skip;                    /* skip in mtab option string */
+  int  inv;                     /* true if flag value should be inverted */
+  int  mask;                    /* flag mask value */
+};
+
+static const struct opt_map opt_map[] = {
+  { "defaults", 0, 0, 0         },      /* default options */
+  { "ro",       1, 0, MS_RDONLY },      /* read-only */
+  { "rw",       1, 1, MS_RDONLY },      /* read-write */
+  { "exec",     0, 1, MS_NOEXEC },      /* permit execution of binaries */
+  { "noexec",   0, 0, MS_NOEXEC },      /* don't execute binaries */
+  { "suid",     0, 1, MS_NOSUID },      /* honor suid executables */
+  { "nosuid",   0, 0, MS_NOSUID },      /* don't honor suid executables */
+  { "dev",      0, 1, MS_NODEV  },      /* interpret device files  */
+  { "nodev",    0, 0, MS_NODEV  },      /* don't interpret devices */
+  { "sync",     0, 0, MS_SYNCHRONOUS},  /* synchronous I/O */
+  { "async",    0, 1, MS_SYNCHRONOUS},  /* asynchronous I/O */
+  { "dirsync",  0, 0, MS_DIRSYNC},      /* synchronous directory modifications */
+  { "remount",  0, 0, MS_REMOUNT},      /* Alter flags of mounted FS */
+  { "bind",     0, 0, MS_BIND   },      /* Remount part of tree elsewhere */
+  { "rbind",    0, 0, MS_BIND|MS_REC }, /* Idem, plus mounted subtrees */
+
+  /* add new options here */
+#ifdef MS_NOSUB
+  { "sub",      0, 1, MS_NOSUB  },      /* allow submounts */
+  { "nosub",    0, 0, MS_NOSUB  },      /* don't allow submounts */
+#endif
+#ifdef MS_SILENT
+  { "quiet",    0, 0, MS_SILENT    },   /* be quiet  */
+  { "loud",     0, 1, MS_SILENT    },   /* print out messages. */
+#endif
+#ifdef MS_MANDLOCK
+  { "mand",     0, 0, MS_MANDLOCK },    /* Allow mandatory locks on this FS */
+  { "nomand",   0, 1, MS_MANDLOCK },    /* Forbid mandatory locks on this FS */
+#endif
+#ifdef MS_NOATIME
+  { "atime",    0, 1, MS_NOATIME },     /* Update access time */
+  { "noatime",  0, 0, MS_NOATIME },     /* Do not update access time */
+#endif
+#ifdef MS_NODIRATIME
+  { "diratime", 0, 1, MS_NODIRATIME },  /* Update dir access times */
+  { "nodiratime", 0, 0, MS_NODIRATIME },/* Do not update dir access times */
+#endif
+  { NULL,	0, 0, 0		}
+};
+
+/* Try to build a canonical options string.  */
+static char * fix_opts_string (int flags, const char *extra_opts) {
+	const struct opt_map *om;
+	char *new_opts;
+
+	new_opts = xstrdup((flags & MS_RDONLY) ? "ro" : "rw");
+	for (om = opt_map; om->opt != NULL; om++) {
+		if (om->skip)
+			continue;
+		if (om->inv || !om->mask || (flags & om->mask) != om->mask)
+			continue;
+		new_opts = xstrconcat3(new_opts, ",", om->opt);
+		flags &= ~om->mask;
+	}
+	if (extra_opts && *extra_opts) {
+		new_opts = xstrconcat3(new_opts, ",", extra_opts);
+	}
+	return new_opts;
+}
+
+
+int add_mtab(char *fsname, char *mount_point, char *fstype, int flags, char *opts, int freq, int passno)
+{
+	struct mntent ment;
+	int fd;
+	FILE *mtab;
+
+	ment.mnt_fsname = fsname;
+	ment.mnt_dir = mount_point;
+	ment.mnt_type = fstype;
+	ment.mnt_opts = fix_opts_string(flags, opts);
+	ment.mnt_freq = 0;
+	ment.mnt_passno= 0;
+
+	if ((fd = open(MTAB_FILE"~", O_RDWR|O_CREAT|O_EXCL, 0600)) == -1)	{
+		fprintf(stderr, "Can't get "MOUNTED"~ lock file");
+		return 1;
+	}
+        close(fd);
+
+        if ((mtab = setmntent(MTAB_FILE, "a+")) == NULL) {
+		fprintf(stderr, "Can't open " MTAB_FILE);
+		return 1;
+	}
+
+        if (addmntent(mtab, &ment) == 1) {
+		fprintf(stderr, "Can't write mount entry");
+		return 1;
+	}
+
+        if (fchmod(fileno(mtab), 0644) == -1) {
+		fprintf(stderr, "Can't set perms on "MTAB_FILE);
+		return 1;
+	}
+
+	endmntent(mtab);
+
+	if (unlink(MTAB_FILE"~") == -1) {
+		fprintf(stderr, "Can't remove "MTAB_FILE"~");
+		return 1;
+	}
+
+	return 0;
+}
+
+int do_mount_syscall(char *spec, char *node, char *type, int flags, void *data)
+{
+	int ret;
+
+	ret = mount(spec, node, type, flags, data);
+
+	return ret;
+}
+
+void mount_usage()
+{
+	printf("usage: %s remotetarget dir [-rvnh] [-t version] [-o nfsoptions]\n", progname);
+	printf("options:\n\t-r\t\tmount readonly\n");
+	printf("\t-v\t\tverbose\n");
+	printf("\t-n\t\tno mtab updation\n");
+	printf("\t-h\t\tprint this help\n");
+	printf("\tversion\t\tnfs4 - NFS version 4, nfs - older NFS version supported\n");
+	printf("\tnfsoptions\tRefer mount.nfs(8) or nfs(5)\n\n");
+}
+
+static inline void
+parse_opt(const char *opt, int *mask, char *extra_opts, int len) {
+	const struct opt_map *om;
+
+	for (om = opt_map; om->opt != NULL; om++) {
+		if (!strcmp (opt, om->opt)) {
+			if (om->inv)
+				*mask &= ~om->mask;
+			else
+				*mask |= om->mask;
+			return;
+		}
+	}
+
+	len -= strlen(extra_opts);
+
+	if (*extra_opts && --len > 0)
+		strcat(extra_opts, ",");
+
+	if ((len -= strlen(opt)) > 0)
+		strcat(extra_opts, opt);
+}
+
+/* Take -o options list and compute 4th and 5th args to mount(2).  flags
+   gets the standard options (indicated by bits) and extra_opts all the rest */
+static void parse_opts (const char *options, int *flags, char **extra_opts)
+{
+	if (options != NULL) {
+		char *opts = xstrdup(options);
+		char *opt;
+		int len = strlen(opts) + 20;
+
+		*extra_opts = xmalloc(len);
+		**extra_opts = '\0';
+
+		for (opt = strtok(opts, ","); opt; opt = strtok(NULL, ","))
+			parse_opt(opt, flags, *extra_opts, len);
+
+		free(opts);
+	}
+
+}
+
+int main(int argc, char *argv[])
+{
+	int c, flags = 0, nfs_mount_vers = 0, mnt_err = 1;
+	char *spec, *mount_point, *extra_opts = NULL;
+	char *mount_opts = NULL, *p;
+
+	progname = argv[0];
+	if ((p = strrchr(progname, '/')) != NULL)
+		progname = p+1;
+
+	if (getuid() != 0) {
+		printf("%s: only root can do that.\n", progname);
+		exit(1);
+	}
+
+	if(!strncmp(progname, "umount", strlen("umount"))) {
+		if(argc < 2) {
+			umount_usage();
+			exit(1);
+		}
+		return(nfsumount(argc, argv));
+	}
+
+	if (argc < 3 || argv[1][0] == '-' || argv[2][0] == '-') {
+		mount_usage();
+		exit(1);
+	}
+
+	spec = canonicalize(argv[1]);
+	mount_point = canonicalize(argv[2]);
+
+	argv += 2;
+	argc -= 2;
+
+	while ((c = getopt_long (argc, argv, "rt:hvno:",
+				longopts, NULL)) != -1) {
+		switch (c) {
+		case 'r':
+			flags |= MS_RDONLY;
+			break;
+		case 't':
+			nfs_mount_vers = (strncmp(optarg, "nfs4", 4)) ? 3 : 4;
+			break;
+		case 'v':
+			++verbose;
+			break;
+		case 'n':
+			++nomtab;
+			break;
+		case 'o':              /* specify mount options */
+			if (mount_opts)
+				mount_opts = xstrconcat3(mount_opts, ",", optarg);
+			else
+				mount_opts = xstrdup(optarg);
+			break;
+		case 128: /* bind */
+			mounttype = MS_BIND;
+			break;
+		case 129: /* replace */
+			mounttype = MS_REPLACE;
+			break;
+		case 130: /* after */
+			mounttype = MS_AFTER;
+			break;
+		case 131: /* before */
+			mounttype = MS_BEFORE;
+			break;
+		case 132: /* over */
+			mounttype = MS_OVER;
+			break;
+		case 133: /* move */
+			mounttype = MS_MOVE;
+			break;
+		case 135: /* rbind */
+			mounttype = MS_BIND | MS_REC;
+			break;
+		case 'h':
+		default:
+			mount_usage();
+			exit(1);
+		}
+	}
+
+
+	parse_opts(mount_opts, &flags, &extra_opts);
+
+	if (!strcmp(progname, "mount.nfs4") || nfs_mount_vers == 4) {
+		nfs_mount_vers = 4;
+		mnt_err = nfs4mount(spec, mount_point, &flags, &extra_opts, &mount_opts, 0);
+	}
+
+	/* fall back to v3 if v4 didn't work */
+	if (mnt_err && errno != EBUSY && errno != ENOENT) {
+		nfs_mount_vers = 3;
+		mnt_err = nfsmount(spec, mount_point, &flags, &extra_opts, &mount_opts, &nfs_mount_vers, 0);
+	}
+
+	if (!mnt_err) {
+		do_mount_syscall(spec, mount_point, nfs_mount_vers == 4 ? "nfs4" : "nfs", flags, mount_opts);
+		if(!nomtab)
+			add_mtab(spec, mount_point, nfs_mount_vers == 4 ? "nfs4" : "nfs",
+				 flags, extra_opts, 0, 0);
+	}
+
+	return 0;
+}
+
diff -uprN nfs-utils-1.0.8/utils/mount/mount_constants.h nfs-utils-1.0.8-ag/utils/mount/mount_constants.h
--- nfs-utils-1.0.8/utils/mount/mount_constants.h	1969-12-31 19:00:00.000000000 -0500
+++ nfs-utils-1.0.8-ag/utils/mount/mount_constants.h	2006-06-08 11:22:22.113815000 -0400
@@ -0,0 +1,74 @@
+#ifndef _NFS_MOUNT_CONSTANTS_H
+#define _NFS_MOUNT_CONSTANTS_H
+
+#ifndef MS_RDONLY
+#define MS_RDONLY	 1	/* Mount read-only */
+#endif
+#ifndef MS_NOSUID
+#define MS_NOSUID	 2	/* Ignore suid and sgid bits */
+#endif
+#ifndef MS_NODEV
+#define MS_NODEV	 4	/* Disallow access to device special files */
+#endif
+#ifndef MS_NOEXEC
+#define MS_NOEXEC	 8	/* Disallow program execution */
+#endif
+#ifndef MS_SYNCHRONOUS
+#define MS_SYNCHRONOUS	16	/* Writes are synced at once */
+#endif
+#ifndef MS_REMOUNT
+#define MS_REMOUNT	32	/* Alter flags of a mounted FS */
+#endif
+#ifndef MS_MANDLOCK
+#define MS_MANDLOCK	64	/* Allow mandatory locks on an FS */
+#endif
+#ifndef MS_DIRSYNC
+#define MS_DIRSYNC	128	/* Directory modifications are synchronous */
+#endif
+
+#ifndef MS_ACTION_MASK
+#define	MS_ACTION_MASK	0x380
+/* Remount, but new filesystem may be different from old. Atomic
+   (i.e. there is no interval when nothing is mounted at the mountpoint).
+   If new fs differs from the old one and old is busy - -EBUSY. */
+#define	MS_REPLACE	0x080	/* 128 */
+/* After, Before: as soon as we get unions these will add a new member
+   in the end or beginning of the chain. Fail if there is a stack
+   on the mountpoint. */
+#define	MS_AFTER	0x100	/* 256 */
+#define	MS_BEFORE	0x180
+/* Over: if nothing mounted on a mountpoint - same as if none of these
+flags had been set; if we have a union with more than one element - fail;
+if we have a stack or plain mount - mount atop of it, forming a stack. */
+#define	MS_OVER		0x200	/* 512 */
+#endif
+#ifndef MS_NOATIME
+#define MS_NOATIME	0x400	/* 1024: Do not update access times. */
+#endif
+#ifndef MS_NODIRATIME
+#define MS_NODIRATIME   0x800	/* 2048: Don't update directory access times */
+#endif
+#ifndef MS_BIND
+#define	MS_BIND		0x1000	/* 4096: Mount existing tree also elsewhere */
+#endif
+#ifndef MS_MOVE
+#define MS_MOVE		0x2000	/* 8192: Atomically move tree */
+#endif
+#ifndef MS_REC
+#define MS_REC		0x4000	/* 16384: Recursive loopback */
+#endif
+#ifndef MS_VERBOSE
+#define MS_VERBOSE	0x8000	/* 32768 */
+#endif
+/*
+ * Magic mount flag number. Had to be or-ed to the flag values.
+ */
+#ifndef MS_MGC_VAL
+#define MS_MGC_VAL 0xC0ED0000	/* magic flag number to indicate "new" flags */
+#endif
+#ifndef MS_MGC_MSK
+#define MS_MGC_MSK 0xffff0000	/* magic flag number mask */
+#endif
+
+#endif /* _NFS_MOUNT_CONSTANTS_H */
+
diff -uprN nfs-utils-1.0.8/utils/mount/mount.nfs.man nfs-utils-1.0.8-ag/utils/mount/mount.nfs.man
--- nfs-utils-1.0.8/utils/mount/mount.nfs.man	1969-12-31 19:00:00.000000000 -0500
+++ nfs-utils-1.0.8-ag/utils/mount/mount.nfs.man	2006-06-08 11:22:22.118815000 -0400
@@ -0,0 +1,87 @@
+.\"@(#)mount.nfs.8"
+.TH MOUNT.NFS 8 "5 Jun 2006"
+.SH NAME
+mount.nfs, mount.nfs4 \- mount a Network File System
+.SH SYNOPSIS
+.BI "mount.nfs" " remotetarget dir" " [\-rvnh ] [\-t " version "] [\-o " options "]
+.SH DESCRIPTION
+.BR mount.nfs
+is a part of 
+.BR nfs (5)
+utilities package, which provides NFS client functionality.
+
+.BR mount.nfs 
+is meant to be used by the
+.BR mount (8)
+command for mounting NFS shares. This subcommand, however, can also be used as a standalone command with limited functionality.
+
+.BR mount.nfs 
+is used for mounting NFSv4 file system, while 
+.BR mount.nfs 
+is used to mount NFS file systems with older versions.
+.I remotetarget 
+is a server share usually in the form of 
+.BR servername:/path/to/share.
+.I dir 
+is the directory on which the file system is to be mounted.
+
+.SH OPTIONS
+.TP
+.BI "\-r"
+Mount file system readonly.
+.TP
+.BI "\-v"
+Be verbose.
+.TP
+.BI "\-n"
+Make no updation to mtab. By default, an entry is created in 
+.I /etc/mtab 
+for every mounted file system. Use this option to skip making an entry.
+.TP
+.BI "\-h"
+Print help message.
+.TP
+.BI "version"
+Specify NFS file system version. Either
+.BR nfs4 
+or 
+.BR nfs.
+By default 
+.BR mount.nfs4 
+takes version 4, and 
+.BR mount.nfs 
+takes any supported older version.
+.TP
+.BI "nfsoptions"
+Refer 
+.BR nfs(5)
+or
+.BR mount(8) 
+manual pages.
+
+.SH NOTE
+For further information please refer 
+.BR nfs (5)
+and
+.BR mount (8)
+manual pages.
+
+.SH FILES
+.TP 18n
+.I /etc/fstab
+file system table
+.TP
+.I /etc/mtab
+table of mounted file systems
+
+.PD
+.SH "SEE ALSO"
+.BR nfs (5),
+.BR mount (8),
+
+.SH BUGS
+Please notify current developers of NFS of any bugs in the current software or mail nfs@lists.sourceforge.net
+
+.SH "AUTHOR"
+Amit Gud <agud@redhat.com>
+
diff -uprN nfs-utils-1.0.8/utils/mount/nfs4mount.c nfs-utils-1.0.8-ag/utils/mount/nfs4mount.c
--- nfs-utils-1.0.8/utils/mount/nfs4mount.c	1969-12-31 19:00:00.000000000 -0500
+++ nfs-utils-1.0.8-ag/utils/mount/nfs4mount.c	2006-06-08 11:27:25.318390000 -0400
@@ -0,0 +1,450 @@
+/*
+ * nfs4mount.c -- Linux NFS mount
+ * Copyright (C) 2002 Trond Myklebust <trond.myklebust@fys.uio.no>
+ *
+ * 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.
+ *
+ * Note: this file based on the original nfsmount.c
+ *
+ * 2006-06-06 Amit Gud <agud@redhat.com>
+ * - Moved to nfs-utils/utils/mount from util-linux/mount.
+ */
+
+#include <linux/posix_types.h>
+#include <asm/posix_types.h>
+#undef __FD_CLR
+#undef __FD_SET
+#undef __FD_ISSET
+#undef __FD_ZERO
+
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <netdb.h>
+#include <time.h>
+#include <sys/stat.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <rpc/auth.h>
+#include <rpc/rpc.h>
+#ifdef HAVE_RPCSVC_NFS_PROT_H
+#include <rpcsvc/nfs_prot.h>
+#else
+#include <linux/nfs.h>
+#define nfsstat nfs_stat
+#endif
+
+#include "nfs4_mount.h"
+#include "nls.h"
+#include "conn.h"
+#include "xcommon.h"
+
+#if defined(VAR_LOCK_DIR)
+#define DEFAULT_DIR VAR_LOCK_DIR
+#else
+#define DEFAULT_DIR "/var/lock/subsys"
+#endif
+
+extern void mount_errors(char *, int , int );
+extern int verbose;
+
+char *IDMAPLCK = DEFAULT_DIR "/rpcidmapd";
+#define idmapd_check() do { \
+	if (access(IDMAPLCK, F_OK)) { \
+		printf(_("Warning: rpc.idmapd appears not to be running.\n" \
+			"         All uids will be mapped to the nobody uid.\n")); \
+	} \
+} while(0);
+
+char *GSSDLCK = DEFAULT_DIR "/rpcgssd";
+#define gssd_check() do { \
+		if (access(GSSDLCK, F_OK)) { \
+			printf(_("Warning: rpc.gssd appears not to be running.\n")); \
+		} \
+} while(0); 
+
+#ifndef NFS_PORT
+#define NFS_PORT 2049
+#endif
+
+struct {
+	char    *flavour;
+	int     fnum;
+} flav_map[] = {
+	{ "krb5",	RPC_AUTH_GSS_KRB5	},
+	{ "krb5i",	RPC_AUTH_GSS_KRB5I	},
+	{ "krb5p",	RPC_AUTH_GSS_KRB5P	},
+	{ "lipkey",	RPC_AUTH_GSS_LKEY	},
+	{ "lipkey-i",	RPC_AUTH_GSS_LKEYI	},
+	{ "lipkey-p",	RPC_AUTH_GSS_LKEYP	},
+	{ "spkm3",	RPC_AUTH_GSS_SPKM	},
+	{ "spkm3i",	RPC_AUTH_GSS_SPKMI	},
+	{ "spkm3p",	RPC_AUTH_GSS_SPKMP	},
+	{ "unix",	AUTH_UNIX		},
+	{ "sys",	AUTH_SYS		},
+	{ "null",	AUTH_NULL		},
+	{ "none",	AUTH_NONE		},
+};
+
+#define FMAPSIZE		(sizeof(flav_map)/sizeof(flav_map[0]))
+#define MAX_USER_FLAVOUR	16
+
+static int parse_sec(char *sec, int *pseudoflavour)
+{
+	int i, num_flavour = 0;
+
+	for (sec = strtok(sec, ":"); sec; sec = strtok(NULL, ":")) {
+		if (num_flavour >= MAX_USER_FLAVOUR) {
+			fprintf(stderr,
+				_("mount: maximum number of security flavors "
+				  "exceeded\n"));
+			return 0;
+		}
+		for (i = 0; i < FMAPSIZE; i++) {
+			if (strcmp(sec, flav_map[i].flavour) == 0) {
+				pseudoflavour[num_flavour++] = flav_map[i].fnum;
+				break;
+			}
+		}
+		if (i == FMAPSIZE) {
+			fprintf(stderr,
+				_("mount: unknown security type %s\n"), sec);
+			return 0;
+		}
+	}
+	if (!num_flavour)
+		fprintf(stderr,
+			_("mount: no security flavors passed to sec= option\n"));
+	return num_flavour;
+}
+
+static int parse_devname(char *hostdir, char **hostname, char **dirname)
+{
+	char *s;
+
+	if (!(s = strchr(hostdir, ':'))) {
+		fprintf(stderr,
+			_("mount: "
+			  "directory to mount not in host:dir format\n"));
+		return -1;
+	}
+	*hostname = hostdir;
+	*dirname = s + 1;
+	*s = '\0';
+	/* Ignore all but first hostname in replicated mounts
+	   until they can be fully supported. (mack@sgi.com) */
+	if ((s = strchr(hostdir, ','))) {
+		*s = '\0';
+		fprintf(stderr,
+			_("mount: warning: "
+			  "multiple hostnames not supported\n"));
+	}
+	return 0;
+}
+
+static int fill_ipv4_sockaddr(const char *hostname, struct sockaddr_in *addr)
+{
+	struct hostent *hp;
+	addr->sin_family = AF_INET;
+
+	if (inet_aton(hostname, &addr->sin_addr))
+		return 0;
+	if ((hp = gethostbyname(hostname)) == NULL) {
+		fprintf(stderr, _("mount: can't get address for %s\n"),
+			hostname);
+		return -1;
+	}
+	if (hp->h_length > sizeof(struct in_addr)) {
+		fprintf(stderr,
+			_("mount: got bad hp->h_length\n"));
+		hp->h_length = sizeof(struct in_addr);
+	}
+	memcpy(&addr->sin_addr, hp->h_addr, hp->h_length);
+	return 0;
+}
+
+static int get_my_ipv4addr(char *ip_addr, int len)
+{
+	char myname[1024];
+	struct sockaddr_in myaddr;
+
+	if (gethostname(myname, sizeof(myname))) {
+		fprintf(stderr, _("mount: can't determine client address\n"));
+		return -1;
+	}
+	if (fill_ipv4_sockaddr(myname, &myaddr))
+		return -1;
+	snprintf(ip_addr, len, "%s", inet_ntoa(myaddr.sin_addr));
+	ip_addr[len-1] = '\0';
+	return 0;
+}
+
+int nfs4mount(const char *spec, const char *node, int *flags,
+	      char **extra_opts, char **mount_opts,
+	      int running_bg)
+{
+	static struct nfs4_mount_data data;
+	static char hostdir[1024];
+	static char ip_addr[16] = "127.0.0.1";
+	static struct sockaddr_in server_addr;
+	static int pseudoflavour[MAX_USER_FLAVOUR];
+	int num_flavour = 0;
+
+	char *hostname, *dirname, *old_opts;
+	char new_opts[1024];
+	char *opt, *opteq;
+	char *s;
+	int val;
+	int bg, soft, intr;
+	int nocto, noac;
+	int retry;
+	int retval;
+	time_t timeout, t;
+
+	retval = EX_FAIL;
+	if (strlen(spec) >= sizeof(hostdir)) {
+		fprintf(stderr, _("mount: "
+				  "excessively long host:dir argument\n"));
+		goto fail;
+	}
+	strcpy(hostdir, spec);
+	if (parse_devname(hostdir, &hostname, &dirname))
+		goto fail;
+
+	if (fill_ipv4_sockaddr(hostname, &server_addr))
+		goto fail;
+	if (get_my_ipv4addr(ip_addr, sizeof(ip_addr)))
+		goto fail;
+
+	/* add IP address to mtab options for use when unmounting */
+	s = inet_ntoa(server_addr.sin_addr);
+	old_opts = *extra_opts;
+	if (!old_opts)
+		old_opts = "";
+	if (strlen(old_opts) + strlen(s) + 10 >= sizeof(new_opts)) {
+		fprintf(stderr, _("mount: "
+				  "excessively long option argument\n"));
+		goto fail;
+	}
+	snprintf(new_opts, sizeof(new_opts), "%s%saddr=%s",
+		 old_opts, *old_opts ? "," : "", s);
+	*extra_opts = xstrdup(new_opts);
+
+	/* Set default options.
+	 * rsize/wsize and timeo are left 0 in order to
+	 * let the kernel decide.
+	 */
+	memset(&data, 0, sizeof(data));
+	data.retrans	= 3;
+	data.acregmin	= 3;
+	data.acregmax	= 60;
+	data.acdirmin	= 30;
+	data.acdirmax	= 60;
+	data.proto	= IPPROTO_TCP;
+
+	bg = 0;
+	soft = 0;
+	intr = NFS4_MOUNT_INTR;
+	nocto = 0;
+	noac = 0;
+	retry = 10000;		/* 10000 minutes ~ 1 week */
+
+	/*
+	 * NFSv4 specifies that the default port should be 2049
+	 */
+	server_addr.sin_port = htons(NFS_PORT);
+
+	/* parse options */
+
+	for (opt = strtok(old_opts, ","); opt; opt = strtok(NULL, ",")) {
+		if ((opteq = strchr(opt, '='))) {
+			val = atoi(opteq + 1);	
+			*opteq = '\0';
+			if (!strcmp(opt, "rsize"))
+				data.rsize = val;
+			else if (!strcmp(opt, "wsize"))
+				data.wsize = val;
+			else if (!strcmp(opt, "timeo"))
+				data.timeo = val;
+			else if (!strcmp(opt, "retrans"))
+				data.retrans = val;
+			else if (!strcmp(opt, "acregmin"))
+				data.acregmin = val;
+			else if (!strcmp(opt, "acregmax"))
+				data.acregmax = val;
+			else if (!strcmp(opt, "acdirmin"))
+				data.acdirmin = val;
+			else if (!strcmp(opt, "acdirmax"))
+				data.acdirmax = val;
+			else if (!strcmp(opt, "actimeo")) {
+				data.acregmin = val;
+				data.acregmax = val;
+				data.acdirmin = val;
+				data.acdirmax = val;
+			}
+			else if (!strcmp(opt, "retry"))
+				retry = val;
+			else if (!strcmp(opt, "port"))
+				server_addr.sin_port = htons(val);
+			else if (!strcmp(opt, "proto")) {
+				if (!strncmp(opteq+1, "tcp", 3))
+					data.proto = IPPROTO_TCP;
+				else if (!strncmp(opteq+1, "udp", 3))
+					data.proto = IPPROTO_UDP;
+				else
+					printf(_("Warning: Unrecognized proto= option.\n"));
+			} else if (!strcmp(opt, "clientaddr")) {
+				if (strlen(opteq+1) >= sizeof(ip_addr))
+					printf(_("Invalid client address %s"),
+								opteq+1);
+				strncpy(ip_addr,opteq+1, sizeof(ip_addr));
+				ip_addr[sizeof(ip_addr)-1] = '\0';
+			} else if (!strcmp(opt, "sec")) {
+				num_flavour = parse_sec(opteq+1, pseudoflavour);
+				if (!num_flavour)
+					goto fail;
+			} else if (!strcmp(opt, "addr")) {
+				/* ignore */;
+			} else {
+				printf(_("unknown nfs mount parameter: "
+					 "%s=%d\n"), opt, val);
+				goto fail;
+			}
+		} else {
+			val = 1;
+			if (!strncmp(opt, "no", 2)) {
+				val = 0;
+				opt += 2;
+			}
+			if (!strcmp(opt, "bg")) 
+				bg = val;
+			else if (!strcmp(opt, "fg")) 
+				bg = !val;
+			else if (!strcmp(opt, "soft"))
+				soft = val;
+			else if (!strcmp(opt, "hard"))
+				soft = !val;
+			else if (!strcmp(opt, "intr"))
+				intr = val;
+			else if (!strcmp(opt, "cto"))
+				nocto = !val;
+			else if (!strcmp(opt, "ac"))
+				noac = !val;
+			else {
+				printf(_("unknown nfs mount option: "
+					 "%s%s\n"), val ? "" : "no", opt);
+				goto fail;
+			}
+		}
+	}
+
+	data.flags = (soft ? NFS4_MOUNT_SOFT : 0)
+		| (intr ? NFS4_MOUNT_INTR : 0)
+		| (nocto ? NFS4_MOUNT_NOCTO : 0)
+		| (noac ? NFS4_MOUNT_NOAC : 0);
+
+	/*
+	 * Give a warning if the rpc.idmapd daemon is not running
+	 */
+	idmapd_check();
+
+	if (num_flavour == 0)
+		pseudoflavour[num_flavour++] = AUTH_UNIX;
+	else {
+		/*
+		 * ditto with rpc.gssd daemon
+		 */
+		gssd_check();
+	}
+	data.auth_flavourlen = num_flavour;
+	data.auth_flavours = pseudoflavour;
+
+	data.client_addr.data = ip_addr;
+	data.client_addr.len = strlen(ip_addr);
+
+	data.mnt_path.data = dirname;
+	data.mnt_path.len = strlen(dirname);
+
+	data.hostname.data = hostname;
+	data.hostname.len = strlen(hostname);
+	data.host_addr = (struct sockaddr *)&server_addr;
+	data.host_addrlen = sizeof(server_addr);
+
+#ifdef NFS_MOUNT_DEBUG
+	printf("rsize = %d, wsize = %d, timeo = %d, retrans = %d\n",
+	       data.rsize, data.wsize, data.timeo, data.retrans);
+	printf("acreg (min, max) = (%d, %d), acdir (min, max) = (%d, %d)\n",
+	       data.acregmin, data.acregmax, data.acdirmin, data.acdirmax);
+	printf("port = %d, bg = %d, retry = %d, flags = %.8x\n",
+	       ntohs(server_addr.sin_port), bg, retry, data.flags);
+	printf("soft = %d, intr = %d, nocto = %d, noac = %d\n",
+	       (data.flags & NFS4_MOUNT_SOFT) != 0,
+	       (data.flags & NFS4_MOUNT_INTR) != 0,
+	       (data.flags & NFS4_MOUNT_NOCTO) != 0,
+	       (data.flags & NFS4_MOUNT_NOAC) != 0);
+
+	if (num_flavour > 0) {
+		int pf_cnt, i;
+
+		printf("sec = ");
+		for (pf_cnt = 0; pf_cnt < num_flavour; pf_cnt++) {
+			for (i = 0; i < FMAPSIZE; i++) {
+				if (flav_map[i].fnum == pseudoflavour[pf_cnt]) {
+					printf("%s", flav_map[i].flavour);
+					break;
+				}
+			}
+			printf("%s", (pf_cnt < num_flavour-1) ? ":" : "\n");
+		}
+	}
+	printf("proto = %s\n", (data.proto == IPPROTO_TCP) ? "tcp" : "udp");
+#endif
+
+	timeout = time(NULL) + 60 * retry;
+	data.version = NFS4_MOUNT_VERSION;
+	for (;;) {
+		if (verbose) {
+			fprintf(stderr, 
+				"mount: pinging: prog %d vers %d prot %s port %d\n", 
+				NFS_PROGRAM, 4, data.proto == IPPROTO_UDP ? "udp" : "tcp", 
+				ntohs(server_addr.sin_port));
+		}
+		clnt_ping(&server_addr, NFS_PROGRAM, 4, data.proto);
+		if (rpc_createerr.cf_stat == RPC_SUCCESS)
+			break;
+
+		switch(rpc_createerr.cf_stat){
+		case RPC_TIMEDOUT:
+			break;
+		case RPC_SYSTEMERROR:
+			if (errno == ETIMEDOUT)
+				break;
+		default:
+			mount_errors(hostname, 0, bg);
+			goto fail;
+		}
+		t = time(NULL);
+		if (t >= timeout) {
+			mount_errors(hostname, 0, bg);
+			goto fail;
+		}
+		mount_errors(hostname, 1, bg);
+		continue;
+	}
+
+	*mount_opts = (char *) &data;
+	/* clean up */
+	return 0;
+
+fail:
+	return retval;
+}
diff -uprN nfs-utils-1.0.8/utils/mount/nfs4_mount.h nfs-utils-1.0.8-ag/utils/mount/nfs4_mount.h
--- nfs-utils-1.0.8/utils/mount/nfs4_mount.h	1969-12-31 19:00:00.000000000 -0500
+++ nfs-utils-1.0.8-ag/utils/mount/nfs4_mount.h	2006-06-08 11:22:22.130816000 -0400
@@ -0,0 +1,85 @@
+#ifndef _LINUX_NFS4_MOUNT_H
+#define _LINUX_NFS4_MOUNT_H
+
+/*
+ *  linux/include/linux/nfs4_mount.h
+ *
+ *  Copyright (C) 2002  Trond Myklebust
+ *
+ *  structure passed from user-space to kernel-space during an nfsv4 mount
+ */
+
+/*
+ * WARNING!  Do not delete or change the order of these fields.  If
+ * a new field is required then add it to the end.  The version field
+ * tracks which fields are present.  This will ensure some measure of
+ * mount-to-kernel version compatibility.  Some of these aren't used yet
+ * but here they are anyway.
+ */
+#define NFS4_MOUNT_VERSION	1
+
+struct nfs_string {
+	unsigned int len;
+	const char* data;
+};
+
+struct nfs4_mount_data {
+	int version;				/* 1 */
+	int flags;				/* 1 */
+	int rsize;				/* 1 */
+	int wsize;				/* 1 */
+	int timeo;				/* 1 */
+	int retrans;				/* 1 */
+	int acregmin;				/* 1 */
+	int acregmax;				/* 1 */
+	int acdirmin;				/* 1 */
+	int acdirmax;				/* 1 */
+
+	/* see the definition of 'struct clientaddr4' in RFC3010 */
+	struct nfs_string client_addr;		/* 1 */
+
+	/* Mount path */
+	struct nfs_string mnt_path;		/* 1 */
+
+	/* Server details */
+	struct nfs_string hostname;		/* 1 */
+	/* Server IP address */
+	unsigned int host_addrlen;		/* 1 */
+	struct sockaddr* host_addr;		/* 1 */
+
+	/* Transport protocol to use */
+	int proto;				/* 1 */
+
+	/* Pseudo-flavours to use for authentication. See RFC2623 */
+	int auth_flavourlen;			/* 1 */
+	int *auth_flavours;			/* 1 */
+};
+
+/* bits in the flags field */
+/* Note: the fields that correspond to existing NFSv2/v3 mount options
+ * 	 should mirror the values from include/linux/nfs_mount.h
+ */
+
+#define NFS4_MOUNT_SOFT		0x0001	/* 1 */
+#define NFS4_MOUNT_INTR		0x0002	/* 1 */
+#define NFS4_MOUNT_NOCTO	0x0010	/* 1 */
+#define NFS4_MOUNT_NOAC		0x0020	/* 1 */
+#define NFS4_MOUNT_STRICTLOCK	0x1000	/* 1 */
+#define NFS4_MOUNT_FLAGMASK	0xFFFF
+
+/* pseudoflavors: */
+
+#define RPC_AUTH_GSS_KRB5       390003
+#define RPC_AUTH_GSS_KRB5I      390004
+#define RPC_AUTH_GSS_KRB5P      390005
+#define RPC_AUTH_GSS_LKEY       390006
+#define RPC_AUTH_GSS_LKEYI      390007
+#define RPC_AUTH_GSS_LKEYP      390008
+#define RPC_AUTH_GSS_SPKM       390009
+#define RPC_AUTH_GSS_SPKMI      390010
+#define RPC_AUTH_GSS_SPKMP      390011
+
+int nfs4mount(const char *, const char *, int *, char **,
+	char **, int);
+
+#endif
diff -uprN nfs-utils-1.0.8/utils/mount/nfsmount.c nfs-utils-1.0.8-ag/utils/mount/nfsmount.c
--- nfs-utils-1.0.8/utils/mount/nfsmount.c	1969-12-31 19:00:00.000000000 -0500
+++ nfs-utils-1.0.8-ag/utils/mount/nfsmount.c	2006-06-08 11:26:54.595616000 -0400
@@ -0,0 +1,1245 @@
+/*
+ * nfsmount.c -- Linux NFS mount
+ * Copyright (C) 1993 Rick Sladkey <jrs@world.std.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.
+ *
+ * Wed Feb  8 12:51:48 1995, biro@yggdrasil.com (Ross Biro): allow all port
+ * numbers to be specified on the command line.
+ *
+ * Fri, 8 Mar 1996 18:01:39, Swen Thuemmler <swen@uni-paderborn.de>:
+ * Omit the call to connect() for Linux version 1.3.11 or later.
+ *
+ * Wed Oct  1 23:55:28 1997: Dick Streefland <dick_streefland@tasking.com>
+ * Implemented the "bg", "fg" and "retry" mount options for NFS.
+ *
+ * 1999-02-22 Arkadiusz Mi¶kiewicz <misiek@pld.ORG.PL>
+ * - added Native Language Support
+ * 
+ * Modified by Olaf Kirch and Trond Myklebust for new NFS code,
+ * plus NFSv3 stuff.
+ *
+ * 2006-06-06 Amit Gud <agud@redhat.com>
+ * - Moved with modifcations to nfs-utils/utils/mount from util-linux/mount.
+ */
+
+/*
+ * nfsmount.c,v 1.1.1.1 1993/11/18 08:40:51 jrs Exp
+ */
+
+#include <ctype.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <netdb.h>
+#include <time.h>
+#include <rpc/rpc.h>
+#include <rpc/pmap_prot.h>
+#include <rpc/pmap_clnt.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/utsname.h>
+#include <sys/stat.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <mntent.h>
+#include <paths.h>
+#include <syslog.h>
+
+#include "conn.h"
+#include "xcommon.h"
+#include "nfsmount.h"
+#include "mount_constants.h"
+#include "nfs_mount.h"
+#include "nls.h"
+
+#ifdef HAVE_RPCSVC_NFS_PROT_H
+#include <rpcsvc/nfs_prot.h>
+#else
+#include <linux/nfs.h>
+#define nfsstat nfs_stat
+#endif
+
+#ifndef NFS_PORT
+#define NFS_PORT 2049
+#endif
+#ifndef NFS_FHSIZE
+#define NFS_FHSIZE 32
+#endif
+
+extern int nfs_call_umount(clnt_addr_t *, dirpath *);
+extern void mount_errors(char *, int , int );
+
+static char *nfs_strerror(int stat);
+
+#define MAKE_VERSION(p,q,r)	(65536*(p) + 256*(q) + (r))
+#define MAX_NFSPROT ((nfs_mount_version >= 4) ? 3 : 2)
+#define MAX_MNTPROT ((nfs_mount_version >= 4) ? 3 : 2)
+#define HAVE_RELIABLE_TCP (nfs_mount_version >= 4)
+
+#ifndef HAVE_INET_ATON
+#define inet_aton(a,b) (0)
+#endif
+
+typedef dirpath mnt2arg_t;
+typedef dirpath mnt3arg_t;
+typedef dirpath mntarg_t;
+
+typedef struct fhstatus  mnt2res_t;
+typedef struct mountres3 mnt3res_t;
+typedef union {
+	mnt2res_t nfsv2;
+	mnt3res_t nfsv3;
+} mntres_t;
+
+static char errbuf[BUFSIZ];
+static char *erreob = &errbuf[BUFSIZ];
+extern int verbose;
+
+/* Convert RPC errors into strings */
+int rpc_strerror(int);
+int rpc_strerror(int spos)
+{
+	int cf_stat = rpc_createerr.cf_stat; 
+	int pos=0, cf_errno = rpc_createerr.cf_error.re_errno;
+	char *ptr, *estr = clnt_sperrno(cf_stat);
+	char *tmp;
+
+	if (estr) {
+		if ((ptr = index(estr, ':')))
+			estr = ++ptr;
+
+		tmp = &errbuf[spos];
+		if (cf_stat == RPC_SYSTEMERROR)
+			pos = snprintf(tmp, (erreob - tmp), 
+				"System Error: %s", strerror(cf_errno));
+		else
+			pos = snprintf(tmp, (erreob - tmp), "RPC Error:%s", estr);
+	}
+	return (pos);
+}
+void mount_errors(char *, int, int);
+void mount_errors(char *server, int will_retry, int bg)
+{
+	int pos = 0;
+	char *tmp;
+	static int onlyonce = 0;
+
+	tmp = &errbuf[pos];
+	if (bg) 
+		pos = snprintf(tmp, (erreob - tmp), 
+			"mount to NFS server '%s' failed: ", server);
+	else
+		pos = snprintf(tmp, (erreob - tmp), 
+			"mount: mount to NFS server '%s' failed: ", server);
+
+	tmp = &errbuf[pos];
+	if (rpc_createerr.cf_stat == RPC_TIMEDOUT) {
+		pos = snprintf(tmp, (erreob - tmp), "timed out %s", 
+			will_retry ? "(retrying)" : "(giving up)");
+	} else {
+		pos += rpc_strerror(pos);
+		tmp = &errbuf[pos];
+		if (bg) {
+			pos = snprintf(tmp, (erreob - tmp), " %s",
+				will_retry ? "(retrying)" : "(giving up)");
+		}
+	}
+	if (bg) {
+		if (onlyonce++ < 1)
+			openlog("mount", LOG_CONS|LOG_PID, LOG_AUTH);
+		syslog(LOG_ERR, "%s.", errbuf);
+	} else
+		fprintf(stderr, "%s.\n", errbuf);
+}
+
+/* Define the order in which to probe for UDP/TCP services */
+enum plist {
+	use_tcp = 0,
+	udp_tcp,
+	udp_only,
+};
+static const u_int *
+proto_probelist(enum plist list)
+{
+	static const u_int probe_udp_tcp[] = { IPPROTO_UDP, IPPROTO_TCP, 0 };
+	static const u_int probe_both[] = { IPPROTO_TCP, IPPROTO_UDP, 0 };
+	static const u_int probe_udponly[] = { IPPROTO_UDP, 0 };
+
+	if (list == use_tcp)
+		return probe_both;
+	if (list == udp_tcp)
+		return probe_udp_tcp;
+	return probe_udponly;
+}
+
+/* Define the order in which NFS versions are probed on portmapper */
+static const u_long *
+nfs_probelist(const int vers)
+{
+	static const u_long nfs2_probe[] = { 2, 0};
+	static const u_long nfs3_probe[] = { 3, 2, 0};
+	switch (vers) {
+	case 3:
+		return nfs3_probe;
+	default:
+		return nfs2_probe;
+	}
+}
+
+/* Define the order in which Mountd versions are probed on portmapper */
+static const u_long *
+mnt_probelist(const int vers)
+{
+	static const u_long mnt1_probe[] = { 1, 2, 0 };
+	static const u_long mnt3_probe[] = { 3, 1, 2, 0 };
+	switch (vers) {
+	case 3:
+		return mnt3_probe;
+	default:
+		return mnt1_probe;
+	}
+}
+
+static int
+linux_version_code(void) {
+	struct utsname my_utsname;
+	int p, q, r;
+
+	if (uname(&my_utsname) == 0) {
+		p = atoi(strtok(my_utsname.release, "."));
+		q = atoi(strtok(NULL, "."));
+		r = atoi(strtok(NULL, "."));
+		return MAKE_VERSION(p,q,r);
+	}
+	return 0;
+}
+
+/*
+ * Unfortunately, the kernel prints annoying console messages
+ * in case of an unexpected nfs mount version (instead of
+ * just returning some error).  Therefore we'll have to try
+ * and figure out what version the kernel expects.
+ *
+ * Variables:
+ *	NFS_MOUNT_VERSION: these nfsmount sources at compile time
+ *	nfs_mount_version: version this source and running kernel can handle
+ */
+int nfs_mount_version = NFS_MOUNT_VERSION;
+
+int
+find_kernel_nfs_mount_version(void) {
+	static int kernel_version = -1;
+	int mnt_version = NFS_MOUNT_VERSION;
+
+	if (kernel_version == -1)
+		kernel_version = linux_version_code();
+
+	if (kernel_version) {
+	     if (kernel_version < MAKE_VERSION(2,1,32))
+		  mnt_version = 1;
+	     else if (kernel_version < MAKE_VERSION(2,2,18))
+		  mnt_version = 3;
+	     else if (kernel_version < MAKE_VERSION(2,3,0))
+		  mnt_version = 4; /* since 2.2.18pre9 */
+	     else if (kernel_version < MAKE_VERSION(2,3,99))
+		  mnt_version = 3;
+	     else if (kernel_version < MAKE_VERSION(2,6,3))
+		  mnt_version = 4;
+	     else
+		  mnt_version = 6;
+	}
+	if (mnt_version > NFS_MOUNT_VERSION)
+	     mnt_version = NFS_MOUNT_VERSION;
+	return mnt_version;
+}
+
+int nfs_gethostbyname(const char *, struct sockaddr_in *);
+int nfs_gethostbyname(const char *hostname, struct sockaddr_in *saddr)
+{
+	struct hostent *hp;
+
+	saddr->sin_family = AF_INET;
+	if (!inet_aton(hostname, &saddr->sin_addr)) {
+		if ((hp = gethostbyname(hostname)) == NULL) {
+			fprintf(stderr, _("mount: can't get address for %s\n"),
+				hostname);
+			return 0;
+		} else {
+			if (hp->h_length > sizeof(*saddr)) {
+				fprintf(stderr,
+					_("mount: got bad hp->h_length\n"));
+				hp->h_length = sizeof(*saddr);
+			}
+			memcpy(&saddr->sin_addr, hp->h_addr, hp->h_length);
+		}
+	}
+	return 1;
+}
+
+/*
+ * getport() is very similar to pmap_getport() with
+ * the exception this version uses a non-reserve ports 
+ * instead of reserve ports since reserve ports
+ * are not needed for pmap requests.
+ */
+static u_short
+getport(
+	struct sockaddr_in *saddr, 
+	u_long prog, 
+	u_long vers, 
+	u_int prot)
+{
+	u_short port;
+	int    socket;
+	CLIENT *clnt = NULL;
+	struct pmap parms;
+	enum clnt_stat stat;
+
+	saddr->sin_port = htons (PMAPPORT);
+	socket = get_socket(saddr, prot, FALSE);
+
+	switch (prot) {
+	case IPPROTO_UDP:
+		clnt = clntudp_bufcreate(saddr,
+					 PMAPPROG, PMAPVERS, TIMEOUT, &socket,
+					 UDPMSGSIZE, UDPMSGSIZE);
+		break;
+	case IPPROTO_TCP:
+		clnt = clnttcp_create(saddr,
+			PMAPPROG, PMAPVERS, &socket, 50, 500);
+		break;
+	}
+	if (clnt != NULL) {
+		parms.pm_prog = prog;
+		parms.pm_vers = vers;
+		parms.pm_prot = prot;
+		parms.pm_port = 0;    /* not needed or used */
+
+		stat = clnt_call(clnt, PMAPPROC_GETPORT, (xdrproc_t)xdr_pmap,
+			(caddr_t)&parms, (xdrproc_t)xdr_u_short, (caddr_t)&port, TIMEOUT);
+		if (stat) {
+			clnt_geterr(clnt, &rpc_createerr.cf_error);
+			rpc_createerr.cf_stat = stat;
+		}
+		clnt_destroy(clnt);
+		if (stat != RPC_SUCCESS)
+			port = 0;
+		else if (port == 0)
+			rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED;
+	}
+	if (socket != 1)
+		close(socket);
+
+	return port;
+}
+
+/*
+ * Use the portmapper to discover whether or not the service we want is
+ * available. The lists 'versions' and 'protos' define ordered sequences
+ * of service versions and udp/tcp protocols to probe for.
+ */
+static int
+probe_port(clnt_addr_t *server, 
+	   const u_long *versions,
+	   const u_int *protos)
+{
+	struct sockaddr_in *saddr = &server->saddr;
+	struct pmap *pmap = &server->pmap;
+	const u_long prog = pmap->pm_prog, *p_vers;
+	const u_int prot = (u_int)pmap->pm_prot,
+		*p_prot;
+	const u_short port = (u_short) pmap->pm_port;
+	u_long vers = pmap->pm_vers;
+	u_short p_port;
+	p_prot = prot ? &prot : protos;
+	p_vers = vers ? &vers : versions;
+	rpc_createerr.cf_stat = 0;
+	for (;;) {
+		saddr->sin_port = htons(PMAPPORT);
+		p_port = getport(saddr, prog, *p_vers, *p_prot);
+		if (p_port) {
+			if (!port || port == p_port) {
+				saddr->sin_port = htons(p_port);
+				if (verbose) {
+					fprintf(stderr, 
+						"mount: trying %s prog %ld vers %ld prot %s port %d\n", 
+						inet_ntoa(saddr->sin_addr), prog, *p_vers,
+						*p_prot == IPPROTO_UDP ? "udp" : "tcp", p_port);
+				}
+				if (clnt_ping(saddr, prog, *p_vers, *p_prot))
+					goto out_ok;
+				if (rpc_createerr.cf_stat == RPC_TIMEDOUT)
+					goto out_bad;
+			}
+		}
+		if (rpc_createerr.cf_stat != RPC_PROGNOTREGISTERED) 
+			goto out_bad;
+
+		if (!prot) {
+			if (*++p_prot)
+				continue;
+			p_prot = protos;
+		}
+		if (vers == pmap->pm_vers) {
+			p_vers = versions;
+			vers = 0;
+		}
+		if (vers || !*++p_vers)
+			break;
+	}
+out_bad:
+	return 0;
+
+ out_ok:
+	if (!vers)
+		pmap->pm_vers = *p_vers;
+	if (!prot)
+		pmap->pm_prot = *p_prot;
+	if (!port)
+		pmap->pm_port = p_port;
+	rpc_createerr.cf_stat = 0;
+	return 1;
+}
+
+static int
+probe_nfsport(clnt_addr_t *nfs_server)
+{
+	const struct pmap *pmap = &nfs_server->pmap;
+	const u_long *probe_vers;
+	const u_int *probe_prot;
+
+	if (pmap->pm_vers && pmap->pm_prot && pmap->pm_port)
+		return 1;
+	probe_vers = nfs_probelist(MAX_NFSPROT);
+	probe_prot = proto_probelist(HAVE_RELIABLE_TCP ? use_tcp : udp_only);
+	return probe_port(nfs_server, probe_vers, probe_prot);
+}
+
+int probe_mntport(clnt_addr_t *mnt_server)
+{
+	const struct pmap *pmap = &mnt_server->pmap;
+	const u_long *probe_vers;
+	const u_int *probe_prot;
+
+	if (pmap->pm_vers && pmap->pm_prot && pmap->pm_port)
+		return 1;
+	probe_vers = mnt_probelist(MAX_MNTPROT);
+	probe_prot = proto_probelist(HAVE_RELIABLE_TCP ? udp_tcp : udp_only);
+	return probe_port(mnt_server, probe_vers, probe_prot);
+}
+
+static int
+probe_bothports(clnt_addr_t *mnt_server, clnt_addr_t *nfs_server)
+{
+	struct pmap *nfs_pmap = &nfs_server->pmap;
+	struct pmap *mnt_pmap = &mnt_server->pmap;
+	struct pmap save_nfs, save_mnt;
+	int res;
+	const u_long *probe_vers;
+
+	if (mnt_pmap->pm_vers && !nfs_pmap->pm_vers)
+		nfs_pmap->pm_vers = mntvers_to_nfs(mnt_pmap->pm_vers);
+	else if (nfs_pmap->pm_vers && !mnt_pmap->pm_vers)
+		mnt_pmap->pm_vers = nfsvers_to_mnt(nfs_pmap->pm_vers);
+	if (nfs_pmap->pm_vers)
+		goto version_fixed;
+	memcpy(&save_nfs, nfs_pmap, sizeof(save_nfs));
+	memcpy(&save_mnt, mnt_pmap, sizeof(save_mnt));
+	for (probe_vers = mnt_probelist(MAX_MNTPROT); *probe_vers; probe_vers++) {
+		nfs_pmap->pm_vers = mntvers_to_nfs(*probe_vers);
+		if ((res = probe_nfsport(nfs_server) != 0)) {
+			mnt_pmap->pm_vers = nfsvers_to_mnt(nfs_pmap->pm_vers);
+			if ((res = probe_mntport(mnt_server)) != 0)
+				return 1;
+			memcpy(mnt_pmap, &save_mnt, sizeof(*mnt_pmap));
+		}
+		switch (rpc_createerr.cf_stat) {
+		case RPC_PROGVERSMISMATCH:
+		case RPC_PROGNOTREGISTERED:
+			break;
+		default:
+			goto out_bad;
+		}
+		memcpy(nfs_pmap, &save_nfs, sizeof(*nfs_pmap));
+	}
+ out_bad:
+	return 0;
+ version_fixed:
+	if (!probe_nfsport(nfs_server))
+		goto out_bad;
+	return probe_mntport(mnt_server);
+}
+
+static inline enum clnt_stat
+nfs3_mount(CLIENT *clnt, mnt3arg_t *mnt3arg, mnt3res_t *mnt3res)
+{
+	return clnt_call(clnt, MOUNTPROC3_MNT,
+			 (xdrproc_t) xdr_dirpath, (caddr_t) mnt3arg,
+			 (xdrproc_t) xdr_mountres3, (caddr_t) mnt3res,
+			 TIMEOUT);
+}
+
+static inline enum clnt_stat
+nfs2_mount(CLIENT *clnt, mnt2arg_t *mnt2arg, mnt2res_t *mnt2res)
+{
+	return clnt_call(clnt, MOUNTPROC_MNT,
+			 (xdrproc_t) xdr_dirpath, (caddr_t) mnt2arg,
+			 (xdrproc_t) xdr_fhstatus, (caddr_t) mnt2res,
+			 TIMEOUT);
+}
+
+static int
+nfs_call_mount(clnt_addr_t *mnt_server, clnt_addr_t *nfs_server,
+	       mntarg_t *mntarg, mntres_t *mntres)
+{
+	CLIENT *clnt;
+	enum clnt_stat stat;
+	int msock;
+
+	if (!probe_bothports(mnt_server, nfs_server))
+		goto out_bad;
+
+	clnt = mnt_openclnt(mnt_server, &msock);
+	if (!clnt)
+		goto out_bad;
+	/* make pointers in xdr_mountres3 NULL so
+	 * that xdr_array allocates memory for us
+	 */
+	memset(mntres, 0, sizeof(*mntres));
+	switch (mnt_server->pmap.pm_vers) {
+	case 3:
+		stat = nfs3_mount(clnt, mntarg, &mntres->nfsv3);
+		break;
+	case 2:
+	case 1:
+		stat = nfs2_mount(clnt, mntarg, &mntres->nfsv2);
+		break;
+	default:
+		goto out_bad;
+	}
+	if (stat != RPC_SUCCESS) {
+		clnt_geterr(clnt, &rpc_createerr.cf_error);
+		rpc_createerr.cf_stat = stat;
+	}
+	mnt_closeclnt(clnt, msock);
+	if (stat == RPC_SUCCESS)
+		return 1;
+ out_bad:
+	return 0;
+}
+
+static int
+parse_options(char *old_opts, struct nfs_mount_data *data,
+	      int *bg, int *retry, clnt_addr_t *mnt_server,
+	      clnt_addr_t *nfs_server, char *new_opts, const int opt_size)
+{
+	struct sockaddr_in *mnt_saddr = &mnt_server->saddr;
+	struct pmap *mnt_pmap = &mnt_server->pmap;
+	struct pmap *nfs_pmap = &nfs_server->pmap;
+	int len;
+	char *opt, *opteq;
+	char *mounthost = NULL;
+	char cbuf[128];
+
+	data->flags = 0;
+	*bg = 0;
+
+	len = strlen(new_opts);
+	for (opt = strtok(old_opts, ","); opt; opt = strtok(NULL, ",")) {
+		if (strlen(opt) >= sizeof(cbuf))
+			goto bad_parameter;
+		if ((opteq = strchr(opt, '=')) && isdigit(opteq[1])) {
+			int val = atoi(opteq + 1);	
+			*opteq = '\0';
+/* printf("opt=%s\n", opt); */
+			if (!strcmp(opt, "rsize"))
+				data->rsize = val;
+			else if (!strcmp(opt, "wsize"))
+				data->wsize = val;
+			else if (!strcmp(opt, "timeo"))
+				data->timeo = val;
+			else if (!strcmp(opt, "retrans"))
+				data->retrans = val;
+			else if (!strcmp(opt, "acregmin"))
+				data->acregmin = val;
+			else if (!strcmp(opt, "acregmax"))
+				data->acregmax = val;
+			else if (!strcmp(opt, "acdirmin"))
+				data->acdirmin = val;
+			else if (!strcmp(opt, "acdirmax"))
+				data->acdirmax = val;
+			else if (!strcmp(opt, "actimeo")) {
+				data->acregmin = val;
+				data->acregmax = val;
+				data->acdirmin = val;
+				data->acdirmax = val;
+			}
+			else if (!strcmp(opt, "retry"))
+				*retry = val;
+			else if (!strcmp(opt, "port"))
+				nfs_pmap->pm_port = val;
+			else if (!strcmp(opt, "mountport"))
+			        mnt_pmap->pm_port = val;
+			else if (!strcmp(opt, "mountprog"))
+				mnt_pmap->pm_prog = val;
+			else if (!strcmp(opt, "mountvers"))
+				mnt_pmap->pm_vers = val;
+			else if (!strcmp(opt, "mounthost"))
+				mounthost=xstrndup(opteq+1, strcspn(opteq+1," \t\n\r,"));
+			else if (!strcmp(opt, "nfsprog"))
+				nfs_pmap->pm_prog = val;
+			else if (!strcmp(opt, "nfsvers") ||
+				 !strcmp(opt, "vers")) {
+				nfs_pmap->pm_vers = val;
+				opt = "nfsvers";
+#if NFS_MOUNT_VERSION >= 2
+			} else if (!strcmp(opt, "namlen")) {
+				if (nfs_mount_version >= 2)
+					data->namlen = val;
+				else
+					goto bad_parameter;
+#endif
+			} else if (!strcmp(opt, "addr")) {
+				/* ignore */;
+				continue;
+ 			} else
+				goto bad_parameter;
+			sprintf(cbuf, "%s=%s,", opt, opteq+1);
+		} else if (opteq) {
+			*opteq = '\0';
+			if (!strcmp(opt, "proto")) {
+				if (!strcmp(opteq+1, "udp")) {
+					nfs_pmap->pm_prot = IPPROTO_UDP;
+					mnt_pmap->pm_prot = IPPROTO_UDP;
+#if NFS_MOUNT_VERSION >= 2
+					data->flags &= ~NFS_MOUNT_TCP;
+				} else if (!strcmp(opteq+1, "tcp") &&
+					   nfs_mount_version > 2) {
+					nfs_pmap->pm_prot = IPPROTO_TCP;
+					mnt_pmap->pm_prot = IPPROTO_TCP;
+					data->flags |= NFS_MOUNT_TCP;
+#endif
+				} else
+					goto bad_parameter;
+#if NFS_MOUNT_VERSION >= 5
+			} else if (!strcmp(opt, "sec")) {
+				char *secflavor = opteq+1;
+				/* see RFC 2623 */
+				if (nfs_mount_version < 5) {
+					printf(_("Warning: ignoring sec=%s option\n"), secflavor);
+					continue;
+				} else if (!strcmp(secflavor, "sys"))
+					data->pseudoflavor = AUTH_SYS;
+				else if (!strcmp(secflavor, "krb5"))
+					data->pseudoflavor = AUTH_GSS_KRB5;
+				else if (!strcmp(secflavor, "krb5i"))
+					data->pseudoflavor = AUTH_GSS_KRB5I;
+				else if (!strcmp(secflavor, "krb5p"))
+					data->pseudoflavor = AUTH_GSS_KRB5P;
+				else if (!strcmp(secflavor, "lipkey"))
+					data->pseudoflavor = AUTH_GSS_LKEY;
+				else if (!strcmp(secflavor, "lipkey-i"))
+					data->pseudoflavor = AUTH_GSS_LKEYI;
+				else if (!strcmp(secflavor, "lipkey-p"))
+					data->pseudoflavor = AUTH_GSS_LKEYP;
+				else if (!strcmp(secflavor, "spkm3"))
+					data->pseudoflavor = AUTH_GSS_SPKM;
+				else if (!strcmp(secflavor, "spkm3i"))
+					data->pseudoflavor = AUTH_GSS_SPKMI;
+				else if (!strcmp(secflavor, "spkm3p"))
+					data->pseudoflavor = AUTH_GSS_SPKMP;
+				else {
+					printf(_("Warning: Unrecognized security flavor %s.\n"),
+						secflavor);
+					goto bad_parameter;
+				}
+				data->flags |= NFS_MOUNT_SECFLAVOUR;
+#endif
+			} else if (!strcmp(opt, "mounthost"))
+			        mounthost=xstrndup(opteq+1,
+						   strcspn(opteq+1," \t\n\r,"));
+			 else if (!strcmp(opt, "context")) {
+ 				char *context = opteq + 1;
+ 				
+ 				if (strlen(context) > NFS_MAX_CONTEXT_LEN) {
+ 					printf(_("context parameter exceeds limit of %d\n"),
+ 						 NFS_MAX_CONTEXT_LEN);
+					goto bad_parameter;
+ 				}
+ 				strncpy(data->context, context, NFS_MAX_CONTEXT_LEN);
+ 			} else
+				goto bad_parameter;
+			sprintf(cbuf, "%s=%s,", opt, opteq+1);
+		} else {
+			int val = 1;
+			if (!strncmp(opt, "no", 2)) {
+				val = 0;
+				opt += 2;
+			}
+			if (!strcmp(opt, "bg")) 
+				*bg = val;
+			else if (!strcmp(opt, "fg")) 
+				*bg = !val;
+			else if (!strcmp(opt, "soft")) {
+				data->flags &= ~NFS_MOUNT_SOFT;
+				if (val)
+					data->flags |= NFS_MOUNT_SOFT;
+			} else if (!strcmp(opt, "hard")) {
+				data->flags &= ~NFS_MOUNT_SOFT;
+				if (!val)
+					data->flags |= NFS_MOUNT_SOFT;
+			} else if (!strcmp(opt, "intr")) {
+				data->flags &= ~NFS_MOUNT_INTR;
+				if (val)
+					data->flags |= NFS_MOUNT_INTR;
+			} else if (!strcmp(opt, "posix")) {
+				data->flags &= ~NFS_MOUNT_POSIX;
+				if (val)
+					data->flags |= NFS_MOUNT_POSIX;
+			} else if (!strcmp(opt, "cto")) {
+				data->flags &= ~NFS_MOUNT_NOCTO;
+				if (!val)
+					data->flags |= NFS_MOUNT_NOCTO;
+			} else if (!strcmp(opt, "ac")) {
+				data->flags &= ~NFS_MOUNT_NOAC;
+				if (!val)
+					data->flags |= NFS_MOUNT_NOAC;
+#if NFS_MOUNT_VERSION >= 2
+			} else if (!strcmp(opt, "tcp")) {
+				data->flags &= ~NFS_MOUNT_TCP;
+				if (val) {
+					if (nfs_mount_version < 2)
+						goto bad_option;
+					nfs_pmap->pm_prot = IPPROTO_TCP;
+					mnt_pmap->pm_prot = IPPROTO_TCP;
+					data->flags |= NFS_MOUNT_TCP;
+				} else {
+					mnt_pmap->pm_prot = IPPROTO_UDP;
+					nfs_pmap->pm_prot = IPPROTO_UDP;
+				}
+			} else if (!strcmp(opt, "udp")) {
+				data->flags &= ~NFS_MOUNT_TCP;
+				if (!val) {
+					if (nfs_mount_version < 2)
+						goto bad_option;
+					nfs_pmap->pm_prot = IPPROTO_TCP;
+					mnt_pmap->pm_prot = IPPROTO_TCP;
+					data->flags |= NFS_MOUNT_TCP;
+				} else {
+					nfs_pmap->pm_prot = IPPROTO_UDP;
+					mnt_pmap->pm_prot = IPPROTO_UDP;
+				}
+#endif
+#if NFS_MOUNT_VERSION >= 3
+			} else if (!strcmp(opt, "lock")) {
+				data->flags &= ~NFS_MOUNT_NONLM;
+				if (!val) {
+					if (nfs_mount_version < 3)
+						goto bad_option;
+					data->flags |= NFS_MOUNT_NONLM;
+				}
+#endif
+#if NFS_MOUNT_VERSION >= 4
+			} else if (!strcmp(opt, "broken_suid")) {
+				data->flags &= ~NFS_MOUNT_BROKEN_SUID;
+				if (val) {
+					if (nfs_mount_version < 4)
+						goto bad_option;
+					data->flags |= NFS_MOUNT_BROKEN_SUID;
+				}
+			} else if (!strcmp(opt, "acl")) {
+				data->flags &= ~NFS_MOUNT_NOACL;
+				if (!val)
+					data->flags |= NFS_MOUNT_NOACL;
+#endif
+			} else {
+			bad_option:
+				printf(_("Unsupported nfs mount option: "
+					 "%s%s\n"), val ? "" : "no", opt);
+				goto out_bad;
+			}
+			sprintf(cbuf, val ? "%s,":"no%s,", opt);
+		}
+		len += strlen(cbuf);
+		if (len >= opt_size) {
+			printf(_("mount: excessively long option argument\n"));
+			goto out_bad;
+		}
+		strcat(new_opts, cbuf);
+	}
+	/* See if the nfs host = mount host. */
+	if (mounthost) {
+		if (!nfs_gethostbyname(mounthost, mnt_saddr))
+			goto out_bad;
+		*mnt_server->hostname = mounthost;
+	}
+	return 1;
+ bad_parameter:
+	printf(_("Bad nfs mount parameter: %s\n"), opt);
+ out_bad:
+	return 0;
+}
+
+static inline int
+nfsmnt_check_compat(const struct pmap *nfs_pmap, const struct pmap *mnt_pmap)
+{
+	if (nfs_pmap->pm_vers && 
+		(nfs_pmap->pm_vers > MAX_NFSPROT || nfs_pmap->pm_vers < 2)) {
+		if (nfs_pmap->pm_vers == 4)
+			fprintf(stderr, _("'vers=4' is not supported.  "
+				"Use '-t nfs4' instead.\n"));
+		else
+			fprintf(stderr, _("NFS version %ld is not supported.\n"), 
+				nfs_pmap->pm_vers);
+		goto out_bad;
+	}
+	if (mnt_pmap->pm_vers > MAX_MNTPROT) {
+		fprintf(stderr, _("NFS mount version %ld s not supported.\n"), 
+			mnt_pmap->pm_vers);
+		goto out_bad;
+	}
+	return 1;
+ out_bad:
+	return 0;
+}
+
+int
+nfsmount(const char *spec, const char *node, int *flags,
+	 char **extra_opts, char **mount_opts, int *nfs_mount_vers,
+	 int running_bg)
+{
+	static char *prev_bg_host;
+	char hostdir[1024];
+	char *hostname, *dirname, *old_opts, *mounthost = NULL;
+	char new_opts[1024], cbuf[1024];
+	static struct nfs_mount_data data;
+	int val;
+	static int doonce = 0;
+
+	clnt_addr_t mnt_server = { &mounthost, };
+	clnt_addr_t nfs_server = { &hostname, };
+	struct sockaddr_in *nfs_saddr = &nfs_server.saddr;
+	struct pmap  *mnt_pmap = &mnt_server.pmap, 
+		     *nfs_pmap = &nfs_server.pmap;
+	struct pmap  save_mnt, save_nfs;
+
+	int fsock;
+
+	mntres_t mntres;
+
+	struct stat statbuf;
+	char *s;
+	int bg, retry;
+	int retval;
+	time_t t;
+	time_t prevt;
+	time_t timeout;
+
+	/* The version to try is either specified or 0
+	   In case it is 0 we tell the caller what we tried */
+	if (!*nfs_mount_vers)
+		*nfs_mount_vers = find_kernel_nfs_mount_version();
+	nfs_mount_version = *nfs_mount_vers;
+
+	retval = EX_FAIL;
+	fsock = -1;
+	if (strlen(spec) >= sizeof(hostdir)) {
+		fprintf(stderr, _("mount: "
+				  "excessively long host:dir argument\n"));
+		goto fail;
+	}
+	strcpy(hostdir, spec);
+	if ((s = strchr(hostdir, ':'))) {
+		hostname = hostdir;
+		dirname = s + 1;
+		*s = '\0';
+		/* Ignore all but first hostname in replicated mounts
+		   until they can be fully supported. (mack@sgi.com) */
+		if ((s = strchr(hostdir, ','))) {
+			*s = '\0';
+			fprintf(stderr,
+				_("mount: warning: "
+				  "multiple hostnames not supported\n"));
+		}
+	} else {
+		fprintf(stderr,
+			_("mount: "
+			  "directory to mount not in host:dir format\n"));
+		goto fail;
+	}
+
+	if (!nfs_gethostbyname(hostname, nfs_saddr))
+		goto fail;
+	mounthost = hostname;
+	memcpy (&mnt_server.saddr, nfs_saddr, sizeof (mnt_server.saddr));
+
+	/* add IP address to mtab options for use when unmounting */
+
+	s = inet_ntoa(nfs_saddr->sin_addr);
+	old_opts = *extra_opts;
+	if (!old_opts)
+		old_opts = "";
+
+	/* Set default options.
+	 * rsize/wsize (and bsize, for ver >= 3) are left 0 in order to
+	 * let the kernel decide.
+	 * timeo is filled in after we know whether it'll be TCP or UDP. */
+	memset(&data, 0, sizeof(data));
+	data.acregmin	= 3;
+	data.acregmax	= 60;
+	data.acdirmin	= 30;
+	data.acdirmax	= 60;
+#if NFS_MOUNT_VERSION >= 2
+	data.namlen	= NAME_MAX;
+#endif
+	data.pseudoflavor = AUTH_SYS;
+
+	bg = 0;
+	retry = 10000;		/* 10000 minutes ~ 1 week */
+
+	memset(mnt_pmap, 0, sizeof(*mnt_pmap));
+	mnt_pmap->pm_prog = MOUNTPROG;
+	memset(nfs_pmap, 0, sizeof(*nfs_pmap));
+	nfs_pmap->pm_prog = NFS_PROGRAM;
+
+	/* parse options */
+	new_opts[0] = 0;
+	if (!parse_options(old_opts, &data, &bg, &retry, &mnt_server, &nfs_server,
+			   new_opts, sizeof(new_opts)))
+		goto fail;
+	if (!nfsmnt_check_compat(nfs_pmap, mnt_pmap))
+		goto fail;
+	
+	if (retry == 10000 && !bg)
+		retry = 2; /* reset for fg mounts */
+	
+
+#ifdef NFS_MOUNT_DEBUG
+	printf("rsize = %d, wsize = %d, timeo = %d, retrans = %d\n",
+	       data.rsize, data.wsize, data.timeo, data.retrans);
+	printf("acreg (min, max) = (%d, %d), acdir (min, max) = (%d, %d)\n",
+	       data.acregmin, data.acregmax, data.acdirmin, data.acdirmax);
+	printf("port = %d, bg = %d, retry = %d, flags = %.8x\n",
+	       nfs_pmap->pm_port, bg, retry, data.flags);
+	printf("mountprog = %d, mountvers = %d, nfsprog = %d, nfsvers = %d\n",
+	       mnt_pmap->pm_prog, mnt_pmap->pm_vers,
+	       nfs_pmap->pm_prog, nfs_pmap->pm_vers);
+	printf("soft = %d, intr = %d, posix = %d, nocto = %d, noac = %d ",
+	       (data.flags & NFS_MOUNT_SOFT) != 0,
+	       (data.flags & NFS_MOUNT_INTR) != 0,
+	       (data.flags & NFS_MOUNT_POSIX) != 0,
+	       (data.flags & NFS_MOUNT_NOCTO) != 0,
+	       (data.flags & NFS_MOUNT_NOAC) != 0);
+#if NFS_MOUNT_VERSION >= 2
+	printf("tcp = %d ",
+	       (data.flags & NFS_MOUNT_TCP) != 0);
+#endif
+#if NFS_MOUNT_VERSION >= 4
+	printf("noacl = %d ", (data.flags & NFS_MOUNT_NOACL) != 0);
+#endif
+#if NFS_MOUNT_VERSION >= 5
+	printf("sec = %u ", data.pseudoflavor);
+#endif
+	printf("\n");
+#endif
+
+	data.version = nfs_mount_version;
+	*mount_opts = (char *) &data;
+
+	if (*flags & MS_REMOUNT)
+		goto out_ok;
+
+	/*
+	 * If the previous mount operation on the same host was
+	 * backgrounded, and the "bg" for this mount is also set,
+	 * give up immediately, to avoid the initial timeout.
+	 */
+	if (bg && !running_bg &&
+	    prev_bg_host && strcmp(hostname, prev_bg_host) == 0) {
+		if (retry > 0)
+			retval = EX_BG;
+		return retval;
+	}
+
+	/* create mount deamon client */
+
+	/*
+	 * The following loop implements the mount retries. On the first
+	 * call, "running_bg" is 0. When the mount times out, and the
+	 * "bg" option is set, the exit status EX_BG will be returned.
+	 * For a backgrounded mount, there will be a second call by the
+	 * child process with "running_bg" set to 1.
+	 *
+	 * The case where the mount point is not present and the "bg"
+	 * option is set, is treated as a timeout. This is done to
+	 * support nested mounts.
+	 *
+	 * The "retry" count specified by the user is the number of
+	 * minutes to retry before giving up.
+	 *
+	 * Only the first error message will be displayed.
+	 */
+	timeout = time(NULL) + 60 * retry;
+	prevt = 0;
+	t = 30;
+	val = 1;
+
+	memcpy(&save_nfs, nfs_pmap, sizeof(save_nfs));
+	memcpy(&save_mnt, mnt_pmap, sizeof(save_mnt));
+	for (;;) {
+		if (bg && stat(node, &statbuf) == -1) {
+			/* no mount point yet - sleep */
+			if (running_bg) {
+				sleep(val);	/* 1, 2, 4, 8, 16, 30, ... */
+				val *= 2;
+				if (val > 30)
+					val = 30;
+			}
+		} else {
+			int stat;
+			/* be careful not to use too many CPU cycles */
+			if (t - prevt < 30)
+				sleep(30);
+
+			stat = nfs_call_mount(&mnt_server, &nfs_server,
+					      &dirname, &mntres);
+			if (stat)
+				break;
+			memcpy(nfs_pmap, &save_nfs, sizeof(*nfs_pmap));
+			memcpy(mnt_pmap, &save_mnt, sizeof(*mnt_pmap));
+			prevt = t;
+		}
+		if (!bg) {
+			switch(rpc_createerr.cf_stat){
+			case RPC_TIMEDOUT:
+				break;
+			case RPC_SYSTEMERROR:
+				if (errno == ETIMEDOUT)
+					break;
+			default:
+				mount_errors(*nfs_server.hostname, 0, bg);
+		        goto fail;
+			}
+			t = time(NULL);
+			if (t >= timeout) {
+				mount_errors(*nfs_server.hostname, 0, bg);
+				goto fail;
+			}
+			mount_errors(*nfs_server.hostname, 1, bg);
+			continue;
+		}
+		if (!running_bg) {
+			prev_bg_host = xstrdup(hostname);
+			if (retry > 0)
+				retval = EX_BG;
+			goto fail;
+		}
+		t = time(NULL);
+		if (t >= timeout) {
+			mount_errors(*nfs_server.hostname, 0, bg);
+			goto fail;
+		}
+		if (doonce++ < 1)
+			mount_errors(*nfs_server.hostname, 1, bg);
+	}
+
+	if (nfs_pmap->pm_vers == 2) {
+		if (mntres.nfsv2.fhs_status != 0) {
+			fprintf(stderr,
+				_("mount: %s:%s failed, reason given by server: %s\n"),
+				hostname, dirname,
+				nfs_strerror(mntres.nfsv2.fhs_status));
+			goto fail;
+		}
+		memcpy(data.root.data,
+		       (char *) mntres.nfsv2.fhstatus_u.fhs_fhandle,
+		       NFS_FHSIZE);
+#if NFS_MOUNT_VERSION >= 4
+		data.root.size = NFS_FHSIZE;
+		memcpy(data.old_root.data,
+		       (char *) mntres.nfsv2.fhstatus_u.fhs_fhandle,
+		       NFS_FHSIZE);
+#endif
+	} else {
+#if NFS_MOUNT_VERSION >= 4
+		mountres3_ok *mountres;
+		fhandle3 *fhandle;
+		int i, *flavor, yum = 0;
+		if (mntres.nfsv3.fhs_status != 0) {
+			fprintf(stderr,
+				_("mount: %s:%s failed, reason given by server: %s\n"),
+				hostname, dirname,
+				nfs_strerror(mntres.nfsv3.fhs_status));
+			goto fail;
+		}
+#if NFS_MOUNT_VERSION >= 5
+		mountres = &mntres.nfsv3.mountres3_u.mountinfo;
+		i = mountres->auth_flavours.auth_flavours_len;
+		if (i <= 0) 
+			goto noauth_flavours;
+
+		flavor = mountres->auth_flavours.auth_flavours_val;
+		while (--i >= 0) {
+			if (flavor[i] == data.pseudoflavor)
+				yum = 1;
+#ifdef NFS_MOUNT_DEBUG
+			printf("auth flavor %d: %d\n",
+				i, flavor[i]);
+#endif
+		}
+		if (!yum) {
+			fprintf(stderr,
+				"mount: %s:%s failed, "
+				"security flavor not supported\n",
+				hostname, dirname);
+			/* server has registered us in mtab, send umount */
+			nfs_call_umount(&mnt_server, &dirname);
+			goto fail;
+		}
+noauth_flavours:
+#endif
+		fhandle = &mntres.nfsv3.mountres3_u.mountinfo.fhandle;
+		memset(data.old_root.data, 0, NFS_FHSIZE);
+		memset(&data.root, 0, sizeof(data.root));
+		data.root.size = fhandle->fhandle3_len;
+		memcpy(data.root.data,
+		       (char *) fhandle->fhandle3_val,
+		       fhandle->fhandle3_len);
+
+		data.flags |= NFS_MOUNT_VER3;
+#endif
+	}
+
+	/* create nfs socket for kernel */
+
+	if (nfs_pmap->pm_prot == IPPROTO_TCP)
+		fsock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+	else
+		fsock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+	if (fsock < 0) {
+		perror(_("nfs socket"));
+		goto fail;
+	}
+	if (bindresvport(fsock, 0) < 0) {
+		perror(_("nfs bindresvport"));
+		goto fail;
+	}
+#ifdef NFS_MOUNT_DEBUG
+	printf(_("using port %d for nfs deamon\n"), nfs_pmap->pm_port);
+#endif
+	nfs_saddr->sin_port = htons(nfs_pmap->pm_port);
+	/*
+	 * connect() the socket for kernels 1.3.10 and below only,
+	 * to avoid problems with multihomed hosts.
+	 * --Swen
+	 */
+	if (linux_version_code() <= 66314
+	    && connect(fsock, (struct sockaddr *) nfs_saddr,
+		       sizeof (*nfs_saddr)) < 0) {
+		perror(_("nfs connect"));
+		goto fail;
+	}
+
+#if NFS_MOUNT_VERSION >= 2
+	if (nfs_pmap->pm_prot == IPPROTO_TCP)
+		data.flags |= NFS_MOUNT_TCP;
+	else
+		data.flags &= ~NFS_MOUNT_TCP;
+#endif
+
+	/* prepare data structure for kernel */
+
+	data.fd = fsock;
+	memcpy((char *) &data.addr, (char *) nfs_saddr, sizeof(data.addr));
+	strncpy(data.hostname, hostname, sizeof(data.hostname));
+
+ out_ok:
+	/* Ensure we have enough padding for the following strcat()s */
+	if (strlen(new_opts) + strlen(s) + 30 >= sizeof(new_opts)) {
+		fprintf(stderr, _("mount: "
+				  "excessively long option argument\n"));
+		goto fail;
+	}
+
+	snprintf(cbuf, sizeof(cbuf)-1, "addr=%s", s);
+	strcat(new_opts, cbuf);
+
+	*extra_opts = xstrdup(new_opts);
+	return 0;
+
+	/* abort */
+ fail:
+	if (fsock != -1)
+		close(fsock);
+	return retval;
+}
+
+/*
+ * We need to translate between nfs status return values and
+ * the local errno values which may not be the same.
+ *
+ * Andreas Schwab <schwab@LS5.informatik.uni-dortmund.de>: change errno:
+ * "after #include <errno.h> the symbol errno is reserved for any use,
+ *  it cannot even be used as a struct tag or field name".
+ */
+
+#ifndef EDQUOT
+#define EDQUOT	ENOSPC
+#endif
+
+static struct {
+	enum nfsstat stat;
+	int errnum;
+} nfs_errtbl[] = {
+	{ NFS_OK,		0		},
+	{ NFSERR_PERM,		EPERM		},
+	{ NFSERR_NOENT,		ENOENT		},
+	{ NFSERR_IO,		EIO		},
+	{ NFSERR_NXIO,		ENXIO		},
+	{ NFSERR_ACCES,		EACCES		},
+	{ NFSERR_EXIST,		EEXIST		},
+	{ NFSERR_NODEV,		ENODEV		},
+	{ NFSERR_NOTDIR,	ENOTDIR		},
+	{ NFSERR_ISDIR,		EISDIR		},
+#ifdef NFSERR_INVAL
+	{ NFSERR_INVAL,		EINVAL		},	/* that Sun forgot */
+#endif
+	{ NFSERR_FBIG,		EFBIG		},
+	{ NFSERR_NOSPC,		ENOSPC		},
+	{ NFSERR_ROFS,		EROFS		},
+	{ NFSERR_NAMETOOLONG,	ENAMETOOLONG	},
+	{ NFSERR_NOTEMPTY,	ENOTEMPTY	},
+	{ NFSERR_DQUOT,		EDQUOT		},
+	{ NFSERR_STALE,		ESTALE		},
+#ifdef EWFLUSH
+	{ NFSERR_WFLUSH,	EWFLUSH		},
+#endif
+	/* Throw in some NFSv3 values for even more fun (HP returns these) */
+	{ 71,			EREMOTE		},
+
+	{ -1,			EIO		}
+};
+
+static char *nfs_strerror(int stat)
+{
+	int i;
+	static char buf[256];
+
+	for (i = 0; nfs_errtbl[i].stat != -1; i++) {
+		if (nfs_errtbl[i].stat == stat)
+			return strerror(nfs_errtbl[i].errnum);
+	}
+	sprintf(buf, _("unknown nfs status return value: %d"), stat);
+	return buf;
+}
diff -uprN nfs-utils-1.0.8/utils/mount/nfs_mount.h nfs-utils-1.0.8-ag/utils/mount/nfs_mount.h
--- nfs-utils-1.0.8/utils/mount/nfs_mount.h	1969-12-31 19:00:00.000000000 -0500
+++ nfs-utils-1.0.8-ag/utils/mount/nfs_mount.h	2006-06-08 11:22:22.146815000 -0400
@@ -0,0 +1,82 @@
+/*
+ * We want to be able to compile mount on old kernels in such a way
+ * that the binary will work well on more recent kernels.
+ * Thus, if necessary we teach nfsmount.c the structure of new fields
+ * that will come later.
+ *
+ * Moreover, the new kernel includes conflict with glibc includes
+ * so it is easiest to ignore the kernel altogether (at compile time).
+ */
+
+#ifndef _NFS_MOUNT_H
+#define _NFS_MOUNT_H
+
+#define NFS_MOUNT_VERSION 6
+#define NFS_MAX_CONTEXT_LEN   256
+
+
+struct nfs2_fh {
+        char                    data[32];
+};
+struct nfs3_fh {
+        unsigned short          size;
+        unsigned char           data[64];
+};
+
+struct nfs_mount_data {
+	int		version;		/* 1 */
+	int		fd;			/* 1 */
+	struct nfs2_fh	old_root;		/* 1 */
+	int		flags;			/* 1 */
+	int		rsize;			/* 1 */
+	int		wsize;			/* 1 */
+	int		timeo;			/* 1 */
+	int		retrans;		/* 1 */
+	int		acregmin;		/* 1 */
+	int		acregmax;		/* 1 */
+	int		acdirmin;		/* 1 */
+	int		acdirmax;		/* 1 */
+	struct sockaddr_in addr;		/* 1 */
+	char		hostname[256];		/* 1 */
+	int		namlen;			/* 2 */
+	unsigned int	bsize;			/* 3 */
+	struct nfs3_fh	root;			/* 4 */
+	int		pseudoflavor;		/* 5 */
+	char    context[NFS_MAX_CONTEXT_LEN + 1]; /* 6 */
+
+};
+
+/* bits in the flags field */
+
+#define NFS_MOUNT_SOFT		0x0001	/* 1 */
+#define NFS_MOUNT_INTR		0x0002	/* 1 */
+#define NFS_MOUNT_SECURE	0x0004	/* 1 */
+#define NFS_MOUNT_POSIX		0x0008	/* 1 */
+#define NFS_MOUNT_NOCTO		0x0010	/* 1 */
+#define NFS_MOUNT_NOAC		0x0020	/* 1 */
+#define NFS_MOUNT_TCP		0x0040	/* 2 */
+#define NFS_MOUNT_VER3		0x0080	/* 3 */
+#define NFS_MOUNT_KERBEROS	0x0100	/* 3 */
+#define NFS_MOUNT_NONLM		0x0200	/* 3 */
+#define NFS_MOUNT_BROKEN_SUID	0x0400	/* 4 */
+#define NFS_MOUNT_NOACL     0x0800  /* 4 */
+#define NFS_MOUNT_SECFLAVOUR	0x2000	/* 5 */
+
+/* security pseudoflavors */
+
+#ifndef AUTH_GSS_KRB5
+#define AUTH_GSS_KRB5		390003
+#define AUTH_GSS_KRB5I		390004
+#define AUTH_GSS_KRB5P		390005
+#define AUTH_GSS_LKEY		390006
+#define AUTH_GSS_LKEYI		390007
+#define AUTH_GSS_LKEYP		390008
+#define AUTH_GSS_SPKM		390009
+#define AUTH_GSS_SPKMI		390010
+#define AUTH_GSS_SPKMP		390011
+#endif
+
+int nfsmount(const char *, const char *, int *, char **,
+		char **, int *, int);
+
+#endif /* _NFS_MOUNT_NFS */
diff -uprN nfs-utils-1.0.8/utils/mount/nfsmount.h nfs-utils-1.0.8-ag/utils/mount/nfsmount.h
--- nfs-utils-1.0.8/utils/mount/nfsmount.h	1969-12-31 19:00:00.000000000 -0500
+++ nfs-utils-1.0.8-ag/utils/mount/nfsmount.h	2006-06-08 11:22:22.152816000 -0400
@@ -0,0 +1,328 @@
+/*
+ * Please do not edit this file.
+ * It was generated using rpcgen.
+ */
+
+#ifndef _NFSMOUNT_H_RPCGEN
+#define _NFSMOUNT_H_RPCGEN
+
+#include <rpc/rpc.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part.  Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user or with the express written consent of
+ * Sun Microsystems, Inc.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California  94043
+ */
+/*
+ * Copyright (c) 1985, 1990 by Sun Microsystems, Inc.
+ */
+
+/* from @(#)mount.x	1.3 91/03/11 TIRPC 1.0 */
+#ifndef _rpcsvc_mount_h
+#define _rpcsvc_mount_h
+#include <asm/types.h>
+#define MNTPATHLEN 1024
+#define MNTNAMLEN 255
+#define FHSIZE 32
+#define FHSIZE3 64
+
+typedef char fhandle[FHSIZE];
+
+typedef struct {
+	u_int fhandle3_len;
+	char *fhandle3_val;
+} fhandle3;
+
+enum mountstat3 {
+	MNT_OK = 0,
+	MNT3ERR_PERM = 1,
+	MNT3ERR_NOENT = 2,
+	MNT3ERR_IO = 5,
+	MNT3ERR_ACCES = 13,
+	MNT3ERR_NOTDIR = 20,
+	MNT3ERR_INVAL = 22,
+	MNT3ERR_NAMETOOLONG = 63,
+	MNT3ERR_NOTSUPP = 10004,
+	MNT3ERR_SERVERFAULT = 10006,
+};
+typedef enum mountstat3 mountstat3;
+
+struct fhstatus {
+	u_int fhs_status;
+	union {
+		fhandle fhs_fhandle;
+	} fhstatus_u;
+};
+typedef struct fhstatus fhstatus;
+
+struct mountres3_ok {
+	fhandle3 fhandle;
+	struct {
+		u_int auth_flavours_len;
+		int *auth_flavours_val;
+	} auth_flavours;
+};
+typedef struct mountres3_ok mountres3_ok;
+
+struct mountres3 {
+	mountstat3 fhs_status;
+	union {
+		mountres3_ok mountinfo;
+	} mountres3_u;
+};
+typedef struct mountres3 mountres3;
+
+typedef char *dirpath;
+
+typedef char *name;
+
+typedef struct mountbody *mountlist;
+
+struct mountbody {
+	name ml_hostname;
+	dirpath ml_directory;
+	mountlist ml_next;
+};
+typedef struct mountbody mountbody;
+
+typedef struct groupnode *groups;
+
+struct groupnode {
+	name gr_name;
+	groups gr_next;
+};
+typedef struct groupnode groupnode;
+
+typedef struct exportnode *exports;
+
+struct exportnode {
+	dirpath ex_dir;
+	groups ex_groups;
+	exports ex_next;
+};
+typedef struct exportnode exportnode;
+
+struct ppathcnf {
+	int pc_link_max;
+	short pc_max_canon;
+	short pc_max_input;
+	short pc_name_max;
+	short pc_path_max;
+	short pc_pipe_buf;
+	u_char pc_vdisable;
+	char pc_xxx;
+	short pc_mask[2];
+};
+typedef struct ppathcnf ppathcnf;
+#endif /*!_rpcsvc_mount_h*/
+
+#define MOUNTPROG 100005
+#define MOUNTVERS 1
+
+#if defined(__STDC__) || defined(__cplusplus)
+#define MOUNTPROC_NULL 0
+extern  void * mountproc_null_1(void *, CLIENT *);
+extern  void * mountproc_null_1_svc(void *, struct svc_req *);
+#define MOUNTPROC_MNT 1
+extern  fhstatus * mountproc_mnt_1(dirpath *, CLIENT *);
+extern  fhstatus * mountproc_mnt_1_svc(dirpath *, struct svc_req *);
+#define MOUNTPROC_DUMP 2
+extern  mountlist * mountproc_dump_1(void *, CLIENT *);
+extern  mountlist * mountproc_dump_1_svc(void *, struct svc_req *);
+#define MOUNTPROC_UMNT 3
+extern  void * mountproc_umnt_1(dirpath *, CLIENT *);
+extern  void * mountproc_umnt_1_svc(dirpath *, struct svc_req *);
+#define MOUNTPROC_UMNTALL 4
+extern  void * mountproc_umntall_1(void *, CLIENT *);
+extern  void * mountproc_umntall_1_svc(void *, struct svc_req *);
+#define MOUNTPROC_EXPORT 5
+extern  exports * mountproc_export_1(void *, CLIENT *);
+extern  exports * mountproc_export_1_svc(void *, struct svc_req *);
+#define MOUNTPROC_EXPORTALL 6
+extern  exports * mountproc_exportall_1(void *, CLIENT *);
+extern  exports * mountproc_exportall_1_svc(void *, struct svc_req *);
+extern int mountprog_1_freeresult (SVCXPRT *, xdrproc_t, caddr_t);
+
+#else /* K&R C */
+#define MOUNTPROC_NULL 0
+extern  void * mountproc_null_1();
+extern  void * mountproc_null_1_svc();
+#define MOUNTPROC_MNT 1
+extern  fhstatus * mountproc_mnt_1();
+extern  fhstatus * mountproc_mnt_1_svc();
+#define MOUNTPROC_DUMP 2
+extern  mountlist * mountproc_dump_1();
+extern  mountlist * mountproc_dump_1_svc();
+#define MOUNTPROC_UMNT 3
+extern  void * mountproc_umnt_1();
+extern  void * mountproc_umnt_1_svc();
+#define MOUNTPROC_UMNTALL 4
+extern  void * mountproc_umntall_1();
+extern  void * mountproc_umntall_1_svc();
+#define MOUNTPROC_EXPORT 5
+extern  exports * mountproc_export_1();
+extern  exports * mountproc_export_1_svc();
+#define MOUNTPROC_EXPORTALL 6
+extern  exports * mountproc_exportall_1();
+extern  exports * mountproc_exportall_1_svc();
+extern int mountprog_1_freeresult ();
+#endif /* K&R C */
+#define MOUNTVERS_POSIX 2
+
+#if defined(__STDC__) || defined(__cplusplus)
+extern  void * mountproc_null_2(void *, CLIENT *);
+extern  void * mountproc_null_2_svc(void *, struct svc_req *);
+extern  fhstatus * mountproc_mnt_2(dirpath *, CLIENT *);
+extern  fhstatus * mountproc_mnt_2_svc(dirpath *, struct svc_req *);
+extern  mountlist * mountproc_dump_2(void *, CLIENT *);
+extern  mountlist * mountproc_dump_2_svc(void *, struct svc_req *);
+extern  void * mountproc_umnt_2(dirpath *, CLIENT *);
+extern  void * mountproc_umnt_2_svc(dirpath *, struct svc_req *);
+extern  void * mountproc_umntall_2(void *, CLIENT *);
+extern  void * mountproc_umntall_2_svc(void *, struct svc_req *);
+extern  exports * mountproc_export_2(void *, CLIENT *);
+extern  exports * mountproc_export_2_svc(void *, struct svc_req *);
+extern  exports * mountproc_exportall_2(void *, CLIENT *);
+extern  exports * mountproc_exportall_2_svc(void *, struct svc_req *);
+#define MOUNTPROC_PATHCONF 7
+extern  ppathcnf * mountproc_pathconf_2(dirpath *, CLIENT *);
+extern  ppathcnf * mountproc_pathconf_2_svc(dirpath *, struct svc_req *);
+extern int mountprog_2_freeresult (SVCXPRT *, xdrproc_t, caddr_t);
+
+#else /* K&R C */
+extern  void * mountproc_null_2();
+extern  void * mountproc_null_2_svc();
+extern  fhstatus * mountproc_mnt_2();
+extern  fhstatus * mountproc_mnt_2_svc();
+extern  mountlist * mountproc_dump_2();
+extern  mountlist * mountproc_dump_2_svc();
+extern  void * mountproc_umnt_2();
+extern  void * mountproc_umnt_2_svc();
+extern  void * mountproc_umntall_2();
+extern  void * mountproc_umntall_2_svc();
+extern  exports * mountproc_export_2();
+extern  exports * mountproc_export_2_svc();
+extern  exports * mountproc_exportall_2();
+extern  exports * mountproc_exportall_2_svc();
+#define MOUNTPROC_PATHCONF 7
+extern  ppathcnf * mountproc_pathconf_2();
+extern  ppathcnf * mountproc_pathconf_2_svc();
+extern int mountprog_2_freeresult ();
+#endif /* K&R C */
+#define MOUNT_V3 3
+
+#if defined(__STDC__) || defined(__cplusplus)
+#define MOUNTPROC3_NULL 0
+extern  void * mountproc3_null_3(void *, CLIENT *);
+extern  void * mountproc3_null_3_svc(void *, struct svc_req *);
+#define MOUNTPROC3_MNT 1
+extern  mountres3 * mountproc3_mnt_3(dirpath *, CLIENT *);
+extern  mountres3 * mountproc3_mnt_3_svc(dirpath *, struct svc_req *);
+#define MOUNTPROC3_DUMP 2
+extern  mountlist * mountproc3_dump_3(void *, CLIENT *);
+extern  mountlist * mountproc3_dump_3_svc(void *, struct svc_req *);
+#define MOUNTPROC3_UMNT 3
+extern  void * mountproc3_umnt_3(dirpath *, CLIENT *);
+extern  void * mountproc3_umnt_3_svc(dirpath *, struct svc_req *);
+#define MOUNTPROC3_UMNTALL 4
+extern  void * mountproc3_umntall_3(void *, CLIENT *);
+extern  void * mountproc3_umntall_3_svc(void *, struct svc_req *);
+#define MOUNTPROC3_EXPORT 5
+extern  exports * mountproc3_export_3(void *, CLIENT *);
+extern  exports * mountproc3_export_3_svc(void *, struct svc_req *);
+extern int mountprog_3_freeresult (SVCXPRT *, xdrproc_t, caddr_t);
+
+#else /* K&R C */
+#define MOUNTPROC3_NULL 0
+extern  void * mountproc3_null_3();
+extern  void * mountproc3_null_3_svc();
+#define MOUNTPROC3_MNT 1
+extern  mountres3 * mountproc3_mnt_3();
+extern  mountres3 * mountproc3_mnt_3_svc();
+#define MOUNTPROC3_DUMP 2
+extern  mountlist * mountproc3_dump_3();
+extern  mountlist * mountproc3_dump_3_svc();
+#define MOUNTPROC3_UMNT 3
+extern  void * mountproc3_umnt_3();
+extern  void * mountproc3_umnt_3_svc();
+#define MOUNTPROC3_UMNTALL 4
+extern  void * mountproc3_umntall_3();
+extern  void * mountproc3_umntall_3_svc();
+#define MOUNTPROC3_EXPORT 5
+extern  exports * mountproc3_export_3();
+extern  exports * mountproc3_export_3_svc();
+extern int mountprog_3_freeresult ();
+#endif /* K&R C */
+
+/* the xdr functions */
+
+#if defined(__STDC__) || defined(__cplusplus)
+extern  bool_t xdr_fhandle (XDR *, fhandle);
+extern  bool_t xdr_fhandle3 (XDR *, fhandle3*);
+extern  bool_t xdr_mountstat3 (XDR *, mountstat3*);
+extern  bool_t xdr_fhstatus (XDR *, fhstatus*);
+extern  bool_t xdr_mountres3_ok (XDR *, mountres3_ok*);
+extern  bool_t xdr_mountres3 (XDR *, mountres3*);
+extern  bool_t xdr_dirpath (XDR *, dirpath*);
+extern  bool_t xdr_name (XDR *, name*);
+extern  bool_t xdr_mountlist (XDR *, mountlist*);
+extern  bool_t xdr_mountbody (XDR *, mountbody*);
+extern  bool_t xdr_groups (XDR *, groups*);
+extern  bool_t xdr_groupnode (XDR *, groupnode*);
+extern  bool_t xdr_exports (XDR *, exports*);
+extern  bool_t xdr_exportnode (XDR *, exportnode*);
+extern  bool_t xdr_ppathcnf (XDR *, ppathcnf*);
+
+#else /* K&R C */
+extern bool_t xdr_fhandle ();
+extern bool_t xdr_fhandle3 ();
+extern bool_t xdr_mountstat3 ();
+extern bool_t xdr_fhstatus ();
+extern bool_t xdr_mountres3_ok ();
+extern bool_t xdr_mountres3 ();
+extern bool_t xdr_dirpath ();
+extern bool_t xdr_name ();
+extern bool_t xdr_mountlist ();
+extern bool_t xdr_mountbody ();
+extern bool_t xdr_groups ();
+extern bool_t xdr_groupnode ();
+extern bool_t xdr_exports ();
+extern bool_t xdr_exportnode ();
+extern bool_t xdr_ppathcnf ();
+
+#endif /* K&R C */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* !_NFSMOUNT_H_RPCGEN */
diff -uprN nfs-utils-1.0.8/utils/mount/nfsmount.x nfs-utils-1.0.8-ag/utils/mount/nfsmount.x
--- nfs-utils-1.0.8/utils/mount/nfsmount.x	1969-12-31 19:00:00.000000000 -0500
+++ nfs-utils-1.0.8-ag/utils/mount/nfsmount.x	2006-06-08 11:22:22.158816000 -0400
@@ -0,0 +1,336 @@
+%/*
+% * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+% * unrestricted use provided that this legend is included on all tape
+% * media and as a part of the software program in whole or part.  Users
+% * may copy or modify Sun RPC without charge, but are not authorized
+% * to license or distribute it to anyone else except as part of a product or
+% * program developed by the user or with the express written consent of
+% * Sun Microsystems, Inc.
+% *
+% * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+% * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+% * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+% *
+% * Sun RPC is provided with no support and without any obligation on the
+% * part of Sun Microsystems, Inc. to assist in its use, correction,
+% * modification or enhancement.
+% *
+% * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+% * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+% * OR ANY PART THEREOF.
+% *
+% * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+% * or profits or other special, indirect and consequential damages, even if
+% * Sun has been advised of the possibility of such damages.
+% *
+% * Sun Microsystems, Inc.
+% * 2550 Garcia Avenue
+% * Mountain View, California  94043
+% */
+
+%/*
+% * Copyright (c) 1985, 1990 by Sun Microsystems, Inc.
+% */
+%
+%/* from @(#)mount.x	1.3 91/03/11 TIRPC 1.0 */
+
+/*
+ * Protocol description for the mount program
+ */
+
+#ifdef RPC_HDR
+%#ifndef _rpcsvc_mount_h
+%#define _rpcsvc_mount_h
+#endif
+
+#ifdef RPC_CLNT
+%#include <string.h>		/* for memset() */
+#endif
+%#include <asm/types.h>
+
+const MNTPATHLEN = 1024;	/* maximum bytes in a pathname argument */
+const MNTNAMLEN = 255;		/* maximum bytes in a name argument */
+const FHSIZE = 32;		/* size in bytes of a file handle */
+const FHSIZE3 = 64;		/* size in bytes of a file handle */
+
+/*
+ * The fhandle is the file handle that the server passes to the client.
+ * All file operations are done using the file handles to refer to a file
+ * or a directory. The file handle can contain whatever information the
+ * server needs to distinguish an individual file.
+ */
+typedef opaque fhandle[FHSIZE];	
+typedef opaque fhandle3<FHSIZE3>;
+
+enum mountstat3 {
+	MNT_OK			= 0,		/* no error */
+	MNT3ERR_PERM		= 1,		/* not owner */
+	MNT3ERR_NOENT		= 2,		/* No such file or directory */
+	MNT3ERR_IO		= 5,		/* I/O error */
+	MNT3ERR_ACCES		= 13,		/* Permission denied */
+	MNT3ERR_NOTDIR		= 20,		/* Not a directory */
+	MNT3ERR_INVAL		= 22,		/* Invalid argument */
+	MNT3ERR_NAMETOOLONG	= 63,		/* File name too long */
+	MNT3ERR_NOTSUPP		= 10004,	/* Operation not supported */
+	MNT3ERR_SERVERFAULT	= 10006		/* A failure on the server */
+};
+
+/*
+ * If a status of zero is returned, the call completed successfully, and 
+ * a file handle for the directory follows. A non-zero status indicates
+ * some sort of error. The status corresponds with UNIX error numbers.
+ */
+union fhstatus switch (unsigned fhs_status) {
+case 0:
+	fhandle fhs_fhandle;
+default:
+	void;
+};
+
+struct mountres3_ok {
+	fhandle3 fhandle;
+	int auth_flavours<>;
+};
+
+union mountres3 switch (mountstat3 fhs_status) {
+case MNT_OK:
+	mountres3_ok mountinfo;
+default:
+	void;
+};
+
+/*
+ * The type dirpath is the pathname of a directory
+ */
+typedef string dirpath<MNTPATHLEN>;
+
+/*
+ * The type name is used for arbitrary names (hostnames, groupnames)
+ */
+typedef string name<MNTNAMLEN>;
+
+/*
+ * A list of who has what mounted
+ */
+typedef struct mountbody *mountlist;
+struct mountbody {
+	name ml_hostname;
+	dirpath ml_directory;
+	mountlist ml_next;
+};
+
+/*
+ * A list of netgroups
+ */
+typedef struct groupnode *groups;
+struct groupnode {
+	name gr_name;
+	groups gr_next;
+};
+
+/*
+ * A list of what is exported and to whom
+ */
+typedef struct exportnode *exports;
+struct exportnode {
+	dirpath ex_dir;
+	groups ex_groups;
+	exports ex_next;
+};
+
+/*
+ * POSIX pathconf information
+ */
+struct ppathcnf {
+	int	pc_link_max;	/* max links allowed */
+	short	pc_max_canon;	/* max line len for a tty */
+	short	pc_max_input;	/* input a tty can eat all at once */
+	short	pc_name_max;	/* max file name length (dir entry) */
+	short	pc_path_max;	/* max path name length (/x/y/x/.. ) */
+	short	pc_pipe_buf;	/* size of a pipe (bytes) */
+	u_char	pc_vdisable;	/* safe char to turn off c_cc[i] */
+	char	pc_xxx;		/* alignment padding; cc_t == char */
+	short	pc_mask[2];	/* validity and boolean bits */
+};
+
+program MOUNTPROG {
+	/*
+	 * Version one of the mount protocol communicates with version two
+	 * of the NFS protocol. The only connecting point is the fhandle 
+	 * structure, which is the same for both protocols.
+	 */
+	version MOUNTVERS {
+		/*
+		 * Does no work. It is made available in all RPC services
+		 * to allow server reponse testing and timing
+		 */
+		void
+		MOUNTPROC_NULL(void) = 0;
+
+		/*	
+		 * If fhs_status is 0, then fhs_fhandle contains the
+	 	 * file handle for the directory. This file handle may
+		 * be used in the NFS protocol. This procedure also adds
+		 * a new entry to the mount list for this client mounting
+		 * the directory.
+		 * Unix authentication required.
+		 */
+		fhstatus 
+		MOUNTPROC_MNT(dirpath) = 1;
+
+		/*
+		 * Returns the list of remotely mounted filesystems. The 
+		 * mountlist contains one entry for each hostname and 
+		 * directory pair.
+		 */
+		mountlist
+		MOUNTPROC_DUMP(void) = 2;
+
+		/*
+		 * Removes the mount list entry for the directory
+		 * Unix authentication required.
+		 */
+		void
+		MOUNTPROC_UMNT(dirpath) = 3;
+
+		/*
+		 * Removes all of the mount list entries for this client
+		 * Unix authentication required.
+		 */
+		void
+		MOUNTPROC_UMNTALL(void) = 4;
+
+		/*
+		 * Returns a list of all the exported filesystems, and which
+		 * machines are allowed to import it.
+		 */
+		exports
+		MOUNTPROC_EXPORT(void)  = 5;
+
+		/*
+		 * Identical to MOUNTPROC_EXPORT above
+		 */
+		exports
+		MOUNTPROC_EXPORTALL(void) = 6;
+	} = 1;
+
+	/*
+	 * Version two of the mount protocol communicates with version two
+	 * of the NFS protocol.
+	 * The only difference from version one is the addition of a POSIX
+	 * pathconf call.
+	 */
+	version MOUNTVERS_POSIX {
+		/*
+		 * Does no work. It is made available in all RPC services
+		 * to allow server reponse testing and timing
+		 */
+		void
+		MOUNTPROC_NULL(void) = 0;
+
+		/*	
+		 * If fhs_status is 0, then fhs_fhandle contains the
+	 	 * file handle for the directory. This file handle may
+		 * be used in the NFS protocol. This procedure also adds
+		 * a new entry to the mount list for this client mounting
+		 * the directory.
+		 * Unix authentication required.
+		 */
+		fhstatus 
+		MOUNTPROC_MNT(dirpath) = 1;
+
+		/*
+		 * Returns the list of remotely mounted filesystems. The 
+		 * mountlist contains one entry for each hostname and 
+		 * directory pair.
+		 */
+		mountlist
+		MOUNTPROC_DUMP(void) = 2;
+
+		/*
+		 * Removes the mount list entry for the directory
+		 * Unix authentication required.
+		 */
+		void
+		MOUNTPROC_UMNT(dirpath) = 3;
+
+		/*
+		 * Removes all of the mount list entries for this client
+		 * Unix authentication required.
+		 */
+		void
+		MOUNTPROC_UMNTALL(void) = 4;
+
+		/*
+		 * Returns a list of all the exported filesystems, and which
+		 * machines are allowed to import it.
+		 */
+		exports
+		MOUNTPROC_EXPORT(void)  = 5;
+
+		/*
+		 * Identical to MOUNTPROC_EXPORT above
+		 */
+		exports
+		MOUNTPROC_EXPORTALL(void) = 6;
+
+		/*
+		 * POSIX pathconf info (Sun hack)
+		 */
+		ppathcnf
+		MOUNTPROC_PATHCONF(dirpath) = 7;
+	} = 2;
+	version MOUNT_V3 {
+		/*
+		 * Does no work. It is made available in all RPC services
+		 * to allow server reponse testing and timing
+		 */
+		void
+		MOUNTPROC3_NULL(void) = 0;
+
+		/*	
+		 * If fhs_status is 0, then fhs_fhandle contains the
+	 	 * file handle for the directory. This file handle may
+		 * be used in the NFS protocol. This procedure also adds
+		 * a new entry to the mount list for this client mounting
+		 * the directory.
+		 * Unix authentication required.
+		 */
+		mountres3
+		MOUNTPROC3_MNT(dirpath) = 1;
+
+		/*
+		 * Returns the list of remotely mounted filesystems. The 
+		 * mountlist contains one entry for each hostname and 
+		 * directory pair.
+		 */
+		mountlist
+		MOUNTPROC3_DUMP(void) = 2;
+
+		/*
+		 * Removes the mount list entry for the directory
+		 * Unix authentication required.
+		 */
+		void
+		MOUNTPROC3_UMNT(dirpath) = 3;
+
+		/*
+		 * Removes all of the mount list entries for this client
+		 * Unix authentication required.
+		 */
+		void
+		MOUNTPROC3_UMNTALL(void) = 4;
+
+		/*
+		 * Returns a list of all the exported filesystems, and which
+		 * machines are allowed to import it.
+		 */
+		exports
+		MOUNTPROC3_EXPORT(void)  = 5;
+
+	} = 3;
+} = 100005;
+
+#ifdef RPC_HDR
+%#endif /*!_rpcsvc_mount_h*/
+#endif
diff -uprN nfs-utils-1.0.8/utils/mount/nfsmount_xdr.c nfs-utils-1.0.8-ag/utils/mount/nfsmount_xdr.c
--- nfs-utils-1.0.8/utils/mount/nfsmount_xdr.c	1969-12-31 19:00:00.000000000 -0500
+++ nfs-utils-1.0.8-ag/utils/mount/nfsmount_xdr.c	2006-06-08 11:22:22.165815000 -0400
@@ -0,0 +1,329 @@
+/*
+ * Please do not edit this file.
+ * It was generated using rpcgen.
+ */
+
+#include "nfsmount.h"
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part.  Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user or with the express written consent of
+ * Sun Microsystems, Inc.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California  94043
+ */
+/*
+ * Copyright (c) 1985, 1990 by Sun Microsystems, Inc.
+ */
+
+/* from @(#)mount.x	1.3 91/03/11 TIRPC 1.0 */
+#include <asm/types.h>
+
+bool_t
+xdr_fhandle (XDR *xdrs, fhandle objp)
+{
+	register int32_t *buf;
+
+	 if (!xdr_opaque (xdrs, objp, FHSIZE))
+		 return FALSE;
+	return TRUE;
+}
+
+bool_t
+xdr_fhandle3 (XDR *xdrs, fhandle3 *objp)
+{
+	register int32_t *buf;
+
+	 if (!xdr_bytes (xdrs, (char **)&objp->fhandle3_val, (u_int *) &objp->fhandle3_len, FHSIZE3))
+		 return FALSE;
+	return TRUE;
+}
+
+bool_t
+xdr_mountstat3 (XDR *xdrs, mountstat3 *objp)
+{
+	register int32_t *buf;
+
+	 if (!xdr_enum (xdrs, (enum_t *) objp))
+		 return FALSE;
+	return TRUE;
+}
+
+bool_t
+xdr_fhstatus (XDR *xdrs, fhstatus *objp)
+{
+	register int32_t *buf;
+
+	 if (!xdr_u_int (xdrs, &objp->fhs_status))
+		 return FALSE;
+	switch (objp->fhs_status) {
+	case 0:
+		 if (!xdr_fhandle (xdrs, objp->fhstatus_u.fhs_fhandle))
+			 return FALSE;
+		break;
+	default:
+		break;
+	}
+	return TRUE;
+}
+
+bool_t
+xdr_mountres3_ok (XDR *xdrs, mountres3_ok *objp)
+{
+	register int32_t *buf;
+
+	 if (!xdr_fhandle3 (xdrs, &objp->fhandle))
+		 return FALSE;
+	 if (!xdr_array (xdrs, (char **)&objp->auth_flavours.auth_flavours_val, (u_int *) &objp->auth_flavours.auth_flavours_len, ~0,
+		sizeof (int), (xdrproc_t) xdr_int))
+		 return FALSE;
+	return TRUE;
+}
+
+bool_t
+xdr_mountres3 (XDR *xdrs, mountres3 *objp)
+{
+	register int32_t *buf;
+
+	 if (!xdr_mountstat3 (xdrs, &objp->fhs_status))
+		 return FALSE;
+	switch (objp->fhs_status) {
+	case MNT_OK:
+		 if (!xdr_mountres3_ok (xdrs, &objp->mountres3_u.mountinfo))
+			 return FALSE;
+		break;
+	default:
+		break;
+	}
+	return TRUE;
+}
+
+bool_t
+xdr_dirpath (XDR *xdrs, dirpath *objp)
+{
+	register int32_t *buf;
+
+	 if (!xdr_string (xdrs, objp, MNTPATHLEN))
+		 return FALSE;
+	return TRUE;
+}
+
+bool_t
+xdr_name (XDR *xdrs, name *objp)
+{
+	register int32_t *buf;
+
+	 if (!xdr_string (xdrs, objp, MNTNAMLEN))
+		 return FALSE;
+	return TRUE;
+}
+
+bool_t
+xdr_mountlist (XDR *xdrs, mountlist *objp)
+{
+	register int32_t *buf;
+
+	 if (!xdr_pointer (xdrs, (char **)objp, sizeof (struct mountbody), (xdrproc_t) xdr_mountbody))
+		 return FALSE;
+	return TRUE;
+}
+
+bool_t
+xdr_mountbody (XDR *xdrs, mountbody *objp)
+{
+	register int32_t *buf;
+
+	 if (!xdr_name (xdrs, &objp->ml_hostname))
+		 return FALSE;
+	 if (!xdr_dirpath (xdrs, &objp->ml_directory))
+		 return FALSE;
+	 if (!xdr_mountlist (xdrs, &objp->ml_next))
+		 return FALSE;
+	return TRUE;
+}
+
+bool_t
+xdr_groups (XDR *xdrs, groups *objp)
+{
+	register int32_t *buf;
+
+	 if (!xdr_pointer (xdrs, (char **)objp, sizeof (struct groupnode), (xdrproc_t) xdr_groupnode))
+		 return FALSE;
+	return TRUE;
+}
+
+bool_t
+xdr_groupnode (XDR *xdrs, groupnode *objp)
+{
+	register int32_t *buf;
+
+	 if (!xdr_name (xdrs, &objp->gr_name))
+		 return FALSE;
+	 if (!xdr_groups (xdrs, &objp->gr_next))
+		 return FALSE;
+	return TRUE;
+}
+
+bool_t
+xdr_exports (XDR *xdrs, exports *objp)
+{
+	register int32_t *buf;
+
+	 if (!xdr_pointer (xdrs, (char **)objp, sizeof (struct exportnode), (xdrproc_t) xdr_exportnode))
+		 return FALSE;
+	return TRUE;
+}
+
+bool_t
+xdr_exportnode (XDR *xdrs, exportnode *objp)
+{
+	register int32_t *buf;
+
+	 if (!xdr_dirpath (xdrs, &objp->ex_dir))
+		 return FALSE;
+	 if (!xdr_groups (xdrs, &objp->ex_groups))
+		 return FALSE;
+	 if (!xdr_exports (xdrs, &objp->ex_next))
+		 return FALSE;
+	return TRUE;
+}
+
+bool_t
+xdr_ppathcnf (XDR *xdrs, ppathcnf *objp)
+{
+	register int32_t *buf;
+
+	int i;
+
+	if (xdrs->x_op == XDR_ENCODE) {
+		buf = XDR_INLINE (xdrs, 6 * BYTES_PER_XDR_UNIT);
+		if (buf == NULL) {
+			 if (!xdr_int (xdrs, &objp->pc_link_max))
+				 return FALSE;
+			 if (!xdr_short (xdrs, &objp->pc_max_canon))
+				 return FALSE;
+			 if (!xdr_short (xdrs, &objp->pc_max_input))
+				 return FALSE;
+			 if (!xdr_short (xdrs, &objp->pc_name_max))
+				 return FALSE;
+			 if (!xdr_short (xdrs, &objp->pc_path_max))
+				 return FALSE;
+			 if (!xdr_short (xdrs, &objp->pc_pipe_buf))
+				 return FALSE;
+
+		} else {
+		IXDR_PUT_LONG(buf, objp->pc_link_max);
+		IXDR_PUT_SHORT(buf, objp->pc_max_canon);
+		IXDR_PUT_SHORT(buf, objp->pc_max_input);
+		IXDR_PUT_SHORT(buf, objp->pc_name_max);
+		IXDR_PUT_SHORT(buf, objp->pc_path_max);
+		IXDR_PUT_SHORT(buf, objp->pc_pipe_buf);
+		}
+		 if (!xdr_u_char (xdrs, &objp->pc_vdisable))
+			 return FALSE;
+		 if (!xdr_char (xdrs, &objp->pc_xxx))
+			 return FALSE;
+		buf = XDR_INLINE (xdrs, ( 2 ) * BYTES_PER_XDR_UNIT);
+		if (buf == NULL) {
+			 if (!xdr_vector (xdrs, (char *)objp->pc_mask, 2,
+				sizeof (short), (xdrproc_t) xdr_short))
+				 return FALSE;
+		} else {
+			{
+				register short *genp;
+
+				for (i = 0, genp = objp->pc_mask;
+					i < 2; ++i) {
+					IXDR_PUT_SHORT(buf, *genp++);
+				}
+			}
+		}
+		return TRUE;
+	} else if (xdrs->x_op == XDR_DECODE) {
+		buf = XDR_INLINE (xdrs, 6 * BYTES_PER_XDR_UNIT);
+		if (buf == NULL) {
+			 if (!xdr_int (xdrs, &objp->pc_link_max))
+				 return FALSE;
+			 if (!xdr_short (xdrs, &objp->pc_max_canon))
+				 return FALSE;
+			 if (!xdr_short (xdrs, &objp->pc_max_input))
+				 return FALSE;
+			 if (!xdr_short (xdrs, &objp->pc_name_max))
+				 return FALSE;
+			 if (!xdr_short (xdrs, &objp->pc_path_max))
+				 return FALSE;
+			 if (!xdr_short (xdrs, &objp->pc_pipe_buf))
+				 return FALSE;
+
+		} else {
+		objp->pc_link_max = IXDR_GET_LONG(buf);
+		objp->pc_max_canon = IXDR_GET_SHORT(buf);
+		objp->pc_max_input = IXDR_GET_SHORT(buf);
+		objp->pc_name_max = IXDR_GET_SHORT(buf);
+		objp->pc_path_max = IXDR_GET_SHORT(buf);
+		objp->pc_pipe_buf = IXDR_GET_SHORT(buf);
+		}
+		 if (!xdr_u_char (xdrs, &objp->pc_vdisable))
+			 return FALSE;
+		 if (!xdr_char (xdrs, &objp->pc_xxx))
+			 return FALSE;
+		buf = XDR_INLINE (xdrs, ( 2 ) * BYTES_PER_XDR_UNIT);
+		if (buf == NULL) {
+			 if (!xdr_vector (xdrs, (char *)objp->pc_mask, 2,
+				sizeof (short), (xdrproc_t) xdr_short))
+				 return FALSE;
+		} else {
+			{
+				register short *genp;
+
+				for (i = 0, genp = objp->pc_mask;
+					i < 2; ++i) {
+					*genp++ = IXDR_GET_SHORT(buf);
+				}
+			}
+		}
+	 return TRUE;
+	}
+
+	 if (!xdr_int (xdrs, &objp->pc_link_max))
+		 return FALSE;
+	 if (!xdr_short (xdrs, &objp->pc_max_canon))
+		 return FALSE;
+	 if (!xdr_short (xdrs, &objp->pc_max_input))
+		 return FALSE;
+	 if (!xdr_short (xdrs, &objp->pc_name_max))
+		 return FALSE;
+	 if (!xdr_short (xdrs, &objp->pc_path_max))
+		 return FALSE;
+	 if (!xdr_short (xdrs, &objp->pc_pipe_buf))
+		 return FALSE;
+	 if (!xdr_u_char (xdrs, &objp->pc_vdisable))
+		 return FALSE;
+	 if (!xdr_char (xdrs, &objp->pc_xxx))
+		 return FALSE;
+	 if (!xdr_vector (xdrs, (char *)objp->pc_mask, 2,
+		sizeof (short), (xdrproc_t) xdr_short))
+		 return FALSE;
+	return TRUE;
+}
diff -uprN nfs-utils-1.0.8/utils/mount/nfsumount.c nfs-utils-1.0.8-ag/utils/mount/nfsumount.c
--- nfs-utils-1.0.8/utils/mount/nfsumount.c	1969-12-31 19:00:00.000000000 -0500
+++ nfs-utils-1.0.8-ag/utils/mount/nfsumount.c	2006-06-08 11:22:22.171816000 -0400
@@ -0,0 +1,386 @@
+/*
+ * nfsumount.c -- Linux NFS umount
+ * Copyright (C) 2006 Amit Gud <gud@eth.net>
+ *
+ * - Basic code and wrapper around NFS umount code originally
+ *   in util-linux/mount/nfsmount.c
+ *
+ * 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.
+ *
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <getopt.h>
+#include <mntent.h>
+#include <ctype.h>
+#include <sys/mount.h>
+
+#include "xcommon.h"
+#include "nfsmount.h"
+#include "mount_constants.h"
+#include "fstab.h"
+#include "nls.h"
+#include "conn.h"
+
+#if !defined(MNT_FORCE)
+/* dare not try to include <linux/mount.h> -- lots of errors */
+#define MNT_FORCE 1
+#endif
+
+#if !defined(MNT_DETACH)
+#define MNT_DETACH 2
+#endif
+
+extern char *progname;
+extern int nfs_mount_version;
+extern int nomtab;
+extern int verbose;
+int force;
+int lazy;
+int remount;
+
+extern int find_kernel_nfs_mount_version(void);
+extern int probe_mntport(clnt_addr_t *);
+extern int nfs_gethostbyname(const char *, struct sockaddr_in *);
+
+static inline enum clnt_stat
+nfs3_umount(dirpath *argp, CLIENT *clnt)
+{
+	static char clnt_res;
+	memset (&clnt_res, 0, sizeof(clnt_res));
+	return clnt_call(clnt, MOUNTPROC_UMNT,
+			 (xdrproc_t) xdr_dirpath, (caddr_t)argp,
+			 (xdrproc_t) xdr_void, (caddr_t) &clnt_res,
+			 TIMEOUT);
+}
+
+static inline enum clnt_stat
+nfs2_umount(dirpath *argp, CLIENT *clnt)
+{
+	static char clnt_res;
+	memset (&clnt_res, 0, sizeof(clnt_res));
+	return clnt_call(clnt, MOUNTPROC_UMNT,
+			 (xdrproc_t) xdr_dirpath, (caddr_t)argp,
+			 (xdrproc_t) xdr_void, (caddr_t) &clnt_res,
+			 TIMEOUT);
+}
+
+int nfs_call_umount(clnt_addr_t *mnt_server, dirpath *argp)
+{
+	CLIENT *clnt;
+	enum clnt_stat res = 0;
+	int msock;
+
+	clnt = mnt_openclnt(mnt_server, &msock);
+	if (!clnt)
+		goto out_bad;
+	switch (mnt_server->pmap.pm_vers) {
+	case 3:
+		res = nfs3_umount(argp, clnt);
+		break;
+	case 2:
+	case 1:
+		res = nfs2_umount(argp, clnt);
+		break;
+	default:
+		break;
+	}
+	mnt_closeclnt(clnt, msock);
+	if (res == RPC_SUCCESS)
+		return 1;
+ out_bad:
+	return 0;
+}
+
+u_int get_mntproto(const char *);
+u_int
+get_mntproto(const char *dirname)
+{
+	FILE *mtab;
+	struct mntent mntbuf;
+	char tmpbuf[BUFSIZ];
+	u_int proto = IPPROTO_TCP; /* assume tcp */
+
+	 mtab = setmntent ("/proc/mounts", "r");
+	 if (mtab == NULL)
+	 	mtab = setmntent (_PATH_MOUNTED, "r");
+	if (mtab == NULL)
+		return proto;
+
+	while(getmntent_r(mtab, &mntbuf, tmpbuf, sizeof (tmpbuf))) {
+		if (strcmp(mntbuf.mnt_type, "nfs"))
+			continue;
+		if (strcmp(dirname,  mntbuf.mnt_fsname))
+			continue;
+		if (hasmntopt(&mntbuf, "udp"))
+			proto = IPPROTO_UDP;
+		break;
+	}
+	endmntent (mtab);
+
+	return proto;
+}
+
+/* complain about a failed umount */
+static void complain(int err, const char *dev) {
+  switch (err) {
+    case ENXIO:
+      nfs_error (_("umount: %s: invalid block device"), dev); break;
+    case EINVAL:
+      nfs_error (_("umount: %s: not mounted"), dev); break;
+    case EIO:
+      nfs_error (_("umount: %s: can't write superblock"), dev); break;
+    case EBUSY:
+     /* Let us hope fstab has a line "proc /proc ..."
+        and not "none /proc ..."*/
+      nfs_error (_("umount: %s: device is busy"), dev); break;
+    case ENOENT:
+      nfs_error (_("umount: %s: not found"), dev); break;
+    case EPERM:
+      nfs_error (_("umount: %s: must be superuser to umount"), dev); break;
+    case EACCES:
+      nfs_error (_("umount: %s: block devices not permitted on fs"), dev); break;
+    default:
+      nfs_error (_("umount: %s: %s"), dev, strerror (err)); break;
+  }
+}
+
+int add_mtab2(const char *spec, const char *node, const char *type,
+		const char *opts, struct mntentchn *mc)
+{
+	int umnt_err, umnt_err2, res;
+
+        umnt_err = umnt_err2 = 0;
+        if (lazy) {
+                res = umount2 (node, MNT_DETACH);
+                if (res < 0)
+                        umnt_err = errno;
+                goto writemtab;
+        }
+
+        if (force) {
+                res = umount2 (node, MNT_FORCE);
+                if (res == -1) {
+                        int errsv = errno;
+                        perror("umount2");
+                        errno = errsv;
+                        if (errno == ENOSYS) {
+                                if (verbose)
+                                        printf(_("no umount2, trying umount...\n"));
+                                res = umount (node);
+                        }
+                }
+        } else
+                res = umount (node);
+
+        if (res < 0) {
+                umnt_err = errno;
+                /* A device might have been mounted on a node that has since
+                   been deleted or renamed, so if node fails, also try spec. */
+                /* Note that this is incorrect in case spec was mounted
+                   several times. */
+                /* if (umnt_err == ENOENT || umnt_err == EINVAL) */
+                if (umnt_err != EBUSY && strcmp(node, spec)) {
+                        if (verbose)
+                                printf (_("could not umount %s - trying %s instead\n"),
+                                        node, spec);
+                        res = umount (spec);
+                        if (res < 0)
+                                umnt_err2 = errno;
+                       /* Do not complain about remote NFS mount points */
+                        if (errno == ENOENT && index(spec, ':'))
+                                umnt_err2 = 0;
+                }
+        }
+
+        if (res < 0 && remount && (umnt_err == EBUSY || umnt_err2 == EBUSY)) {
+                /* Umount failed - let us try a remount */
+                res = mount(spec, node, NULL,
+                            MS_MGC_VAL | MS_REMOUNT | MS_RDONLY, NULL);
+                if (res == 0) {
+                        nfs_mntent_t remnt;
+                        fprintf(stderr,
+                                _("umount: %s busy - remounted read-only\n"),
+                                spec);
+                        remnt.mnt_type = remnt.mnt_fsname = NULL;
+                        remnt.mnt_dir = xstrdup(node);
+                        remnt.mnt_opts = xstrdup("ro");
+                        if (!nomtab)
+                                update_mtab(node, &remnt);
+                        return 0;
+                } else if (errno != EBUSY) {    /* hmm ... */
+                        perror("remount");
+                        fprintf(stderr,
+                                _("umount: could not remount %s read-only\n"),
+                                spec);
+                }
+        }
+
+        if (res >= 0) {
+                /* Umount succeeded */
+                if (verbose)
+                        printf (_("%s umounted\n"), spec);
+        }
+
+ writemtab:
+        if (!nomtab &&
+            (umnt_err == 0 || umnt_err == EINVAL || umnt_err == ENOENT)) {
+               update_mtab (node, NULL);
+        }
+
+        if (res >= 0)
+                return 0;
+
+        if (umnt_err2)
+                complain(umnt_err2, spec);
+        if (umnt_err && umnt_err != umnt_err2)
+                complain(umnt_err, node);
+        return 1;
+}
+
+int _nfsumount(const char *spec, const char *opts)
+{
+	char *hostname;
+	char *dirname;
+	clnt_addr_t mnt_server = { &hostname, };
+	struct pmap *pmap = &mnt_server.pmap;
+	char *p;
+
+	nfs_mount_version = find_kernel_nfs_mount_version();
+	if (spec == NULL || (p = strchr(spec,':')) == NULL)
+		goto out_bad;
+	hostname = xstrndup(spec, p-spec);
+	dirname = xstrdup(p+1);
+#ifdef NFS_MOUNT_DEBUG
+	printf(_("host: %s, directory: %s\n"), hostname, dirname);
+#endif
+
+	if (opts && (p = strstr(opts, "addr="))) {
+		char *q;
+
+		free(hostname);
+		p += 5;
+		q = p;
+		while (*q && *q != ',') q++;
+		hostname = xstrndup(p,q-p);
+	}
+
+	if (opts && (p = strstr(opts, "mounthost="))) {
+		char *q;
+
+		free(hostname);
+		p += 10;
+		q = p;
+		while (*q && *q != ',') q++;
+		hostname = xstrndup(p,q-p);
+	}
+
+	pmap->pm_prog = MOUNTPROG;
+	pmap->pm_vers = MOUNTVERS;
+	pmap->pm_prot = get_mntproto(spec);
+	if (opts && (p = strstr(opts, "mountprog=")) && isdigit(*(p+10)))
+		pmap->pm_prog = atoi(p+10);
+	if (opts && (p = strstr(opts, "mountport=")) && isdigit(*(p+10)))
+		pmap->pm_port = atoi(p+10);
+	if (opts && (p = strstr(opts, "nfsvers=")) && isdigit(*(p+8)))
+		pmap->pm_vers = nfsvers_to_mnt(atoi(p+8));
+	if (opts && (p = strstr(opts, "mountvers=")) && isdigit(*(p+10)))
+		pmap->pm_vers = atoi(p+10);
+
+	if (!nfs_gethostbyname(hostname, &mnt_server.saddr))
+		goto out_bad;
+	if (!probe_mntport(&mnt_server))
+		goto out_bad;
+	return nfs_call_umount(&mnt_server, &dirname);
+ out_bad:
+	return 0;
+}
+
+static struct option umount_longopts[] =
+{
+  { "force", 0, 0, 'f' },
+  { "help", 0, 0, 'h' },
+  { "no-mtab", 0, 0, 'n' },
+  { "verbose", 0, 0, 'v' },
+  { "read-only", 0, 0, 'r' },
+  { NULL, 0, 0, 0 }
+};
+
+void umount_usage()
+{
+	printf("usage: %s dir [-fvnrlh]\n", progname);
+	printf("options:\n\t-f\t\tforce unmount\n");
+	printf("\t-v\t\tverbose\n");
+	printf("\t-n\t\tno mtab updation\n");
+	printf("\t-r\t\tremount\n");
+	printf("\t-l\t\tlazy unmount\n");
+	printf("\t-h\t\tprint this help\n\n");
+}
+
+int nfsumount(int argc, char *argv[])
+{
+	int c, ret;
+	char *spec;
+	struct mntentchn *mc;
+
+	spec = canonicalize(argv[1]);
+
+	argv += 1;
+	argc -= 1;
+
+	while ((c = getopt_long (argc, argv, "fvnrlh",
+				umount_longopts, NULL)) != -1) {
+
+		switch (c) {
+		case 'f':
+			++force;
+			break;
+		case 'v':
+			++verbose;
+			break;
+		case 'n':
+			++nomtab;
+			break;
+		case 'r':
+			++remount;
+			break;
+		case 'l':
+			++lazy;
+			break;
+		case 'h':
+		default:
+			umount_usage();
+			break;
+		}
+	}
+
+	mc = getmntdirbackward(spec, NULL);
+	if (!mc)
+		mc = getmntdevbackward(spec, NULL);
+	if (!mc && verbose)
+	printf(_("Could not find %s in mtab\n"), spec);
+
+	if(mc) {
+		ret = _nfsumount(mc->m.mnt_fsname, mc->m.mnt_opts);
+		if(ret)
+			ret = add_mtab2(mc->m.mnt_fsname, mc->m.mnt_dir,
+				mc->m.mnt_type, mc->m.mnt_opts, mc);
+	}
+	else {
+		ret = _nfsumount(spec, NULL);
+		if(ret)
+			ret = add_mtab2(spec, spec, spec, spec, NULL);
+	}
+
+	return(ret);
+}
+
diff -uprN nfs-utils-1.0.8/utils/mount/umount.nfs.man nfs-utils-1.0.8-ag/utils/mount/umount.nfs.man
--- nfs-utils-1.0.8/utils/mount/umount.nfs.man	1969-12-31 19:00:00.000000000 -0500
+++ nfs-utils-1.0.8-ag/utils/mount/umount.nfs.man	2006-06-08 11:22:22.177815000 -0400
@@ -0,0 +1,76 @@
+.\"@(#)mount.nfs.8"
+.TH UMOUNT.NFS 8 "6 Jun 2006"
+.SH NAME
+umount.nfs, umount.nfs4 \- unmount a Network File System
+.SH SYNOPSIS
+.BI "umount.nfs" " dir" " [\-fvnrlh ]"
+.SH DESCRIPTION
+.BR umount.nfs
+and
+.BR umount.nfs4
+are a part of 
+.BR nfs (5)
+utilities package, which provides NFS client functionality.
+
+.BR umount.nfs4 
+and
+.BR umount.nfs
+are meant to be used by the
+.BR umount (8)
+command for unmounting NFS shares. This subcommand, however, can also be used as a standalone command with limited functionality.
+
+.BR umount.nfs4 
+is used for mounting NFSv4 file system, while 
+.BR umount.nfs 
+is used to mount NFS file systems with older versions.
+.I dir 
+is the directory on which the file system is mounted.
+
+.SH OPTIONS
+.TP
+.BI "\-f"
+Force unmount the file system in case of unreachable NFS system.
+.TP
+.BI "\-v"
+Be verbose.
+.TP
+.BI "\-n"
+Make no updation to mtab. By default, an entry is created in 
+.I /etc/mtab 
+for every mounted file system. Use this option to skip deleting an entry.
+.TP
+.BI "\-r"
+In case unmounting fails, try to mount read-only.
+.TP
+.BI "\-l"
+Lazy unmount. Detach the file system from the file system hierarchy now, and cleanup all references to the file system as soon as it is not busy anymore.
+.TP
+.BI "\-h"
+Print help message.
+
+.SH NOTE
+For further information please refer 
+.BR nfs (5)
+and
+.BR umount (8)
+manual pages.
+
+.SH FILES
+.TP 18n
+.I /etc/fstab
+file system table
+.TP
+.I /etc/mtab
+table of mounted file systems
+
+.PD
+.SH "SEE ALSO"
+.BR nfs (5),
+.BR umount (8),
+
+.SH BUGS
+Please notify current developers of NFS of any bugs in the current software or mail nfs@lists.sourceforge.net
+
+.SH "AUTHOR"
+Amit Gud <agud@redhat.com>
+
--- nfs-utils-1.0.8/configure.in	2006-04-11 22:55:51.000000000 -0400
+++ nfs-utils-1.0.8-ag/configure.in	2006-06-08 11:22:22.181815000 -0400
@@ -313,6 +313,7 @@ AC_CONFIG_FILES([
 	utils/gssd/Makefile
 	utils/idmapd/Makefile
 	utils/lockd/Makefile
+	utils/mount/Makefile
 	utils/mountd/Makefile
 	utils/nfsd/Makefile
 	utils/nfsstat/Makefile

[-- Attachment #3: Type: text/plain, Size: 0 bytes --]



[-- Attachment #4: Type: text/plain, Size: 140 bytes --]

_______________________________________________
NFS maillist  -  NFS@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/nfs

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

* Re: [PATCH 1 / 2] Move NFS mount code from util-linux to nfs-utils
  2006-06-08 19:10 [PATCH 1 / 2] Move NFS mount code from util-linux to nfs-utils Amit Gud
@ 2006-06-09  6:14 ` Neil Brown
  0 siblings, 0 replies; 2+ messages in thread
From: Neil Brown @ 2006-06-09  6:14 UTC (permalink / raw)
  To: Amit Gud; +Cc: nfs, Steve Dickson

On Thursday June 8, agud@redhat.com wrote:
> 
> Adds the mount directory and the code to mount and umount the NFS file system.
> 
> 
> Signed-off-by: Amit Gud <agud@redhat.com>
> Signed-off-by: Steve Dickson <steved@redhat.com>
> 
> ---
> diff -uprN nfs-utils-1.0.8/utils/mount/mount.c nfs-utils-1.0.8-ag/utils/mount/mount.c
> --- nfs-utils-1.0.8/utils/mount/mount.c	1969-12-31 19:00:00.000000000 -0500
> +++ nfs-utils-1.0.8-ag/utils/mount/mount.c	2006-06-08 11:22:22.107815000 -0400
> +
> +extern int nfsumount(int, char **);
> +extern int nfs4mount(const char *, const char *, int *, char **,
> +		char **, int);
> +extern int nfsmount(const char *, const char *, int *, char **,
> +		char **, int *, int);

Any chance of these going in an include file?  I really like the same
include file to be included both where the function is defined and
where it is used, so there is a some real checking of signature
consistency going on.

> +int add_mtab(char *fsname, char *mount_point, char *fstype, int flags, char *opts, int freq, int passno)
> +{
> +	struct mntent ment;
> +	int fd;
> +	FILE *mtab;
> +
> +	ment.mnt_fsname = fsname;
> +	ment.mnt_dir = mount_point;
> +	ment.mnt_type = fstype;
> +	ment.mnt_opts = fix_opts_string(flags, opts);
> +	ment.mnt_freq = 0;
> +	ment.mnt_passno= 0;
> +
> +	if ((fd = open(MTAB_FILE"~", O_RDWR|O_CREAT|O_EXCL, 0600)) == -1)	{
> +		fprintf(stderr, "Can't get "MOUNTED"~ lock file");

I think you mean "MTAB_FILE"~

But in the next patch, it is _PATH_MOUNTED.
A bit of consistence here would be a good thing!

> +		return 1;
> +	}
> +        close(fd);
> +
> +        if ((mtab = setmntent(MTAB_FILE, "a+")) == NULL) {
> +		fprintf(stderr, "Can't open " MTAB_FILE);
> +		return 1;
> +	}

> +
> +void mount_usage()
> +{
> +	printf("usage: %s remotetarget dir [-rvnh] [-t version] [-o nfsoptions]\n", progname);
> +	printf("options:\n\t-r\t\tmount readonly\n");
> +	printf("\t-v\t\tverbose\n");
> +	printf("\t-n\t\tno mtab updation\n");

I don't think 'updation' is a word :-)
Maybe:   -n    Do not update /etc/mtab

> +	printf("\t-h\t\tprint this help\n");
> +	printf("\tversion\t\tnfs4 - NFS version 4, nfs - older NFS version supported\n");
> +	printf("\tnfsoptions\tRefer mount.nfs(8) or nfs(5)\n\n");
> +}


> +
> +	spec = canonicalize(argv[1]);
> +	mount_point = canonicalize(argv[2]);
> +

I'm certain you don't want to 'canonicalize' "spec" as it is not a
local path name.  I'm not convinced that you want to canonicalize
mount_point, but I cannot immediately see any harm in it.

> +
> +	parse_opts(mount_opts, &flags, &extra_opts);
> +
> +	if (!strcmp(progname, "mount.nfs4") || nfs_mount_vers == 4) {
> +		nfs_mount_vers = 4;
> +		mnt_err = nfs4mount(spec, mount_point, &flags, &extra_opts, &mount_opts, 0);
> +	}
> +
> +	/* fall back to v3 if v4 didn't work */

Nope.  Falling back to v2 if v3 didn't work and no explicit version
was given is OK,  Falling back to v3 if v4 doesn't work is definitely
not ok because
  1- we only use v4 if an explicit version is asked for
  2- v4 is very different, and has different path names for places on
            the server.

> +	if (mnt_err && errno != EBUSY && errno != ENOENT) {
> +		nfs_mount_vers = 3;
> +		mnt_err = nfsmount(spec, mount_point, &flags, &extra_opts, &mount_opts, &nfs_mount_vers, 0);
> +	}
> +
> +	if (!mnt_err) {
> +		do_mount_syscall(spec, mount_point, nfs_mount_vers == 4 ? "nfs4" : "nfs", flags, mount_opts);
> +		if(!nomtab)
> +			add_mtab(spec, mount_point, nfs_mount_vers == 4 ? "nfs4" : "nfs",
> +				 flags, extra_opts, 0, 0);
> +	}

I think I would prefer to have two completely separate branches here,
one for v4, one for v2/3 (But if you really really don't like that
idea, I might listen).

> diff -uprN nfs-utils-1.0.8/utils/mount/mount_constants.h nfs-utils-1.0.8-ag/utils/mount/mount_constants.h
> --- nfs-utils-1.0.8/utils/mount/mount_constants.h	1969-12-31 19:00:00.000000000 -0500
> +++ nfs-utils-1.0.8-ag/utils/mount/mount_constants.h	2006-06-08 11:22:22.113815000 -0400
> @@ -0,0 +1,74 @@
> +#ifndef _NFS_MOUNT_CONSTANTS_H
> +#define _NFS_MOUNT_CONSTANTS_H
> +
> +#ifndef MS_RDONLY
> +#define MS_RDONLY	 1	/* Mount read-only */
> +#endif
> +#ifndef MS_NOSUID
> +#define MS_NOSUID	 2	/* Ignore suid and sgid bits */
> +#endif
> +#ifndef MS_NODEV
> +#define MS_NODEV	 4	/* Disallow access to device special files */
> +#endif
> +#ifndef MS_NOEXEC
> +#define MS_NOEXEC	 8	/* Disallow program execution */
> +#endif
> +#ifndef MS_SYNCHRONOUS
> +#define MS_SYNCHRONOUS	16	/* Writes are synced at once */
> +#endif
> +#ifndef MS_REMOUNT
> +#define MS_REMOUNT	32	/* Alter flags of a mounted FS */
> +#endif
> +#ifndef MS_MANDLOCK
> +#define MS_MANDLOCK	64	/* Allow mandatory locks on an FS */
> +#endif
> +#ifndef MS_DIRSYNC
> +#define MS_DIRSYNC	128	/* Directory modifications are synchronous */
> +#endif

Do we really need all of this?  Is there any system at all that we
want to support that doesn't have these in <sys/mount.h> ??



> diff -uprN nfs-utils-1.0.8/utils/mount/mount.nfs.man nfs-utils-1.0.8-ag/utils/mount/mount.nfs.man
> --- nfs-utils-1.0.8/utils/mount/mount.nfs.man	1969-12-31 19:00:00.000000000 -0500
> +++ nfs-utils-1.0.8-ag/utils/mount/mount.nfs.man	2006-06-08 11:22:22.118815000 -0400
> @@ -0,0 +1,87 @@
> +.\"@(#)mount.nfs.8"
> +.TH MOUNT.NFS 8 "5 Jun 2006"
> +.SH NAME
> +mount.nfs, mount.nfs4 \- mount a Network File System
> +.SH SYNOPSIS
> +.BI "mount.nfs" " remotetarget dir" " [\-rvnh ] [\-t " version "] [\-o " options "]
> +.SH DESCRIPTION
> +.BR mount.nfs
> +is a part of 
> +.BR nfs (5)
> +utilities package, which provides NFS client functionality.
> +
> +.BR mount.nfs 
> +is meant to be used by the
> +.BR mount (8)
> +command for mounting NFS shares. This subcommand, however, can also be used as a standalone command with limited functionality.
> +
> +.BR mount.nfs 
                ^^^ 4 ??

> +is used for mounting NFSv4 file system, while 
> +.BR mount.nfs 
> +is used to mount NFS file systems with older versions.
                        v2 or v3 filesystems.
Saying "older versions" is, I think, the wrong emphasis.  They are
simply different versions.

> +.I remotetarget 
> +is a server share usually in the form of 
> +.BR servername:/path/to/share.
> +.I dir 
> +is the directory on which the file system is to be mounted.
> +
> +.SH OPTIONS
> +.TP
> +.BI "\-r"
> +Mount file system readonly.
> +.TP
> +.BI "\-v"
> +Be verbose.
> +.TP
> +.BI "\-n"
> +Make no updation to mtab. By default, an entry is created in 
           ^^^^^^^^
There's that word again :-)


> +.I /etc/mtab 
> +for every mounted file system. Use this option to skip making an entry.
> +.TP
> +.BI "\-h"
> +Print help message.
> +.TP
> +.BI "version"
> +Specify NFS file system version. Either
> +.BR nfs4 
> +or 
> +.BR nfs.
> +By default 
> +.BR mount.nfs4 
> +takes version 4, and 
> +.BR mount.nfs 
> +takes any supported older version.

This implied that
         mount.nfs4 -t nfs
will use a v3 or v2 mount, but that code doesn't do that.
I would say something like:
   If the command is "mount.nfs4" or the filesystem type is nfs4,
   then version4 is used, else version 3 or 2 is used.


> +.TP
> +.BI "nfsoptions"
> +Refer 

Refer to

> +.BR nfs(5)
> +or
> +.BR mount(8) 
> +manual pages.
> +
> +.SH NOTE
> +For further information please refer 
                                        to
> +.BR nfs (5)
> +and
> +.BR mount (8)
> +manual pages.


> diff -uprN nfs-utils-1.0.8/utils/mount/nfs4mount.c nfs-utils-1.0.8-ag/utils/mount/nfs4mount.c
> --- nfs-utils-1.0.8/utils/mount/nfs4mount.c	1969-12-31 19:00:00.000000000 -0500
> +++ nfs-utils-1.0.8-ag/utils/mount/nfs4mount.c	2006-06-08 11:27:25.318390000 -0400
> @@ -0,0 +1,450 @@
> +/*
> + * nfs4mount.c -- Linux NFS mount
> + * Copyright (C) 2002 Trond Myklebust <trond.myklebust@fys.uio.no>
> + *
> + * 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.
> + *
> + * Note: this file based on the original nfsmount.c
> + *
> + * 2006-06-06 Amit Gud <agud@redhat.com>
> + * - Moved to nfs-utils/utils/mount from util-linux/mount.
> + */
> +
> +#include <linux/posix_types.h>
> +#include <asm/posix_types.h>
> +#undef __FD_CLR
> +#undef __FD_SET
> +#undef __FD_ISSET
> +#undef __FD_ZERO

Is it possible to avoid including anything from 'linux' or 'asm' ?? 
It is generally considered to be bad form.


> diff -uprN nfs-utils-1.0.8/utils/mount/nfsmount.h nfs-utils-1.0.8-ag/utils/mount/nfsmount.h
> --- nfs-utils-1.0.8/utils/mount/nfsmount.h	1969-12-31 19:00:00.000000000 -0500
> +++ nfs-utils-1.0.8-ag/utils/mount/nfsmount.h	2006-06-08 11:22:22.152816000 -0400
> @@ -0,0 +1,328 @@
> +/*
> + * Please do not edit this file.
> + * It was generated using rpcgen.
> + */

Please do not post this file.  It was generated using rpcgen
:-)

> diff -uprN nfs-utils-1.0.8/utils/mount/umount.nfs.man nfs-utils-1.0.8-ag/utils/mount/umount.nfs.man
> --- nfs-utils-1.0.8/utils/mount/umount.nfs.man	1969-12-31 19:00:00.000000000 -0500
> +++ nfs-utils-1.0.8-ag/utils/mount/umount.nfs.man	2006-06-08 11:22:22.177815000 -0400
> +.BI "\-n"
> +Make no updation to mtab. By default, an entry is created in 

and again....


I haven't looked closely at the core mount/umount code, but it seemed
reasonable and I assume it works...

If you'd like to send me a revised patch, it can probably get included
in the next nfs-utils.... though it occurs to me that it might be good
to have a  
   --without-mount
option to configure for distros that don't want to start using the
new-improved approach just yet.

NeilBrown


_______________________________________________
NFS maillist  -  NFS@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/nfs

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

end of thread, other threads:[~2006-06-09  6:15 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2006-06-08 19:10 [PATCH 1 / 2] Move NFS mount code from util-linux to nfs-utils Amit Gud
2006-06-09  6:14 ` Neil Brown

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.