]> err.no Git - util-linux/commitdiff
2.12r-4ubuntu5
authorLaMont Jones <lamont@mmjgroup.com>
Thu, 19 Jul 2007 02:38:59 +0000 (20:38 -0600)
committerLaMont Jones <lamont@mmjgroup.com>
Thu, 19 Jul 2007 02:40:09 +0000 (20:40 -0600)
debian/changelog
debian/control
debian/hwclock.rules [new file with mode: 0644]
debian/hwclock.udev [new file with mode: 0644]
debian/hwclockfirst.sh [deleted file]
debian/patches/00list
debian/patches/30nfs4-fix.dpatch [new file with mode: 0755]
debian/patches/30nfs4.dpatch [new file with mode: 0755]

index 30c35cced24b62c303bd7f20b0c3742d97cb8cbc..1e43ed7f7ada3df427c6b19aacc5a5960353ca7d 100644 (file)
@@ -1,3 +1,15 @@
+util-linux (2.12r-4ubuntu5) dapper; urgency=low
+
+  * Merge NFSv4 from debian (2.12r-9 versions 27-32)
+    - Leave hwclock.sh alone
+    - Turn on fixed nfsv4 patch.  Closes: #302420, #239031
+      - fix compiler warnings in said patch.
+      - Apply nfs4mount.c fix to (dropped) nfsv4 patch.  Closes: #354193
+      Closes: Ubuntu#43581, Ubuntu#27425
+      Thanks to Steinar H. Gunderson <sgunderson@bigfoot.com>
+
+ -- LaMont Jones <lamont@ubuntu.com>  Mon,  8 May 2006 13:37:50 -0600
+
 util-linux (2.12r-4ubuntu4) dapper; urgency=low
 
   * Rip out the log message code from the init script, as it's run in the
index a875f538a73460e5a81f5b2d620d16922af3b3b5..5cc53ea209b560592873e01fed98b846fac3744b 100644 (file)
@@ -3,7 +3,7 @@ Section: base
 Priority: required
 Build-Depends: libncurses5-dev, libslang2-dev (>=2.0.4-1), gettext, zlib1g-dev, libblkid-dev, uuid-dev, dpatch
 Maintainer: LaMont Jones <lamont@debian.org>
-Standards-Version: 3.5.6.0
+Standards-Version: 3.6.2.0
 
 Package: util-linux
 Architecture: any
diff --git a/debian/hwclock.rules b/debian/hwclock.rules
new file mode 100644 (file)
index 0000000..92b5e11
--- /dev/null
@@ -0,0 +1,3 @@
+# This file causes the hardware clock to be set when /dev/rtc is available.
+
+KERNEL=="rtc", ACTION=="add", RUN+="set_hwclock"
diff --git a/debian/hwclock.udev b/debian/hwclock.udev
new file mode 100644 (file)
index 0000000..d768f90
--- /dev/null
@@ -0,0 +1,29 @@
+#!/bin/sh
+# udev helper for hwclock
+#
+# This is based on the hwclock.sh init script, but somewhat simplified.
+
+[ ! -x /sbin/hwclock ] && exit 0
+. /etc/default/rcS
+
+[ "$GMT" = "-u" ] && UTC="yes"
+case "$UTC" in
+    no|"")     GMT="--localtime"
+               UTC=""
+               ;;
+    yes)       GMT="--utc"
+               UTC="--utc"
+               ;;
+    *)         exit 1 ;;
+esac
+
+case "$BADYEAR" in
+    no|"")     BADYEAR="" ;;
+    yes)       BADYEAR="--badyear" ;;
+    *)         exit 1 ;;
+esac
+
+# Copies Hardware Clock time to System Clock using the correct
+# timezone for hardware clocks in local time, and sets kernel
+# timezone. DO NOT REMOVE.
+/sbin/hwclock --hctosys $GMT $HWCLOCKPARS $BADYEAR
diff --git a/debian/hwclockfirst.sh b/debian/hwclockfirst.sh
deleted file mode 100644 (file)
index 1923e2b..0000000
+++ /dev/null
@@ -1,102 +0,0 @@
-#!/bin/bash
-# hwclockfirst.sh Set system clock to hardware clock, according to the UTC
-#               setting in /etc/default/rcS (see also rcS(5)).
-#
-#
-# WARNING:      Runs without write permission on /etc, and before
-#               mounting all filesystems! If you need write permission
-#               to do something, do it in hwclock.sh.
-#
-# WARNING:      If your hardware clock is not in UTC/GMT, this script
-#               must know the local time zone. This information is
-#               stored in /etc/localtime. This might be a problem if
-#               your /etc/localtime is a symlink to something in
-#               /usr/share/zoneinfo AND /usr isn't in the root
-#               partition! The workaround is to define TZ either
-#               in /etc/default/rcS, or in the proper place below.
-#
-# REMEMBER TO EDIT hwclock.sh AS WELL! 
-
-# Set this to any options you might need to give to hwclock, such
-# as machine hardware clock type for Alphas.
-HWCLOCKPARS=
-
-[ ! -x /sbin/hwclock ] && exit 0
-
-. /etc/default/rcS
-
-# Define TZ to the desired timezone here if you need it.
-# see tzset(3) for how to define TZ.
-# WARNING: TZ takes precedence over /etc/localtime !
-TZ=
-
-
-case "$UTC" in
-       no|"") GMT="--localtime"
-              UTC=""
-              if [ ! -r /etc/localtime ]
-               then
-               if [ -z "$TZ" ]
-                 then
-                     echo "$0: System clock was not updated at this time." >&2
-                      exit 1
-                fi
-              fi
-              ;;
-       yes)   GMT="--utc"
-              UTC="--utc"
-              ;;
-       *)     echo "$0: Unknown UTC setting: \"$UTC\"" >&2
-              exit 1
-              ;;
-esac
-
-
-case "$1" in
-        start)
-               # Copies Hardware Clock time to System Clock using the correct
-               # timezone for hardware clocks in local time, and sets kernel 
-               # timezone. DO NOT REMOVE.
-               if [ "$HWCLOCKACCESS" != no ]
-               then
-                       /sbin/hwclock --hctosys $GMT $BADYEAR
-               fi
-                if [ "$VERBOSE" != no ]
-                then
-                        echo "System time was `date --utc`."
-                        echo "Setting the System Clock using the Hardware Clock as reference..."
-                fi
-
-                # Copies Hardware Clock time to System Clock using the correct
-                # timezone for hardware clocks in local time, and sets kernel
-                # timezone. DO NOT REMOVE.
-               if [ -z "$TZ" ]
-               then
-                   /sbin/hwclock --noadjfile --hctosys $GMT $HWCLOCKPARS
-               else
-                  TZ="$TZ" /sbin/hwclock --noadjfile --hctosys $GMT $HWCLOCKPARS
-               fi
-
-               if /sbin/hwclock --show $GMT $HWCLOCKPARS 2>&1 > /dev/null | grep -q '^The Hardware Clock registers contain values that are either invalid'; then
-                       echo "Invalid system date -- setting to 1/1/2002"
-                       /sbin/hwclock --set --date '1/1/2002 00:00:00' $GMT $HWCLOCKPARS
-               fi
-                
-                if [ "$VERBOSE" != no ]
-                then
-                        echo "System Clock set. System local time is now `date $UTC`."
-                fi
-                ;;
-        stop|restart|reload|force-reload)
-                # Does nothing
-                exit 0
-                ;;
-        *)
-                echo "Usage: hwclockfirst.sh {start|stop|reload|restart}" >&2
-                echo "       start sets kernel (system) clock from hardware (RTC) clock" >&2
-                echo "       stop, restart, reload and force-reload do nothing." >&2
-                echo "       Refer to hwclock.sh as well." >&2
-                exit 1
-                ;;
-esac
-
index 0dfbd8076227a6c6c374bd126b212bf1c9e66a7e..7868cc3737c4fee8cea9c4259077febc8043d121 100644 (file)
@@ -10,6 +10,8 @@
 10sparcumount
 10warnings
 20guesshelper
+30nfs4
+30nfs4-fix
 #20xgethostname
 #50hurd
 60_opt_O1
