summaryrefslogtreecommitdiffstats
path: root/meta/recipes-devtools/unfs-server/unfs-server-2.2beta47
diff options
context:
space:
mode:
Diffstat (limited to 'meta/recipes-devtools/unfs-server/unfs-server-2.2beta47')
-rw-r--r--meta/recipes-devtools/unfs-server/unfs-server-2.2beta47/001-2.2b47-2.2b51.patch2344
-rw-r--r--meta/recipes-devtools/unfs-server/unfs-server-2.2beta47/002-destdir.patch68
-rw-r--r--meta/recipes-devtools/unfs-server/unfs-server-2.2beta47/003-manpages.patch28
-rw-r--r--meta/recipes-devtools/unfs-server/unfs-server-2.2beta47/004-strsignal.patch48
-rw-r--r--meta/recipes-devtools/unfs-server/unfs-server-2.2beta47/005-sys-time.patch29
-rw-r--r--meta/recipes-devtools/unfs-server/unfs-server-2.2beta47/006-reiserfs.patch1272
-rw-r--r--meta/recipes-devtools/unfs-server/unfs-server-2.2beta47/007-map.patch78
-rw-r--r--meta/recipes-devtools/unfs-server/unfs-server-2.2beta47/008-configure.patch13
-rw-r--r--meta/recipes-devtools/unfs-server/unfs-server-2.2beta47/009-multirw.patch15
-rw-r--r--meta/recipes-devtools/unfs-server/unfs-server-2.2beta47/010-realpath.patch30
-rw-r--r--meta/recipes-devtools/unfs-server/unfs-server-2.2beta47/011-fno-strict-aliasing.patch13
-rw-r--r--meta/recipes-devtools/unfs-server/unfs-server-2.2beta47/012-nostrip.patch13
-rw-r--r--meta/recipes-devtools/unfs-server/unfs-server-2.2beta47/013-mntpathlen.patch32
-rw-r--r--meta/recipes-devtools/unfs-server/unfs-server-2.2beta47/014-uninitialized.patch12
-rw-r--r--meta/recipes-devtools/unfs-server/unfs-server-2.2beta47/015-setattr.patch26
-rw-r--r--meta/recipes-devtools/unfs-server/unfs-server-2.2beta47/016-makefile.in.patch14
-rw-r--r--meta/recipes-devtools/unfs-server/unfs-server-2.2beta47/017-wrs-dynamic-rpc.patch258
-rw-r--r--meta/recipes-devtools/unfs-server/unfs-server-2.2beta47/018-remove-tcp-wrappers.patch20
-rw-r--r--meta/recipes-devtools/unfs-server/unfs-server-2.2beta47/019-pid-before-fork.patch125
-rw-r--r--meta/recipes-devtools/unfs-server/unfs-server-2.2beta47/020-undefined-chmod-fix.patch18
-rw-r--r--meta/recipes-devtools/unfs-server/unfs-server-2.2beta47/021-nolibwrap.patch20
-rw-r--r--meta/recipes-devtools/unfs-server/unfs-server-2.2beta47/022-add-close-on-exec-descriptors.patch61
22 files changed, 4537 insertions, 0 deletions
diff --git a/meta/recipes-devtools/unfs-server/unfs-server-2.2beta47/001-2.2b47-2.2b51.patch b/meta/recipes-devtools/unfs-server/unfs-server-2.2beta47/001-2.2b47-2.2b51.patch
new file mode 100644
index 0000000..886ce92
--- /dev/null
+++ b/meta/recipes-devtools/unfs-server/unfs-server-2.2beta47/001-2.2b47-2.2b51.patch
@@ -0,0 +1,2344 @@
+# Patch origin: nfs-server source RPM from openSUSE 10.3
+
+diff -urN nfs-server-2.2beta47/.version nfs-server-2.2beta51/.version
+--- nfs-server-2.2beta47/.version Tue Sep 7 09:47:27 1999
++++ nfs-server-2.2beta51/.version Fri Nov 8 14:45:36 2002
+@@ -1 +1 @@
+-2.2beta46
++2.2beta51
+diff -urN nfs-server-2.2beta47/ChangeLog nfs-server-2.2beta51/ChangeLog
+--- nfs-server-2.2beta47/ChangeLog Wed Nov 10 10:17:51 1999
++++ nfs-server-2.2beta51/ChangeLog Fri Nov 8 14:45:36 2002
+@@ -1,8 +1,59 @@
++Thu Nov 9 17:03:05 2000
++
++ * No longer use OPEN_MAX
++
++ * Reworked configure.in, BUILD script no longer needed
++ (nor functioning)
++
++ * Be more anal about matching cached fh's and real files.
++ In addition to the psi, we also store dev/ino/type now
++ and match that in fh_find.
++
++ * Write pidfiles
++
++ * Support nosetuid
++
++Wed Feb 9 14:52:34 2000
++
++ * auth_init.c didn't properly parse options--rot_squash
++ which is obviously a typo was parsed as ro.
++ Thanks to Jan Steffan for complaining about this :-)
++
++Mon Jan 31 11:48:34 2000
++
++ * Fixed Y2K bug in logging.c.
++ Thanks to Jonathan Hankins <jhankins@homewood.k12.al.us>.
++
++Thu Dec 9 11:14:21 1999
++
++ * Fix handling of NFS-mounted and /proc directories.
++ They weren't properly hidden.
++ Thanks to Dick Streefland <dick_streefland@tasking.com>
++ for the report and a first patch.
++
+ Wed Nov 10 10:17:16 1999
+
+ * Security fix for buffer overflow in fh_buildpath
+ No thanks to Mariusz who reported it to bugtraq
+ rather than me.
++
++Wed Nov 09 17:10:00 1999
++
++ * Workaround for broken Solaris clients that can't handle
++ atime/mtime/ctime of 0.
++ Thanks to Frank Wuebbelin for his problem report and
++ testing the fix.
++
++ * Fixed typo in exports.man
++
++Tue Nov 2 10:31:14 1999
++
++ * Patch for mode 0100 and 0100 executables by
++ Michael Deutschmann <michael@talamasca.wkpowerlink.com>
++
++ * Common startup stuff for all daemons.
++ Inspired by code sent to me by someone (sorry, I forgot
++ your name, and the mail's gone!)
+
+ Wed Sep 8 09:07:38 1999
+
+diff -urN nfs-server-2.2beta47/Makefile.in nfs-server-2.2beta51/Makefile.in
+--- nfs-server-2.2beta47/Makefile.in Tue Jun 22 14:53:10 1999
++++ nfs-server-2.2beta51/Makefile.in Fri Nov 8 14:45:36 2002
+@@ -17,23 +17,30 @@
+
+ #### Start of system configuration section. ####
+
+-srcdir = @srcdir@
+-VPATH = @srcdir@
++srcdir = @srcdir@
++VPATH = @srcdir@
+
+-CC = @CC@
+-AR = ar
+-RANLIB = @RANLIB@
+-
+-INSTALL = @INSTALL@
+-INSTALL_PROGRAM = @INSTALL_PROGRAM@ -m 755
+-INSTALL_DATA = @INSTALL_DATA@
+-MAKEINFO = makeinfo
+-TEXI2DVI = texi2dvi
+-RPCGEN = @RPCGEN@ @RPCGEN_C@
++CC = @CC@
++AR = ar
++RANLIB = @RANLIB@
++
++INSTALL = @INSTALL@
++INSTALL_PROGRAM = @INSTALL_PROGRAM@ -m 755
++INSTALL_DATA = @INSTALL_DATA@
++MAKEINFO = makeinfo
++TEXI2DVI = texi2dvi
++RPCGEN = @RPCGEN@ @RPCGEN_C@
+
+ # General compile options and libs:
+-DEFS = @DEFS@ $(NFSD_DEFS)
+-LIBS = libnfs.a @LIBS@
++DEFS = @DEFS@ $(NFSD_DEFS)
++LIBS = libnfs.a @LIBS@
++
++# Ugidd support
++UGIDD_PROG = @UGIDD_PROG@
++UGIDD_MAN = @UGIDD_MAN@
++
++# New inode mapping scheme
++DEVTAB_FILE = $(install_prefix)@PATH_DEVTAB@
+
+ # Compile options for nfsd:
+ # CALL_PROFILING
+@@ -80,9 +87,6 @@
+
+ #### End of system configuration section. ####
+
+-# include site-specific defintions generated by BUILD.
+-include site.mk
+-
+ SHELL = /bin/sh
+
+ SRCS = version.c logging.c fh.c devtab.c \
+@@ -96,19 +100,19 @@
+ utimes.c mkdir.c rename.c getopt.c getopt_long.c \
+ alloca.c mountlist.c xmalloc.c \
+ xstrdup.c strdup.c strstr.c nfsmounted.c faccess.c \
+- haccess.c failsafe.c signals.c
++ haccess.c daemon.c signals.c
+ XDRFILES = mount.x nfs_prot.x
+ GENFILES = mount.h mount_xdr.c mount_svc.c nfs_prot.h nfs_prot_xdr.c \
+ ugid.h ugid_xdr.c ugid_clnt.c
+ HDRS = system.h nfsd.h auth.h fh.h logging.h fakefsuid.h \
+ rpcmisc.h faccess.h rquotad.h rquota.h haccess.h
+-LIBHDRS = fsusage.h getopt.h mountlist.h failsafe.h signals.h
++LIBHDRS = fsusage.h getopt.h mountlist.h daemon.h signals.h
+ MANPAGES5 = exports
+ MANPAGES8p = mountd nfsd $(UGIDD_MAN)
+ MANPAGES8 = showmount
+ MANPAGES = $(MANPAGES5) $(MANPAGES8p) $(MANPAGES8)
+ LIBOBJS = version.o fsusage.o mountlist.o xmalloc.o xstrdup.o \
+- nfsmounted.o faccess.o haccess.o failsafe.o \
++ nfsmounted.o faccess.o haccess.o daemon.o \
+ signals.o @LIBOBJS@ @ALLOCA@
+ OBJS = logging.o fh.o devtab.o auth_init.o auth_clnt.o auth.o
+ NFSD_OBJS = nfsd.o rpcmisc.o nfs_dispatch.o getattr.o setattr.o \
+@@ -174,15 +178,13 @@
+ ${srcdir}/mkinstalldirs $(bindir) $(man5dir) $(man8dir)
+
+ $(rpcprefix)mountd: $(MOUNTD_OBJS) libnfs.a
+- $(CC) $(LDFLAGS) -o $@ $(MOUNTD_OBJS) $(LIBS) \
+- $(LIBWRAP_DIR) $(LIBWRAP_LIB)
++ $(CC) $(LDFLAGS) -o $@ $(MOUNTD_OBJS) $(LIBS)
+
+ $(rpcprefix)nfsd: $(NFSD_OBJS) libnfs.a
+ $(CC) $(LDFLAGS) -o $@ $(NFSD_OBJS) $(LIBS)
+
+ $(rpcprefix)ugidd: $(UGIDD_OBJS) libnfs.a
+- $(CC) $(LDFLAGS) -o $@ $(UGIDD_OBJS) $(LIBS) \
+- $(LIBWRAP_DIR) $(LIBWRAP_LIB)
++ $(CC) $(LDFLAGS) -o $@ $(UGIDD_OBJS) $(LIBS)
+
+ showmount: $(SHOWMOUNT_OBJS) libnfs.a
+ $(CC) $(LDFLAGS) -o $@ $(SHOWMOUNT_OBJS) $(LIBS)
+diff -urN nfs-server-2.2beta47/aclocal.m4 nfs-server-2.2beta51/aclocal.m4
+--- nfs-server-2.2beta47/aclocal.m4 Fri Jun 11 12:04:22 1999
++++ nfs-server-2.2beta51/aclocal.m4 Fri Nov 8 14:45:36 2002
+@@ -221,20 +221,14 @@
+ ])dnl
+ dnl *********** libwrap bug **************
+ define(AC_LIBWRAP_BUG,
+- [if test -f site.mk; then
+- . ./site.mk
+- fi
+- if test ! -z "$LIBWRAP_DIR"; then
++ [if test "$ac_cv_lib_wrap_main" = yes; then
+ AC_MSG_CHECKING(for link problem with libwrap.a)
+ AC_CACHE_VAL(nfsd_cv_lib_wrap_bug,
+- [ac_save_LIBS=$LIBS
+- LIBS="$LIBS $LIBWRAP_DIR $LIBWRAP_LIB"
+- AC_TRY_LINK([
++ [AC_TRY_LINK([
+ extern int deny_severity;
+ ],[
+ deny_severity=1;
+ ], nfsd_cv_lib_wrap_bug=no, nfsd_cv_lib_wrap_bug=yes)
+- LIBS=$ac_save_LIBS
+ ]) dnl
+ AC_MSG_RESULT($nfsd_cv_lib_wrap_bug)
+ test $nfsd_cv_lib_wrap_bug = yes && AC_DEFINE(HAVE_LIBWRAP_BUG)
+diff -urN nfs-server-2.2beta47/auth.c nfs-server-2.2beta51/auth.c
+--- nfs-server-2.2beta47/auth.c Mon Sep 13 16:56:03 1999
++++ nfs-server-2.2beta51/auth.c Fri Nov 8 14:45:36 2002
+@@ -84,8 +84,9 @@
+ 0, /* relative links */
+ 0, /* noaccess */
+ 1, /* cross_mounts */
+- (uid_t)-2, /* default uid */
+- (gid_t)-2, /* default gid */
++ 1, /* allow setuid */
++ 65534, /* default uid */
++ 65534, /* default gid */
+ 0, /* no NIS domain */
+ };
+
+@@ -99,8 +100,9 @@
+ 0, /* relative links */
+ 0, /* noaccess */
+ 1, /* cross_mounts */
+- (uid_t)-2, /* default uid */
+- (gid_t)-2, /* default gid */
++ 0, /* allow setuid */
++ 65534, /* default uid */
++ 65534, /* default gid */
+ 0, /* no NIS domain */
+ };
+
+@@ -673,6 +675,7 @@
+ cpp = &unknown_clients;
+ } else {
+ cpp = &known_clients;
++ cp->clnt_addr = *(struct in_addr *) hp->h_addr;
+ auth_hash_host(cp, hp);
+ }
+ cp->next = *cpp;
+diff -urN nfs-server-2.2beta47/auth.h nfs-server-2.2beta51/auth.h
+--- nfs-server-2.2beta47/auth.h Thu Apr 8 14:47:56 1999
++++ nfs-server-2.2beta51/auth.h Fri Nov 8 14:45:36 2002
+@@ -23,14 +23,6 @@
+ extern char * public_root_path;
+ extern struct nfs_fh public_root;
+
+-#if defined(linux) && defined(i386) && !defined(HAVE_SETFSUID)
+-# define MAYBE_HAVE_SETFSUID
+-#endif
+-
+-#ifdef MAYBE_HAVE_SETFSUID
+-extern int have_setfsuid;
+-#endif
+-
+ /*
+ * These externs are set in the dispatcher (dispatch.c) and auth_fh
+ * (nfsd.c) so that we can determine access rights, export options,
+@@ -59,6 +51,7 @@
+ int link_relative;
+ int noaccess;
+ int cross_mounts;
++ int allow_setuid;
+ uid_t nobody_uid;
+ gid_t nobody_gid;
+ char * clnt_nisdomain;
+@@ -112,7 +105,7 @@
+ extern void auth_free_lists(void);
+ extern nfs_client *auth_clnt(struct svc_req *rqstp);
+ extern nfs_mount *auth_path(nfs_client *, struct svc_req *, char *);
+-extern void auth_user(nfs_mount *, struct svc_req *);
++extern int auth_user(nfs_mount *, struct svc_req *);
+
+ extern nfs_client *auth_get_client(char *);
+ extern nfs_mount *auth_match_mount(nfs_client *, char *);
+diff -urN nfs-server-2.2beta47/auth_clnt.c nfs-server-2.2beta51/auth_clnt.c
+--- nfs-server-2.2beta47/auth_clnt.c Wed Nov 10 10:18:06 1999
++++ nfs-server-2.2beta51/auth_clnt.c Fri Nov 8 14:45:36 2002
+@@ -12,20 +12,17 @@
+ */
+
+
++#include <sys/fsuid.h>
+ #include "system.h"
+ #include "nfsd.h"
+-#include "fakefsuid.h"
+-
+-#ifndef svc_getcaller
+-#define svc_getcaller(x) ((struct sockaddr_in *) &(x)->xp_rtaddr.buf)
+-#endif
++#include "rpcmisc.h"
+
+
+-#if defined(HAVE_SETFSUID) || defined(MAYBE_HAVE_SETFSUID)
+-static void setfsids(uid_t, gid_t, gid_t *, int);
++#if defined(HAVE_SETFSUID)
++static int setfsids(uid_t, gid_t, gid_t *, int);
+ #endif
+ #ifndef HAVE_SETFSUID
+-static void seteids(uid_t, gid_t, gid_t *, int);
++static int seteids(uid_t, gid_t, gid_t *, int);
+ #endif
+
+ uid_t auth_uid = 0; /* Current effective user ids */
+@@ -43,6 +40,17 @@
+ short *gid, short *nrgids, int *groups);
+ #endif
+
++/*
++ * The following crap is required for glibc 2.1 which has 32bit uids
++ * in user land mapped to 16bit uids in the Linux kernel
++ */
++#if defined(HAVE_BROKEN_SETFSUID)
++# define native_uid(u) ((unsigned short)(u))
++# define native_gid(g) ((unsigned short)(g))
++#else
++# define native_uid(u) (u)
++# define native_gid(g) (g)
++#endif
+
+ /*
+ * For an RPC request, look up the NFS client info along with the
+@@ -92,8 +100,9 @@
+ }
+
+ if (logging_enabled(D_AUTH)) {
+- Dprintf(D_AUTH, "auth_path(%s): mount point %s, (%s%s%s%s%s)\n",
+- path, mp->path,
++ Dprintf(D_AUTH, "auth_path(%s, %s): "
++ "mount point %s, (%s%s%s%s%s)\n",
++ inet_ntoa(cp->clnt_addr), path, mp->path,
+ mp->o.all_squash? "all_squash " : (
+ mp->o.root_squash? "root_squash " : ""),
+ (mp->o.uidmap == map_daemon)? "uidmap " : "",
+@@ -105,7 +114,8 @@
+ return mp;
+ }
+
+-void auth_user(nfs_mount *mp, struct svc_req *rqstp)
++int
++auth_user(nfs_mount *mp, struct svc_req *rqstp)
+ {
+ uid_t cuid;
+ gid_t cgid;
+@@ -160,23 +170,18 @@
+ else if (cred_len > NGRPS)
+ cred_len = NGRPS;
+
+- cuid = luid(cred_uid, mp, rqstp);
+- cgid = lgid(cred_gid, mp, rqstp);
++ cuid = luid(native_uid(cred_uid), mp, rqstp);
++ cgid = lgid(native_gid(cred_gid), mp, rqstp);
+ clen = cred_len;
+ for (i = 0; i < cred_len; i++)
+- cgids[i] = lgid(cred_gids[i], mp, rqstp);
++ cgids[i] = lgid(native_gid(cred_gids[i]), mp, rqstp);
+ } else {
+ /* On systems that have 32bit uid_t in user space but
+ * 16bit in the kernel, we need to truncate the
+ * nobody ID (default -2).
+ */
+-#if !defined(HAVE_BROKEN_SETFSUID)
+- cuid = mp->o.nobody_uid;
+- cgid = mp->o.nobody_gid;
+-#else
+- cuid = (unsigned short) mp->o.nobody_uid;
+- cgid = (unsigned short) mp->o.nobody_gid;
+-#endif
++ cuid = native_uid(mp->o.nobody_uid);
++ cgid = native_gid(mp->o.nobody_gid);
+ /* Construct a list of one gid. */
+ cgids[0] = cgid;
+ clen = 1;
+@@ -193,14 +198,9 @@
+ * upper 16 bits set (including our default nobody uid -2).
+ */
+ #if defined(HAVE_SETFSUID)
+- setfsids(cuid, cgid, cgids, clen);
++ return setfsids(cuid, cgid, cgids, clen);
+ #else
+-#if defined(MAYBE_HAVE_SETFSUID)
+- if (have_setfsuid)
+- setfsids(cuid, cgid, cgids, clen);
+- else
+-#endif
+- seteids(cuid, cgid, cgids, clen);
++ return seteids(cuid, cgid, cgids, clen);
+ #endif
+ }
+
+@@ -210,6 +210,8 @@
+ void
+ auth_override_uid(uid_t uid)
+ {
++ int res;
++
+ /* extension hooks: */
+ efs_setfsuid(uid);
+
+@@ -217,19 +219,18 @@
+ uid = (unsigned short) uid;
+ #endif
+ #if defined(HAVE_SETFSUID)
+- setfsuid(uid);
++ res = setfsuid(uid);
+ #else
+-#if defined(MAYBE_HAVE_SETFSUID)
+- if (have_setfsuid)
+- setfsuid(uid);
+- else
+-#endif
+- seteuid(uid);
++ res = seteuid(uid);
+ #endif
++ /* should never happen */
++ if (res < 0)
++ Dprintf(L_FATAL, "auth_override_uid(%d) failed: %s",
++ uid, strerror(errno));
+ }
+
+-#if defined(HAVE_SETFSUID) || defined(MAYBE_HAVE_SETFSUID)
+-static void
++#if defined(HAVE_SETFSUID)
++static int
+ setfsids(uid_t cred_uid, gid_t cred_gid, gid_t *cred_gids, int cred_len)
+ {
+ /* extension hooks: */
+@@ -238,43 +239,47 @@
+
+ /* First, set the user ID. */
+ if (auth_uid != cred_uid) {
+- if (setfsuid(cred_uid) < 0)
++ if (setfsuid(cred_uid) < 0) {
+ Dprintf(L_ERROR, "Unable to setfsuid %d: %s\n",
+ cred_uid, strerror(errno));
+- else
+- auth_uid = cred_uid;
++ return 0;
++ }
++ auth_uid = cred_uid;
+ }
+
+ /* Next, the group ID. */
+ if (auth_gid != cred_gid) {
+- if (setfsgid(cred_gid) < 0)
++ if (setfsgid(cred_gid) < 0) {
+ Dprintf(L_ERROR, "Unable to setfsgid %d: %s\n",
+ cred_gid, strerror(errno));
+- else
+- auth_gid = cred_gid;
++ return 0;
++ }
++ auth_gid = cred_gid;
+ }
+
+ #ifdef HAVE_SETGROUPS
+ /* Finally, set the supplementary group IDs if possible. */
+- if (cred_len < 0 || cred_len > NGRPS)
++ if (cred_len < 0 || cred_len > NGRPS) {
+ Dprintf(L_ERROR, "Negative or huge cred_len: %d\n", cred_len);
+- else if (cred_len != auth_gidlen
+- || memcmp(cred_gids, auth_gids, auth_gidlen*sizeof(gid_t))) {
+- if (setgroups(cred_len, cred_gids) < 0)
++ return 0;
++ }
++ if (cred_len != auth_gidlen
++ || memcmp(cred_gids, auth_gids, auth_gidlen*sizeof(gid_t))) {
++ if (setgroups(cred_len, cred_gids) < 0) {
+ Dprintf(L_ERROR, "Unable to setgroups: %s\n",
+ strerror(errno));
+- else {
+- memcpy(auth_gids, cred_gids, cred_len*sizeof(gid_t));
+- auth_gidlen = cred_len;
++ return 0;
+ }
++ memcpy(auth_gids, cred_gids, cred_len*sizeof(gid_t));
++ auth_gidlen = cred_len;
+ }
+ #endif /* HAVE_SETGROUPS */
+-
++ return 1;
+ }
+ #endif
+
+ #if !defined(HAVE_SETFSUID)
+-static void
++static int
+ seteids(uid_t cred_uid, gid_t cred_gid, gid_t *cred_gids, int cred_len)
+ {
+ /* extension hooks: */
+@@ -286,52 +291,62 @@
+ /* First set the group ID. */
+ if (auth_gid != cred_gid) {
+ if (auth_uid != ROOT_UID) {
+- if (seteuid(ROOT_UID) < 0)
++ if (seteuid(ROOT_UID) < 0) {
+ Dprintf(L_ERROR, "Unable to seteuid(%d): %s\n",
+ ROOT_UID, strerror(errno));
+- else
+- auth_uid = ROOT_UID;
++ return 0;
++ }
++ auth_uid = ROOT_UID;
+ }
+- if (setegid(cred_gid) < 0)
++ if (setegid(cred_gid) < 0) {
+ Dprintf(L_ERROR, "Unable to setegid(%d): %s\n",
+ cred_gid, strerror(errno));
+- else
+- auth_gid = cred_gid;
++ return 0;
++ }
++ auth_gid = cred_gid;
+ }
+
+ #ifdef HAVE_SETGROUPS
+ /* Next set the supplementary group IDs if possible. */
+- if (cred_len < 0 || cred_len > NGRPS)
++ if (cred_len < 0 || cred_len > NGRPS) {
+ Dprintf(L_ERROR, "Negative or huge cred_len: %d\n", cred_len);
+- else if (cred_len != auth_gidlen
+- || memcmp(cred_gids, auth_gids, auth_gidlen*sizeof(gid_t))) {
++ return 0;
++ }
++ if (cred_len != auth_gidlen
++ || memcmp(cred_gids, auth_gids, auth_gidlen*sizeof(gid_t))) {
+ if (auth_uid != ROOT_UID) {
+- if (seteuid(ROOT_UID) < 0)
++ if (seteuid(ROOT_UID) < 0) {
+ Dprintf(L_ERROR, "Unable to seteuid(%d): %s\n",
+ ROOT_UID, strerror(errno));
+- else
+- auth_uid = ROOT_UID;
++ return 0;
++ }
++ auth_uid = ROOT_UID;
+ }
+- if (setgroups(cred_len, cred_gids) < 0)
++ if (setgroups(cred_len, cred_gids) < 0) {
+ Dprintf(L_ERROR, "Unable to setgroups: %s\n",
+ strerror(errno));
+- else {
+- memcpy(auth_gids, cred_gids, cred_len*sizeof(gid_t));
+- auth_gidlen = cred_len;
++ return 0;
+ }
++ memcpy(auth_gids, cred_gids, cred_len*sizeof(gid_t));
++ auth_gidlen = cred_len;
+ }
+ #endif /* HAVE_SETGROUPS */
+
+ /* Finally, set the user ID. */
+ if (auth_uid != cred_uid) {
+- if (auth_uid != ROOT_UID && seteuid(ROOT_UID) < 0)
++ if (auth_uid != ROOT_UID && seteuid(ROOT_UID) < 0) {
+ Dprintf(L_ERROR, "Unable to seteuid(%d): %s\n",
+ ROOT_UID, strerror(errno));
+- if (seteuid(cred_uid) < 0)
++ return 0;
++ }
++ if (seteuid(cred_uid) < 0) {
+ Dprintf(L_ERROR, "Unable to seteuid(%d): %s\n",
+ cred_uid, strerror(errno));
+- else
+- auth_uid = cred_uid;
++ return 0;
++ }
++ auth_uid = cred_uid;
+ }
++
++ return 1;
+ }
+ #endif
+diff -urN nfs-server-2.2beta47/auth_init.c nfs-server-2.2beta51/auth_init.c
+--- nfs-server-2.2beta47/auth_init.c Mon Apr 19 14:01:21 1999
++++ nfs-server-2.2beta51/auth_init.c Fri Nov 8 14:45:36 2002
+@@ -13,7 +13,6 @@
+ */
+
+ #include "nfsd.h"
+-#include "fakefsuid.h"
+ #include <pwd.h>
+
+ #define LINE_SIZE 1024
+@@ -263,55 +262,63 @@
+ cp++;
+ while (*cp != terminator) {
+ kwd = cp;
+- while (isalpha(*cp) || *cp == '_' || *cp == '=') {
+- /* break out of loop after = sign */
+- if (*cp++ == '=')
+- break;
+- }
++ /* Gobble up keyword and "=" if there is one */
++ while (isalpha(*cp) || *cp == '_')
++ ++cp;
++ if (*cp == '=')
++ ++cp;
++
+ klen = cp - kwd;
+
+ /* process keyword */
+- if (strncmp(kwd, "secure", 6) == 0)
++#define ifkwd(n, string) \
++ if (klen == (n) && !strncmp(kwd, string, (n)))
++
++ ifkwd(2, "ro")
++ mp->o.read_only = 1;
++ else ifkwd(2, "rw")
++ mp->o.read_only = 0;
++ else ifkwd(6, "secure")
+ mp->o.secure_port = 1;
+- else if (strncmp(kwd, "insecure", 8) == 0)
++ else ifkwd(8, "insecure")
+ mp->o.secure_port = 0;
+- else if (strncmp(kwd, "root_squash", 11) == 0)
++ else ifkwd(11, "root_squash")
+ mp->o.root_squash = 1;
+- else if (strncmp(kwd, "no_root_squash", 14) == 0)
++ else ifkwd(14, "no_root_squash")
+ mp->o.root_squash = 0;
+- else if (strncmp(kwd, "ro", 2) == 0)
+- mp->o.read_only = 1;
+- else if (strncmp(kwd, "rw", 2) == 0)
+- mp->o.read_only = 0;
+- else if (strncmp(kwd, "link_relative", 13) == 0)
++ else ifkwd(13, "link_relative")
+ mp->o.link_relative = 1;
+- else if (strncmp(kwd, "link_absolute", 13) == 0)
++ else ifkwd(13, "link_absolute")
+ mp->o.link_relative = 0;
+- else if (strncmp(kwd, "map_daemon", 10) == 0)
++ else ifkwd(10, "map_daemon")
+ mp->o.uidmap = map_daemon;
+- else if (strncmp(kwd, "map_nis=", 8) == 0)
++ else ifkwd(8, "map_nis=")
+ parse_nis_uidmap(mp, &cp);
+- else if (strncmp(kwd, "map_static=", 11) == 0)
++ else ifkwd(11, "map_static=")
+ parse_static_uidmap(mp, &cp);
+- else if (strncmp(kwd, "map_identity", 12) == 0)
++ else ifkwd(12, "map_identity")
+ mp->o.uidmap = identity;
+- else if (strncmp(kwd, "all_squash", 10) == 0)
++ else ifkwd(10, "all_squash")
+ mp->o.all_squash = 1;
+- else if (strncmp(kwd, "no_all_squash", 13) == 0)
++ else ifkwd(13, "no_all_squash")
+ mp->o.all_squash = 0;
+- else if (strncmp(kwd, "noaccess", 8) == 0)
++ else ifkwd(8, "noaccess")
+ mp->o.noaccess = 1;
+- else if (strncmp(kwd, "squash_uids=", 12) == 0)
++ else ifkwd(12, "squash_uids=")
+ parse_squash(mp, 1, &cp);
+- else if (strncmp(kwd, "squash_gids=", 12) == 0)
++ else ifkwd(12, "squash_gids=")
+ parse_squash(mp, 0, &cp);
+- else if (strncmp(kwd, "anonuid=", 8) == 0)
++ else ifkwd(8, "anonuid=")
+ mp->o.nobody_uid = parse_num(&cp);
+- else if (strncmp(kwd, "anongid=", 8) == 0)
++ else ifkwd(8, "anongid=")
+ mp->o.nobody_gid = parse_num(&cp);
+- else if (strncmp(kwd, "async", 5) == 0)
++ else ifkwd(6, "setuid")
++ mp->o.allow_setuid = 1;
++ else ifkwd(8, "nosetuid")
++ mp->o.allow_setuid = 0;
++ else ifkwd(5, "async")
+ /* knfsd compatibility, ignore */;
+- else if (strncmp(kwd, "sync", 4) == 0)
++ else ifkwd(4, "sync")
+ /* knfsd compatibility, ignore */;
+ else {
+ Dprintf(L_ERROR,
+@@ -566,11 +573,6 @@
+ auth_check_all_wildcards();
+ auth_sort_all_mountlists();
+ auth_log_all();
+-
+-#if defined(MAYBE_HAVE_SETFSUID) && !defined(HAVE_SETFSUID)
+- /* check if the a.out setfsuid syscall works on this machine */
+- have_setfsuid = (setfsuid(0) >= 0);
+-#endif
+
+ auth_initialized = 1;
+ }
+diff -urN nfs-server-2.2beta47/config.h.in nfs-server-2.2beta51/config.h.in
+--- nfs-server-2.2beta47/config.h.in Fri Jun 11 12:01:22 1999
++++ nfs-server-2.2beta51/config.h.in Fri Nov 8 14:45:36 2002
+@@ -3,7 +3,7 @@
+ /* Define if on AIX 3.
+ System headers sometimes define this.
+ We just want to avoid a redefinition error message. */
+-#ifndef _ALL_SOURCE
++#ifdef _ALL_SOURCE
+ #undef _ALL_SOURCE
+ #endif
+
+diff -urN nfs-server-2.2beta47/configure.in nfs-server-2.2beta51/configure.in
+--- nfs-server-2.2beta47/configure.in Fri Jun 11 11:58:10 1999
++++ nfs-server-2.2beta51/configure.in Fri Nov 8 14:45:36 2002
+@@ -2,7 +2,36 @@
+ dnl Updated for autoconf 2.
+ dnl
+ AC_INIT(nfsd.c)
+-AC_CONFIG_HEADER(config.h)
++AC_CONFIG_HEADER(config.h site.h)
++
++dnl **************************************************************
++dnl * handle --enable options
++dnl **************************************************************
++AC_ARG_ENABLE(new-inodes,
++ [ --enable-new-inodes Enable new-style inode inodes])
++AC_ARG_WITH(devtab,
++ [ --with-devtab=file Specify location for devtab [/var/lib/nfs/devtab]],
++ PATH_DEVTAB=$withval,
++ PATH_DEVTAB=/var/lib/nfs/devtab)
++AC_ARG_ENABLE(ugid-dynamic,
++ [ --enable-ugid-dynamic Enable uid mapping using rpc.ugidd (not recommended)])
++AC_ARG_ENABLE(ugid-nis,
++ [ --enable-ugid-nis Enable NIS-based uid mapping])
++AC_ARG_ENABLE(host-access,
++ [ --enable-host-access Enable host access checking])
++AC_ARG_ENABLE(mount-logging,
++ [ --disable-mount-logging Do not log mount operations to syslog],,
++ enable_mount_logging=yes)
++AC_ARG_WITH(exports-uid,
++ [ --with-exports-uid=N Make sure that /etc/exports is owned by uid N],,
++ with_exports_uid=0)
++AC_ARG_WITH(exports-gid,
++ [ --with-exports-gid=N Make sure that /etc/exports is owned by gid N],,
++ with_exports_gid=0)
++
++dnl **************************************************************
++dnl * Check for all kinds of stuff
++dnl **************************************************************
+ AC_PROG_CC
+ # If we're using gcc, we want warning flags
+ test -n "$GCC" &&
+@@ -19,7 +48,7 @@
+ AC_MINIX
+ AC_ISC_POSIX
+ AC_PROG_INSTALL
+-AC_CROSS_CHECK
++dnl AC_CROSS_CHECK
+ AC_STDC_HEADERS
+ AC_GNULIBC
+ AC_CONST
+@@ -52,14 +81,45 @@
+ AC_CHECK_LIB(rpc, main)
+ AC_CHECK_LIB(crypt, main)
+ AC_CHECK_LIB(nys, main)
+-AC_REPLACE_FUNCS(strerror realpath mkdir rename utimes strdup strstr getopt getopt_long)
+ AC_HAVE_FUNCS(getcwd seteuid setreuid getdtablesize setgroups lchown setsid setfsuid setfsgid innetgr quotactl authdes_getucred)
+ AC_AUTHDES_GETUCRED
+ AC_BROKEN_SETFSUID
+ AC_MOUNTLIST
+ AC_FSUSAGE
++AC_CHECK_LIB(wrap, main)
+ AC_LIBWRAP_BUG
+ AC_BSD_SIGNALS
++
++dnl **************************************************************
++dnl * Munge user specified options
++dnl **************************************************************
++if test "$enable_new_inodes" = yes; then
++ AC_DEFINE(ENABLE_DEVTAB)
++fi
++if test "$enable_ugid_dynamic" = yes; then
++ AC_DEFINE(ENABLE_UGID_DAEMON)
++ UGIDD_PROG=\${rpcprefix}.ugidd
++ UGIDD_MAN=ugidd
++fi
++if test "$enable_ugid_nis" = yes; then
++ AC_DEFINE(ENABLE_UGID_NIS)
++fi
++if test "$enable_host_access" = yes; then
++ AC_DEFINE(HOSTS_ACCESS)
++fi
++if test "$enable_mount_logging" = yes; then
++ AC_DEFINE(WANT_LOG_MOUNTS)
++fi
++AC_DEFINE_UNQUOTED(EXPORTSOWNERUID, $with_exports_uid)
++AC_DEFINE_UNQUOTED(EXPORTSOWNERGID, $with_exports_gid)
++AC_SUBST(PATH_DEVTAB)
++AC_SUBST(UGIDD_PROG)
++AC_SUBST(UGIDD_MAN)
++
++dnl **************************************************************
++dnl * Output CFLAGS and LDFLAGS
++dnl **************************************************************
+ AC_SUBST(LDFLAGS)
+ AC_SUBST(CFLAGS)
++
+ AC_OUTPUT(Makefile)
+diff -urN nfs-server-2.2beta47/daemon.c nfs-server-2.2beta51/daemon.c
+--- nfs-server-2.2beta47/daemon.c Thu Jan 1 01:00:00 1970
++++ nfs-server-2.2beta51/daemon.c Fri Nov 8 14:45:52 2002
+@@ -0,0 +1,270 @@
++/*
++ * daemon.c
++ *
++ * Copyright (C) 1998, <okir@monad.swb.de>
++ *
++ * Implements common daemon stuff and
++ * fail-safe mode for nfsd/mountd.
++ */
++
++#include "system.h"
++#include "logging.h"
++#include "signals.h"
++#include <sys/wait.h>
++
++static const char * pidfilename = 0;
++static const char * get_signame(int signo);
++
++/*
++ * Do the Crawley Thing
++ */
++void
++daemonize(void)
++{
++ int c;
++
++ /* Ignore SIGHUP so the parent can exit while we're still
++ * in limbo */
++ ignore_signal(SIGHUP);
++
++ /* Now fork */
++ c = fork();
++ if (c < 0)
++ Dprintf(L_FATAL, "unable to fork: %s", strerror(errno));
++
++ /* Parent process: exit */
++ if (c > 0)
++ exit(0);
++
++ /* Do the session stuff */
++ close(0);
++ close(1);
++ close(2);
++#ifdef HAVE_SETSID
++ setsid();
++#else
++ if ((c = open("/dev/tty", O_RDWR)) >= 0) {
++ ioctl(c, TIOCNOTTY, (char *) NULL);
++ close(c);
++ }
++#endif
++
++ /* Stop stderr logging */
++ background_logging();
++}
++
++void
++setpidpath(const char *filename)
++{
++ pidfilename = filename;
++}
++
++void
++writepid(pid_t pid, int clear)
++{
++ FILE *fp;
++
++ fp = fopen(pidfilename, clear? "w" : "a");
++ if (fp == NULL)
++ Dprintf(L_FATAL, "Unable to open %s: %m", pidfilename);
++ fprintf(fp, "%d\n", pid);
++ fclose(fp);
++ return;
++}
++
++void
++failsafe(int level, int ncopies)
++{
++ int *servers, running, child, i;
++ int pid, signo, status;
++ time_t last_restart = 0, now;
++ int restarts = 0, backoff = 60;
++
++ servers = (int *) xmalloc(ncopies * sizeof(int));
++ memset(servers, 0, ncopies * sizeof(int));
++
++ /* Loop forever, until we get SIGTERM */
++ running = 0;
++ while (1) {
++ /* Rewrite the pidfile */
++ writepid(getpid(), 1);
++ for (i = 0; i < ncopies; i++) {
++ if (servers[i] != 0)
++ writepid(servers[i], 0);
++ }
++
++ while (running < ncopies) {
++ if ((now = time(NULL)) == last_restart) {
++ if (++restarts > 2 * ncopies) {
++ Dprintf(L_ERROR,
++ "Servers restarting too "
++ "quickly, backing off.");
++ if (backoff < 60 * 60)
++ backoff <<= 1;
++ sleep(backoff);
++ }
++ } else {
++ last_restart = now;
++ restarts = 0;
++ backoff = 60;
++ }
++
++ /* Locate a free pid slot */
++ for (i = 0, child = -1; i < ncopies; i++) {
++ if (servers[i] == 0) {
++ child = i;
++ break;
++ }
++ }
++
++ if (child < 0)
++ Dprintf(L_FATAL, "failsafe: no pid slot?!");
++
++ Dprintf(D_GENERAL,
++ "starting server thread %d...\n", child + 1);
++
++ pid = fork();
++ if (pid < 0)
++ Dprintf(L_FATAL,
++ "Unable to fork for failsafe: %s",
++ strerror(errno));
++
++ if (pid == 0) {
++ /* Child process: continue with execution. */
++ return;
++ }
++
++ writepid(pid, 0);
++ servers[child] = pid;
++ running++;
++ }
++
++ /* Ignore some signals */
++ ignore_signal(SIGTERM);
++ ignore_signal(SIGHUP);
++ ignore_signal(SIGINT);
++ ignore_signal(SIGCHLD);
++
++ if ((pid = wait(&status)) < 0) {
++ Dprintf((errno == ECHILD)? L_FATAL : L_WARNING,
++ "failsafe: wait(): %s", strerror(errno));
++ continue;
++ }
++
++ /* Locate the child */
++ for (i = 0, child = -1; i < ncopies; i++) {
++ if (servers[i] == pid) {
++ child = i;
++ break;
++ }
++ }
++
++ if (child < 0) {
++ Dprintf(L_WARNING,
++ "failsafe: unknown child (pid %d) terminated",
++ pid);
++ continue;
++ }
++
++ /* Book-keeping */
++ servers[child] = 0;
++ running--;
++
++ if (WIFSIGNALED(status)) {
++ signo = WTERMSIG(status);
++ if (signo == SIGTERM) {
++ Dprintf(L_NOTICE, "failsafe: "
++ "child %d terminated by SIGTERM. %s.",
++ pid, running? "Continue" : "Exit");
++ } else {
++ Dprintf(L_WARNING, "failsafe: "
++ "child %d terminated by %s. "
++ "Restarting.",
++ pid, get_signame(signo));
++ child = -1; /* Restart */
++ }
++ } else if (WIFEXITED(status)) {
++ Dprintf(L_NOTICE, "failsafe: "
++ "child %d exited, status %d.",
++ pid, WEXITSTATUS(status));
++ } else {
++ Dprintf(L_ERROR, "failsafe: "
++ "abnormal child termination, "
++ "pid=%d status=%d. Restarting.",
++ pid, status);
++ child = -1; /* Restart */
++ }
++
++ /* If child >= 0, we should not restart */
++ if (child >= 0) {
++ if (!running) {
++ Dprintf(D_GENERAL,
++ "No more children, exiting.");
++ exit(0);
++ }
++ for (i = child; i < ncopies-1; i++)
++ servers[i] = servers[i+1];
++ ncopies--; /* Make sure we start no new servers */
++ }
++ }
++}
++
++/*
++ * Failsafe session, catch core file.
++ *
++ * Not yet implemented.
++ * General outline: we need to fork first, because nfsd changes
++ * uids frequently, and the kernel won't write out a core file after
++ * that. The forked proc starts out with a clean dumpable flag though.
++ *
++ * After the fork, we might want to make sure we end up in some common
++ * directory that the failsafe loop knows about.
++ */
++void
++failsafe_loop(int level, void (*function)(void))
++{
++ /* NOP */
++}
++
++static const char *
++get_signame(int signo)
++{
++ static char namebuf[30];
++
++ switch (signo) {
++ case SIGHUP: return "SIGHUP";
++ case SIGINT: return "SIGINT";
++ case SIGQUIT: return "SIGQUIT";
++ case SIGILL: return "SIGILL";
++ case SIGTRAP: return "SIGTRAP";
++ case SIGIOT: return "SIGIOT";
++ case SIGBUS: return "SIGBUS";
++ case SIGFPE: return "SIGFPE";
++ case SIGKILL: return "SIGKILL";
++ case SIGUSR1: return "SIGUSR1";
++ case SIGSEGV: return "SIGSEGV";
++ case SIGUSR2: return "SIGUSR2";
++ case SIGPIPE: return "SIGPIPE";
++ case SIGALRM: return "SIGALRM";
++ case SIGTERM: return "SIGTERM";
++ case SIGCHLD: return "SIGCHLD";
++ case SIGCONT: return "SIGCONT";
++ case SIGSTOP: return "SIGSTOP";
++ case SIGTSTP: return "SIGTSTP";
++ case SIGTTIN: return "SIGTTIN";
++ case SIGTTOU: return "SIGTTOU";
++ case SIGURG: return "SIGURG";
++ case SIGXCPU: return "SIGXCPU";
++ case SIGXFSZ: return "SIGXFSZ";
++ case SIGVTALRM: return "SIGVTALRM";
++ case SIGPROF: return "SIGPROF";
++ case SIGWINCH: return "SIGWINCH";
++ case SIGIO: return "SIGIO";
++#ifdef SIGPWR
++ case SIGPWR: return "SIGPWR";
++#endif
++ }
++
++ sprintf(namebuf, "signal #%d", signo);
++ return namebuf;
++}
+diff -urN nfs-server-2.2beta47/daemon.h nfs-server-2.2beta51/daemon.h
+--- nfs-server-2.2beta47/daemon.h Thu Jan 1 01:00:00 1970
++++ nfs-server-2.2beta51/daemon.h Fri Nov 8 14:45:52 2002
+@@ -0,0 +1,18 @@
++/*
++ * daemon.h
++ *
++ * Daemon support
++ */
++
++#ifndef CRAWLEY_H
++#define CRAWLEY_H
++
++#define _PATH_NFSD_PIDFILE "/var/run/nfsd.pid"
++#define _PATH_MOUNTD_PIDFILE "/var/run/mountd.pid"
++
++extern void daemonize(void);
++extern void setpidpath(const char *);
++extern void writepid(pid_t, int);
++extern void failsafe(int level, int ncopies);
++
++#endif /* CRAWLEY_H */
+diff -urN nfs-server-2.2beta47/exports.man nfs-server-2.2beta51/exports.man
+--- nfs-server-2.2beta47/exports.man Wed Nov 10 10:18:49 1999
++++ nfs-server-2.2beta51/exports.man Fri Nov 8 14:45:36 2002
+@@ -45,6 +45,12 @@
+ simultaneously. This is done by specifying an IP address and netmask pair
+ as
+ .IR address/netmask .
++.IP "world
++You can export a directory to the world (i.e. to all computers that
++are able to reach your NFS server network-wise) by using the empty
++hostname. When exporting to the world, the
++.BR root_squash ", " all_squash ", " ro " and " nosetuid
++options are turned on by default.
+ .TP
+ .B =public
+ This is a special ``hostname'' that identifies the given directory name
+@@ -81,6 +87,12 @@
+ by using the
+ .IR ro " option.
+ .TP
++.I setuid
++This allows clients to assert the setuid and setgid bits on regular
++files. For non-anonymous exports, this option is on by default.
++For anonymous exports, the default is
++.IR nosetuid .
++.TP
+ .I noaccess
+ This makes everything below the directory inaccessible for the named
+ client. This is useful when you want to export a directory hierarchy to
+@@ -296,6 +308,22 @@
+ .I /usr/X11R6
+ entry apply. This is also true when the latter is a wildcard or netgroup
+ entry.
++.PP
++You should also be careful about where you place spaces in the
++exports file. For instance, the following may appear as if you've
++exported
++.BR /pub " readonly to host " foozle ,
++but what this does in fact is export the directory to
++.B foozle
++with the default options,
++.I and
++export it to the world with the readonly option:
++.PP
++.nf
++.ta +3i
++# bad: export to the world
++/pub foozle (ro)
++.fi
+ .SH FILES
+ /etc/exports
+ .SH DIAGNOSTICS
+diff -urN nfs-server-2.2beta47/fh.c nfs-server-2.2beta51/fh.c
+--- nfs-server-2.2beta47/fh.c Wed Nov 10 10:41:14 1999
++++ nfs-server-2.2beta51/fh.c Fri Nov 8 14:45:36 2002
+@@ -95,17 +95,14 @@
+ static int fh_list_size;
+ static time_t curtime;
+
+-#ifndef FOPEN_MAX
+-#define FOPEN_MAX 256
+-#endif
+-
+ #ifndef FHTRACE
+ #undef D_FHTRACE
+ #define D_FHTRACE D_FHCACHE
+ #endif
+
+-static fhcache * fd_cache[FOPEN_MAX] = { NULL };
++static fhcache ** fd_cache = NULL;
+ static int fd_cache_size = 0;
++static int fd_cache_max = 0;
+
+ #ifndef NFSERR_INVAL /* that Sun forgot */
+ #define NFSERR_INVAL 22
+@@ -141,10 +138,13 @@
+
+ /* Forward declared local functions */
+ static psi_t path_psi(char *, nfsstat *, struct stat *, int);
++static psi_t path_psi_m(char *, nfsstat *, struct stat *,
++ struct stat *, int);
+ static int fh_flush_fds(void);
+ static char * fh_dump(svc_fh *);
+ static void fh_insert_fdcache(fhcache *fhc);
+ static void fh_unlink_fdcache(fhcache *fhc);
++static void fh_complain(const char *msg, fhcache *fhc);
+
+ static void
+ fh_move_to_front(fhcache *fhc)
+@@ -192,6 +192,13 @@
+ static void
+ fh_insert_fdcache(fhcache *fhc)
+ {
++#ifdef FHTRACE
++ Dprintf(D_FHTRACE, "insert fh %x into fdcache @%d\n", fhc->h.psi, fhc->fd);
++ if (fhc->fd < 0) {
++ fh_complain("fd cache bug: bad fd", fhc);
++ return;
++ }
++#endif
+ if (fhc == fd_lru_head)
+ return;
+ if (fhc->fd_next || fhc->fd_prev)
+@@ -203,9 +210,20 @@
+ fhc->fd_next = fd_lru_head;
+ fd_lru_head = fhc;
+
++ if (fhc->fd >= fd_cache_max) {
++ int oldmax = fd_cache_max, newmax;
++
++ newmax = (fhc->fd + 8) & ~7;
++ fd_cache = (fhcache **) xrealloc(fd_cache, newmax * sizeof(fhcache *));
++ memset(fd_cache + oldmax, 0, (newmax - oldmax) * sizeof(fhcache *));
++ fd_cache_max = newmax;
++ }
++
+ #ifdef FHTRACE
+ if (fd_cache[fhc->fd] != NULL) {
+- Dprintf(L_ERROR, "fd cache inconsistency!\n");
++ Dprintf(L_ERROR, "fd cache inconsistency (two fh's for same fd)");
++ fh_complain("new fh", fhc);
++ fh_complain("old fh", fd_cache[fhc->fd]);
+ return;
+ }
+ #endif
+@@ -225,7 +243,7 @@
+ } else if (fd_lru_tail == fhc) {
+ fd_lru_tail = prev;
+ } else {
+- Dprintf(L_ERROR, "fd cache inconsistency\n");
++ fh_complain("fd cache inconsistency (no next and not at tail)", fhc);
+ return;
+ }
+ if (prev) {
+@@ -233,13 +251,13 @@
+ } else if (fd_lru_head == fhc) {
+ fd_lru_head = next;
+ } else {
+- Dprintf(L_ERROR, "fd cache inconsistency\n");
++ fh_complain("fd cache inconsistency (no prev and not at head)", fhc);
+ return;
+ }
+
+ #ifdef FHTRACE
+ if (fd_cache[fhc->fd] != fhc) {
+- Dprintf(L_ERROR, "fd cache inconsistency!\n");
++ fh_complain("fd cache inconsistency (fd cache ptr mismatch)", fhc);
+ return;
+ }
+ #endif
+@@ -285,7 +303,7 @@
+ hash_slot = &((*hash_slot)->hash_next);
+ if (*hash_slot == NULL)
+ Dprintf(L_ERROR,
+- "internal inconsistency -- fhc(%x) not in hash table\n",
++ "internal inconsistency -- fhc(%x) not in hash table!\n",
+ fhc);
+ else
+ *hash_slot = fhc->hash_next;
+@@ -572,7 +590,7 @@
+ efs_seekdir(dir, cookie_stack[i]);
+ while ((dp = efs_readdir(dir))) {
+ char *name = dp->d_name;
+- int n = strlen(name);
++ int n = strlen(name); /* or: dp->d_reclen */
+
+ if (pathlen + n + 1 >= NFS_MAXPATHLEN
+ || (name[0] == '.'
+@@ -738,7 +756,16 @@
+ static psi_t
+ path_psi(char *path, nfsstat *status, struct stat *sbp, int svalid)
+ {
+- struct stat sbuf;
++ struct stat smounted;
++
++ return path_psi_m(path, status, sbp, &smounted, svalid);
++}
++
++static psi_t
++path_psi_m(char *path, nfsstat *status,
++ struct stat *sbp, struct stat *mbp, int svalid)
++{
++ struct stat sbuf, ddbuf;
+
+ if (sbp == NULL)
+ sbp = &sbuf;
+@@ -746,10 +773,10 @@
+ *status = nfs_errno();
+ return (0);
+ }
++ *mbp = *sbp;
+ if (S_ISDIR(sbp->st_mode) && strcmp(path, "/") != 0) {
+ /* Special case for directories--test for mount point. */
+- struct stat ddbuf;
+- char *fname;
++ char *fname;
+
+ /* Find start of last component of path. */
+ #if 1
+@@ -819,6 +846,19 @@
+ return (pseudo_inode(sbp->st_ino, sbp->st_dev));
+ }
+
++/*
++ * Match attributes to make sure we're still referring to the original file
++ */
++static inline int
++fh_attrmatch(struct fhcache *fhc, struct stat *attr)
++{
++ if (fhc->dev == attr->st_dev
++ && fhc->ino == attr->st_ino
++ && fhc->type == (attr->st_mode & S_IFMT))
++ return 1;
++ return 0;
++}
++
+ fhcache *
+ fh_find(svc_fh *h, int mode)
+ {
+@@ -838,6 +878,9 @@
+ ex_state = active;
+ time(&curtime);
+ while ((fhc = fh_lookup(h->psi)) != NULL) {
++ struct stat sbuf, *s = NULL;
++ nfsstat dummy;
++
+ Dprintf(D_FHCACHE, "fh_find: psi=%lx... found '%s', fd=%d\n",
+ (unsigned long) h->psi,
+ fhc->path ? fhc->path : "<unnamed>",
+@@ -857,33 +900,27 @@
+ * If it doesn't try to rebuild the path.
+ */
+ if (check) {
+- struct stat *s = &fhc->attrs;
+- psi_t psi;
+- nfsstat dummy;
+-
++ s = &sbuf;
+ if (efs_lstat(fhc->path, s) < 0) {
+ Dprintf(D_FHTRACE,
+ "fh_find: stale fh: lstat: %m\n");
+ } else {
+- fhc->flags |= FHC_ATTRVALID;
+- /* If pseudo-inos don't match, we fhc->path
+- * may be a mount point (hence lstat() returns
++ /* If device/ino don't match, fhc->path may
++ * be a mount point (hence lstat() returns
+ * a different inode number than the readdir()
+ * stuff used in path_psi)
+ */
+- psi = pseudo_inode(s->st_ino, s->st_dev);
+- if (h->psi == psi)
++ if (fh_attrmatch(fhc, s))
+ goto fh_return;
+
+- /* Try again by computing the path psi */
+- psi = path_psi(fhc->path, &dummy, s, 1);
+- if (h->psi == psi)
++ /* Get the dev/ino of the underlying
++ * mount point. */
++ path_psi(fhc->path, &dummy, s, 1);
++ if (fh_attrmatch(fhc, s))
+ goto fh_return;
+
+- Dprintf(D_FHTRACE, "fh_find: stale fh: "
+- "dev/ino %x/%lx psi %lx",
+- s->st_dev, s->st_ino,
+- (unsigned long) psi);
++ Dprintf(D_FHTRACE, "fh_find: stale fh: %lx",
++ (unsigned long) h->psi);
+ }
+
+ fh_discard:
+@@ -896,6 +933,12 @@
+ }
+
+ fh_return:
++ /* Valid attributes; cache them */
++ if (s != NULL) {
++ memcpy(&fhc->attrs, s, sizeof(*s));
++ fhc->flags |= FHC_ATTRVALID;
++ }
++
+ /* The cached fh seems valid */
+ if (fhc != fh_head.next)
+ fh_move_to_front(fhc);
+@@ -905,7 +948,8 @@
+ }
+
+ Dprintf(D_FHCACHE, "fh_find: psi=%lx... not found\n",
+- (unsigned long) h->psi);
++ (unsigned long) h->psi);
++
+ if (mode == FHFIND_FCACHED) {
+ ex_state = inactive;
+ return NULL;
+@@ -918,6 +962,7 @@
+ fhc = flush->prev;
+ fh_delete(flush);
+ }
++
+ fhc = (fhcache *) xmalloc(sizeof *fhc);
+ if (mode == FHFIND_FCREATE) {
+ /* File will be created */
+@@ -937,11 +982,31 @@
+ }
+ fhc->path = path;
+ }
++
+ fhc->flags = 0;
+ if (fhc->path && efs_lstat(fhc->path, &fhc->attrs) >= 0) {
+- if (re_export && nfsmounted(fhc->path, &fhc->attrs))
++ if (nfsmounted(fhc->path, &fhc->attrs)) {
+ fhc->flags |= FHC_NFSMOUNTED;
++#if 0
++ /* We must allow the client to send us the
++ * file handle for the NFS mount point itself,
++ * but not for entries within an NFS mount.
++ * XXX: needs fixing.
++ */
++ if (!re_export) {
++ Dprintf(D_FHTRACE,
++ "Attempt to use %s (non-exportable)\n",
++ fhc->path);
++ free(fhc);
++ ex_state = inactive;
++ return NULL;
++ }
++#endif
++ }
+ fhc->flags |= FHC_ATTRVALID;
++ fhc->dev = fhc->attrs.st_dev;
++ fhc->ino = fhc->attrs.st_ino;
++ fhc->type = fhc->attrs.st_mode & S_IFMT;
+ }
+ fhc->fd = -1;
+ fhc->last_used = curtime;
+@@ -993,6 +1058,14 @@
+ return buf;
+ }
+
++static void
++fh_complain(const char *msg, fhcache *fhc)
++{
++ Dprintf(L_ERROR, "%s: ptr=%p fd=%d path=%s\n", msg,
++ fhc, fhc->fd,
++ fhc->path? fhc->path : "<unnamed>");
++}
++
+ /*
+ * This routine is only used by the mount daemon.
+ * It creates the initial file handle.
+@@ -1000,23 +1073,25 @@
+ int
+ fh_create(nfs_fh *fh, char *path)
+ {
+- svc_fh key;
+- fhcache *h;
+- psi_t psi;
+- nfsstat status;
+- char *s;
++ struct stat stb;
++ svc_fh key;
++ fhcache *h;
++ psi_t psi;
++ nfsstat status;
++ char *s;
+
+ memset(&key, 0, sizeof(key));
+ status = NFS_OK;
+- if ((psi = path_psi("/", &status, NULL, 0)) == 0)
++ if ((psi = path_psi("/", &status, &stb, 0)) == 0)
+ return ((int) status);
++
+ s = path;
+ while ((s = strchr(s + 1, '/')) != NULL) {
+ if (++(key.hash_path[0]) >= HP_LEN)
+ return ((int) NFSERR_NAMETOOLONG);
+ key.hash_path[key.hash_path[0]] = hash_psi(psi);
+ *s = '\0';
+- if ((psi = path_psi(path, &status, NULL, 0)) == 0)
++ if ((psi = path_psi(path, &status, &stb, 0)) == 0)
+ return ((int) status);
+ *s = '/';
+ }
+@@ -1024,7 +1099,7 @@
+ if (++(key.hash_path[0]) >= HP_LEN)
+ return ((int) NFSERR_NAMETOOLONG);
+ key.hash_path[key.hash_path[0]] = hash_psi(psi);
+- if ((psi = path_psi(path, &status, NULL, 0)) == 0)
++ if ((psi = path_psi(path, &status, &stb, 0)) == 0)
+ return ((int) status);
+ }
+ key.psi = psi;
+@@ -1037,9 +1112,12 @@
+
+ /* assert(h != NULL); */
+ if (h->path == NULL) {
+- h->fd = -1;
+- h->path = xstrdup(path);
++ h->fd = -1;
++ h->path = xstrdup(path);
+ h->flags = 0;
++ h->dev = stb.st_dev;
++ h->ino = stb.st_ino;
++ h->type = stb.st_mode & S_IFMT;
+ }
+ memcpy(fh, &key, sizeof(key));
+ return ((int) status);
+@@ -1064,6 +1142,44 @@
+ return ((nfs_fh*)&(h->h));
+ }
+
++
++static inline int
++access_override(int omode, int perm, struct stat *buf)
++{
++ /* Be suspicous of flags, particularly O_CREAT/O_TRUNC. A previous
++ * comment said:
++ *
++ * "[Not checking this] would truncate read-only files on creat()
++ * calls. Of course, ftruncate(fd, 0) should still be legal for
++ * the user when the file was chmoded *after* opening it, but we
++ * have no way to tell, and a semi-succeding `cp foo readonly-file'
++ * is much more unintuitive and destructive than a failing
++ * ftruncate()."
++ */
++ if (omode & ~O_ACCMODE)
++ return 0;
++
++ /* Users can do anything to their own files. Harmless (since they
++ * could chown anyway), and helps to mask NFSes statelessness.
++ *
++ * (in passing, this also handles mode 0100 execution)
++ */
++ if (buf->st_uid == auth_uid)
++ return 1;
++
++ /* Henceforth, we are considering granting read access to facilitate
++ * exec access. This is read only */
++ if (omode != O_RDONLY)
++ return 0;
++
++ /* Mode 0110 execution */
++ if (buf->st_gid == auth_gid)
++ return (buf->st_mode & S_IXGRP) != 0;
++
++ /* Mode 0111 execution */
++ return (buf->st_mode & S_IXOTH) != 0;
++}
++
+ int
+ path_open(char *path, int omode, int perm)
+ {
+@@ -1113,30 +1229,15 @@
+ * lishes two things: first, it gives the file owner r/w access to
+ * the file whatever the permissions are, so that files are still
+ * accessible after an fchown(fd, 0). The second part of the
+- * condition allows read access to mode 0111 executables.
+- *
+- * The old conditon read like this:
+- * if (fd < 0 && oerrno == EACCES) {
+- * if (oerrno == EACCES && (buf.st_uid == auth_uid
+- * || (omode == O_RDONLY && (buf.st_mode & S_IXOTH)))) {
+- * override uid; etc...
+- * }
+- * }
+- * This would truncate read-only files on creat() calls. Now
+- * ftruncate(fd, 0) should still be legal for the user when the
+- * file was chmoded *after* opening it, but we have no way to tell,
+- * and a semi-succeding `cp foo readonly-file' is much more
+- * unintuitive and destructive than a failing ftruncate().
++ * condition allows read access to `execute-only' files.
+ */
+- if (fd < 0 && oerrno == EACCES && !(omode & (O_CREAT|O_TRUNC))) {
+- if ((buf.st_uid == auth_uid && (omode & O_ACCMODE) == omode)
+- || ((buf.st_mode & S_IXOTH) && omode == O_RDONLY)) {
+- auth_override_uid(ROOT_UID);
+- fd = efs_open(path, omode, perm);
+- oerrno = errno;
+- auth_override_uid(auth_uid);
+- }
++ if (fd < 0 && oerrno == EACCES && access_override(omode, perm, &buf)) {
++ auth_override_uid(ROOT_UID);
++ fd = efs_open(path, omode, perm);
++ oerrno = errno;
++ auth_override_uid(auth_uid);
+ }
++
+
+ if (fd < 0) {
+ Dprintf(D_FHCACHE,
+@@ -1241,7 +1342,7 @@
+ char *sindx;
+ int is_dd;
+ nfsstat ret;
+- struct stat sbuf;
++ struct stat sbuf, smount;
+ char pathbuf[PATH_MAX + NAME_MAX + 1], *fname;
+
+ /* should not happen */
+@@ -1318,7 +1419,7 @@
+
+ *new_fh = dopa->dir;
+ key = (svc_fh *) new_fh;
+- if ((key->psi = path_psi(pathbuf, &ret, sbp, 0)) == 0)
++ if ((key->psi = path_psi_m(pathbuf, &ret, sbp, &smount, 0)) == 0)
+ return (ret);
+
+ if (is_dd) {
+@@ -1344,6 +1445,10 @@
+ h->h.hash_path[0]);
+ return NFSERR_STALE;
+ }
++ if (sbp->st_dev != smount.st_dev) {
++ Dprintf(D_FHTRACE, "fh_compose: %s hit%s mount point\n",
++ pathbuf, nfsmounted(pathbuf, &smount)? " NFS" : "");
++ }
+ #endif
+
+ /* New code added by Don Becker */
+@@ -1356,7 +1461,8 @@
+ if (!h) return NFSERR_STALE;
+ #endif
+ if (h->path)
+- Dprintf(L_ERROR, "Internal inconsistency: double entry (path '%s', now '%s').\n",
++ Dprintf(L_ERROR,
++ "internal inconsistency: double entry (path '%s', now '%s').\n",
+ h->path, pathbuf);
+ }
+ Dprintf(D_FHCACHE, "fh_compose: using handle %x ('%s', fd=%d)\n",
+@@ -1365,9 +1471,18 @@
+
+ /* assert(h != NULL); */
+ if (h->path == 0) {
+- h->path = xstrdup(pathbuf);
++ h->path = xstrdup(pathbuf);
+ h->flags = 0;
+- if (!re_export && nfsmounted(pathbuf, sbp))
++ h->dev = sbp->st_dev;
++ h->ino = sbp->st_ino;
++ h->type = sbp->st_mode & S_IFMT;
++
++ /* Note: in the case of a mount point,
++ * sbp contains the stats of the mount point, while
++ * ddbuf has the dev/ino of the underlying directory
++ */
++ if (sbp->st_dev != smount.st_dev
++ && nfsmounted(pathbuf, &smount))
+ h->flags |= FHC_NFSMOUNTED;
+ #ifdef FHTRACE
+ Dprintf(D_FHTRACE, "fh_compose: created handle %s\n", h->path);
+diff -urN nfs-server-2.2beta47/fh.h nfs-server-2.2beta51/fh.h
+--- nfs-server-2.2beta47/fh.h Mon Nov 23 12:15:43 1998
++++ nfs-server-2.2beta51/fh.h Fri Nov 8 14:45:36 2002
+@@ -97,7 +97,13 @@
+ struct fhcache * hash_next;
+ struct fhcache * fd_next;
+ struct fhcache * fd_prev;
++
++ /* These are fixed during the lifetime of this object */
+ svc_fh h;
++ dev_t dev;
++ ino_t ino;
++ mode_t type; /* st_mode & S_IFMT */
++
+ int fd;
+ int omode;
+ char * path;
+diff -urN nfs-server-2.2beta47/getattr.c nfs-server-2.2beta51/getattr.c
+--- nfs-server-2.2beta47/getattr.c Fri Oct 30 18:10:11 1998
++++ nfs-server-2.2beta51/getattr.c Fri Nov 8 14:45:36 2002
+@@ -115,6 +115,16 @@
+ attr->fsid = 1;
+ attr->fileid = fh_psi((nfs_fh *)&(fhc->h));
+ #endif
++
++ /* This may be needed by some Suns... testing */
++#define MINTIME (24 * 2600)
++ if (s->st_atime < MINTIME)
++ s->st_atime = MINTIME;
++ if (s->st_mtime < MINTIME)
++ s->st_mtime = MINTIME;
++ if (s->st_ctime < MINTIME)
++ s->st_ctime = MINTIME;
++
+ attr->atime.seconds = s->st_atime;
+ attr->atime.useconds = 0;
+ attr->mtime.seconds = s->st_mtime;
+diff -urN nfs-server-2.2beta47/logging.c nfs-server-2.2beta51/logging.c
+--- nfs-server-2.2beta47/logging.c Fri Oct 30 17:11:22 1998
++++ nfs-server-2.2beta51/logging.c Fri Nov 8 14:45:36 2002
+@@ -147,8 +147,9 @@
+ (void) time(&now);
+ tm = localtime(&now);
+ fprintf(log_fp, "%s %02d/%02d/%02d %02d:%02d %s",
+- log_name, tm->tm_mon + 1, tm->tm_mday, tm->tm_year,
+- tm->tm_hour, tm->tm_min, buff);
++ log_name, tm->tm_mon + 1, tm->tm_mday,
++ tm->tm_year % 100,
++ tm->tm_hour, tm->tm_min, buff);
+ if (strchr(buff, '\n') == NULL)
+ fputc('\n', log_fp);
+ }
+@@ -182,7 +183,8 @@
+ tm = localtime(&unix_cred->aup_time);
+ snprintf(buffer + len, total - len,
+ "%d/%d/%d %02d:%02d:%02d %s %d.%d",
+- tm->tm_year, tm->tm_mon + 1, tm->tm_mday,
++ tm->tm_year %100,
++ tm->tm_mon + 1, tm->tm_mday,
+ tm->tm_hour, tm->tm_min, tm->tm_sec,
+ unix_cred->aup_machname,
+ unix_cred->aup_uid,
+diff -urN nfs-server-2.2beta47/mountd.c nfs-server-2.2beta51/mountd.c
+--- nfs-server-2.2beta47/mountd.c Wed Jun 2 14:10:33 1999
++++ nfs-server-2.2beta51/mountd.c Fri Nov 8 14:45:36 2002
+@@ -32,7 +32,7 @@
+ #include "rpcmisc.h"
+ #include "rmtab.h"
+ #include "haccess.h"
+-#include "failsafe.h"
++#include "daemon.h"
+ #include "signals.h"
+ #include <rpc/pmap_clnt.h>
+
+@@ -44,6 +44,8 @@
+ /*
+ * Option table for mountd
+ */
++#define OPT_NOTCP 300
++#define OPT_LOOPBACK 301
+ static struct option longopts[] =
+ {
+ { "debug", required_argument, 0, 'd' },
+@@ -56,6 +58,8 @@
+ { "no-spoof-trace", 0, 0, 't' },
+ { "version", 0, 0, 'v' },
+ { "fail-safe", optional_argument, 0, 'z' },
++ { "no-tcp", 0, 0, OPT_NOTCP },
++ { "loopback-only", 0, 0, OPT_LOOPBACK },
+
+ { NULL, 0, 0, 0 }
+ };
+@@ -358,6 +362,12 @@
+ break;
+ case 0:
+ break;
++ case OPT_NOTCP:
++ udp_only = 1;
++ break;
++ case OPT_LOOPBACK:
++ loopback_only = 1;
++ break;
+ case '?':
+ default:
+ usage(stderr, 1);
+@@ -384,38 +394,27 @@
+ /* Create services and register with portmapper */
+ rpc_init("mountd", MOUNTPROG, mountd_versions, mount_dispatch, port, 0);
+
+- if (!foreground && !_rpcpmstart) {
+-#ifndef RPC_SVC_FG
+- /* We first fork off a child. */
+- if ((c = fork()) > 0)
+- exit(0);
+- if (c < 0) {
+- Dprintf(L_FATAL, "mountd: cannot fork: %s\n",
+- strerror(errno));
+- }
+- /* No more logging to stderr */
+- background_logging();
++ if (_rpcpmstart) {
++ /* Always foreground mode */
++ foreground = 1;
+
+- /* Now we remove ourselves from the foreground. */
+- (void) close(0);
+- (void) close(1);
+- (void) close(2);
+-#ifdef TIOCNOTTY
+- if ((c = open("/dev/tty", O_RDWR)) >= 0) {
+- (void) ioctl(c, TIOCNOTTY, (char *) NULL);
+- (void) close(c);
+- }
+-#else
+- setsid();
+-#endif
+-#endif /* not RPC_SVC_FG */
++ /* ... but no logging */
++ background_logging();
+ }
+
++ /* Become a daemon */
++ if (!foreground)
++ daemonize();
++
+ /* Initialize the FH module. */
+ fh_init();
+
+ /* Initialize the AUTH module. */
+ auth_init(auth_file);
++
++ /* Write pidfile */
++ setpidpath(_PATH_MOUNTD_PIDFILE);
++ writepid(getpid(), 1);
+
+ /* Failsafe mode */
+ if (failsafe_level)
+diff -urN nfs-server-2.2beta47/mountd.man nfs-server-2.2beta51/mountd.man
+--- nfs-server-2.2beta47/mountd.man Wed Jun 2 14:12:21 1999
++++ nfs-server-2.2beta51/mountd.man Fri Nov 8 14:45:36 2002
+@@ -14,6 +14,8 @@
+ .B "[\ \-\-allow\-non\-root\ ]"
+ .B "[\ \-\-re\-export\ ]"
+ .B "[\ \-\-no\-spoof\-trace\ ]"
++.B "[\ \-\-no\-tcp ]"
++.B "[\ \-\-loopback\-only ]"
+ .B "[\ \-\-version\ ]"
+ .ad b
+ .SH DESCRIPTION
+@@ -123,6 +125,18 @@
+ .TP
+ .BR \-v " or " \-\-version
+ Report the current version number of the program.
++.TP
++.BR \-\-no\-tcp
++Force
++.I mountd
++to register only the UDP transport, but no TCP.
++This is an experimental option.
++.TP
++.BR \-\-loopback\-only
++Force
++.I mountd
++to bind to the loopback interface.
++This is an experimental option.
+ .SS Access Control
+ For enhanced security, access to
+ .I mountd
+diff -urN nfs-server-2.2beta47/nfsd.c nfs-server-2.2beta51/nfsd.c
+--- nfs-server-2.2beta47/nfsd.c Wed Nov 10 10:33:28 1999
++++ nfs-server-2.2beta51/nfsd.c Fri Nov 8 14:45:36 2002
+@@ -21,7 +21,7 @@
+ #include "getopt.h"
+ #include "fsusage.h"
+ #include "rpcmisc.h"
+-#include "failsafe.h"
++#include "daemon.h"
+ #include "signals.h"
+ #ifdef __linux__ /* XXX - MvS: for UNIX sockets. */
+ # include <sys/un.h>
+@@ -30,7 +30,6 @@
+ # include <syslog.h>
+ #endif
+
+-#define MULTIPLE_SERVERS
+
+ /* Flags for auth_fh */
+ #define CHK_READ 0
+@@ -51,6 +50,8 @@
+ /*
+ * Option table
+ */
++#define OPT_NOTCP 300
++#define OPT_LOOPBACK 301
+ static struct option longopts[] = {
+ { "auth-deamon", required_argument, 0, 'a' },
+ { "debug", required_argument, 0, 'd' },
+@@ -68,6 +69,9 @@
+ { "version", 0, 0, 'v' },
+ { "no-cross-mounts", 0, 0, 'x' },
+ { "fail-safe", optional_argument, 0, 'z' },
++ { "no-tcp", 0, 0, OPT_NOTCP },
++ { "udp-only", 0, 0, OPT_NOTCP },
++ { "loopback-only", 0, 0, OPT_LOOPBACK },
+
+ { NULL, 0, 0, 0 }
+ };
+@@ -173,7 +177,10 @@
+ return NULL;
+ }
+
+- auth_user(nfsmount, rqstp);
++ if (!auth_user(nfsmount, rqstp)) {
++ *statp = NFSERR_ACCES;
++ return NULL;
++ }
+
+ *statp = NFS_OK;
+ return fhc;
+@@ -211,7 +218,11 @@
+
+ if ((nfsmount = auth_path(nfsclient, rqstp, path)) == NULL)
+ return NFSERR_ACCES;
+- auth_user(nfsmount, rqstp);
++
++ /* XXX: really need to call it again here?
++ * Already invoked in auth_fh */
++ if (!auth_user(nfsmount, rqstp))
++ return NFSERR_ACCES;
+
+ return (NFS_OK);
+ }
+@@ -575,7 +586,8 @@
+ #endif
+
+ /* MvS: Some clients use chardev 0xFFFF for a FIFO. */
+- if (S_ISCHR(argp->attributes.mode) && dev == 0xFFFF) {
++ if (S_ISCHR(argp->attributes.mode)
++ && (dev == 0xFFFF || dev == (dev_t) -1)) {
+ is_borc = 0;
+ dev = 0;
+ argp->attributes.mode &= ~S_IFMT;
+@@ -623,7 +635,7 @@
+ flags = (argp->attributes.size == 0 ?
+ CREATE_OMODE | O_TRUNC : CREATE_OMODE);
+ if (!exists)
+- flags |= O_CREAT;
++ flags |= O_CREAT|O_EXCL;
+ tmpfd = path_open(pathbuf, flags,
+ argp->attributes.mode & ~S_IFMT);
+ if (tmpfd < 0)
+@@ -965,9 +977,7 @@
+ int nfsport = 0;
+ int failsafe_level = 0;
+ int c;
+-#ifdef MULTIPLE_SERVERS
+ int i, ncopies = 1;
+-#endif
+
+ program_name = argv[0];
+ chdir("/");
+@@ -1031,12 +1041,17 @@
+ break;
+ case 0:
+ break;
++ case OPT_NOTCP:
++ udp_only = 1;
++ break;
++ case OPT_LOOPBACK:
++ loopback_only = 1;
++ break;
+ case '?':
+ default:
+ usage(stderr, 1);
+ }
+
+-#ifdef MULTIPLE_SERVERS
+ if (optind == argc-1 && isdigit(argv[optind][0])) {
+ ncopies = atoi(argv[optind++]);
+ if (ncopies <= 0) {
+@@ -1051,7 +1066,6 @@
+ ncopies = 1;
+ }
+ }
+-#endif
+
+ /* No more arguments allowed. */
+ if (optind != argc)
+@@ -1075,72 +1089,54 @@
+ rpc_init("nfsd", NFS_PROGRAM, nfsd_versions, nfs_dispatch,
+ nfsport, NFS_MAXDATA);
+
+- /* No more than 1 copy when run from inetd */
+- if (_rpcpmstart && ncopies > 1) {
+- Dprintf(L_WARNING,
+- "nfsd: warning: can run only "
+- "one server in inetd mode\n");
+- ncopies = 1;
++ if (_rpcpmstart) {
++ /* Always do foreground mode */
++ foreground = 1;
++
++ /* ... but don't log to stderr */
++ background_logging();
++
++ /* No more than 1 copy when run from inetd */
++ if (ncopies > 1) {
++ Dprintf(L_WARNING,
++ "nfsd: warning: can run only "
++ "one server in inetd mode\n");
++ ncopies = 1;
++ }
+ }
+
+-#ifndef MULTIPLE_SERVERS_READWRITE
+ if (ncopies > 1)
+ read_only = 1;
+-#endif
+
+- /* We first fork off a child. */
+- if (!foreground) {
+- if ((c = fork()) > 0)
+- exit(0);
+- if (c < 0) {
+- Dprintf(L_FATAL, "nfsd: cannot fork: %s\n",
+- strerror(errno));
+- }
+- }
++ /*
++ * We first fork off a child and detach from tty
++ */
++ if (!foreground)
++ daemonize();
+
+ /* Initialize the AUTH module. */
+ auth_init(auth_file);
+
++ setpidpath(_PATH_NFSD_PIDFILE);
+ if (failsafe_level == 0) {
+ /* Start multiple copies of the server */
++ writepid(getpid(), 1);
+ for (i = 1; i < ncopies; i++) {
++ pid_t pid;
++
+ Dprintf(D_GENERAL, "Forking server thread...\n");
+- if ((c = fork()) < 0) {
++ if ((pid = fork()) < 0) {
+ Dprintf(L_ERROR, "Unable to fork: %s",
+ strerror(errno));
+- } else if (c == 0) {
+- /* Child process */
+- break;
++ } else if (pid != 0) {
++ writepid(pid, 0);
++ } else {
++ break; /* Child process */
+ }
+ }
+ } else {
+ /* Init for failsafe mode */
+ failsafe(failsafe_level, ncopies);
+- }
+-
+- /* Now that we've done all the required forks, we make do all the
+- * session magic.
+- */
+- if (!foreground) {
+- /* No more logging to stderr */
+- background_logging();
+-
+- /* Now we remove ourselves from the foreground. */
+- close(0);
+- close(1);
+- close(2);
+-#ifdef HAVE_SETSID
+- setsid();
+-#else
+- {
+- int fd;
+-
+- if ((fd = open("/dev/tty", O_RDWR)) >= 0) {
+- ioctl(fd, TIOCNOTTY, (char *) NULL);
+- close(fd);
+- }
+- }
+-#endif
+ }
+
+ /*
+diff -urN nfs-server-2.2beta47/nfsd.man nfs-server-2.2beta51/nfsd.man
+--- nfs-server-2.2beta47/nfsd.man Wed Jun 2 14:13:37 1999
++++ nfs-server-2.2beta51/nfsd.man Fri Nov 8 14:45:36 2002
+@@ -8,7 +8,7 @@
+ .B "[\ \-d\ facility\ ]"
+ .B "[\ \-P\ port\ ]"
+ .B "[\ \-R\ dirname\ ]"
+-.B "[\ \-Fhlnprstv\ ]"
++.B "[\ \-Fhlnprstuv\ ]"
+ .B "[\ \-\-debug\ facility\ ]"
+ .B "[\ \-\-exports\-file=file\ ]"
+ .B "[\ \-\-foreground\ ]"
+@@ -18,6 +18,8 @@
+ .B "[\ \-\-public\-root\ dirname\ ]"
+ .\".B "[\ \-\-synchronous\-writes\ ]"
+ .B "[\ \-\-no\-spoof\-trace\ ]"
++.B "[\ \-\-no\-tcp ]"
++.B "[\ \-\-loopback-only ]"
+ .B "[\ \-\-port\ port\ ]"
+ .B "[\ \-\-log-transfers\ ]"
+ .B "[\ \-\-version\ ]"
+@@ -56,7 +58,7 @@
+ .PP
+ When run from
+ .IR inetd ,
+-.i nfsd
++.I nfsd
+ will terminate after a certain period of inactivity.
+ .SH OPTIONS
+ .TP
+@@ -167,6 +169,14 @@
+ .BR \-v " or " \-\-version
+ Report the current version number of the program.
+ .TP
++.BR \-\-no\-tcp
++Force nfsd to only register a UDP transport, but not TCP.
++This is an experimental option.
++.TP
++.BR \-\-loopback\-only
++Force nfsd to bind to the loopback interface.
++This is an experimental option.
++.TP
+ .BR numcopies
+ This is an experimental feature that lets you run several instances of
+ .I nfsd
+@@ -174,15 +184,8 @@
+ .B numcopies
+ greater than one,
+ .I nfsd
+-will fork as many times as specified by this value.
+-However, the servers do not share a common file handle
+-cache, which makes certain file operations impossible.
+-.IP
+-For this reason,
+-.I nfsd
+-will disallow all write operations when invoked with this option. Although
+-this is very limiting, this feature may still prove useful for exporting
+-public FTP areas or Usenet News spools.
++will fork as many times as specified by this value so it is able to
++handle that many NFS requests in parallel.
+ .SS WebNFS Support
+ WebNFS is an extension to the normal NFS protocol developed by Sun
+ that is particularly well-suited for file retrieval over the
+@@ -268,6 +271,19 @@
+ .I nfsd
+ writes out a transfer record whenever it encounters a READ or WRITE
+ request at offset zero.
++.SS Generating a debug trace
++When suspecting a bug in nfsd, it is helpful to look at a debug trace
++of what's going on. You can create such a trace by first killing nfsd,
++and then restarting it as
++.PP
++.nf
++.ta +3i
++/usr/sbin/rpc.nfsd -F -d all
++.fi
++.PP
++Instead of
++.BR all ,
++you can use less verbose debug facilities as described above.
+ .SH "SEE ALSO"
+ exports(5), mountd(8), ugidd(8C)
+ .SH AUTHORS
+diff -urN nfs-server-2.2beta47/rmtab.c nfs-server-2.2beta51/rmtab.c
+--- nfs-server-2.2beta47/rmtab.c Fri Feb 6 09:43:25 1998
++++ nfs-server-2.2beta51/rmtab.c Fri Nov 8 14:45:36 2002
+@@ -8,6 +8,7 @@
+
+ #include "nfsd.h"
+ #include "rmtab.h"
++#include "rpcmisc.h"
+
+ static char * rmtab_gethost(struct svc_req *);
+ static int rmtab_insert(char *, char *);
+diff -urN nfs-server-2.2beta47/rpcmisc.c nfs-server-2.2beta51/rpcmisc.c
+--- nfs-server-2.2beta47/rpcmisc.c Tue Sep 7 10:42:58 1999
++++ nfs-server-2.2beta51/rpcmisc.c Fri Nov 8 14:45:36 2002
+@@ -39,6 +39,8 @@
+ int _rpcfdtype = 0;
+ int _rpcsvcdirty = 0;
+ const char * auth_daemon = 0;
++int udp_only = 0;
++int loopback_only = 0;
+
+ #ifdef AUTH_DAEMON
+ static bool_t (*tcp_rendevouser)(SVCXPRT *, struct rpc_msg *);
+@@ -96,7 +98,7 @@
+ }
+ }
+
+- if ((_rpcfdtype == 0) || (_rpcfdtype == SOCK_STREAM)) {
++ if ((_rpcfdtype == 0 && !udp_only) || (_rpcfdtype == SOCK_STREAM)) {
+ if (_rpcfdtype == 0 && defport != 0)
+ sock = makesock(defport, IPPROTO_TCP, bufsiz);
+ transp = svctcp_create(sock, 0, 0);
+@@ -199,6 +201,9 @@
+ sin.sin_family = AF_INET;
+ sin.sin_addr.s_addr = INADDR_ANY;
+ sin.sin_port = htons(port);
++
++ if (loopback_only)
++ sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+
+ #ifdef DEBUG
+ {
+diff -urN nfs-server-2.2beta47/rpcmisc.h nfs-server-2.2beta51/rpcmisc.h
+--- nfs-server-2.2beta47/rpcmisc.h Tue Sep 7 10:37:38 1999
++++ nfs-server-2.2beta51/rpcmisc.h Fri Nov 8 14:45:36 2002
+@@ -9,6 +9,8 @@
+ extern int _rpcpmstart;
+ extern int _rpcfdtype;
+ extern int _rpcsvcdirty;
++extern int udp_only;
++extern int loopback_only;
+ extern const char * auth_daemon;
+
+ extern void rpc_init(const char *name, int prog, int *verstbl,
+@@ -16,5 +18,13 @@
+ int defport, int bufsize);
+ extern void rpc_exit(int prog, int *verstbl);
+ extern void rpc_closedown(void);
++
++/*
++ * Some older systems don't have svc_getcaller.
++ * Some, like glibc 2.2, have it but it returns some type that's
++ * not a sockaddr_in anymore.
++ */
++#undef svc_getcaller
++#define svc_getcaller(xprt) ((struct sockaddr_in *) (&(xprt)->xp_raddr))
+
+ #endif /* RPCMISC_H */
+diff -urN nfs-server-2.2beta47/setattr.c nfs-server-2.2beta51/setattr.c
+--- nfs-server-2.2beta47/setattr.c Fri Oct 30 18:29:42 1998
++++ nfs-server-2.2beta51/setattr.c Fri Nov 8 14:45:36 2002
+@@ -103,6 +103,10 @@
+ if (flags & SATTR_CHMOD) {
+ unsigned int mode = attr->mode;
+
++ /* If setuid is not allowed, silently squash them */
++ if (!nfsmount->o.allow_setuid && S_ISREG(s->st_mode))
++ mode &= ~(S_ISUID|S_ISGID) | s->st_mode;
++
+ if (mode != -1 && mode != 0xFFFF /* ultrix bug */
+ && (mode & 07777) != (s->st_mode & 07777)) {
+ if (efs_chmod(path, mode) < 0)
+diff -urN nfs-server-2.2beta47/showmount.c nfs-server-2.2beta51/showmount.c
+--- nfs-server-2.2beta47/showmount.c Wed Jun 12 22:31:04 1996
++++ nfs-server-2.2beta51/showmount.c Fri Nov 8 14:45:36 2002
+@@ -162,17 +162,13 @@
+ break;
+ }
+
+- if (hostname[0] >= '0' && hostname[0] <= '9') {
+- server_addr.sin_family = AF_INET;
+- server_addr.sin_addr.s_addr = inet_addr(hostname);
+- }
+- else {
++ server_addr.sin_family = AF_INET;
++ if (!inet_aton(hostname, &server_addr.sin_addr)) {
+ if ((hp = gethostbyname(hostname)) == NULL) {
+ fprintf(stderr, "%s: can't get address for %s\n",
+ program_name, hostname);
+ exit(1);
+ }
+- server_addr.sin_family = AF_INET;
+ memcpy(&server_addr.sin_addr, hp->h_addr, hp->h_length);
+ }
+
+diff -urN nfs-server-2.2beta47/site.h.in nfs-server-2.2beta51/site.h.in
+--- nfs-server-2.2beta47/site.h.in Thu Jan 1 01:00:00 1970
++++ nfs-server-2.2beta51/site.h.in Fri Nov 8 14:45:57 2002
+@@ -0,0 +1,50 @@
++/*
++ * Site-specific configuration options generated by BUILD.
++ * Please do not edit.
++ */
++
++/*
++ * If ENABLE_DEVTAB is defined, nfsd will use the new inode
++ * number generation scheme for avoiding inode number clashes
++ * on big hard disks.
++ */
++#undef ENABLE_DEVTAB
++
++/*
++ * If MULTIPLE_SERVER_READWRITE is defined, you will be able
++ * to run several nfsd process in parallel servicing all NFS
++ * requests.
++ */
++#define MULTIPLE_SERVERS_READWRITE
++
++/*
++ * If ENABLE_UGID_DAEMON is defined, the real rpc.ugidd is built,
++ * nfsd is built to support ugidd queries.
++ * Otherwise, a dummy program is created
++ */
++#undef ENABLE_UGID_DAEMON
++
++/*
++ * If ENABLE_UGID_NIS is defined, nfsd will support user mapping
++ * vie the client's NIS server.
++ */
++#undef ENABLE_UGID_NIS
++
++/*
++ * if HOSTS_ACCESS is defined, ugidd uses host access control
++ * provided by libwrap.a from tcp_wrappers
++ */
++#define HOSTS_ACCESS
++
++/*
++ * Define correct ownership of export control file
++ */
++#define EXPORTSOWNERUID 0
++#define EXPORTSOWNERGID 0
++
++/*
++ * If WANT_LOG_MOUNTS is defined, every mount request will be logged
++ * to syslogd with the name of source site and a path that was
++ * it requested
++ */
++#define WANT_LOG_MOUNTS
+diff -urN nfs-server-2.2beta47/ugidd.c nfs-server-2.2beta51/ugidd.c
+--- nfs-server-2.2beta47/ugidd.c Wed Dec 10 12:34:16 1997
++++ nfs-server-2.2beta51/ugidd.c Fri Nov 8 14:45:36 2002
+@@ -43,9 +43,7 @@
+ };
+
+ int
+-main(argc, argv)
+-int argc;
+-char **argv;
++main(int argc, char **argv)
+ {
+ SVCXPRT *transp;
+ int c, longind;
+@@ -92,32 +90,11 @@
+ exit(1);
+ }
+
+- if (!foreground) {
+- if ((c = fork()) > 0)
+- exit(0);
+- if (c < 0) {
+- fprintf(stderr, "ugidd: cannot fork: %s\n",
+- strerror(errno));
+- exit(-1);
+- }
+- close(0);
+- close(1);
+- close(2);
+-#ifdef HAVE_SETSID
+- setsid();
+-#else
+- {
+- int fd;
+-
+- if ((fd = open("/dev/tty", O_RDWR)) >= 0) {
+- ioctl(fd, TIOCNOTTY, (char *) NULL);
+- close(fd);
+- }
+- }
+-#endif
+- }
+-
+ log_open("ugidd", foreground);
++
++ /* Become a daemon */
++ if (!foreground)
++ daemonize();
+
+ svc_run();
+ Dprintf(L_ERROR, "svc_run returned\n");
+diff -urN nfs-server-2.2beta47/version.c nfs-server-2.2beta51/version.c
+--- nfs-server-2.2beta47/version.c Wed Nov 10 10:33:33 1999
++++ nfs-server-2.2beta51/version.c Fri Nov 8 14:45:36 2002
+@@ -1 +1 @@
+-char version[] = "Universal NFS Server 2.2beta47";
++char version[] = "Universal NFS Server 2.2beta51";
diff --git a/meta/recipes-devtools/unfs-server/unfs-server-2.2beta47/002-destdir.patch b/meta/recipes-devtools/unfs-server/unfs-server-2.2beta47/002-destdir.patch
new file mode 100644
index 0000000..9388332
--- /dev/null
+++ b/meta/recipes-devtools/unfs-server/unfs-server-2.2beta47/002-destdir.patch
@@ -0,0 +1,68 @@
+# Patch origin: nfs-server source RPM from openSUSE 10.3
+
+--- nfs-server/Makefile.in 2002/11/07 16:56:07 1.1
++++ nfs-server/Makefile.in 2002/11/07 17:08:41
+@@ -74,10 +74,10 @@
+
+ bindir = $(exec_prefix)/sbin
+ #vardir = $(install_prefix)/var/lib/nfs
+-infodir = $(prefix)/info
+-man5dir = $(prefix)/man/man5
++infodir = $(prefix)/share/info
++man5dir = $(prefix)/share/man/man5
+ man5ext = .5
+-man8dir = $(prefix)/man/man8
++man8dir = $(prefix)/share/man/man8
+ man8ext = .8
+
+ # Prefix to be prepended to each installed RPC program, normally `rpc.'.
+@@ -145,37 +145,37 @@
+ .PHONY: install installdirs
+ install: $(DAEMONS) $(CLIENTS) installdirs
+ @for prog in $(DAEMONS) $(CLIENTS); do \
+- echo "installing $$prog in $(bindir)"; \
+- $(INSTALL_PROGRAM) $$prog $(bindir)/$$prog; \
++ echo "installing $$prog in $(DESTDIR)$(bindir)"; \
++ $(INSTALL_PROGRAM) $$prog $(DESTDIR)$(bindir)/$$prog; \
+ done
+ @for manp in $(MANPAGES5); do \
+- echo "installing $$manp$(man5ext) in $(man5dir)"; \
++ echo "installing $$manp$(man5ext) in $(DESTDIR)$(man5dir)"; \
+ $(INSTALL_DATA) $(srcdir)/$$manp.man \
+- $(man5dir)/$$manp$(man5ext); \
++ $(DESTDIR)$(man5dir)/$$manp$(man5ext); \
+ done
+ @for manp in $(MANPAGES8p); do \
+- echo "installing $$manp$(man8ext) in $(man8dir)"; \
++ echo "installing $$manp$(man8ext) in $(DESTDIR)$(man8dir)"; \
+ $(INSTALL_DATA) $(srcdir)/$$manp.man \
+- $(man8dir)/$$manp$(man8ext); \
++ $(DESTDIR)$(man8dir)/$$manp$(man8ext); \
+ if [ 'x$(rpcprefix)' != 'x' ]; then \
+ rm -f $(man8dir)/$(rpcprefix)$$manp$(man8ext); \
+ ln -s $$manp$(man8ext) \
+- $(man8dir)/$(rpcprefix)$$manp$(man8ext); \
++ $(DESTDIR)$(man8dir)/$(rpcprefix)$$manp$(man8ext); \
+ fi; \
+ done
+ @for manp in $(MANPAGES8); do \
+- echo "installing $$manp$(man8ext) in $(man8dir)"; \
++ echo "installing $$manp$(man8ext) in $(DESTDIR)$(man8dir)"; \
+ $(INSTALL_DATA) $(srcdir)/$$manp.man \
+- $(man8dir)/$$manp$(man8ext); \
++ $(DESTDIR)$(man8dir)/$$manp$(man8ext); \
+ done
+ @if [ -n "$(DEVTAB_FILE)" -a ! -f "$(DEVTAB_FILE)" ]; then \
+ echo "Initializing $(DEVTAB_FILE)"; \
+- $(INSTALL) -m 755 -d `dirname $(DEVTAB_FILE)`; \
+- echo "# Device mapping for unfsd" > "$(DEVTAB_FILE)"; \
++ $(INSTALL) -m 755 -d `dirname $(DESTDIR)$(DEVTAB_FILE)`; \
++ echo "# Device mapping for unfsd" > $(DESTDIR)"$(DEVTAB_FILE)"; \
+ fi
+
+ installdirs:
+- ${srcdir}/mkinstalldirs $(bindir) $(man5dir) $(man8dir)
++ ${srcdir}/mkinstalldirs $(DESTDIR)$(bindir) $(DESTDIR)$(man5dir) $(DESTDIR)$(man8dir)
+
+ $(rpcprefix)mountd: $(MOUNTD_OBJS) libnfs.a
+ $(CC) $(LDFLAGS) -o $@ $(MOUNTD_OBJS) $(LIBS)
diff --git a/meta/recipes-devtools/unfs-server/unfs-server-2.2beta47/003-manpages.patch b/meta/recipes-devtools/unfs-server/unfs-server-2.2beta47/003-manpages.patch
new file mode 100644
index 0000000..a17a8dc
--- /dev/null
+++ b/meta/recipes-devtools/unfs-server/unfs-server-2.2beta47/003-manpages.patch
@@ -0,0 +1,28 @@
+# Patch origin: nfs-server source RPM from openSUSE 10.3
+
+--- nfs-server/exports.man 2002/11/07 17:15:59 1.1
++++ nfs-server/exports.man 2002/11/07 17:17:19
+@@ -110,6 +110,14 @@
+ .TP
+ .IR link_absolute
+ Leave all symbolic link as they are. This is the default operation.
++.SS Anonymous Entries
++.PP
++Entries where hosts are not specified are known as anonymous entries. They
++have different default settings compared to normal entries. The differences
++include
++.IR all_squash ,
++.IR no_secure ", and"
++.IR ro .
+ .SS User ID Mapping
+ .PP
+ .I nfsd
+@@ -231,7 +239,7 @@
+ # Mapping for client foobar:
+ # remote local
+ uid 0-99 - # squash these
+-uid 100-500 1000 # map 100-500 to 1000-1500
++uid 100-500 1000 # map 100-500 to 1000-1400
+ gid 0-49 - # squash these
+ gid 50-100 700 # map 50-100 to 700-750
+ .fi
diff --git a/meta/recipes-devtools/unfs-server/unfs-server-2.2beta47/004-strsignal.patch b/meta/recipes-devtools/unfs-server/unfs-server-2.2beta47/004-strsignal.patch
new file mode 100644
index 0000000..3ac4ed7
--- /dev/null
+++ b/meta/recipes-devtools/unfs-server/unfs-server-2.2beta47/004-strsignal.patch
@@ -0,0 +1,48 @@
+# Patch origin: nfs-server source RPM from openSUSE 10.3
+
+--- nfs-server/failsafe.c 2002/11/07 17:12:46 1.1
++++ nfs-server/failsafe.c 2002/11/07 17:15:16
+@@ -10,8 +10,12 @@
+ #include "logging.h"
+ #include "signals.h"
+ #include <sys/wait.h>
++#ifdef HAVE_STRSIGNAL
++#include <string.h>
++#else
+
+ static const char * get_signame(int signo);
++#endif
+
+ void
+ failsafe(int level, int ncopies)
+@@ -111,9 +115,17 @@
+ pid, running? "Continue" : "Exit");
+ } else {
+ Dprintf(L_WARNING, "failsafe: "
++#ifdef HAVE_STRSIGNAL
++ "child %d terminated by: %s. "
++#else
+ "child %d terminated by %s. "
++#endif
+ "Restarting.",
++#ifdef HAVE_STRSIGNAL
++ pid, strsignal(signo));
++#else
+ pid, get_signame(signo));
++#endif
+ child = -1; /* Restart */
+ }
+ } else if (WIFEXITED(status)) {
+@@ -159,6 +171,7 @@
+ /* NOP */
+ }
+
++#ifndef HAVE_STRSIGNAL
+ static const char *
+ get_signame(int signo)
+ {
+@@ -199,3 +212,4 @@
+ sprintf(namebuf, "signal #%d", signo);
+ return namebuf;
+ }
++#endif
diff --git a/meta/recipes-devtools/unfs-server/unfs-server-2.2beta47/005-sys-time.patch b/meta/recipes-devtools/unfs-server/unfs-server-2.2beta47/005-sys-time.patch
new file mode 100644
index 0000000..c21fb05
--- /dev/null
+++ b/meta/recipes-devtools/unfs-server/unfs-server-2.2beta47/005-sys-time.patch
@@ -0,0 +1,29 @@
+# Patch origin: nfs-server source RPM from openSUSE 10.3
+
+--- nfs-server/system.h 2002/11/07 17:10:47 1.1
++++ nfs-server/system.h 2002/11/07 17:11:53
+@@ -66,20 +66,16 @@
+ # include <grp.h> /* for setgroups */
+ #endif
+
+-#ifdef TIME_WITH_SYS_TIME
++#ifdef HAVE_SYS_TIME_H
+ # include <sys/time.h>
+ # include <time.h>
+-#else /* not TIME_WITH_SYS_TIME */
+-# ifdef HAVE_SYS_TIME_H
+-# include <sys/time.h>
+-# else /* not HAVE_SYS_TIME_H */
+-# include <time.h>
++#else /* not HAVE_SYS_TIME_H */
++# include <time.h>
+ struct timeval {
+ long tv_sec;
+ long tv_usec;
+ };
+-# endif /* not HAVE_SYS_TIME_H */
+-#endif /* not TIME_WITH_SYS_TIME */
++#endif /* not HAVE_SYS_TIME_H */
+ #ifdef HAVE_SYS_FILE_H
+ # include <sys/file.h>
+ #endif
diff --git a/meta/recipes-devtools/unfs-server/unfs-server-2.2beta47/006-reiserfs.patch b/meta/recipes-devtools/unfs-server/unfs-server-2.2beta47/006-reiserfs.patch
new file mode 100644
index 0000000..abdc674
--- /dev/null
+++ b/meta/recipes-devtools/unfs-server/unfs-server-2.2beta47/006-reiserfs.patch
@@ -0,0 +1,1272 @@
+# Patch origin: nfs-server source RPM from openSUSE 10.3
+
+--- nfs-server/Makefile.in
++++ nfs-server/Makefile.in 2002/11/08 13:59:16
+@@ -100,7 +100,7 @@
+ utimes.c mkdir.c rename.c getopt.c getopt_long.c \
+ alloca.c mountlist.c xmalloc.c \
+ xstrdup.c strdup.c strstr.c nfsmounted.c faccess.c \
+- haccess.c daemon.c signals.c
++ haccess.c daemon.c signals.c teahash3.c
+ XDRFILES = mount.x nfs_prot.x
+ GENFILES = mount.h mount_xdr.c mount_svc.c nfs_prot.h nfs_prot_xdr.c \
+ ugid.h ugid_xdr.c ugid_clnt.c
+@@ -112,7 +112,7 @@
+ MANPAGES8 = showmount
+ MANPAGES = $(MANPAGES5) $(MANPAGES8p) $(MANPAGES8)
+ LIBOBJS = version.o fsusage.o mountlist.o xmalloc.o xstrdup.o \
+- nfsmounted.o faccess.o haccess.o daemon.o \
++ nfsmounted.o faccess.o haccess.o daemon.o teahash3.o \
+ signals.o @LIBOBJS@ @ALLOCA@
+ OBJS = logging.o fh.o devtab.o auth_init.o auth_clnt.o auth.o
+ NFSD_OBJS = nfsd.o rpcmisc.o nfs_dispatch.o getattr.o setattr.o \
+--- nfs-server/auth.c
++++ nfs-server/auth.c 2002/11/08 13:59:16
+@@ -83,6 +83,7 @@
+ 0, /* read-only */
+ 0, /* relative links */
+ 0, /* noaccess */
++ 0, /* hashed inodes */
+ 1, /* cross_mounts */
+ 1, /* allow setuid */
+ 65534, /* default uid */
+@@ -100,6 +101,7 @@
+ 0, /* relative links */
+ 0, /* noaccess */
+ 1, /* cross_mounts */
++ 0, /* hashed inodes */
+ 0, /* allow setuid */
+ 65534, /* default uid */
+ 65534, /* default gid */
+@@ -991,6 +993,7 @@
+ if (mp == 0) {
+ mp = (nfs_mount*) xmalloc(sizeof(nfs_mount));
+ memset(mp, 0, sizeof(*mp));
++ mp->mount_dev = 0;
+ mp->origin = cp;
+ mp->client = cp;
+ mp->path = xstrdup(path);
+@@ -1169,6 +1172,8 @@
+ default_options.nobody_gid = anon_gid;
+ anonymous_options.nobody_uid = anon_uid;
+ anonymous_options.nobody_gid = anon_gid;
++ default_options.cross_mounts = cross_mounts;
++ default_options.hashed_inodes = hashed_inodes;
+
+ memset(cached_clients, 0, sizeof(cached_clients));
+ cached_next = 0;
+--- nfs-server/auth.h
++++ nfs-server/auth.h 2002/11/08 13:59:16
+@@ -43,15 +43,16 @@
+
+ typedef struct nfs_options {
+ ugid_mapping_t uidmap; /* uid/gid mapping behavior */
+- int root_squash;
+- int all_squash;
+- int some_squash; /* speed up luid() etc. */
+- int secure_port;
+- int read_only;
+- int link_relative;
+- int noaccess;
+- int cross_mounts;
+- int allow_setuid;
++ unsigned root_squash : 1;
++ unsigned all_squash : 1;
++ unsigned some_squash : 1; /* speed up luid() etc. */
++ unsigned secure_port : 1;
++ unsigned read_only : 1;
++ unsigned link_relative : 1;
++ unsigned noaccess : 1;
++ unsigned cross_mounts : 1;
++ unsigned hashed_inodes : 1;
++ unsigned allow_setuid : 1;
+ uid_t nobody_uid;
+ gid_t nobody_gid;
+ char * clnt_nisdomain;
+@@ -64,6 +65,7 @@
+ int length;
+ char * path;
+ nfs_options o;
++ dev_t mount_dev;
+ /* Original NFS client */
+ struct nfs_client * origin;
+ } nfs_mount;
+@@ -121,6 +123,8 @@
+ extern void auth_check_all_netmasks(void);
+ extern void auth_sort_all_mountlists(void);
+ extern void auth_log_all(void);
++extern int auth_checkdev(nfs_mount *, dev_t dev);
++extern int auth_checkpathdev(char *, dev_t dev);
+
+ /* This function lets us set our euid/fsuid temporarily */
+ extern void auth_override_uid(uid_t);
+--- nfs-server/auth_clnt.c
++++ nfs-server/auth_clnt.c 2002/11/08 13:59:16
+@@ -89,6 +89,13 @@
+ return NULL;
+ }
+
++ if (!mp->o.cross_mounts && !mp->mount_dev) {
++ struct stat st;
++ if (!lstat(mp->path, &st) < 0)
++ return NULL;
++ mp->mount_dev = st.st_dev;
++ }
++
+ /* Check request originated on a privileged port. */
+ if (!allow_non_root && mp->o.secure_port
+ && !SECURE_PORT(svc_getcaller(rqstp->rq_xprt)->sin_port)) {
+@@ -350,3 +357,28 @@
+ return 1;
+ }
+ #endif
++
++int auth_checkpathdev(char *path, dev_t dev)
++{
++ nfs_mount *mp = auth_match_mount(nfsclient, path);
++ if (!mp)
++ return 0;
++ return auth_checkdev(mp, dev);
++}
++
++int auth_checkdev(nfs_mount *mp, dev_t dev)
++{
++ if (!mp->mount_dev)
++ return 1;
++ if (mp->mount_dev != dev) {
++ struct stat st;
++ /* Restat in case the cd switched */
++ if (efs_lstat(mp->path, &st) < 0) {
++ Dprintf(L_ERROR, "Unable to stat mount point %s\n", mp->path);
++ return 0;
++ }
++ mp->mount_dev = st.st_dev;
++ }
++ return mp->mount_dev == dev;
++}
++
+--- nfs-server/auth_init.c
++++ nfs-server/auth_init.c 2002/11/08 13:59:16
+@@ -320,6 +320,14 @@
+ /* knfsd compatibility, ignore */;
+ else ifkwd(4, "sync")
+ /* knfsd compatibility, ignore */;
++ else ifkwd(13, "hashed_inodes")
++ mp->o.hashed_inodes = 1;
++ else ifkwd(16, "no_hashed_inodes")
++ mp->o.hashed_inodes = 0;
++ else ifkwd(12, "cross_mounts")
++ mp->o.cross_mounts = 1;
++ else ifkwd(15, "no_cross_mounts")
++ mp->o.cross_mounts = 0;
+ else {
+ Dprintf(L_ERROR,
+ "Unknown keyword \"%.*s\" in export file\n",
+--- nfs-server/exports.man
++++ nfs-server/exports.man 2002/11/08 13:59:16
+@@ -208,6 +208,17 @@
+ .IR no_all_squash ,
+ which is the default setting.
+ .TP
++.IR hashed_inodes
++Use a special scheme to generate inode numbers that may work better with
++reiserfs filesystems.
++.IR no_hashed_inodes
++which uses a direct mapping is the default.
++.TP
++.IR cross_mounts
++Do not cross mount points in exports. Turning this off with
++.IR no_cross_mounts
++avoids inode number space conflicts when there are too many files.
++.TP
+ .IR map_daemon
+ This option turns on dynamic uid/gid mapping. Each uid in an NFS request
+ will be translated to the equivalent server uid, and each uid in an
+--- nfs-server/fh.c
++++ nfs-server/fh.c 2002/11/08 14:11:31
+@@ -4,8 +4,9 @@
+ *
+ * Interfaces:
+ * pseudo_inode
+- * mostly used internally, but also called from unfsd.c
+- * when reporting directory contents.
++ * mostly used internally, for hash tables
++ * visible_inode
++ * generate visible inode shown to the client in the fattr.
+ * fh_init
+ * Initializes the queues and 'flush' timer
+ * fh_pr
+@@ -47,6 +48,8 @@
+ * Note: the original code mistakenly assumes that the overall path
+ * length remains within the value given by PATH_MAX... that leads
+ * to interesting buffer overflows all over the place.
++ *
++ * Depends that dev_t only uses 16bits.
+ */
+
+ #include <assert.h>
+@@ -137,9 +140,9 @@
+ };
+
+ /* Forward declared local functions */
+-static psi_t path_psi(char *, nfsstat *, struct stat *, int);
++static psi_t path_psi(char *, nfsstat *, struct stat *, int, int *);
+ static psi_t path_psi_m(char *, nfsstat *, struct stat *,
+- struct stat *, int);
++ struct stat *, int, int *);
+ static int fh_flush_fds(void);
+ static char * fh_dump(svc_fh *);
+ static void fh_insert_fdcache(fhcache *fhc);
+@@ -173,19 +176,22 @@
+ fh_list_size++;
+
+ /* Insert into hash tab. */
+- hash_slot = &(fh_hashed[fhc->h.psi % HASH_TAB_SIZE]);
++ hash_slot = &(fh_hashed[pseudo_inode(fhc->h.ino,fhc->h.dev) % HASH_TAB_SIZE]);
+ fhc->hash_next = *hash_slot;
+ *hash_slot = fhc;
+ }
+
+ static fhcache *
+-fh_lookup(psi_t psi)
++fh_lookup(ino_t ino, dev_t dev)
+ {
+ register fhcache *fhc;
+
+- fhc = fh_hashed[psi % HASH_TAB_SIZE];
+- while (fhc != NULL && fhc->h.psi != psi)
++ fhc = fh_hashed[pseudo_inode(ino,dev) % HASH_TAB_SIZE];
++ while (fhc != NULL) {
++ if (fhc->h.ino == ino && fhc->h.dev == dev)
++ break;
+ fhc = fhc->hash_next;
++ }
+ return (fhc);
+ }
+
+@@ -193,7 +199,8 @@
+ fh_insert_fdcache(fhcache *fhc)
+ {
+ #ifdef FHTRACE
+- Dprintf(D_FHTRACE, "insert fh %x into fdcache @%d\n", fhc->h.psi, fhc->fd);
++ Dprintf(D_FHTRACE, "insert fh %x,%x into fdcache @%d\n",
++ fhc->h.ino, fhc->h.dev, fhc->fd);
+ if (fhc->fd < 0) {
+ fh_complain("fd cache bug: bad fd", fhc);
+ return;
+@@ -289,8 +296,9 @@
+ #endif
+
+ Dprintf(D_FHTRACE|D_FHCACHE,
+- "fh_delete: deleting handle %x ('%s', fd=%d)\n",
+- fhc, fhc->path ? fhc->path : "<unnamed>", fhc->fd);
++ "fh_delete: deleting handle %x [%x,%x] ('%s', fd=%d)\n",
++ fhc, fhc->h.dev, fhc->h.ino, fhc->path ? fhc->path : "<unnamed>",
++ fhc->fd);
+
+ /* Remove from current posn */
+ fhc->prev->next = fhc->next;
+@@ -298,7 +306,7 @@
+ fh_list_size--;
+
+ /* Remove from hash tab */
+- hash_slot = &(fh_hashed[fhc->h.psi % HASH_TAB_SIZE]);
++ hash_slot = &(fh_hashed[pseudo_inode(fhc->h.ino,fhc->h.dev) % HASH_TAB_SIZE]);
+ while (*hash_slot != NULL && *hash_slot != fhc)
+ hash_slot = &((*hash_slot)->hash_next);
+ if (*hash_slot == NULL)
+@@ -528,6 +536,7 @@
+ index -= 8;
+ }
+
++#if 0
+ /* If we have an XXL inode number, spew out warning (but at most
+ * once a second) */
+ if (inode & ~mask) {
+@@ -541,14 +550,34 @@
+ }
+ inode &= mask;
+ }
+-
++#endif
+ return (psi_t) (prefix | inode);
+ #endif
+ }
+
++/* Inode as handed out by attr calls. */
++psi_t
++visible_inode(ino_t ino, dev_t dev, nfs_mount *mount)
++{
++ if (!mount->o.cross_mounts)
++ return ino;
++
++ if (mount->o.hashed_inodes) {
++ extern __u32 teahash3(/*u32 k[2], *//*u8*/const char *msg, int len);
++
++ struct {
++ ino_t ino;
++ dev_t dev;
++ } tup = { ino,dev };
++ return teahash3((char *) &tup, sizeof tup);
++ }
++
++ return pseudo_inode(ino, dev);
++}
++
+ #if 1
+ static char *
+-fh_buildpath(svc_fh *h)
++fh_buildpath(svc_fh *h, dev_t basedev)
+ {
+ char pathbuf[PATH_MAX + NAME_MAX + 1], *path;
+ long cookie_stack[HP_LEN + 1];
+@@ -565,13 +594,17 @@
+
+ if (efs_stat("/", &sbuf) < 0)
+ return (NULL);
+- psi = pseudo_inode(sbuf.st_ino, sbuf.st_dev);
+ if (h->hash_path[0] == 0) {
+- if (psi != h->psi)
+- return (NULL);
+- return xstrdup("/");
++ if (sbuf.st_ino == h->ino && sbuf.st_dev == h->dev)
++ ;
++ else
++ return NULL;
++ strcpy(pathbuf,"/");
++ path = xstrdup(pathbuf);
++ return (path);
+ }
+
++ psi = pseudo_inode(sbuf.st_ino, sbuf.st_dev);
+ if (hash_psi(psi) != h->hash_path[1])
+ return (NULL);
+
+@@ -599,11 +632,18 @@
+
+ psi = pseudo_inode(dp->d_ino, sbuf.st_dev);
+ if (i == h->hash_path[0] + 1) {
+- if (psi != h->psi)
++ if (sbuf.st_dev != h->dev || dp->d_ino != h->ino)
+ continue;
+ /* GOT IT */
+ strcpy(pathbuf + pathlen, dp->d_name);
+- path = xstrdup(pathbuf);
++ if (!basedev || sbuf.st_dev == basedev ||
++ auth_checkpathdev(pathbuf, sbuf.st_dev)) {
++ path = xstrdup(pathbuf);
++ } else {
++ dprintf(L_ERROR, "fh_buildpath: basedev %x != dev %x for %s\n",
++ (unsigned)basedev,(unsigned)sbuf.st_dev,pathbuf);
++ path = NULL;
++ }
+ efs_closedir(dir);
+ auth_override_uid(auth_uid);
+ return (path);
+@@ -754,16 +794,16 @@
+ #endif
+
+ static psi_t
+-path_psi(char *path, nfsstat *status, struct stat *sbp, int svalid)
++path_psi(char *path, nfsstat *status, struct stat *sbp, int svalid, int *mp)
+ {
+ struct stat smounted;
+
+- return path_psi_m(path, status, sbp, &smounted, svalid);
++ return path_psi_m(path, status, sbp, &smounted, svalid, mp);
+ }
+
+ static psi_t
+ path_psi_m(char *path, nfsstat *status,
+- struct stat *sbp, struct stat *mbp, int svalid)
++ struct stat *sbp, struct stat *mbp, int svalid, int *mp)
+ {
+ struct stat sbuf, ddbuf;
+
+@@ -815,6 +855,8 @@
+ DIR *dirp;
+ struct dirent *dp;
+
++ if (mp) *mp = 1;
++
+ errno = 0;
+ dirp = efs_opendir(dname);
+ fname[-1] = '/'; /* Restore path */
+@@ -860,9 +902,70 @@
+ }
+
+ fhcache *
+-fh_find(svc_fh *h, int mode)
++fh_newfh(svc_fh *h, int mode, dev_t basedev)
++{
++ fhcache *fhc, *flush;
++
++ ex_state = active;
++ for (flush = fh_tail.prev; fh_list_size > FH_CACHE_LIMIT; flush = fhc) {
++ /* Don't flush current head. */
++ if (flush == &fh_head)
++ break;
++ fhc = flush->prev;
++ fh_delete(flush);
++ }
++ fhc = (fhcache *) xmalloc(sizeof *fhc);
++ if (mode == FHFIND_FCREATE) {
++ /* File will be created */
++ fhc->path = NULL;
++ } else {
++ /* File must exist. Attempt to construct from hash_path */
++ char *path;
++
++ if ((path = fh_buildpath(h, basedev)) == NULL) {
++#ifdef FHTRACE
++ Dprintf(D_FHTRACE, "fh_find: stale fh (hash path)\n");
++ Dprintf(D_FHTRACE, "\tdata: %s\n", fh_dump(h));
++#endif
++ free(fhc);
++ ex_state = inactive;
++ return NULL;
++ }
++ fhc->path = path;
++ }
++ fhc->flags = 0;
++ if (fhc->path && efs_lstat(fhc->path, &fhc->attrs) >= 0) {
++ if (re_export && nfsmounted(fhc->path, &fhc->attrs))
++ fhc->flags |= FHC_NFSMOUNTED;
++ fhc->flags |= FHC_ATTRVALID;
++ }
++ fhc->fd = -1;
++ fhc->last_used = curtime;
++ fhc->h = *h;
++ fhc->last_clnt = NULL;
++ fhc->last_mount = NULL;
++ fhc->last_uid = (uid_t)-1;
++ fhc->fd_next = fhc->fd_prev = NULL;
++ fh_inserthead(fhc);
++ Dprintf(D_FHCACHE,
++ "fh_find: created new handle %x (path `%s' ino:%x dev:%x)\n",
++ fhc, fhc->path ? fhc->path : "<unnamed>", fhc->h.ino, fhc->h.dev);
++ ex_state = inactive;
++ if (fh_list_size > FH_CACHE_LIMIT)
++ flush_cache(0);
++#ifdef FHTRACE
++ if (fhc->h.hash_path[0] == 0xFF) {
++ Dprintf(L_ERROR, "newly created fh instantly flushed?!");
++ return NULL;
++ }
++#endif
++ return (fhc);
++}
++
++fhcache *
++fh_find(svc_fh *h, int mode, dev_t basedev)
+ {
+- register fhcache *fhc, *flush;
++ register fhcache *fhc;
+ int check;
+
+ check = (mode & FHFIND_CHECK);
+@@ -877,12 +980,12 @@
+
+ ex_state = active;
+ time(&curtime);
+- while ((fhc = fh_lookup(h->psi)) != NULL) {
++ while ((fhc = fh_lookup(h->ino,h->dev)) != NULL) {
+ struct stat sbuf, *s = NULL;
+ nfsstat dummy;
+
+- Dprintf(D_FHCACHE, "fh_find: psi=%lx... found '%s', fd=%d\n",
+- (unsigned long) h->psi,
++ Dprintf(D_FHCACHE, "fh_find: (%u,%u)... found '%s', fd=%d\n",
++ h->ino, h->dev,
+ fhc->path ? fhc->path : "<unnamed>",
+ fhc->fd);
+
+@@ -905,6 +1008,7 @@
+ Dprintf(D_FHTRACE,
+ "fh_find: stale fh: lstat: %m\n");
+ } else {
++ int mp = 0;
+ /* If device/ino don't match, fhc->path may
+ * be a mount point (hence lstat() returns
+ * a different inode number than the readdir()
+@@ -915,19 +1019,26 @@
+
+ /* Get the dev/ino of the underlying
+ * mount point. */
+- path_psi(fhc->path, &dummy, s, 1);
+- if (fh_attrmatch(fhc, s))
+- goto fh_return;
++ if (path_psi(fhc->path, &dummy, s, 1, &mp) &&
++ fh_attrmatch(fhc, s)) {
++ if (!mp)
++ Dprintf(D_FHTRACE,"fh_find: should be mount point %x,%x\n",
++ h->dev,h->ino);
++
++ }
+
+- Dprintf(D_FHTRACE, "fh_find: stale fh: %lx",
+- (unsigned long) h->psi);
++ Dprintf(D_FHTRACE, "fh_find: stale fh: "
++ "dev/ino %x/%lx ino:%x dev:%x",
++ s->st_dev, s->st_ino,
++ (unsigned)h->ino, (unsigned)h->dev);
+ }
+
+ fh_discard:
+ #ifdef FHTRACE
+ Dprintf(D_FHTRACE, "\tdata: %s\n", fh_dump(h));
+ #endif
+- Dprintf(D_FHCACHE, "fh_find: delete cached handle\n");
++ Dprintf(D_FHCACHE, "fh_find: delete cached handle %x,%x <%x>\n",
++ fhc->h.dev,fhc->h.ino,fhc->path ? fhc->path : "no path");
+ fh_delete(fhc);
+ break;
+ }
+@@ -947,88 +1058,13 @@
+ return (fhc);
+ }
+
+- Dprintf(D_FHCACHE, "fh_find: psi=%lx... not found\n",
+- (unsigned long) h->psi);
+-
+- if (mode == FHFIND_FCACHED) {
+- ex_state = inactive;
+- return NULL;
+- }
+-
+- for (flush = fh_tail.prev; fh_list_size > FH_CACHE_LIMIT; flush = fhc) {
+- /* Don't flush current head. */
+- if (flush == &fh_head)
+- break;
+- fhc = flush->prev;
+- fh_delete(flush);
+- }
+-
+- fhc = (fhcache *) xmalloc(sizeof *fhc);
+- if (mode == FHFIND_FCREATE) {
+- /* File will be created */
+- fhc->path = NULL;
+- } else {
+- /* File must exist. Attempt to construct from hash_path */
+- char *path;
+-
+- if ((path = fh_buildpath(h)) == NULL) {
+-#ifdef FHTRACE
+- Dprintf(D_FHTRACE, "fh_find: stale fh (hash path)\n");
+- Dprintf(D_FHTRACE, "\tdata: %s\n", fh_dump(h));
+-#endif
+- free(fhc);
+- ex_state = inactive;
+- return NULL;
+- }
+- fhc->path = path;
+- }
+-
+- fhc->flags = 0;
+- if (fhc->path && efs_lstat(fhc->path, &fhc->attrs) >= 0) {
+- if (nfsmounted(fhc->path, &fhc->attrs)) {
+- fhc->flags |= FHC_NFSMOUNTED;
+-#if 0
+- /* We must allow the client to send us the
+- * file handle for the NFS mount point itself,
+- * but not for entries within an NFS mount.
+- * XXX: needs fixing.
+- */
+- if (!re_export) {
+- Dprintf(D_FHTRACE,
+- "Attempt to use %s (non-exportable)\n",
+- fhc->path);
+- free(fhc);
+- ex_state = inactive;
+- return NULL;
+- }
+-#endif
+- }
+- fhc->flags |= FHC_ATTRVALID;
+- fhc->dev = fhc->attrs.st_dev;
+- fhc->ino = fhc->attrs.st_ino;
+- fhc->type = fhc->attrs.st_mode & S_IFMT;
+- }
+- fhc->fd = -1;
+- fhc->last_used = curtime;
+- fhc->h = *h;
+- fhc->last_clnt = NULL;
+- fhc->last_mount = NULL;
+- fhc->last_uid = (uid_t)-1;
+- fhc->fd_next = fhc->fd_prev = NULL;
+- fh_inserthead(fhc);
+- Dprintf(D_FHCACHE,
+- "fh_find: created new handle %x (path `%s' psi %08x)\n",
+- fhc, fhc->path ? fhc->path : "<unnamed>", fhc->h.psi);
+ ex_state = inactive;
+- if (fh_list_size > FH_CACHE_LIMIT)
+- flush_cache(0);
+-#ifdef FHTRACE
+- if (fhc->h.hash_path[0] == 0xFF) {
+- Dprintf(L_ERROR, "newly created fh instantly flushed?!");
++
++ Dprintf(D_FHCACHE, "fh_find: (%u,%u) ... not found\n",
++ h->ino, h->dev);
++ if (mode == FHFIND_FCACHED)
+ return NULL;
+- }
+-#endif
+- return (fhc);
++ return fh_newfh(h, mode, basedev);
+ }
+
+ /*
+@@ -1040,7 +1076,7 @@
+ {
+ fhcache *h;
+
+- if ((h = fh_find((svc_fh *) fh, FHFIND_FCACHED)) == NULL)
++ if ((h = fh_find((svc_fh *) fh, FHFIND_FCACHED, 0)) == NULL)
+ return fh_dump((svc_fh *) fh);
+ return (h->path);
+ }
+@@ -1050,10 +1086,10 @@
+ {
+ static char buf[65];
+ char *sp;
+- int i, n = fh->hash_path[0];
++ int i, n = fh->hash_path[0], l;
+
+- sprintf(buf, "%08x %02x ", fh->psi, fh->hash_path[0]);
+- for (i = 1, sp = buf + 12; i <= n && i < HP_LEN; i++, sp += 2)
++ l = sprintf(buf, "%08x %04x %02x ", fh->ino, fh->dev, fh->hash_path[0]);
++ for (i = 1, sp = buf + l; i <= n && i < HP_LEN; i++, sp += 2)
+ sprintf(sp, "%02x", fh->hash_path[i]);
+ return buf;
+ }
+@@ -1082,7 +1118,7 @@
+
+ memset(&key, 0, sizeof(key));
+ status = NFS_OK;
+- if ((psi = path_psi("/", &status, &stb, 0)) == 0)
++ if ((psi = path_psi("/", &status, &stb, 0, NULL)) == 0)
+ return ((int) status);
+
+ s = path;
+@@ -1091,7 +1127,7 @@
+ return ((int) NFSERR_NAMETOOLONG);
+ key.hash_path[key.hash_path[0]] = hash_psi(psi);
+ *s = '\0';
+- if ((psi = path_psi(path, &status, &stb, 0)) == 0)
++ if ((psi = path_psi(path, &status, &stb, 0, NULL)) == 0)
+ return ((int) status);
+ *s = '/';
+ }
+@@ -1099,11 +1135,12 @@
+ if (++(key.hash_path[0]) >= HP_LEN)
+ return ((int) NFSERR_NAMETOOLONG);
+ key.hash_path[key.hash_path[0]] = hash_psi(psi);
+- if ((psi = path_psi(path, &status, &stb, 0)) == 0)
++ if ((psi = path_psi(path, &status, &stb, 0, NULL)) == 0)
+ return ((int) status);
+ }
+- key.psi = psi;
+- h = fh_find(&key, FHFIND_FCREATE);
++ key.dev = stb.st_dev;
++ key.ino = stb.st_ino;
++ h = fh_find(&key, FHFIND_FCREATE, 0);
+
+ #ifdef FHTRACE
+ if (!h)
+@@ -1123,6 +1160,7 @@
+ return ((int) status);
+ }
+
++#if 0
+ char *
+ fh_path(nfs_fh *fh, nfsstat *status)
+ {
+@@ -1135,6 +1173,7 @@
+ *status = NFS_OK;
+ return (h->path);
+ }
++#endif
+
+ nfs_fh *
+ fh_handle(fhcache *h)
+@@ -1349,7 +1388,7 @@
+ if (sbp == NULL)
+ sbp = &sbuf;
+
+- if ((dirh = fh_find((svc_fh *) &dopa->dir, FHFIND_FEXISTS)) == NULL)
++ if ((dirh = fh_find((svc_fh *) &dopa->dir, FHFIND_FEXISTS, 0)) == NULL)
+ return NFSERR_STALE;
+
+ /*
+@@ -1419,8 +1458,22 @@
+
+ *new_fh = dopa->dir;
+ key = (svc_fh *) new_fh;
+- if ((key->psi = path_psi_m(pathbuf, &ret, sbp, &smount, 0)) == 0)
++
++ if (path_psi_m(pathbuf, &ret, sbp, &smount, 0, NULL) == 0)
+ return (ret);
++ key->ino = sbp->st_ino;
++ key->dev = sbp->st_dev;
++
++ if (sbp->st_dev != dirh->h.dev) {
++ nfs_mount *mp = dirh->last_mount;
++ if (!mp)
++ Dprintf(L_ERROR, "no last mount in fh_compose for %s\n", pathbuf);
++ else if (auth_checkdev(mp, sbp->st_dev) == 0) {
++ Dprintf(L_ERROR, "access to no cross path below mountpoint (<%s>, %x<->%x)\n",
++ pathbuf, mp->mount_dev, sbp->st_dev);
++ return NFSERR_STALE;
++ }
++ }
+
+ if (is_dd) {
+ /* Don't cd .. from root, or mysterious ailments will
+@@ -1430,11 +1483,12 @@
+ } else {
+ if (++(key->hash_path[0]) >= HP_LEN)
+ return NFSERR_NAMETOOLONG;
+- key->hash_path[key->hash_path[0]] = hash_psi(dirh->h.psi);
++ key->hash_path[key->hash_path[0]] = hash_psi(pseudo_inode(dirh->h.ino,
++ dirh->h.dev));
+ }
+ /* FIXME: when crossing a mount point, we'll find the real
+ * dev/ino in sbp and can store it in h... */
+- h = fh_find(key, FHFIND_FCREATE);
++ h = fh_find(key, FHFIND_FCREATE, 0);
+
+ #ifdef FHTRACE
+ if (h == NULL)
+@@ -1456,7 +1510,7 @@
+ /* We must have cached an old file under the same inode # */
+ Dprintf(D_FHTRACE, "Disposing of fh with bad path.\n");
+ fh_delete(h);
+- h = fh_find(key, FHFIND_FCREATE);
++ h = fh_find(key, FHFIND_FCREATE, dirh->last_mount ? dirh->last_mount->mount_dev : 0);
+ #ifdef FHTRACE
+ if (!h) return NFSERR_STALE;
+ #endif
+@@ -1511,12 +1565,14 @@
+ return (NFS_OK);
+ }
+
++#if 0
+ psi_t
+ fh_psi(nfs_fh *fh)
+ {
+ svc_fh *h = (svc_fh *) fh;
+ return (h->psi);
+ }
++#endif
+
+ void
+ fh_remove(char *path)
+@@ -1524,12 +1580,13 @@
+ psi_t psi;
+ nfsstat status;
+ fhcache *fhc;
++ struct stat st;
+
+- psi = path_psi(path, &status, NULL, 0);
++ psi = path_psi(path, &status, &st, 0, NULL);
+ if (psi == 0)
+ return;
+ ex_state = active;
+- fhc = fh_lookup(psi);
++ fhc = fh_lookup(st.st_ino,st.st_dev);
+ if (fhc != NULL)
+ fh_delete(fhc);
+
+@@ -1634,6 +1691,11 @@
+ fh_init(void)
+ {
+ static int initialized = 0;
++
++ if (sizeof(svc_fh) > 32) {
++ fprintf(stderr, "filehandle wrong size %d\n", sizeof(svc_fh));
++ exit(10);
++ }
+
+ if (initialized)
+ return;
+--- nfs-server/fh.h
++++ nfs-server/fh.h 2002/11/08 13:59:16
+@@ -20,6 +20,7 @@
+ #define FHC_XONLY_PATH 001 /* NOT USED ANYMORE */
+ #define FHC_ATTRVALID 002
+ #define FHC_NFSMOUNTED 004
++#define FHC_CROSS 010
+
+ /* Modes for fh_find */
+ #define FHFIND_FEXISTS 0 /* file must exist */
+@@ -65,11 +66,12 @@
+ *
+ * hash_path[hash_path[0]+1] ... hash_path[HP_LEN-1] == 0
+ */
+-#define HP_LEN (NFS_FHSIZE - sizeof(psi_t))
++#define HP_LEN (NFS_FHSIZE-sizeof(u_int32_t)-sizeof(u_int16_t))
+ typedef struct {
+- psi_t psi;
++ u_int32_t ino;
++ u_int16_t dev;
+ __u8 hash_path[HP_LEN];
+-} svc_fh;
++} svc_fh __attribute__((packed));
+
+ typedef enum { inactive, active } mutex;
+
+@@ -100,6 +102,7 @@
+
+ /* These are fixed during the lifetime of this object */
+ svc_fh h;
++ psi_t psi;
+ dev_t dev;
+ ino_t ino;
+ mode_t type; /* st_mode & S_IFMT */
+@@ -122,10 +125,11 @@
+ /* Global function prototypes. */
+ extern nfsstat nfs_errno(void);
+ extern psi_t pseudo_inode(ino_t inode, dev_t dev);
++extern psi_t visible_inode(ino_t inode, dev_t dev, nfs_mount *);
+ extern void fh_init(void);
+ extern char *fh_pr(nfs_fh *fh);
+ extern int fh_create(nfs_fh *fh, char *path);
+-extern fhcache *fh_find(svc_fh *h, int create);
++extern fhcache *fh_find(svc_fh *h, int create, dev_t basedev);
+ extern char *fh_path(nfs_fh *fh, nfsstat *status);
+ extern int path_open(char *path, int omode, int perm);
+ extern int fh_fd(fhcache *fhc, nfsstat *status, int omode);
+@@ -139,6 +143,7 @@
+ extern void fh_flush(int force);
+ extern RETSIGTYPE flush_cache(int sig);
+ extern int nfsmounted(const char *path, struct stat *sbp);
++extern fhcache *fh_newfh(svc_fh *fh, int mode, dev_t basedev);
+
+ #ifdef ENABLE_DEVTAB
+ extern unsigned int devtab_index(dev_t);
+--- nfs-server/getattr.c
++++ nfs-server/getattr.c 2002/11/08 13:59:16
+@@ -43,7 +43,7 @@
+ {
+ fhcache *fhc;
+
+- if ((fhc = fh_find((svc_fh*)fh, FHFIND_FEXISTS)) == NULL) {
++ if ((fhc = fh_find((svc_fh*)fh, FHFIND_FEXISTS, 0)) == NULL) {
+ Dprintf(D_CALL, "getattr: failed! No such file.\n");
+ return (NFSERR_STALE);
+ }
+@@ -103,18 +103,8 @@
+ #else
+ attr->blocks = st_blocks(s);
+ #endif
+-#if 0
+- if (nfsmount->o.cross_mounts) {
+- attr->fsid = 1;
+- attr->fileid = fh_psi((nfs_fh *)&(fhc->h));
+- } else {
+- attr->fsid = s->st_dev;
+- attr->fileid = covered_ino(fhc->path);
+- }
+-#else
+- attr->fsid = 1;
+- attr->fileid = fh_psi((nfs_fh *)&(fhc->h));
+-#endif
++ attr->fsid = 1; // XXX
++ attr->fileid = visible_inode(fhc->h.ino, fhc->h.dev, nfsmount);
+
+ /* This may be needed by some Suns... testing */
+ #define MINTIME (24 * 2600)
+--- nfs-server/mountd.c
++++ nfs-server/mountd.c 2002/11/08 13:59:16
+@@ -36,6 +36,8 @@
+ #include "signals.h"
+ #include <rpc/pmap_clnt.h>
+
++int cross_mounts = 1;
++int hashed_inodes; /* dummy */
+
+ static void usage(FILE *, int);
+ static void terminate(void);
+@@ -58,9 +60,9 @@
+ { "no-spoof-trace", 0, 0, 't' },
+ { "version", 0, 0, 'v' },
+ { "fail-safe", optional_argument, 0, 'z' },
++ { "no-cross-mounts", 0, 0, 'x' },
+ { "no-tcp", 0, 0, OPT_NOTCP },
+ { "loopback-only", 0, 0, OPT_LOOPBACK },
+-
+ { NULL, 0, 0, 0 }
+ };
+ static const char * shortopts = "Fd:f:hnpP:rtvz::";
+@@ -80,6 +82,7 @@
+ int need_reinit = 0;
+ int need_flush = 0;
+ extern char version[];
++nfs_client *nfsclient; /* dummy */
+
+ /*
+ * NULL
+@@ -319,6 +322,9 @@
+ opterr = 0;
+ while ((c = getopt_long(argc, argv, shortopts, longopts, NULL)) != EOF)
+ switch (c) {
++ case 'x':
++ cross_mounts = 0;
++ break;
+ case 'F':
+ foreground = 1;
+ break;
+@@ -444,7 +450,7 @@
+ program_name);
+ fprintf(fp, " [--debug kind] [--help] [--allow-non-root]\n");
+ fprintf(fp, " [--promiscuous] [--version] [--port portnum]\n");
+- fprintf(fp, " [--exports-file=file]\n");
++ fprintf(fp, " [--exports-file=file] [--no-cross-mounts]\n");
+ exit(n);
+ }
+
+--- nfs-server/nfsd.c
++++ nfs-server/nfsd.c 2002/11/08 14:20:57
+@@ -72,7 +72,7 @@
+ { "no-tcp", 0, 0, OPT_NOTCP },
+ { "udp-only", 0, 0, OPT_NOTCP },
+ { "loopback-only", 0, 0, OPT_LOOPBACK },
+-
++ { "hashed-inodes", 0, 0, 'I' },
+ { NULL, 0, 0, 0 }
+ };
+ static const char * shortopts = "a:d:Ff:hlnP:prR:tvz::";
+@@ -91,6 +91,7 @@
+ int need_flush = 0; /* flush fh cache */
+ int read_only = 0; /* Global ro forced */
+ int cross_mounts = 1; /* Transparently cross mnts */
++int hashed_inodes = 0;
+ int log_transfers = 0; /* Log transfers */
+ static svc_fh public_fh; /* Public NFSv2 FH */
+
+@@ -122,12 +123,17 @@
+ {
+ static int total = 0, cached = 0;
+ fhcache *fhc;
++ int newfh = 0;
+
+- /* Try to map FH. If not cached, reconstruct path with root priv */
+- fhc = fh_find((svc_fh *)fh, FHFIND_FEXISTS|FHFIND_CHECK);
+- if (fhc == NULL) {
+- *statp = NFSERR_STALE;
+- return NULL;
++ /* Try to map FH. */
++ fhc = fh_find((svc_fh *)fh, FHFIND_FCACHED|FHFIND_CHECK, 0);
++ if (!fhc) {
++ fhc = fh_newfh((svc_fh*)fh, FHFIND_FEXISTS|FHFIND_CHECK, 0);
++ if (!fhc) {
++ *statp = NFSERR_STALE;
++ return NULL;
++ }
++ newfh = 1;
+ }
+
+ /* Try to retrieve last client who accessed this fh */
+@@ -163,6 +169,16 @@
+ 100 * (double) cached / total);
+ */
+
++ /* Trust the crossmount check of the parent directory for creates */
++ if (newfh &&
++ (fhc->flags & FHC_ATTRVALID) &&
++ auth_checkdev(nfsmount, fhc->attrs.st_dev) == 0) {
++ Dprintf(L_ERROR, "auth_fh: fh crossed mount %s: %x<->%x\n",
++ fhc->path ? fhc->path : "???", nfsmount->mount_dev, fhc->attrs.st_dev);
++ *statp = NFSERR_STALE; /* or ACCES? */
++ return NULL;
++ }
++
+ if (nfsmount->o.noaccess &&
+ ((flags & CHK_NOACCESS) || strcmp(nfsmount->path, fhc->path))) {
+ struct in_addr addr = svc_getcaller(rqstp->rq_xprt)->sin_addr;
+@@ -195,6 +211,7 @@
+ fhcache *fhc;
+ nfsstat status;
+ char *path = buf, *sp;
++ struct stat st;
+
+ /* Authenticate directory file handle */
+ if ((fhc = auth_fh(rqstp, &dopa->dir, &status, flags)) == NULL)
+@@ -219,6 +236,9 @@
+ if ((nfsmount = auth_path(nfsclient, rqstp, path)) == NULL)
+ return NFSERR_ACCES;
+
++ if (efs_lstat(path, &st) >= 0 && !auth_checkdev(nfsmount, st.st_dev))
++ return NFSERR_ACCES;
++
+ /* XXX: really need to call it again here?
+ * Already invoked in auth_fh */
+ if (!auth_user(nfsmount, rqstp))
+@@ -318,7 +338,8 @@
+ int ispublic = 0;
+
+ /* First check whether this is the public FH */
+- if (((svc_fh *) fh)->psi == 0 && !memcmp(fh, &public_fh, FHSIZE)) {
++ if (((svc_fh *) fh)->dev == 0 && ((svc_fh*)fh)->ino == 0 &&
++ !memcmp(fh, &public_fh, FHSIZE)) {
+ if (public_root_path == NULL)
+ return NFSERR_ACCES;
+ memcpy(&argp->dir, &public_root, NFS_FHSIZE);
+@@ -333,6 +354,7 @@
+ if (!(fhc = auth_fh(rqstp, fh, &status, CHK_READ)))
+ return status;
+
++ /* FIXME: does too many stats */
+ status = fh_compose(argp, &dp->file, &sbuf, -1, -1, ispublic);
+ if (status != NFS_OK)
+ return status;
+@@ -896,6 +918,9 @@
+ errno = 0;
+ if (efs_lstat(h->path, &sbuf) < 0 || !(S_ISDIR(sbuf.st_mode)))
+ return (NFSERR_NOTDIR);
++ if (!auth_checkdev(h->last_mount, sbuf.st_dev))
++ dotsonly = 1;
++
+ if ((dirp = efs_opendir(h->path)) == NULL)
+ return ((errno ? nfs_errno() : NFSERR_NAMETOOLONG));
+
+@@ -923,7 +948,7 @@
+ }
+
+ e = *ep = (entry *) xmalloc(sizeof(entry));
+- e->fileid = pseudo_inode(dp->d_ino, sbuf.st_dev);
++ e->fileid = visible_inode(dp->d_ino, sbuf.st_dev, h->last_mount);
+ e->name = xmalloc(NLENGTH(dp) + 1);
+ strcpy(e->name, dp->d_name);
+ dloc = htonl(efs_telldir(dirp));
+@@ -1033,6 +1058,9 @@
+ case 'x':
+ cross_mounts = 0;
+ break;
++ case 'I':
++ hashed_inodes = 1;
++ break;
+ case 'z':
+ if (optarg)
+ failsafe_level = atoi(optarg);
+@@ -1189,7 +1217,7 @@
+ " [--debug kind] [--exports-file=file] [--port port]\n"
+ " [--allow-non-root] [--promiscuous] [--version] [--foreground]\n"
+ " [--re-export] [--log-transfers] [--public-root path]\n"
+-" [--no-spoof-trace] [--help]\n"
++" [--no-spoof-trace] [--no-cross-mounts] [--hashed-inodes] [--help]\n"
+ , program_name);
+ exit(n);
+ }
+--- nfs-server/nfsd.h
++++ nfs-server/nfsd.h 2002/11/08 13:59:16
+@@ -51,6 +51,7 @@
+ extern int need_reinit;
+ extern int need_flush;
+ extern time_t nfs_dispatch_time;
++extern int cross_mounts, hashed_inodes;
+
+ /* Include the other module definitions. */
+ #include "auth.h"
+--- nfs-server/setattr.c
++++ nfs-server/setattr.c 2002/11/08 13:59:16
+@@ -17,6 +17,7 @@
+
+ #define IGNORE_TIME ((unsigned int) -1)
+
++#if 0
+ /*
+ * Set file attributes based on file handle
+ */
+@@ -33,6 +34,7 @@
+ }
+ return setattr(path, attr, s, rqstp, flags);
+ }
++#endif
+
+ /*
+ * Set file attributes given the path. The flags argument
+--- nfs-server/teahash3.c
++++ nfs-server/teahash3.c 2002/11/08 13:59:16
+@@ -0,0 +1,168 @@
++/* Taken from the reiserfs source code and hacked slightly by AK.
++ * This is GPLed. */
++/*
++ * Keyed 32-bit hash function using TEA in a Davis-Meyer function
++ * H0 = Key
++ * Hi = E Mi(Hi-1) + Hi-1
++ *
++ * (see Applied Cryptography, 2nd edition, p448).
++ *
++ * Jeremy Fitzhardinge <jeremy@zip.com.au> 1998
++ *
++ * Jeremy has agreed to the contents of reiserfs/README. -Hans
++ */
++
++#include <assert.h>
++
++#if 0
++/* OK for Intel */
++typedef unsigned long u32;
++typedef const unsigned char u8;
++#else
++#include <inttypes.h>
++typedef uint32_t u32;
++typedef uint8_t u8;
++#endif
++
++
++#define DELTA 0x9E3779B9
++#define FULLROUNDS 10 /* 32 is overkill, 16 is strong crypto */
++#define PARTROUNDS 6 /* 6 gets complete mixing */
++
++/* a, b, c, d - data; h0, h1 - accumulated hash */
++#define TEACORE(rounds) \
++ do { \
++ u32 sum = 0; \
++ int n = rounds; \
++ u32 b0, b1; \
++ \
++ b0 = h0; \
++ b1 = h1; \
++ \
++ do \
++ { \
++ sum += DELTA; \
++ b0 += ((b1 << 4)+a) ^ (b1+sum) ^ ((b1 >> 5)+b); \
++ b1 += ((b0 << 4)+c) ^ (b0+sum) ^ ((b0 >> 5)+d); \
++ } while(--n); \
++ \
++ h0 += b0; \
++ h1 += b1; \
++ } while(0)
++
++u32 teahash3(/*u32 k[2], *//*u8*/const char *msg, int len)
++{
++ u32 k[] = { 0x9464a485, 0x542e1a94, 0x3e846bff, 0xb75bcfc3};
++
++ u32 h0 = k[0], h1 = k[1];
++ u32 a, b, c, d;
++ u32 pad;
++ int i;
++
++ assert(len >= 0 && len < 256);
++
++ pad = (u32)len | ((u32)len << 8);
++ pad |= pad << 16;
++
++ while(len >= 16)
++ {
++ a = (u32)msg[ 0] |
++ (u32)msg[ 1] << 8 |
++ (u32)msg[ 2] << 16|
++ (u32)msg[ 3] << 24;
++ b = (u32)msg[ 4] |
++ (u32)msg[ 5] << 8 |
++ (u32)msg[ 6] << 16|
++ (u32)msg[ 7] << 24;
++ c = (u32)msg[ 8] |
++ (u32)msg[ 9] << 8 |
++ (u32)msg[10] << 16|
++ (u32)msg[11] << 24;
++ d = (u32)msg[12] |
++ (u32)msg[13] << 8 |
++ (u32)msg[14] << 16|
++ (u32)msg[15] << 24;
++
++ TEACORE(PARTROUNDS);
++
++ len -= 16;
++ msg += 16;
++ }
++
++ if (len >= 12)
++ {
++ assert(len < 16);
++
++ a = (u32)msg[ 0] |
++ (u32)msg[ 1] << 8 |
++ (u32)msg[ 2] << 16|
++ (u32)msg[ 3] << 24;
++ b = (u32)msg[ 4] |
++ (u32)msg[ 5] << 8 |
++ (u32)msg[ 6] << 16|
++ (u32)msg[ 7] << 24;
++ c = (u32)msg[ 8] |
++ (u32)msg[ 9] << 8 |
++ (u32)msg[10] << 16|
++ (u32)msg[11] << 24;
++
++ d = pad;
++ for(i = 12; i < len; i++)
++ {
++ d <<= 8;
++ d |= msg[i];
++ }
++ }
++ else if (len >= 8)
++ {
++ assert(len < 12);
++
++ a = (u32)msg[ 0] |
++ (u32)msg[ 1] << 8 |
++ (u32)msg[ 2] << 16|
++ (u32)msg[ 3] << 24;
++ b = (u32)msg[ 4] |
++ (u32)msg[ 5] << 8 |
++ (u32)msg[ 6] << 16|
++ (u32)msg[ 7] << 24;
++
++ c = d = pad;
++ for(i = 8; i < len; i++)
++ {
++ c <<= 8;
++ c |= msg[i];
++ }
++ }
++ else if (len >= 4)
++ {
++ assert(len < 8);
++
++ a = (u32)msg[ 0] |
++ (u32)msg[ 1] << 8 |
++ (u32)msg[ 2] << 16|
++ (u32)msg[ 3] << 24;
++
++ b = c = d = pad;
++ for(i = 4; i < len; i++)
++ {
++ b <<= 8;
++ b |= msg[i];
++ }
++ }
++ else
++ {
++ assert(len < 4);
++
++ a = b = c = d = pad;
++ for(i = 0; i < len; i++)
++ {
++ a <<= 8;
++ a |= msg[i];
++ }
++ }
++
++ TEACORE(FULLROUNDS);
++
++/* return 0;*/
++ return h0^h1;
++}
+--- nfs-server/ugid_map.c
++++ nfs-server/ugid_map.c 2002/11/08 13:59:16
+@@ -276,8 +276,10 @@
+ if ((gid == 0 && mountp->o.root_squash) || mountp->o.all_squash)
+ retgid = mountp->o.nobody_gid;
+
++#if 0
+ Dprintf(D_UGID, "lgid(%s, %d) = %d\n",
+ inet_ntoa(mountp->client->clnt_addr), gid, retgid);
++#endif
+ return retgid;
+ }
+
diff --git a/meta/recipes-devtools/unfs-server/unfs-server-2.2beta47/007-map.patch b/meta/recipes-devtools/unfs-server/unfs-server-2.2beta47/007-map.patch
new file mode 100644
index 0000000..89baabe
--- /dev/null
+++ b/meta/recipes-devtools/unfs-server/unfs-server-2.2beta47/007-map.patch
@@ -0,0 +1,78 @@
+# Patch origin: nfs-server source RPM from openSUSE 10.3
+
+--- nfs-server/auth.c
++++ nfs-server/auth.c 2002/11/08 12:49:13
+@@ -595,7 +595,6 @@
+ cp->clnt_addr.s_addr = INADDR_ANY;
+ cp->flags = 0;
+ cp->m = NULL;
+- cp->umap = NULL;
+
+ if (hname == NULL) {
+ if (anonymous_client != NULL) {
+@@ -1200,10 +1199,9 @@
+ free (mp->path);
+ if (mp->o.clnt_nisdomain)
+ free(mp->o.clnt_nisdomain);
++ if (mp->umap)
++ ugid_free_map(mp->umap);
+ free (mp);
+- }
+- if (cp->umap != NULL) {
+- ugid_free_map(cp->umap);
+ }
+ free (cp);
+ }
+--- nfs-server/auth.h
++++ nfs-server/auth.h 2002/11/08 12:50:24
+@@ -66,6 +66,11 @@
+ char * path;
+ nfs_options o;
+ dev_t mount_dev;
++ /*
++ * This is the uid/gid map.
++ * See ugid_map.c for details
++ */
++ struct ugid_map * umap;
+ /* Original NFS client */
+ struct nfs_client * origin;
+ } nfs_mount;
+@@ -77,12 +82,6 @@
+ char * clnt_name;
+ unsigned short flags;
+ nfs_mount * m;
+-
+- /*
+- * This is the uid/gid map.
+- * See ugid_map.c for details
+- */
+- struct ugid_map * umap;
+ } nfs_client;
+
+ #define AUTH_CLNT_WILDCARD 0x0001
+--- nfs-server/ugid_map.c
++++ nfs-server/ugid_map.c 2002/11/08 12:49:14
+@@ -401,12 +401,11 @@
+ static ugid_map *
+ ugid_get_map(nfs_mount *mountp)
+ {
+- nfs_client *clientp = mountp->client;
+ struct ugid_map *umap;
+ unsigned int how;
+
+- if (clientp->umap == NULL) {
+- clientp->umap = umap = (ugid_map *) xmalloc(sizeof(ugid_map));
++ if (mountp->umap == NULL) {
++ mountp->umap = umap = (ugid_map *) xmalloc(sizeof(ugid_map));
+ memset(umap, 0, sizeof(ugid_map));
+
+ for (how = 0; how < 4; how++) {
+@@ -415,7 +414,7 @@
+ }
+ }
+
+- return clientp->umap;
++ return mountp->umap;
+ }
+
+ static void
diff --git a/meta/recipes-devtools/unfs-server/unfs-server-2.2beta47/008-configure.patch b/meta/recipes-devtools/unfs-server/unfs-server-2.2beta47/008-configure.patch
new file mode 100644
index 0000000..a6d4599
--- /dev/null
+++ b/meta/recipes-devtools/unfs-server/unfs-server-2.2beta47/008-configure.patch
@@ -0,0 +1,13 @@
+# Patch origin: nfs-server source RPM from openSUSE 10.3
+
+--- nfs-server/configure.in 2002/11/08 14:24:55 1.1
++++ nfs-server/configure.in 2002/11/08 14:25:27
+@@ -98,7 +98,7 @@
+ fi
+ if test "$enable_ugid_dynamic" = yes; then
+ AC_DEFINE(ENABLE_UGID_DAEMON)
+- UGIDD_PROG=\${rpcprefix}.ugidd
++ UGIDD_PROG=\${rpcprefix}ugidd
+ UGIDD_MAN=ugidd
+ fi
+ if test "$enable_ugid_nis" = yes; then
diff --git a/meta/recipes-devtools/unfs-server/unfs-server-2.2beta47/009-multirw.patch b/meta/recipes-devtools/unfs-server/unfs-server-2.2beta47/009-multirw.patch
new file mode 100644
index 0000000..65b0b9e
--- /dev/null
+++ b/meta/recipes-devtools/unfs-server/unfs-server-2.2beta47/009-multirw.patch
@@ -0,0 +1,15 @@
+# Patch origin: nfs-server source RPM from openSUSE 10.3
+
+--- nfs-server/nfsd.c
++++ nfs-server/nfsd.c
+@@ -1133,8 +1133,8 @@
+ }
+ }
+
+- if (ncopies > 1)
+- read_only = 1;
++ /* if (ncopies > 1)
++ read_only = 1; */
+
+ /*
+ * We first fork off a child and detach from tty
diff --git a/meta/recipes-devtools/unfs-server/unfs-server-2.2beta47/010-realpath.patch b/meta/recipes-devtools/unfs-server/unfs-server-2.2beta47/010-realpath.patch
new file mode 100644
index 0000000..c3b5d58
--- /dev/null
+++ b/meta/recipes-devtools/unfs-server/unfs-server-2.2beta47/010-realpath.patch
@@ -0,0 +1,30 @@
+# Patch origin: nfs-server source RPM from openSUSE 10.3
+
+--- nfs-server/configure.in
++++ nfs-server/configure.in
+@@ -81,7 +81,7 @@
+ AC_CHECK_LIB(rpc, main)
+ AC_CHECK_LIB(crypt, main)
+ AC_CHECK_LIB(nys, main)
+-AC_HAVE_FUNCS(getcwd seteuid setreuid getdtablesize setgroups lchown setsid setfsuid setfsgid innetgr quotactl authdes_getucred)
++AC_HAVE_FUNCS(getcwd seteuid setreuid getdtablesize setgroups lchown setsid setfsuid setfsgid innetgr quotactl authdes_getucred realpath)
+ AC_AUTHDES_GETUCRED
+ AC_BROKEN_SETFSUID
+ AC_MOUNTLIST
+--- nfs-server/realpath.c
++++ nfs-server/realpath.c
+@@ -53,6 +53,8 @@
+
+ #define MAX_READLINKS 32
+
++#ifndef HAVE_REALPATH
++
+ #ifdef __STDC__
+ char *realpath(const char *path, char resolved_path [])
+ #else
+@@ -173,3 +175,5 @@
+ strcpy (resolved_path, got_path);
+ return resolved_path;
+ }
++
++#endif /* HAVE_REALPATH */
diff --git a/meta/recipes-devtools/unfs-server/unfs-server-2.2beta47/011-fno-strict-aliasing.patch b/meta/recipes-devtools/unfs-server/unfs-server-2.2beta47/011-fno-strict-aliasing.patch
new file mode 100644
index 0000000..695b8c7
--- /dev/null
+++ b/meta/recipes-devtools/unfs-server/unfs-server-2.2beta47/011-fno-strict-aliasing.patch
@@ -0,0 +1,13 @@
+# Patch origin: nfs-server source RPM from openSUSE 10.3
+
+--- nfs-server/Makefile.in
++++ nfs-server/Makefile.in
+@@ -225,7 +225,7 @@
+ $(RPCGEN) -l -o $@ $?
+
+ nfs_prot_xdr.o: nfs_prot_xdr.c
+- $(COMPILE) $(RPC_WARNFLAGS) -c nfs_prot_xdr.c
++ $(COMPILE) $(RPC_WARNFLAGS) -fno-strict-aliasing -c nfs_prot_xdr.c
+ mount_xdr.o: mount_xdr.c
+ $(COMPILE) $(RPC_WARNFLAGS) -c mount_xdr.c
+ mount_svc.o: mount_svc.c
diff --git a/meta/recipes-devtools/unfs-server/unfs-server-2.2beta47/012-nostrip.patch b/meta/recipes-devtools/unfs-server/unfs-server-2.2beta47/012-nostrip.patch
new file mode 100644
index 0000000..a815ee4
--- /dev/null
+++ b/meta/recipes-devtools/unfs-server/unfs-server-2.2beta47/012-nostrip.patch
@@ -0,0 +1,13 @@
+# Patch origin: nfs-server source RPM from openSUSE 10.3
+
+--- nfs-server/Makefile.in.xx 2006-01-12 12:43:09.000000000 +0100
++++ nfs-server/Makefile.in 2006-01-12 12:43:10.000000000 +0100
+@@ -64,7 +64,7 @@
+ NFSD_DEFS =
+
+ CFLAGS = @CFLAGS@
+-LDFLAGS = @LDFLAGS@ -s
++LDFLAGS = @LDFLAGS@
+ WARNFLAGS = @WARNFLAGS@
+ RPC_WARNFLAGS = @RPC_WARNFLAGS@
+ TRANSPORTFLAGS = @RPCGEN_I@ -s udp -s tcp
diff --git a/meta/recipes-devtools/unfs-server/unfs-server-2.2beta47/013-mntpathlen.patch b/meta/recipes-devtools/unfs-server/unfs-server-2.2beta47/013-mntpathlen.patch
new file mode 100644
index 0000000..1f10d3c
--- /dev/null
+++ b/meta/recipes-devtools/unfs-server/unfs-server-2.2beta47/013-mntpathlen.patch
@@ -0,0 +1,32 @@
+# Patch origin: nfs-server source RPM from openSUSE 10.3
+
+--- nfs-server/mountd.c 2006/01/12 14:00:13 1.13
++++ nfs-server/mountd.c 2006/01/12 14:37:35
+@@ -76,7 +76,7 @@
+ 0
+ };
+
+-char argbuf[MNTPATHLEN + 1];
++char argbuf[PATH_MAX + 1];
+ char *auth_file = NULL;
+ static char *program_name;
+ int need_reinit = 0;
+@@ -97,6 +97,9 @@
+ /*
+ * MOUNT
+ * This is what the whole protocol is all about
++ *
++ * Note: librpc gets us MNTPATHLEN length strings, but realpath
++ * needs a PATH_MAX length output buffer.
+ */
+ fhstatus *
+ mountproc_mnt_1_svc(dirpath *argp, struct svc_req *rqstp)
+@@ -105,7 +108,7 @@
+ struct stat stbuf;
+ nfs_client *cp;
+ nfs_mount *mp;
+- char nargbuf[MNTPATHLEN + 1];
++ char nargbuf[PATH_MAX + 1];
+ int saved_errno = 0;
+ #ifdef WANT_LOG_MOUNTS
+ struct in_addr addr;
diff --git a/meta/recipes-devtools/unfs-server/unfs-server-2.2beta47/014-uninitialized.patch b/meta/recipes-devtools/unfs-server/unfs-server-2.2beta47/014-uninitialized.patch
new file mode 100644
index 0000000..233c08a
--- /dev/null
+++ b/meta/recipes-devtools/unfs-server/unfs-server-2.2beta47/014-uninitialized.patch
@@ -0,0 +1,12 @@
+# Patch origin: nfs-server source RPM from openSUSE 10.3
+
+--- nfs-server/mountd.c
++++ nfs-server/mountd.c
+@@ -278,6 +278,7 @@
+ || (mp = auth_path(cp, rqstp, dir)) == NULL
+ || mp->o.noaccess) {
+ #ifdef WANT_LOG_MOUNTS
++ addr = svc_getcaller(rqstp->rq_xprt)->sin_addr;
+ Dprintf(L_WARNING, "Blocked attempt of %s to pathconf(%s)\n",
+ inet_ntoa(addr), dir);
+ #endif /* WANT_LOG_MOUNTS */
diff --git a/meta/recipes-devtools/unfs-server/unfs-server-2.2beta47/015-setattr.patch b/meta/recipes-devtools/unfs-server/unfs-server-2.2beta47/015-setattr.patch
new file mode 100644
index 0000000..cbfb8e8
--- /dev/null
+++ b/meta/recipes-devtools/unfs-server/unfs-server-2.2beta47/015-setattr.patch
@@ -0,0 +1,26 @@
+# Patch origin: nfs-server source RPM from openSUSE 10.3
+
+--- nfs-server/setattr.c.orig 2006-07-28 16:38:26.000000000 +0200
++++ nfs-server/setattr.c 2006-07-28 16:42:28.000000000 +0200
+@@ -97,7 +97,20 @@
+ tvp[1].tv_sec = s->st_mtime;
+ tvp[1].tv_usec = 0;
+ }
+- if (efs_utimes(path, tvp) < 0)
++ if (m_secs != IGNORE_TIME && attr->mtime.useconds == 1000000) {
++ /*
++ * from kernel/fs/nfsd/nfsxdr.c:
++ * Passing the invalid value useconds=1000000 for mtime
++ * is a Sun convention for "set both mtime and atime to
++ * current server time". It's needed to make permissions
++ * checks for the "touch" program across v2 mounts to
++ * Solaris and Irix boxes work correctly. See description of
++ * sattr in section 6.1 of "NFS Illustrated" by
++ * Brent Callaghan, Addison-Wesley, ISBN 0-201-32750-5
++ */
++ if (utime(path, (struct utimbuf *)0) < 0)
++ goto failure;
++ } else if (efs_utimes(path, tvp) < 0)
+ goto failure;
+ }
+ }
diff --git a/meta/recipes-devtools/unfs-server/unfs-server-2.2beta47/016-makefile.in.patch b/meta/recipes-devtools/unfs-server/unfs-server-2.2beta47/016-makefile.in.patch
new file mode 100644
index 0000000..634ce46
--- /dev/null
+++ b/meta/recipes-devtools/unfs-server/unfs-server-2.2beta47/016-makefile.in.patch
@@ -0,0 +1,14 @@
+# Makefile fix for staging to work correctly.
+# Scott Garman <scott.a.garman@intel.com>
+
+--- nfs-server-2.2beta47/Makefile.in.orig 2010-08-03 20:55:05.000000000 -0700
++++ nfs-server-2.2beta47/Makefile.in 2010-08-03 20:55:42.000000000 -0700
+@@ -69,7 +69,7 @@
+ RPC_WARNFLAGS = @RPC_WARNFLAGS@
+ TRANSPORTFLAGS = @RPCGEN_I@ -s udp -s tcp
+
+-prefix = $(install_prefix)/usr
++prefix = @prefix@
+ exec_prefix = $(prefix)
+
+ bindir = $(exec_prefix)/sbin
diff --git a/meta/recipes-devtools/unfs-server/unfs-server-2.2beta47/017-wrs-dynamic-rpc.patch b/meta/recipes-devtools/unfs-server/unfs-server-2.2beta47/017-wrs-dynamic-rpc.patch
new file mode 100644
index 0000000..18e12de
--- /dev/null
+++ b/meta/recipes-devtools/unfs-server/unfs-server-2.2beta47/017-wrs-dynamic-rpc.patch
@@ -0,0 +1,258 @@
+# Add the ability to choose alternate RPC ports at runtime and disable
+# security so that it can run as a userland process
+# Patch origin: Wind River
+
+Index: nfs-server-2.2beta47/auth_init.c
+===================================================================
+--- nfs-server-2.2beta47.orig/auth_init.c
++++ nfs-server-2.2beta47/auth_init.c
+@@ -409,6 +409,7 @@ auth_init(char *fname)
+ fname = EXPORTSFILE;
+ auth_file = fname; /* Save for re-initialization */
+
++#ifdef ROOT_LEVEL_SECURITY
+ /* Check protection of exports file. */
+ switch(iCheckAccess(auth_file, EXPORTSOWNERUID, EXPORTSOWNERGID)) {
+ case FACCESSWRITABLE:
+@@ -424,6 +425,7 @@ auth_init(char *fname)
+ Dprintf(L_ERROR, "exiting because of security violation.\n");
+ exit(1);
+ }
++#endif
+
+ if ((ef = fopen(fname, "r")) == NULL) {
+ Dprintf(L_ERROR, "Could not open exports file %s: %s\n",
+Index: nfs-server-2.2beta47/nfsd.c
+===================================================================
+--- nfs-server-2.2beta47.orig/nfsd.c
++++ nfs-server-2.2beta47/nfsd.c
+@@ -46,6 +46,7 @@ static char pathbuf_1[NFS_MAXPATHLEN + N
+
+ extern char version[];
+ static char *program_name;
++static int nfs_prog = NFS_PROGRAM;
+
+ /*
+ * Option table
+@@ -60,6 +61,7 @@ static struct option longopts[] = {
+ { "help", 0, 0, 'h' },
+ { "log-transfers", 0, 0, 'l' },
+ { "allow-non-root", 0, 0, 'n' },
++ { "prog", required_argument, 0, 'g' },
+ { "port", required_argument, 0, 'P' },
+ { "promiscuous", 0, 0, 'p' },
+ { "re-export", 0, 0, 'r' },
+@@ -73,9 +75,10 @@ static struct option longopts[] = {
+ { "udp-only", 0, 0, OPT_NOTCP },
+ { "loopback-only", 0, 0, OPT_LOOPBACK },
+ { "hashed-inodes", 0, 0, 'I' },
++ { "nfs-pid", required_argument, 0, 'N' },
+ { NULL, 0, 0, 0 }
+ };
+-static const char * shortopts = "a:d:Ff:hlnP:prR:tvz::";
++static const char * shortopts = "a:d:Ff:g:hlnN:P:prR:tvz::";
+
+ /*
+ * Table of supported versions
+@@ -1003,6 +1006,8 @@ main(int argc, char **argv)
+ int failsafe_level = 0;
+ int c;
+ int i, ncopies = 1;
++ char *nfs_pid_file = NULL;
++
+
+ program_name = argv[0];
+ chdir("/");
+@@ -1026,9 +1031,15 @@ main(int argc, char **argv)
+ case 'f':
+ auth_file = optarg;
+ break;
++ case 'g':
++ nfs_prog = atoi(optarg);
++ break;
+ case 'l':
+ log_transfers = 1;
+ break;
++ case 'N':
++ nfs_pid_file = strdup(optarg);
++ break;
+ case 'n':
+ allow_non_root = 1;
+ break;
+@@ -1114,7 +1125,7 @@ main(int argc, char **argv)
+ log_open("nfsd", foreground);
+
+ /* Initialize RPC stuff */
+- rpc_init("nfsd", NFS_PROGRAM, nfsd_versions, nfs_dispatch,
++ rpc_init("nfsd", nfs_prog, nfsd_versions, nfs_dispatch,
+ nfsport, NFS_MAXDATA);
+
+ if (_rpcpmstart) {
+@@ -1145,7 +1156,10 @@ main(int argc, char **argv)
+ /* Initialize the AUTH module. */
+ auth_init(auth_file);
+
+- setpidpath(_PATH_NFSD_PIDFILE);
++ if (nfs_pid_file == 0)
++ nfs_pid_file = _PATH_NFSD_PIDFILE;
++ setpidpath(nfs_pid_file);
++
+ if (failsafe_level == 0) {
+ /* Start multiple copies of the server */
+ writepid(getpid(), 1);
+@@ -1215,9 +1229,11 @@ usage(FILE *fp, int n)
+ fprintf(fp,
+ "Usage: %s [-Fhnpv] [-d kind] [-f exports-file] [-P port] [--version]\n"
+ " [--debug kind] [--exports-file=file] [--port port]\n"
++" [--prog alternate_rpc_port_nubmer]\n"
+ " [--allow-non-root] [--promiscuous] [--version] [--foreground]\n"
+ " [--re-export] [--log-transfers] [--public-root path]\n"
+ " [--no-spoof-trace] [--no-cross-mounts] [--hashed-inodes] [--help]\n"
++" [--nfs-pid file]\n"
+ , program_name);
+ exit(n);
+ }
+@@ -1234,7 +1250,7 @@ sigterm(int sig)
+ static void
+ terminate(void)
+ {
+- rpc_exit(NFS_PROGRAM, nfsd_versions);
++ rpc_exit(nfs_prog, nfsd_versions);
+ efs_shutdown();
+ }
+
+Index: nfs-server-2.2beta47/mountd.c
+===================================================================
+--- nfs-server-2.2beta47.orig/mountd.c
++++ nfs-server-2.2beta47/mountd.c
+@@ -42,6 +42,7 @@ int hashed_inodes; /* dummy */
+ static void usage(FILE *, int);
+ static void terminate(void);
+ static RETSIGTYPE sigterm(int sig);
++int mount_prog = MOUNTPROG;
+
+ /*
+ * Option table for mountd
+@@ -55,6 +56,7 @@ static struct option longopts[] =
+ { "help", 0, 0, 'h' },
+ { "allow-non-root", 0, 0, 'n' },
+ { "port", required_argument, 0, 'P' },
++ { "prog", required_argument, 0, 'g' },
+ { "promiscous", 0, 0, 'p' },
+ { "re-export", 0, 0, 'r' },
+ { "no-spoof-trace", 0, 0, 't' },
+@@ -63,9 +65,11 @@ static struct option longopts[] =
+ { "no-cross-mounts", 0, 0, 'x' },
+ { "no-tcp", 0, 0, OPT_NOTCP },
+ { "loopback-only", 0, 0, OPT_LOOPBACK },
++ { "mount-pid", required_argument, 0, 'N' },
++ { "rmtab", required_argument, 0, 'R' },
+ { NULL, 0, 0, 0 }
+ };
+-static const char * shortopts = "Fd:f:hnpP:rtvz::";
++static const char * shortopts = "Fd:f:g:hnN:pP:rRtvz::";
+
+ /*
+ * Table of supported versions
+@@ -318,6 +322,7 @@ main(int argc, char **argv)
+ int failsafe_level = 0;
+ int port = 0;
+ int c;
++ char *mount_pid_file = NULL;
+
+ program_name = argv[0];
+
+@@ -340,9 +345,15 @@ main(int argc, char **argv)
+ case 'f':
+ auth_file = optarg;
+ break;
++ case 'g':
++ mount_prog = port = atoi(optarg);
++ break;
+ case 'n':
+ allow_non_root = 1;
+ break;
++ case 'N':
++ mount_pid_file = strdup(optarg);
++ break;
+ case 'P':
+ port = atoi(optarg);
+ if (port <= 0 || port > 65535) {
+@@ -354,6 +365,9 @@ main(int argc, char **argv)
+ case 'p':
+ promiscuous = 1;
+ break;
++ case 'R':
++ _PATH_RMTAB = strdup(optarg);
++ break;
+ case 'r':
+ re_export = 1;
+ break;
+@@ -401,7 +415,7 @@ main(int argc, char **argv)
+ log_open("mountd", foreground);
+
+ /* Create services and register with portmapper */
+- rpc_init("mountd", MOUNTPROG, mountd_versions, mount_dispatch, port, 0);
++ rpc_init("mountd", mount_prog, mountd_versions, mount_dispatch, port, 0);
+
+ if (_rpcpmstart) {
+ /* Always foreground mode */
+@@ -422,7 +436,9 @@ main(int argc, char **argv)
+ auth_init(auth_file);
+
+ /* Write pidfile */
+- setpidpath(_PATH_MOUNTD_PIDFILE);
++ if (mount_pid_file == 0)
++ mount_pid_file = _PATH_MOUNTD_PIDFILE;
++ setpidpath(mount_pid_file);
+ writepid(getpid(), 1);
+
+ /* Failsafe mode */
+@@ -453,7 +469,9 @@ usage(FILE *fp, int n)
+ program_name);
+ fprintf(fp, " [--debug kind] [--help] [--allow-non-root]\n");
+ fprintf(fp, " [--promiscuous] [--version] [--port portnum]\n");
++ fprintf(fp, " [--prog alternate_rpc_port_nubmer]\n");
+ fprintf(fp, " [--exports-file=file] [--no-cross-mounts]\n");
++ fprintf(fp, " [--mount-pid file] [--rmtab file]\n");
+ exit(n);
+ }
+
+@@ -467,7 +485,7 @@ sigterm(int sig)
+ static void
+ terminate(void)
+ {
+- rpc_exit(MOUNTPROG, mountd_versions);
++ rpc_exit(mount_prog, mountd_versions);
+ }
+
+ RETSIGTYPE
+Index: nfs-server-2.2beta47/rmtab.c
+===================================================================
+--- nfs-server-2.2beta47.orig/rmtab.c
++++ nfs-server-2.2beta47/rmtab.c
+@@ -14,6 +14,8 @@ static char * rmtab_gethost(struct svc_r
+ static int rmtab_insert(char *, char *);
+ static void rmtab_file(char);
+
++char *_PATH_RMTAB = _PATH_RMTAB_VAL;
++
+ /*
+ * global top to linklist
+ */
+Index: nfs-server-2.2beta47/rmtab.h
+===================================================================
+--- nfs-server-2.2beta47.orig/rmtab.h
++++ nfs-server-2.2beta47/rmtab.h
+@@ -11,8 +11,9 @@
+ * Location of rmtab file. /etc/rmtab is the standard on most systems.
+ */
+ #include <paths.h>
+-#ifndef _PATH_RMTAB
+-#define _PATH_RMTAB "/etc/rmtab"
++extern char *_PATH_RMTAB;
++#ifndef _PATH_RMTAB_VAL
++#define _PATH_RMTAB_VAL "/etc/rmtab"
+ #endif
+
+ extern void rmtab_add_client(dirpath, struct svc_req *);
diff --git a/meta/recipes-devtools/unfs-server/unfs-server-2.2beta47/018-remove-tcp-wrappers.patch b/meta/recipes-devtools/unfs-server/unfs-server-2.2beta47/018-remove-tcp-wrappers.patch
new file mode 100644
index 0000000..95ecdee
--- /dev/null
+++ b/meta/recipes-devtools/unfs-server/unfs-server-2.2beta47/018-remove-tcp-wrappers.patch
@@ -0,0 +1,20 @@
+# Remove the requirement to link with libwrap
+# Patch origin: Wind River
+
+Index: nfs-server-2.2beta47/haccess.c
+===================================================================
+--- nfs-server-2.2beta47.orig/haccess.c 1999-04-08 08:47:19.000000000 -0400
++++ nfs-server-2.2beta47/haccess.c 2006-08-07 17:05:31.868221639 -0400
+@@ -79,8 +79,12 @@
+ clients[hash] = hp;
+
+ hp->clnt_addr = addr;
++#ifdef USE_TCP_WRAPPERS
+ hp->status = hosts_ctl(rpcprog, "unknown",
+ inet_ntoa(addr), "root");
++#else
++ hp->status = 1;
++#endif
+ nrhosts++;
+ }
+
diff --git a/meta/recipes-devtools/unfs-server/unfs-server-2.2beta47/019-pid-before-fork.patch b/meta/recipes-devtools/unfs-server/unfs-server-2.2beta47/019-pid-before-fork.patch
new file mode 100644
index 0000000..960ca8e
--- /dev/null
+++ b/meta/recipes-devtools/unfs-server/unfs-server-2.2beta47/019-pid-before-fork.patch
@@ -0,0 +1,125 @@
+# Write a pid file before forking
+# Patch origin: Wind River
+
+Index: nfs-server-2.2beta47/daemon.c
+===================================================================
+--- nfs-server-2.2beta47.orig/daemon.c
++++ nfs-server-2.2beta47/daemon.c
+@@ -15,6 +15,19 @@
+ static const char * pidfilename = 0;
+ static const char * get_signame(int signo);
+
++void
++writepid(pid_t pid, int clear)
++{
++ FILE *fp;
++
++ fp = fopen(pidfilename, clear? "w" : "a");
++ if (fp == NULL)
++ Dprintf(L_FATAL, "Unable to open %s: %m", pidfilename);
++ fprintf(fp, "%d\n", pid);
++ fclose(fp);
++ return;
++}
++
+ /*
+ * Do the Crawley Thing
+ */
+@@ -33,8 +46,10 @@ daemonize(void)
+ Dprintf(L_FATAL, "unable to fork: %s", strerror(errno));
+
+ /* Parent process: exit */
+- if (c > 0)
++ if (c > 0) {
++ writepid(c, 1);
+ exit(0);
++ }
+
+ /* Do the session stuff */
+ close(0);
+@@ -60,19 +75,6 @@ setpidpath(const char *filename)
+ }
+
+ void
+-writepid(pid_t pid, int clear)
+-{
+- FILE *fp;
+-
+- fp = fopen(pidfilename, clear? "w" : "a");
+- if (fp == NULL)
+- Dprintf(L_FATAL, "Unable to open %s: %m", pidfilename);
+- fprintf(fp, "%d\n", pid);
+- fclose(fp);
+- return;
+-}
+-
+-void
+ failsafe(int level, int ncopies)
+ {
+ int *servers, running, child, i;
+Index: nfs-server-2.2beta47/mountd.c
+===================================================================
+--- nfs-server-2.2beta47.orig/mountd.c
++++ nfs-server-2.2beta47/mountd.c
+@@ -425,9 +425,6 @@ main(int argc, char **argv)
+ background_logging();
+ }
+
+- /* Become a daemon */
+- if (!foreground)
+- daemonize();
+
+ /* Initialize the FH module. */
+ fh_init();
+@@ -435,11 +432,15 @@ main(int argc, char **argv)
+ /* Initialize the AUTH module. */
+ auth_init(auth_file);
+
+- /* Write pidfile */
+ if (mount_pid_file == 0)
+ mount_pid_file = _PATH_MOUNTD_PIDFILE;
+ setpidpath(mount_pid_file);
+- writepid(getpid(), 1);
++
++ /* Become a daemon */
++ if (!foreground)
++ daemonize();
++ else
++ writepid(getpid(), 1);
+
+ /* Failsafe mode */
+ if (failsafe_level)
+Index: nfs-server-2.2beta47/nfsd.c
+===================================================================
+--- nfs-server-2.2beta47.orig/nfsd.c
++++ nfs-server-2.2beta47/nfsd.c
+@@ -1147,11 +1147,6 @@ main(int argc, char **argv)
+ /* if (ncopies > 1)
+ read_only = 1; */
+
+- /*
+- * We first fork off a child and detach from tty
+- */
+- if (!foreground)
+- daemonize();
+
+ /* Initialize the AUTH module. */
+ auth_init(auth_file);
+@@ -1160,9 +1155,16 @@ main(int argc, char **argv)
+ nfs_pid_file = _PATH_NFSD_PIDFILE;
+ setpidpath(nfs_pid_file);
+
++ /*
++ * We first fork off a child and detach from tty
++ */
++ if (!foreground)
++ daemonize();
++ else
++ writepid(getpid(), 1);
++
+ if (failsafe_level == 0) {
+ /* Start multiple copies of the server */
+- writepid(getpid(), 1);
+ for (i = 1; i < ncopies; i++) {
+ pid_t pid;
+
diff --git a/meta/recipes-devtools/unfs-server/unfs-server-2.2beta47/020-undefined-chmod-fix.patch b/meta/recipes-devtools/unfs-server/unfs-server-2.2beta47/020-undefined-chmod-fix.patch
new file mode 100644
index 0000000..0f1108c
--- /dev/null
+++ b/meta/recipes-devtools/unfs-server/unfs-server-2.2beta47/020-undefined-chmod-fix.patch
@@ -0,0 +1,18 @@
+# Fix a problem with chmod attributes when using no_squash_all
+# Patch origin: Wind River
+
+---
+ setattr.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/setattr.c
++++ b/setattr.c
+@@ -115,7 +115,7 @@ nfsstat setattr(char *path, sattr *attr,
+ }
+ }
+
+- if (flags & SATTR_CHMOD) {
++ if (flags & SATTR_CHMOD && attr->mode != -1) {
+ unsigned int mode = attr->mode;
+
+ /* If setuid is not allowed, silently squash them */
diff --git a/meta/recipes-devtools/unfs-server/unfs-server-2.2beta47/021-nolibwrap.patch b/meta/recipes-devtools/unfs-server/unfs-server-2.2beta47/021-nolibwrap.patch
new file mode 100644
index 0000000..c0901fa
--- /dev/null
+++ b/meta/recipes-devtools/unfs-server/unfs-server-2.2beta47/021-nolibwrap.patch
@@ -0,0 +1,20 @@
+# Remove libwrap linkage
+# Patch origin: Wind River
+
+---
+ configure.in | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/configure.in
++++ b/configure.in
+@@ -86,8 +86,8 @@ AC_AUTHDES_GETUCRED
+ AC_BROKEN_SETFSUID
+ AC_MOUNTLIST
+ AC_FSUSAGE
+-AC_CHECK_LIB(wrap, main)
+-AC_LIBWRAP_BUG
++dnl AC_CHECK_LIB(wrap, main)
++dnl AC_LIBWRAP_BUG
+ AC_BSD_SIGNALS
+
+ dnl **************************************************************
diff --git a/meta/recipes-devtools/unfs-server/unfs-server-2.2beta47/022-add-close-on-exec-descriptors.patch b/meta/recipes-devtools/unfs-server/unfs-server-2.2beta47/022-add-close-on-exec-descriptors.patch
new file mode 100644
index 0000000..011ae74
--- /dev/null
+++ b/meta/recipes-devtools/unfs-server/unfs-server-2.2beta47/022-add-close-on-exec-descriptors.patch
@@ -0,0 +1,61 @@
+# Force socket fds to close on exec when used in conjunction with pseudo
+# Patch origin: Wind River
+
+---
+ nfsd.c | 8 ++++++++
+ rpcmisc.c | 9 +++++++++
+ ugidd.c | 8 ++++++++
+ 3 files changed, 25 insertions(+)
+
+--- a/nfsd.c
++++ b/nfsd.c
+@@ -630,6 +630,14 @@ nfsd_nfsproc_create_2(createargs *argp,
+ if (S_ISSOCK(argp->attributes.mode)) {
+ if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
+ return(nfs_errno());
++ /* if there is a pseudo exec mark the socket to be
++ * closed automatically
++ */
++ {
++ long f_flags;
++ f_flags = fcntl(s, F_GETFD);
++ f_flags = fcntl(s, F_SETFD, f_flags | FD_CLOEXEC);
++ }
+ sa.sun_family = AF_UNIX;
+ strncpy(sa.sun_path, pathbuf, sizeof(sa.sun_path));
+ sa.sun_path[sizeof(sa.sun_path)-1] = '\0';
+--- a/rpcmisc.c
++++ b/rpcmisc.c
+@@ -197,6 +197,15 @@ makesock(int port, int proto, int socksz
+ Dprintf(L_FATAL, "Could not make a %s socket: %s\n",
+ prot_name, strerror(errno));
+
++ /* if there is a pseudo exec mark the socket to be
++ * closed automatically
++ */
++ {
++ long f_flags;
++ f_flags = fcntl(s, F_GETFD);
++ f_flags = fcntl(s, F_SETFD, f_flags | FD_CLOEXEC);
++ }
++ fcntl(s, FD_CLOEXEC, 1);
+ memset((char *) &sin, 0, sizeof(sin));
+ sin.sin_family = AF_INET;
+ sin.sin_addr.s_addr = INADDR_ANY;
+--- a/ugidd.c
++++ b/ugidd.c
+@@ -195,6 +195,14 @@ authenticate_1_svc(argp, rqstp)
+ destaddr.sin_port = htons(*argp);
+ if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
+ goto bad;
++ /* if there is a pseudo exec mark the socket to be
++ * closed automatically
++ */
++ {
++ long f_flags;
++ f_flags = fcntl(s, F_GETFD);
++ f_flags = fcntl(s, F_SETFD, f_flags | FD_CLOEXEC);
++ }
+ setsockopt(s, SOL_SOCKET, SO_LINGER, 0, 0);
+ bzero((char *) &sendaddr, sizeof sendaddr);
+ /* find a reserved port */
OpenPOWER on IntegriCloud