diff --git a/debian/patches/30nfs4-fix.dpatch b/debian/patches/30nfs4-fix.dpatch
new file mode 100755 (executable)
index 0000000..8a7d119
--- /dev/null
@@ -0,0 +1,28 @@
+#! /bin/sh /usr/share/dpatch/dpatch-run
+## 30nfs4-fix.dpatch by Steinar H. Gunderson <sesse@debian.org>
+##
+## All lines beginning with `## DP:' are a description of the patch.
+## DP: No description.
+
+@DPATCH@
+diff -urNad util-linux-2.12r~/mount/nfsmount.c util-linux-2.12r/mount/nfsmount.c
+--- util-linux-2.12r~/mount/nfsmount.c 2006-04-28 18:59:19.000000000 +0200
++++ util-linux-2.12r/mount/nfsmount.c  2006-04-28 19:00:18.000000000 +0200
+@@ -301,6 +301,7 @@
+                        (xdrproc_t)xdr_void, (caddr_t)NULL,
+                        (xdrproc_t)xdr_void, (caddr_t)&clnt_res,
+                        TIMEOUT);
++      rpc_createerr.cf_stat = stat;
+       clnt_destroy(clnt);
+       close(sock);
+       if (stat != RPC_PROGVERSMISMATCH)
+@@ -416,7 +417,8 @@
+                               return 1;
+                       memcpy(mnt_pmap, &save_mnt, sizeof(*mnt_pmap));
+               }
+-              if (rpc_createerr.cf_stat != RPC_PROGNOTREGISTERED)
++              if (rpc_createerr.cf_stat != RPC_PROGNOTREGISTERED &&
++                  rpc_createerr.cf_stat != RPC_PROGVERSMISMATCH)
+                       break;
+               memcpy(nfs_pmap, &save_nfs, sizeof(*nfs_pmap));
+       }
diff --git a/debian/patches/30nfs4.dpatch b/debian/patches/30nfs4.dpatch
new file mode 100755 (executable)
index 0000000..ff1dc86
--- /dev/null
@@ -0,0 +1,2602 @@
+#! /bin/sh /usr/share/dpatch/dpatch-run
+## 30nfs4.dpatch by LaMont Jones <lamont@debian.org>
+##
+## All lines beginning with `## DP:' are a description of the patch.
+## DP: No description.
+
+@DPATCH@
+diff -urNad --exclude=CVS --exclude=.svn ./mount/Makefile /tmp/dpep-work.TJbhsa/2.12r-5.1/mount/Makefile
+--- ./mount/Makefile   2006-01-18 12:52:52.000000000 -0700
++++ /tmp/dpep-work.TJbhsa/2.12r-5.1/mount/Makefile     2006-01-18 12:53:26.000000000 -0700
+@@ -30,7 +30,7 @@
+ MAYBE = pivot_root swapoff
+ LO_OBJS = lomount.o $(LIB)/xstrncpy.o rmd160.o
+-NFS_OBJS = nfsmount.o nfsmount_xdr.o nfsmount_clnt.o
++NFS_OBJS = nfsmount.o nfsmount_xdr.o nfsmount_clnt.o nfs4mount.o
+ GEN_FILES = nfsmount.h nfsmount_xdr.c nfsmount_clnt.c
+ all: $(PROGS)
+@@ -54,7 +54,7 @@
+ umount: umount.o fstab.o sundries.o xmalloc.o realpath.o mntent.o \
+       getusername.o get_label_uuid.o mount_by_label.o mount_blkid.o \
+-      version.o $(LIB)/env.o $(LO_OBJS)
++      version.o  nfsmount.o nfsmount_xdr.o $(LIB)/env.o $(LO_OBJS)
+       $(LINK) $^ -o $@ $(BLKID_LIB)
+ swapon:       swapon.o version.o xmalloc.o \
+diff -urNad --exclude=CVS --exclude=.svn ./mount/mount.8 /tmp/dpep-work.TJbhsa/2.12r-5.1/mount/mount.8
+--- ./mount/mount.8    2006-01-18 12:52:52.000000000 -0700
++++ /tmp/dpep-work.TJbhsa/2.12r-5.1/mount/mount.8      2006-01-18 12:52:52.000000000 -0700
+@@ -389,6 +389,7 @@
+ .IR msdos ,
+ .IR ncpfs ,
+ .IR nfs ,
++.IR nfs4 ,
+ .IR ntfs ,
+ .IR proc ,
+ .IR qnx4 ,
+@@ -426,7 +427,7 @@
+ program has to do is issue a simple
+ .IR mount (2)
+ system call, and no detailed knowledge of the filesystem type is required.
+-For a few types however (like nfs, smbfs, ncpfs) ad hoc code is
++For a few types however (like nfs, nfs4, smbfs, ncpfs) ad hoc code is
+ necessary. The nfs ad hoc code is built in, but smbfs and ncpfs
+ have a separate mount program. In order to make it possible to
+ treat all types in a uniform way, mount will execute the program
+@@ -454,9 +455,10 @@
+ All of the filesystem types listed there will be tried,
+ except for those that are labeled "nodev" (e.g.,
+ .IR devpts ,
+-.I proc
++.IR proc ,
++.IR nfs ,
+ and
+-.IR nfs ).
++.IR nfs4 ).
+ If
+ .I /etc/filesystems
+ ends in a line with a single * only, mount will read
+@@ -1379,6 +1381,73 @@
+ .B nolock
+ Do not use locking. Do not start lockd.
++.SH "Mount options for nfs4"
++Instead of a textual option string, parsed by the kernel, the
++.I nfs4
++file system expects a binary argument of type
++.IR "struct nfs4_mount_data" .
++The program
++.B mount
++itself parses the following options of the form `tag=value',
++and puts them in the structure mentioned:
++.BI rsize= n,
++.BI wsize= n,
++.BI timeo= n,
++.BI retrans= n,
++.BI acregmin= n,
++.BI acregmax= n,
++.BI acdirmin= n,
++.BI acdirmax= n,
++.BI actimeo= n,
++.BI retry= n,
++.BI port= n,
++.BI proto= n,
++.BI clientaddr= n,
++.BI sec= n.
++The option
++.BI addr= n
++is accepted but ignored.
++Also the following Boolean options, possibly preceded by
++.B no
++are recognized:
++.BR bg ,
++.BR fg ,
++.BR soft ,
++.BR hard ,
++.BR intr ,
++.BR cto ,
++.BR ac ,
++For details, see
++.BR nfs (5).
++
++Especially useful options include
++.TP
++.B rsize=32768,wsize=32768
++This will make your NFS connection faster than with the default
++buffer size of 4096.
++.TP
++.B hard
++The program accessing a file on a NFS mounted file system will hang
++when the server crashes. The process cannot be interrupted or
++killed unless you also specify
++.BR intr .
++When the NFS server is back online the program will continue undisturbed
++from where it was. This is probably what you want.
++.TP
++.B soft
++This option allows the kernel to time out if the NFS server is not
++responding for some time. The time can be
++specified with
++.BR timeo=time .
++This timeout value is expressed in tenths of a second.
++The
++.BR soft
++option might be useful if your NFS server sometimes doesn't respond
++or will be rebooted while some process tries to get a file from the server.
++Avoid using this option with
++.BR proto=udp
++or with a short timeout.
++
+ .SH "Mount options for ntfs"
+ .TP
+ .BI iocharset= name
+diff -urNad --exclude=CVS --exclude=.svn ./mount/mount.c /tmp/dpep-work.TJbhsa/2.12r-5.1/mount/mount.c
+--- ./mount/mount.c    2006-01-18 12:52:52.000000000 -0700
++++ /tmp/dpep-work.TJbhsa/2.12r-5.1/mount/mount.c      2006-01-18 12:52:52.000000000 -0700
+@@ -873,8 +873,23 @@
+                     "without support for the type `nfs'"));
+ #endif
+   }
++#ifdef HAVE_NFS
++  /*
++   * NFSv4 support
++   */
++  if (!fake && types && streq (types, "nfs4")) {
++    mnt_err = nfs4mount(spec, node, &flags, &extra_opts, &mount_opts, bg);
++    if (mnt_err)
++      return mnt_err;
++      goto nosigblock;
++#else
++    die (EX_SOFTWARE, _("mount: this version was compiled "
++                    "without support for the type `nfs4'"));
++#endif
++  }
+   block_signals (SIG_BLOCK);
++nosigblock:
+   if (!fake) {
+     mnt5_res = guess_fstype_and_mount (spec, node, &types, flags & ~MS_NOSYS,
+diff -urNad --exclude=CVS --exclude=.svn ./mount/nfs4mount.c /tmp/dpep-work.TJbhsa/2.12r-5.1/mount/nfs4mount.c
+--- ./mount/nfs4mount.c        1969-12-31 17:00:00.000000000 -0700
++++ /tmp/dpep-work.TJbhsa/2.12r-5.1/mount/nfs4mount.c  2006-01-18 12:52:52.000000000 -0700
+@@ -0,0 +1,433 @@
++/*
++ * 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
++ */
++
++#include "../defines.h"       /* for HAVE_rpcsvc_nfs_prot_h and HAVE_inet_aton */
++
++#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/socket.h>
++#include <sys/time.h>
++#include <sys/utsname.h>
++#include <sys/stat.h>
++#include <netinet/in.h>
++#include <arpa/inet.h>
++#include <rpc/auth.h>
++#ifdef HAVE_rpcsvc_nfs_prot_h
++#include <rpcsvc/nfs_prot.h>
++#else
++#include <linux/nfs.h>
++#define nfsstat nfs_stat
++#endif
++
++#include "sundries.h"
++
++#include "mount_constants.h"
++#include "nfs4_mount.h"
++
++#include "nls.h"
++
++#if defined(VAR_LOCK_DIR)
++#define DEFAULT_DIR VAR_LOCK_DIR
++#else
++#define DEFAULT_DIR "/var/run"
++#endif
++
++char *IDMAPLCK = DEFAULT_DIR "/rpc.idmapd.pid";
++#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 "/rpc.gssd";
++#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
++
++extern int clnt_ping(struct sockaddr_in *, const u_long, const u_long, const u_int);
++extern void rpc_strerror(void);
++
++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;
++
++      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 {
++                              if (!sloppy) {
++                                      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
++
++      data.version = NFS4_MOUNT_VERSION;
++
++      clnt_ping(&server_addr, NFS_PROGRAM, 4, data.proto);
++      if (rpc_createerr.cf_stat) {
++              fprintf(stderr, "mount to NFS server '%s' failed.\n", data.hostname.data);
++              goto fail;
++      }
++
++      *mount_opts = (char *) &data;
++      /* clean up */
++      return 0;
++
++fail:
++      if (verbose) {
++              rpc_strerror();
++      }
++      return retval;
++}
+diff -urNad --exclude=CVS --exclude=.svn ./mount/nfs4_mount.h /tmp/dpep-work.TJbhsa/2.12r-5.1/mount/nfs4_mount.h
+--- ./mount/nfs4_mount.h       1969-12-31 17:00:00.000000000 -0700
++++ /tmp/dpep-work.TJbhsa/2.12r-5.1/mount/nfs4_mount.h 2006-01-18 12:52:52.000000000 -0700
+@@ -0,0 +1,82 @@
++#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
++
++#endif
+diff -urNad --exclude=CVS --exclude=.svn ./mount/nfs.5 /tmp/dpep-work.TJbhsa/2.12r-5.1/mount/nfs.5
+--- ./mount/nfs.5      2006-01-18 12:50:07.000000000 -0700
++++ /tmp/dpep-work.TJbhsa/2.12r-5.1/mount/nfs.5        2006-01-18 12:52:52.000000000 -0700
+@@ -3,7 +3,7 @@
+ .\" patches. "
+ .TH NFS 5 "20 November 1993" "Linux 0.99" "Linux Programmer's Manual"
+ .SH NAME
+-nfs \- nfs fstab format and options
++nfs \- nfs and nfs4 fstab format and options
+ .SH SYNOPSIS
+ .B /etc/fstab
+ .SH DESCRIPTION
+@@ -17,14 +17,51 @@
+ and the NFS specific options that control
+ the way the filesystem is mounted.
+ .P
+-Here is an example from an \fI/etc/fstab\fP file from an NFS mount.
++Three different versions of the NFS protocol are
++supported by the Linux NFS client:
++NFS version 2, NFS version 3, and NFS version 4.
++To mount via NFS version 2, use the
++.BR nfs
++file system type and specify
++.BR nfsvers=2 .
++Version 2 is the default protocol version for the
++.BR nfs
++file system type when
++.BR nfsvers=
++is not specified on the mount command.
++To mount via NFS version 3, use the
++.BR nfs
++file system type and specify
++.BR nfsvers=3 .
++To mount via NFS version 4, use the
++.BR nfs4
++file system type.
++The
++.BR nfsvers=
++keyword is not supported for the
++.BR nfs4
++file system type.
++.P
++These file system types share similar mount options;
++the differences are listed below.
++.P
++Here is an example from an \fI/etc/fstab\fP file for an NFSv2 mount
++over UDP.
+ .sp
+ .nf
+ .ta 2.5i +0.75i +0.75i +1.0i
+ server:/usr/local/pub /pub    nfs     rsize=8192,wsize=8192,timeo=14,intr
+ .fi
++.P
++Here is an example for an NFSv4 mount over TCP using Kerberos
++5 mutual authentication.
++.sp
++.nf
++.ta 2.5i +0.75i +0.75i +1.0i
++server:/usr/local/pub /pub    nfs4    proto=tcp,sec=krb5,hard,intr
++.fi
+ .DT
+-.SS Options
++.SS Options for the nfs file system type
+ .TP 1.5i
+ .I rsize=n
+ The number of bytes NFS uses when reading files from an NFS server.
+@@ -128,7 +165,7 @@
+ Use an alternate RPC version number to contact the
+ mount daemon on the remote host.  This option is useful
+ for hosts that can run multiple NFS servers.
+-The default value is version 1.
++The default value depends on which kernel you are using.
+ .TP 1.5i
+ .I nfsprog=n
+ Use an alternate RPC program number to contact the
+@@ -141,7 +178,7 @@
+ Use an alternate RPC version number to contact the
+ NFS daemon on the remote host.  This option is useful
+ for hosts that can run multiple NFS servers.
+-The default value is version 2.
++The default value depends on which kernel you are using.
+ .TP 1.5i
+ .I nolock
+ Disable NFS locking. Do not start lockd.
+@@ -193,9 +230,25 @@
+ .TP 1.5i
+ .I noac
+ Disable all forms of attribute caching entirely.  This extracts a
+-server performance penalty but it allows two different NFS clients
+-to get reasonable good results when both clients are actively
+-writing to common filesystem on the server.
++significant performance penalty but it allows two different NFS clients
++to get reasonable results when both clients are actively
++writing to a common export on the server.
++.TP 1.5i
++.I sec=mode
++Set the security flavor for this mount to "mode".
++The default setting is \f3sec=sys\f1, which uses local
++unix uids and gids to authenticate NFS operations (AUTH_SYS).
++Other currently supported settings are:
++\f3sec=krb5\f1, which uses Kerberos V5 instead of local unix uids
++and gids to authenticate users;
++\f3sec=krb5i\f1, which uses Kerberos V5 for user authentication
++and performs integrity checking of NFS operations using secure
++checksums to prevent data tampering; and
++\f3sec=krb5p\f1, which uses Kerberos V5 for user authentication
++and integrity checking, and encrypts NFS traffic to prevent
++traffic sniffing (this is the most secure setting).
++Note that there is a performance penalty when using integrity
++or privacy.
+ .TP 1.5i
+ .I tcp
+ Mount the NFS filesystem using the TCP protocol instead of the
+@@ -208,6 +261,156 @@
+ All of the non-value options have corresponding nooption forms.
+ For example, nointr means don't allow file operations to be
+ interrupted.
++.SS Options for the nfs4 file system type
++.TP 1.5i
++.I rsize=n
++The number of bytes NFS uses when reading files from an NFS server.
++The default value is dependent on the kernel, currently 4096 bytes.
++(However, throughput is improved greatly by asking for
++.IR rsize=32768 .)
++This value is negotiated with the server.
++.TP 1.5i
++.I wsize=n
++The number of bytes NFS uses when writing files to an NFS server.
++The default value is dependent on the kernel, currently 4096 bytes.
++(However, throughput is improved greatly by asking for
++.IR wsize=32768 .)
++This value is negotiated with the server.
++.TP 1.5i
++.I timeo=n
++The value in tenths of a second before sending the
++first retransmission after an RPC timeout.
++The default value depends on whether
++.IR proto=udp
++or
++.IR proto=tcp
++is in effect (see below).
++The default value for UDP is 7 tenths of a second.
++The default value for TCP is 60 seconds.
++After the first timeout,
++the timeout is doubled after each successive timeout until a maximum
++timeout of 60 seconds is reached or the enough retransmissions
++have occured to cause a major timeout.  Then, if the filesystem
++is hard mounted, each new timeout cascade restarts at twice the
++initial value of the previous cascade, again doubling at each
++retransmission.  The maximum timeout is always 60 seconds.
++.TP 1.5i
++.I retrans=n
++The number of minor timeouts and retransmissions that must occur before
++a major timeout occurs.  The default is 5 timeouts for
++.IR proto=udp
++and 2 timeouts for
++.IR proto=tcp .
++When a major timeout
++occurs, the file operation is either aborted or a "server not responding"
++message is printed on the console.
++.TP 1.5i
++.I acregmin=n
++The minimum time in seconds that attributes of a regular file should
++be cached before requesting fresh information from a server.
++The default is 3 seconds.
++.TP 1.5i
++.I acregmax=n
++The maximum time in seconds that attributes of a regular file can
++be cached before requesting fresh information from a server.
++The default is 60 seconds.
++.TP 1.5i
++.I acdirmin=n
++The minimum time in seconds that attributes of a directory should
++be cached before requesting fresh information from a server.
++The default is 30 seconds.
++.TP 1.5i
++.I acdirmax=n
++The maximum time in seconds that attributes of a directory can
++be cached before requesting fresh information from a server.
++The default is 60 seconds.
++.TP 1.5i
++.I actimeo=n
++Using actimeo sets all of
++.I acregmin,
++.I acregmax,
++.I acdirmin,
++and
++.I acdirmax
++to the same value.
++There is no default value.
++.TP 1.5i
++.I retry=n
++The number of minutes to retry an NFS mount operation
++in the foreground or background before giving up.
++The default value is 10000 minutes, which is roughly one week.
++.TP 1.5i
++.I port=n
++The numeric value of the port to connect to the NFS server on.
++If the port number is 0 (the default) then query the
++remote host's portmapper for the port number to use.
++If the remote host's NFS daemon is not registered with
++its portmapper, the standard NFS port number 2049 is
++used instead.
++.TP 1.5i
++.I proto=n
++Mount the NFS filesystem using a specific network protocol
++instead of the default UDP protocol.
++Many NFS version 4 servers only support TCP.
++Valid protocol types are
++.IR udp
++and
++.IR tcp .
++.TP 1.5i
++.I clientaddr=n
++On a multi-homed client, this
++causes the client to use a specific callback address when
++communicating with an NFS version 4 server.
++This option is currently ignored.
++.TP 1.5i
++.I sec=mode
++Same as \f3sec=mode\f1 for the nfs filesystem type (see above).
++.TP 1.5i
++.I bg
++If an NFS mount attempt times out, retry the mount
++in the background.
++After a mount operation is backgrounded, all subsequent mounts
++on the same NFS server will be backgrounded immediately, without
++first attempting the mount.
++A missing mount point is treated as a timeout,
++to allow for nested NFS mounts.
++.TP 1.5i
++.I fg
++If the first NFS mount attempt times out, retry the mount
++in the foreground.
++This is the complement of the
++.I bg
++option, and also the default behavior.
++.TP 1.5i
++.I soft
++If an NFS file operation has a major timeout then report an I/O error to
++the calling program.
++The default is to continue retrying NFS file operations indefinitely.
++.TP 1.5i
++.I hard
++If an NFS file operation has a major timeout then report
++"server not responding" on the console and continue retrying indefinitely.
++This is the default.
++.TP 1.5i
++.I intr
++If an NFS file operation has a major timeout and it is hard mounted,
++then allow signals to interupt the file operation and cause it to
++return EINTR to the calling program.  The default is to not
++allow file operations to be interrupted.
++.TP 1.5i
++.I nocto
++Suppress the retrieval of new attributes when creating a file.
++.TP 1.5i
++.I noac
++Disable attribute caching, and force synchronous writes.
++This extracts a
++server performance penalty but it allows two different NFS clients
++to get reasonable good results when both clients are actively
++writing to common filesystem on the server.
++.P
++All of the non-value options have corresponding nooption forms.
++For example, nointr means don't allow file operations to be
++interrupted.
+ .SH FILES
+ .I /etc/fstab
+ .SH "SEE ALSO"
+diff -urNad --exclude=CVS --exclude=.svn ./mount/nfs_mount4.h /tmp/dpep-work.TJbhsa/2.12r-5.1/mount/nfs_mount4.h
+--- ./mount/nfs_mount4.h       2006-01-18 12:50:08.000000000 -0700
++++ /tmp/dpep-work.TJbhsa/2.12r-5.1/mount/nfs_mount4.h 2006-01-18 12:52:52.000000000 -0700
+@@ -8,7 +8,9 @@
+  * so it is easiest to ignore the kernel altogether (at compile time).
+  */
+-#define NFS_MOUNT_VERSION     4
++#define NFS_MOUNT_VERSION 6
++#define NFS_MAX_CONTEXT_LEN   256
++
+ struct nfs2_fh {
+         char                    data[32];
+@@ -36,6 +38,9 @@
+       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 */
+@@ -51,4 +56,19 @@
+ #define NFS_MOUNT_KERBEROS    0x0100  /* 3 */
+ #define NFS_MOUNT_NONLM               0x0200  /* 3 */
+ #define NFS_MOUNT_BROKEN_SUID 0x0400  /* 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
+diff -urNad --exclude=CVS --exclude=.svn ./mount/nfsmount.c /tmp/dpep-work.TJbhsa/2.12r-5.1/mount/nfsmount.c
+--- ./mount/nfsmount.c 2006-01-18 12:50:08.000000000 -0700
++++ /tmp/dpep-work.TJbhsa/2.12r-5.1/mount/nfsmount.c   2006-01-18 12:52:52.000000000 -0700
+@@ -34,6 +34,7 @@
+ #include "../defines.h"       /* for HAVE_rpcsvc_nfs_prot_h and HAVE_inet_aton */
++#include <ctype.h>
+ #include <unistd.h>
+ #include <stdio.h>
+ #include <string.h>
+@@ -72,11 +73,121 @@
+ #define NFS_FHSIZE 32
+ #endif
++#define MNT_SENDBUFSIZE ((u_int)2048)
++#define MNT_RECVBUFSIZE ((u_int)1024)
++
+ 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;
++
++typedef struct {
++      char **hostname;
++      struct sockaddr_in saddr;
++      struct pmap pmap;
++} clnt_addr_t;
++
++/* RPC call timeout values */
++static const struct timeval TIMEOUT = { 20, 0 };
++static const struct timeval RETRY_TIMEOUT = { 3, 0 };
++
++static int nfs_call_umount(clnt_addr_t *mnt_server, dirpath *argp);
++
++int clnt_ping(struct sockaddr_in *, const u_long, const u_long, const u_int);
++
++/* Convert RPC errors into strings */
++void rpc_strerror(void)
++{
++      int cf_stat = rpc_createerr.cf_stat; 
++      int cf_errno = rpc_createerr.cf_error.re_errno;
++      char *ptr, *estr = clnt_sperrno(cf_stat);
++
++      if (estr) {
++              if ((ptr = index(estr, ':')))
++                      estr = ++ptr;
++
++              fprintf(stderr, "RPC Error: %d (%s )\n", cf_stat, estr);
++              if (cf_stat == RPC_SYSTEMERROR)
++                      fprintf(stderr, "System Error: %d (%s)\n", cf_errno, strerror(cf_errno));
++      }
++}
++
++/* Define the order in which to probe for UDP/TCP services */
++static const u_int *
++proto_probelist(const int use_tcp)
++{
++      static const u_int probe_both[] = { IPPROTO_TCP, IPPROTO_UDP, 0 };
++      static const u_int probe_udponly[] = { IPPROTO_UDP, 0 };
++      if (use_tcp)
++              return probe_both;
++      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;
++      }
++}
++
++/* Map an NFS version into the corresponding Mountd version */
++static u_long
++nfsvers_to_mnt(const u_long vers)
++{
++      static const u_long nfs_to_mnt[] = { 0, 0, 1, 3 };
++      if (vers <= 3)
++              return nfs_to_mnt[vers];
++      return 0;
++}
++
++/* Map a Mountd version into the corresponding NFS version */
++static u_long
++mntvers_to_nfs(const u_long vers)
++{
++      static const u_long mnt_to_nfs[] = { 0, 2, 2, 3 };
++      if (vers <= 3)
++              return mnt_to_nfs[vers];
++      return 0;
++}
+ static int
+ linux_version_code(void) {
+@@ -102,123 +213,632 @@
+  *    NFS_MOUNT_VERSION: these nfsmount sources at compile time
+  *    nfs_mount_version: version this source and running kernel can handle
+  */
++static int nfs_mount_version = NFS_MOUNT_VERSION;
++
+ static int
+ find_kernel_nfs_mount_version(void) {
+       static int kernel_version = -1;
+-      int nfs_mount_version = NFS_MOUNT_VERSION;
++      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))
+-                nfs_mount_version = 1;
++                mnt_version = 1;
+            else if (kernel_version < MAKE_VERSION(2,2,18))
+-                nfs_mount_version = 3;
++                mnt_version = 3;
+            else if (kernel_version < MAKE_VERSION(2,3,0))
+-                nfs_mount_version = 4; /* since 2.2.18pre9 */
++                mnt_version = 4; /* since 2.2.18pre9 */
+            else if (kernel_version < MAKE_VERSION(2,3,99))
+-                nfs_mount_version = 3;
++                mnt_version = 3;
++           else if (kernel_version < MAKE_VERSION(2,6,3))
++                mnt_version = 4;
+            else
+-                nfs_mount_version = 4; /* since 2.3.99pre4 */
++                mnt_version = 6;
+       }
+-      if (nfs_mount_version > NFS_MOUNT_VERSION)
+-           nfs_mount_version = NFS_MOUNT_VERSION;
+-      return nfs_mount_version;
++      if (mnt_version > NFS_MOUNT_VERSION)
++           mnt_version = NFS_MOUNT_VERSION;
++      return mnt_version;
+ }
+-static struct pmap *
+-get_mountport(struct sockaddr_in *server_addr,
+-      long unsigned prog,
+-      long unsigned version,
+-      long unsigned proto,
+-      long unsigned port,
+-      int nfs_mount_version)
++static int
++nfs_gethostbyname(const char *hostname, struct sockaddr_in *saddr)
+ {
+-      struct pmaplist *pmap;
+-      static struct pmap p = {0, 0, 0, 0};
++      struct hostent *hp;
+-      if (version > MAX_NFSPROT)
+-              version = MAX_NFSPROT;
+-      if (!prog)
+-              prog = MOUNTPROG;
+-      p.pm_prog = prog;
+-      p.pm_vers = version;
+-      p.pm_prot = proto;
+-      p.pm_port = port;
++      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;
++}
+-      server_addr->sin_port = PMAPPORT;
+-      pmap = pmap_getmaps(server_addr);
++/*
++ * Sigh... pmap_getport() doesn't actually check the version number.
++ * In order to make sure that the server actually supports the service
++ * we're requesting, we open and RPC client, and fire off a NULL
++ * RPC call.
++ */
++int
++clnt_ping(struct sockaddr_in *saddr, const u_long prog, const u_long vers,
++        const u_int prot)
++{
++      CLIENT *clnt=NULL;
++      int sock, stat;
++      static char clnt_res;
+-      while (pmap) {
+-              if (pmap->pml_map.pm_prog != prog)
+-                      goto next;
+-              if (!version && p.pm_vers > pmap->pml_map.pm_vers)
+-                      goto next;
+-              if (version > 2 && pmap->pml_map.pm_vers != version)
+-                      goto next;
+-              if (version && version <= 2 && pmap->pml_map.pm_vers > 2)
+-                      goto next;
+-              if (pmap->pml_map.pm_vers > MAX_NFSPROT ||
+-                  (proto && p.pm_prot && pmap->pml_map.pm_prot != proto) ||
+-                  (port && pmap->pml_map.pm_port != port))
+-                      goto next;
+-              memcpy(&p, &pmap->pml_map, sizeof(p));
+-      next:
+-              pmap = pmap->pml_next;
++      rpc_createerr.cf_stat = stat = 0;
++      sock = RPC_ANYSOCK;
++      switch(prot) {
++      case IPPROTO_UDP:
++              clnt = clntudp_bufcreate(saddr, prog, vers,
++                                       RETRY_TIMEOUT, &sock,
++                                       RPCSMALLMSGSIZE, RPCSMALLMSGSIZE);
++              break;
++      case IPPROTO_TCP:
++              clnt = clnttcp_create(saddr, prog, vers, &sock,
++                                    RPCSMALLMSGSIZE, RPCSMALLMSGSIZE);
++              break;
++      default:
++              goto out_bad;
+       }
+-      if (!p.pm_vers)
+-              p.pm_vers = MOUNTVERS;
+-      if (!p.pm_prot)
+-              p.pm_prot = IPPROTO_TCP;
+-#if 0
+-      if (!p.pm_port) {
+-              p.pm_port = pmap_getport(server_addr, p.pm_prog, p.pm_vers,
+-                                       p.pm_prot);
++      if (!clnt)
++              goto out_bad;
++      memset(&clnt_res, 0, sizeof(clnt_res));
++      stat = clnt_call(clnt, NULLPROC,
++                       (xdrproc_t)xdr_void, (caddr_t)NULL,
++                       (xdrproc_t)xdr_void, (caddr_t)&clnt_res,
++                       TIMEOUT);
++      clnt_destroy(clnt);
++      close(sock);
++      if (stat != RPC_PROGVERSMISMATCH)
++              return 1;
++
++ out_bad:
++      return 0;
++}
++
++/*
++ * 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,
++              vers = pmap->pm_vers,
++              *p_vers;
++      const u_int prot = (u_int)pmap->pm_prot,
++              *p_prot;
++      const u_short port = (u_short) pmap->pm_port;
++      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 = pmap_getport(saddr, prog, *p_vers, *p_prot);
++              if (p_port) {
++                      if (!port || port == p_port) {
++                              saddr->sin_port = htons(port);
++                              if (clnt_ping(saddr, prog, *p_vers, *p_prot))
++                                      goto out_ok;
++                      }
++              } else if (rpc_createerr.cf_stat != RPC_PROGNOTREGISTERED)
++                      break;
++              if (!prot) {
++                      if (*++p_prot)
++                              continue;
++                      p_prot = protos;
++              }
++              if (vers || !*++p_vers)
++                      break;
+       }
++      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);
++      return probe_port(nfs_server, probe_vers, probe_prot);
++}
++
++static 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);
++      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 = *probe_vers;
++                      if ((res = probe_mntport(mnt_server)) != 0)
++                              return 1;
++                      memcpy(mnt_pmap, &save_mnt, sizeof(*mnt_pmap));
++              }
++              if (rpc_createerr.cf_stat != RPC_PROGNOTREGISTERED)
++                      break;
++              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 CLIENT *
++mnt_openclnt(clnt_addr_t *mnt_server, int *msock, const int report_errs)
++{
++      struct sockaddr_in *mnt_saddr = &mnt_server->saddr;
++      struct pmap *mnt_pmap = &mnt_server->pmap;
++      CLIENT *clnt;
++
++      /* contact the mount daemon via TCP */
++      mnt_saddr->sin_port = htons((u_short)mnt_pmap->pm_port);
++      *msock = RPC_ANYSOCK;
++
++      switch (mnt_pmap->pm_prot) {
++      case IPPROTO_UDP:
++              clnt = clntudp_bufcreate(mnt_saddr,
++                                       mnt_pmap->pm_prog, mnt_pmap->pm_vers,
++                                       RETRY_TIMEOUT, msock,
++                                       MNT_SENDBUFSIZE, MNT_RECVBUFSIZE);
++              break;
++      case IPPROTO_TCP:
++              clnt = clnttcp_create(mnt_saddr,
++                                    mnt_pmap->pm_prog, mnt_pmap->pm_vers,
++                                    msock,
++                                    MNT_SENDBUFSIZE, MNT_RECVBUFSIZE);
++              break;
++      default:
++              goto out_bad;
++      }
++      if (!clnt)
++              goto report_err;
++      /* try to mount hostname:dirname */
++      clnt->cl_auth = authunix_create_default();
++      return clnt;
++ report_err:
++      if (report_errs)
++              clnt_pcreateerror("mount");
++ out_bad:
++      return NULL;
++}
++
++static inline void
++mnt_closeclnt(CLIENT *clnt, int msock)
++{
++      auth_destroy(clnt->cl_auth);
++      clnt_destroy(clnt);
++      close(msock);
++}
++
++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, const int report_errs)
++{
++      CLIENT *clnt;
++      enum clnt_stat stat;
++      int msock;
++
++      if (!probe_bothports(mnt_server, nfs_server)) {
++              if (report_errs) {
++                      fprintf(stderr, "mount to NFS server '%s' failed", 
++                              *nfs_server->hostname);
++                      if (rpc_createerr.cf_stat != RPC_PROGNOTREGISTERED) {
++                              fprintf(stderr, ": server is down.\n");
++                      } else  if (nfs_server->pmap.pm_prot) {
++                              fprintf(stderr, ": possible invalid protocol.\n");
++                      } else if (nfs_server->pmap.pm_port) {
++                              fprintf(stderr, ": possible invalid port.\n");
++                      } else {
++                              fprintf(stderr, ".\n");
++                      }
++                      if (verbose) {
++                              rpc_strerror();
++                      }
++              }
++              goto out_bad;
++      }
++
++      clnt = mnt_openclnt(mnt_server, &msock, report_errs);
++      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 && report_errs)
++              clnt_perror(clnt, "mount");
++      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 if (!sloppy)
++                                      goto bad_parameter;
+ #endif
+-#if 0
+-#define MOUNTPORT 635
+-      /* HJLu wants to remove all traces of the old default port.
+-         Are there still people running a mount RPC service on this
+-         port without having a portmapper? */
+-      if (!p.pm_port)
+-              p.pm_port = MOUNTPORT;
++                      } else if (!strcmp(opt, "addr")) {
++                              /* ignore */;
++                              continue;
++                      } else if (!sloppy)
++                              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;
++#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;
++                                      data->flags |= NFS_MOUNT_TCP;
+ #endif
+-      return &p;
++                              } else if (!sloppy)
++                                      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 if(!sloppy) {
++                                      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 if (!sloppy)
++                              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;
++                                      data->flags |= NFS_MOUNT_TCP;
++                              } else
++                                      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;
++                                      data->flags |= NFS_MOUNT_TCP;
++                              } else
++                                      nfs_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;
++                              }
++#endif
++                      } else {
++                      bad_option:
++                              if (!sloppy) {
++                                      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;
+ }
+-int nfsmount(const char *spec, const char *node, int *flags,
+-           char **extra_opts, char **mount_opts, int *nfs_mount_vers,
+-           int running_bg)
++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];
+-      CLIENT *mclient;
+       char *hostname, *dirname, *old_opts, *mounthost = NULL;
+-      char new_opts[1024];
+-      struct timeval total_timeout;
+-      enum clnt_stat clnt_stat;
++      char new_opts[1024], cbuf[1024];
+       static struct nfs_mount_data data;
+-      char *opt, *opteq;
+-      int nfs_mount_version;
+       int val;
+-      struct hostent *hp;
+-      struct sockaddr_in server_addr;
+-      struct sockaddr_in mount_server_addr;
+-      struct pmap *pm_mnt;
+-      int msock, fsock;
+-      struct timeval retry_timeout;
+-      union {
+-              struct fhstatus nfsv2;
+-              struct mountres3 nfsv3;
+-      } status;
++
++      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 port, mountport, proto, bg, soft, intr;
+-      int posix, nocto, noac, nolock, broken_suid;
+-      int retry, tcp;
+-      int mountprog, mountvers, nfsprog, nfsvers;
++      int bg, retry;
+       int retval;
+       time_t t;
+       time_t prevt;
+@@ -231,8 +851,7 @@
+       nfs_mount_version = *nfs_mount_vers;
+       retval = EX_FAIL;
+-      msock = fsock = -1;
+-      mclient = NULL;
++      fsock = -1;
+       if (strlen(spec) >= sizeof(hostdir)) {
+               fprintf(stderr, _("mount: "
+                                 "excessively long host:dir argument\n"));
+@@ -258,49 +877,23 @@
+               goto fail;
+       }
+-      server_addr.sin_family = AF_INET;
+-#ifdef HAVE_inet_aton
+-      if (!inet_aton(hostname, &server_addr.sin_addr))
+-#endif
+-      {
+-              if ((hp = gethostbyname(hostname)) == NULL) {
+-                      fprintf(stderr, _("mount: can't get address for %s\n"),
+-                              hostname);
+-                      goto fail;
+-              } else {
+-                      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(&server_addr.sin_addr,
+-                             hp->h_addr, hp->h_length);
+-              }
+-      }
+-
+-      memcpy (&mount_server_addr, &server_addr, sizeof (mount_server_addr));
++      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(server_addr.sin_addr);
++      s = inet_ntoa(nfs_saddr->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;
+-      }
+-      sprintf(new_opts, "%s%saddr=%s",
+-              old_opts, *old_opts ? "," : "", s);
+-      *extra_opts = xstrdup(new_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.retrans    = 3;
+       data.acregmin   = 3;
+       data.acregmax   = 60;
+       data.acdirmin   = 30;
+@@ -308,169 +901,24 @@
+ #if NFS_MOUNT_VERSION >= 2
+       data.namlen     = NAME_MAX;
+ #endif
++      data.pseudoflavor = AUTH_SYS;
+       bg = 0;
+-      soft = 0;
+-      intr = 0;
+-      posix = 0;
+-      nocto = 0;
+-      nolock = 0;
+-      broken_suid = 0;
+-      noac = 0;
+       retry = 10000;          /* 10000 minutes ~ 1 week */
+-      tcp = 0;
+-      mountprog = MOUNTPROG;
+-      mountvers = 0;
+-      port = 0;
+-      mountport = 0;
+-      nfsprog = NFS_PROGRAM;
+-      nfsvers = 0;
++      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;
+-      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"))
+-                              port = val;
+-                      else if (!strcmp(opt, "mountport"))
+-                              mountport = val;
+-                      else if (!strcmp(opt, "mounthost"))
+-                              mounthost=xstrndup(opteq+1,
+-                                                 strcspn(opteq+1," \t\n\r,"));
+-                      else if (!strcmp(opt, "mountprog"))
+-                              mountprog = val;
+-                      else if (!strcmp(opt, "mountvers"))
+-                              mountvers = val;
+-                      else if (!strcmp(opt, "nfsprog"))
+-                              nfsprog = val;
+-                      else if (!strcmp(opt, "nfsvers") ||
+-                               !strcmp(opt, "vers"))
+-                              nfsvers = val;
+-                      else if (!strcmp(opt, "proto")) {
+-                              if (!strncmp(opteq+1, "tcp", 3))
+-                                      tcp = 1;
+-                              else if (!strncmp(opteq+1, "udp", 3))
+-                                      tcp = 0;
+-                              else
+-                                      printf(_("Warning: Unrecognized proto= option.\n"));
+-                      } else if (!strcmp(opt, "namlen")) {
+-#if NFS_MOUNT_VERSION >= 2
+-                              if (nfs_mount_version >= 2)
+-                                      data.namlen = val;
+-                              else
+-#endif
+-                                      printf(_("Warning: Option namlen is not supported.\n"));
+-                      } 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, "posix"))
+-                              posix = val;
+-                      else if (!strcmp(opt, "cto"))
+-                              nocto = !val;
+-                      else if (!strcmp(opt, "ac"))
+-                              noac = !val;
+-                      else if (!strcmp(opt, "tcp"))
+-                              tcp = val;
+-                      else if (!strcmp(opt, "udp"))
+-                              tcp = !val;
+-                      else if (!strcmp(opt, "lock")) {
+-                              if (nfs_mount_version >= 3)
+-                                      nolock = !val;
+-                              else
+-                                      printf(_("Warning: option nolock is not supported.\n"));
+-                      } else if (!strcmp(opt, "broken_suid")) {
+-                              broken_suid = val;
+-                      } else {
+-                              if (!sloppy) {
+-                                      printf(_("unknown nfs mount option: "
+-                                               "%s%s\n"), val ? "" : "no", opt);
+-                                      goto fail;
+-                              }
+-                      }
+-              }
+-      }
+-      proto = (tcp) ? IPPROTO_TCP : IPPROTO_UDP;
+-
+-      data.flags = (soft ? NFS_MOUNT_SOFT : 0)
+-              | (intr ? NFS_MOUNT_INTR : 0)
+-              | (posix ? NFS_MOUNT_POSIX : 0)
+-              | (nocto ? NFS_MOUNT_NOCTO : 0)
+-              | (noac ? NFS_MOUNT_NOAC : 0);
+-#if NFS_MOUNT_VERSION >= 2
+-      if (nfs_mount_version >= 2)
+-              data.flags |= (tcp ? NFS_MOUNT_TCP : 0);
+-#endif
+-#if NFS_MOUNT_VERSION >= 3
+-      if (nfs_mount_version >= 3)
+-              data.flags |= (nolock ? NFS_MOUNT_NONLM : 0);
+-#endif
+-#if NFS_MOUNT_VERSION >= 4
+-      if (nfs_mount_version >= 4)
+-              data.flags |= (broken_suid ? NFS_MOUNT_BROKEN_SUID : 0);
+-#endif
+-      if (nfsvers > MAX_NFSPROT) {
+-              fprintf(stderr, "NFSv%d not supported!\n", nfsvers);
+-              return 0;
+-      }
+-      if (mountvers > MAX_NFSPROT) {
+-              fprintf(stderr, "NFSv%d not supported!\n", nfsvers);
+-              return 0;
+-      }
+-      if (nfsvers && !mountvers)
+-              mountvers = (nfsvers < 3) ? 1 : nfsvers;
+-      if (nfsvers && nfsvers < mountvers)
+-              mountvers = nfsvers;
+-
+-      /* Adjust options if none specified */
+-      if (!data.timeo)
+-              data.timeo = tcp ? 70 : 7;
+ #ifdef NFS_MOUNT_DEBUG
+       printf("rsize = %d, wsize = %d, timeo = %d, retrans = %d\n",
+@@ -478,9 +926,10 @@
+       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",
+-             port, bg, retry, data.flags);
++             nfs_pmap->pm_port, bg, retry, data.flags);
+       printf("mountprog = %d, mountvers = %d, nfsprog = %d, nfsvers = %d\n",
+-             mountprog, mountvers, nfsprog, nfsvers);
++             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\n",
+              (data.flags & NFS_MOUNT_SOFT) != 0,
+              (data.flags & NFS_MOUNT_INTR) != 0,
+@@ -491,13 +940,16 @@
+       printf("tcp = %d\n",
+              (data.flags & NFS_MOUNT_TCP) != 0);
+ #endif
++#if NFS_MOUNT_VERSION >= 5
++      printf("sec = %u\n", data.pseudoflavor);
++#endif
+ #endif
+       data.version = nfs_mount_version;
+       *mount_opts = (char *) &data;
+       if (*flags & MS_REMOUNT)
+-              return 0;
++              goto out_ok;
+       /*
+        * If the previous mount operation on the same host was
+@@ -512,28 +964,6 @@
+       }
+       /* create mount deamon client */
+-      /* See if the nfs host = mount host. */
+-      if (mounthost) {
+-              if (mounthost[0] >= '0' && mounthost[0] <= '9') {
+-                      mount_server_addr.sin_family = AF_INET;
+-                      mount_server_addr.sin_addr.s_addr = inet_addr(hostname);
+-              } else {
+-                      if ((hp = gethostbyname(mounthost)) == NULL) {
+-                              fprintf(stderr, _("mount: can't get address for %s\n"),
+-                                      mounthost);
+-                              goto fail;
+-                      } else {
+-                              if (hp->h_length > sizeof(struct in_addr)) {
+-                                      fprintf(stderr,
+-                                              _("mount: got bad hp->h_length?\n"));
+-                                      hp->h_length = sizeof(struct in_addr);
+-                              }
+-                              mount_server_addr.sin_family = AF_INET;
+-                              memcpy(&mount_server_addr.sin_addr,
+-                                     hp->h_addr, hp->h_length);
+-                      }
+-              }
+-      }
+       /*
+        * The following loop implements the mount retries. On the first
+@@ -551,15 +981,13 @@
+        *
+        * Only the first error message will be displayed.
+        */
+-      retry_timeout.tv_sec = 3;
+-      retry_timeout.tv_usec = 0;
+-      total_timeout.tv_sec = 20;
+-      total_timeout.tv_usec = 0;
+       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 */
+@@ -570,89 +998,18 @@
+                                       val = 30;
+                       }
+               } else {
++                      int stat;
+                       /* be careful not to use too many CPU cycles */
+                       if (t - prevt < 30)
+                               sleep(30);
+-                      pm_mnt = get_mountport(&mount_server_addr,
+-                                             mountprog,
+-                                             mountvers,
+-                                             proto,
+-                                             mountport,
+-                                             nfs_mount_version);
+-
+-                      /* contact the mount daemon via TCP */
+-                      mount_server_addr.sin_port = htons(pm_mnt->pm_port);
+-                      msock = RPC_ANYSOCK;
+-
+-                      switch (pm_mnt->pm_prot) {
+-                      case IPPROTO_UDP:
+-                              mclient = clntudp_create(&mount_server_addr,
+-                                                       pm_mnt->pm_prog,
+-                                                       pm_mnt->pm_vers,
+-                                                       retry_timeout,
+-                                                       &msock);
+-                              if (mclient)
+-                                      break;
+-                              mount_server_addr.sin_port =
+-                                      htons(pm_mnt->pm_port);
+-                              msock = RPC_ANYSOCK;
+-                      case IPPROTO_TCP:
+-                              mclient = clnttcp_create(&mount_server_addr,
+-                                                       pm_mnt->pm_prog,
+-                                                       pm_mnt->pm_vers,
+-                                                       &msock, 0, 0);
++                      stat = nfs_call_mount(&mnt_server, &nfs_server,
++                                            &dirname, &mntres,
++                                            !running_bg && prevt == 0);
++                      if (stat)
+                               break;
+-                      default:
+-                              mclient = 0;
+-                      }
+-
+-                      if (mclient) {
+-                              /* try to mount hostname:dirname */
+-                              mclient->cl_auth = authunix_create_default();
+-
+-                              /* make pointers in xdr_mountres3 NULL so
+-                               * that xdr_array allocates memory for us
+-                               */
+-                              memset(&status, 0, sizeof(status));
+-
+-                              if (pm_mnt->pm_vers == 3)
+-                                      clnt_stat = clnt_call(mclient,
+-                                                   MOUNTPROC3_MNT,
+-                                                   (xdrproc_t) xdr_dirpath,
+-                                                   (caddr_t) &dirname,
+-                                                   (xdrproc_t) xdr_mountres3,
+-                                                   (caddr_t) &status,
+-                                                   total_timeout);
+-                              else
+-                                      clnt_stat = clnt_call(mclient,
+-                                                   MOUNTPROC_MNT,
+-                                                   (xdrproc_t) xdr_dirpath,
+-                                                   (caddr_t) &dirname,
+-                                                   (xdrproc_t) xdr_fhstatus,
+-                                                   (caddr_t) &status,
+-                                                   total_timeout);
+-
+-                              if (clnt_stat == RPC_SUCCESS)
+-                                      break;          /* we're done */
+-#if 0
+-                              /* errno? who sets errno? */
+-                              /* this fragment breaks bg mounting */
+-                              if (errno != ECONNREFUSED) {
+-                                      clnt_perror(mclient, "mount");
+-                                      goto fail;      /* don't retry */
+-                              }
+-#endif
+-                              if (!running_bg && prevt == 0)
+-                                      clnt_perror(mclient, "mount");
+-                              auth_destroy(mclient->cl_auth);
+-                              clnt_destroy(mclient);
+-                              mclient = 0;
+-                              close(msock);
+-                      } else {
+-                              if (!running_bg && prevt == 0)
+-                                      clnt_pcreateerror("mount");
+-                      }
++                      memcpy(nfs_pmap, &save_nfs, sizeof(*nfs_pmap));
++                      memcpy(mnt_pmap, &save_mnt, sizeof(*mnt_pmap));
+                       prevt = t;
+               }
+@@ -668,36 +1025,63 @@
+               if (t >= timeout)
+                       goto fail;
+       }
+-      nfsvers = (pm_mnt->pm_vers < 2) ? 2 : pm_mnt->pm_vers;
+-      if (nfsvers == 2) {
+-              if (status.nfsv2.fhs_status != 0) {
++      if (nfs_pmap->pm_vers == 2) {
++              if (mntres.nfsv2.fhs_status != 0) {
+                       fprintf(stderr,
+-                              "mount: %s:%s failed, reason given by server: %s\n",
++                              _("mount: %s:%s failed, reason given by server: %s\n"),
+                               hostname, dirname,
+-                              nfs_strerror(status.nfsv2.fhs_status));
++                              nfs_strerror(mntres.nfsv2.fhs_status));
+                       goto fail;
+               }
+               memcpy(data.root.data,
+-                     (char *) status.nfsv2.fhstatus_u.fhs_fhandle,
++                     (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 *) status.nfsv2.fhstatus_u.fhs_fhandle,
++                     (char *) mntres.nfsv2.fhstatus_u.fhs_fhandle,
+                      NFS_FHSIZE);
+ #endif
+       } else {
+ #if NFS_MOUNT_VERSION >= 4
++              mountres3_ok *mountres;
+               fhandle3 *fhandle;
+-              if (status.nfsv3.fhs_status != 0) {
++              int i, *flavor, yum = 0;
++              if (mntres.nfsv3.fhs_status != 0) {
+                       fprintf(stderr,
+-                              "mount: %s:%s failed, reason given by server: %s\n",
++                              _("mount: %s:%s failed, reason given by server: %s\n"),
+                               hostname, dirname,
+-                              nfs_strerror(status.nfsv3.fhs_status));
++                              nfs_strerror(mntres.nfsv3.fhs_status));
+                       goto fail;
+               }
+-              fhandle = &status.nfsv3.mountres3_u.mountinfo.fhandle;
++#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;
+@@ -711,13 +1095,9 @@
+       /* create nfs socket for kernel */
+-      if (tcp) {
+-              if (nfs_mount_version < 3) {
+-                      printf(_("NFS over TCP is not supported.\n"));
+-                      goto fail;
+-              }
++      if (nfs_pmap->pm_prot == IPPROTO_TCP)
+               fsock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+-      } else
++      else
+               fsock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+       if (fsock < 0) {
+               perror(_("nfs socket"));
+@@ -727,72 +1107,163 @@
+               perror(_("nfs bindresvport"));
+               goto fail;
+       }
+-      if (port == 0) {
+-              server_addr.sin_port = PMAPPORT;
+-              port = pmap_getport(&server_addr, nfsprog, nfsvers,
+-                                  tcp ? IPPROTO_TCP : IPPROTO_UDP);
+-#if 1
+-              /* Here we check to see if user is mounting with the
+-               * tcp option.  If so, and if the portmap returns a
+-               * '0' for port (service unavailable), we then exit,
+-               * notifying the user, rather than hanging up mount.
+-               */
+-              if (port == 0 && tcp == 1) {
+-                      perror(_("nfs server reported service unavailable"));
+-                      goto fail;
+-              }
+-#endif
+-
+-              if (port == 0)
+-                      port = NFS_PORT;
+-#ifdef NFS_MOUNT_DEBUG
+-              else
+-                      printf(_("used portmapper to find NFS port\n"));
+-#endif
+-      }
+ #ifdef NFS_MOUNT_DEBUG
+-      printf(_("using port %d for nfs deamon\n"), port);
++      printf(_("using port %d for nfs deamon\n"), nfs_pmap->pm_port);
+ #endif
+-      server_addr.sin_port = htons(port);
++      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 *) &server_addr,
+-                     sizeof (server_addr)) < 0) {
++          && 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 *) &server_addr, sizeof(data.addr));
++      memcpy((char *) &data.addr, (char *) nfs_saddr, sizeof(data.addr));
+       strncpy(data.hostname, hostname, sizeof(data.hostname));
+-      /* clean up */
++ 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;
++      }
+-      auth_destroy(mclient->cl_auth);
+-      clnt_destroy(mclient);
+-      close(msock);
++      snprintf(cbuf, sizeof(cbuf)-1, "addr=%s", s);
++      strcat(new_opts, cbuf);
++
++      *extra_opts = xstrdup(new_opts);
+       return 0;
+       /* abort */
+-
+  fail:
+-      if (msock != -1) {
+-              if (mclient) {
+-                      auth_destroy(mclient->cl_auth);
+-                      clnt_destroy(mclient);
+-              }
+-              close(msock);
+-      }
+       if (fsock != -1)
+               close(fsock);
+       return retval;
+-}     
++}
++
++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);
++}
++
++static 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, 1);
++      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;
++}
++
++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;
++      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;
++}
+ /*
+  * We need to translate between nfs status return values and
+diff -urNad --exclude=CVS --exclude=.svn ./mount/sundries.h /tmp/dpep-work.TJbhsa/2.12r-5.1/mount/sundries.h
+--- ./mount/sundries.h 2006-01-18 12:50:08.000000000 -0700
++++ /tmp/dpep-work.TJbhsa/2.12r-5.1/mount/sundries.h   2006-01-18 12:52:52.000000000 -0700
+@@ -37,6 +37,9 @@
+ #ifdef HAVE_NFS
+ int nfsmount (const char *spec, const char *node, int *flags,
+             char **orig_opts, char **opt_args, int *version, int running_bg);
++int nfs4mount (const char *spec, const char *node, int *flags,
++              char **orig_opts, char **opt_args, int running_bg);
++int nfsumount(const char *spec, const char *opts);
+ #endif
+ /* exit status - bits below are ORed */
+diff -urNad --exclude=CVS --exclude=.svn ./mount/umount.c /tmp/dpep-work.TJbhsa/2.12r-5.1/mount/umount.c
+--- ./mount/umount.c   2006-01-18 12:52:52.000000000 -0700
++++ /tmp/dpep-work.TJbhsa/2.12r-5.1/mount/umount.c     2006-01-18 12:52:52.000000000 -0700
+@@ -90,6 +90,11 @@
+ /* True if ruid != euid.  */
+ int suid = 0;
++/* Needed by nfs4mount.c */
++int sloppy = 0;
++
++
++
+ /*
+  * check_special_umountprog()
+  *    If there is a special umount program for this type, exec it.
+@@ -297,7 +302,7 @@
+       /* Ignore any RPC errors, so that you can umount the filesystem
+          if the server is down.  */
+       if (strcasecmp(type, "nfs") == 0)
+-              nfs_umount_rpc_call(spec, opts);
++              nfsumount(spec, opts);
+ #endif
+  
+       umnt_err = umnt_err2 = 0;