[[RFC V1] 0/4] OSv NFS filesystem

266 views
Skip to first unread message

Benoît Canet

unread,
Nov 26, 2015, 3:22:53 PM11/26/15
to osv...@googlegroups.com, Benoît Canet
Hi list,

After a bit of work here is the first version of the OSv filesystem
client implementation.

I am posting this code dump because having the existing test to pass is
clearly a millestone and also because as someone would say "show me the code".

There are some caveats:

- The sfx-linux.c tests are running slow if the guest lo interface
has a big mtu because QEMU slirp code try to cope with it.
It should be set to 1500 before running the tests.

- Even with a 1500 mtu on the lo of the host the performance is twice lower
than the one of the linux client running on the host with the same server

- The thread_local storage of the mount_context variables would leak
if the application spend it's time mount and umounting NFS file systems.

- unfsd should be always killed at scripts/test.py exits

- the mount-nfs.so and umount.so commands are not written yet

- The mmu patch is ugly

- rpcbind should be started on the host prior running the test

- probably more to fix.

Best regards

Benoît


Benoît Canet (4):
vfs: Fix vfsop_umount_t prototype declaration
nfs: Add a makefile option to build in libnfs.
Add nfs server
nfs: Add nfs client and corresponding unit tests

.gitignore | 2 +
.gitmodules | 3 +
Makefile | 40 +-
core/mmu.cc | 27 +-
external/fs/libnfs | 1 +
external/fs/nfs-ganesha | 1 +
external/fs/unfs3-0.9.22/BRANCHES | 21 +
external/fs/unfs3-0.9.22/CREDITS | 37 +
external/fs/unfs3-0.9.22/Config/Makefile.in | 33 +
external/fs/unfs3-0.9.22/Config/exports.h | 45 +
external/fs/unfs3-0.9.22/Config/exports.l | 70 +
external/fs/unfs3-0.9.22/Config/exports.y | 848 +++
external/fs/unfs3-0.9.22/Config/lex.yy.c | 1664 +++++
external/fs/unfs3-0.9.22/Config/y.tab.c | 2403 +++++++
external/fs/unfs3-0.9.22/Config/y.tab.h | 78 +
external/fs/unfs3-0.9.22/Extras/Makefile.in | 23 +
external/fs/unfs3-0.9.22/Extras/cluster.c | 512 ++
external/fs/unfs3-0.9.22/Extras/cluster.h | 27 +
external/fs/unfs3-0.9.22/Extras/tags.7 | 123 +
external/fs/unfs3-0.9.22/LICENSE | 24 +
external/fs/unfs3-0.9.22/Makefile.in | 158 +
external/fs/unfs3-0.9.22/NEWS | 242 +
external/fs/unfs3-0.9.22/README | 89 +
external/fs/unfs3-0.9.22/README.nfsroot | 44 +
external/fs/unfs3-0.9.22/aclocal.m4 | 25 +
external/fs/unfs3-0.9.22/attr.c | 496 ++
external/fs/unfs3-0.9.22/attr.h | 26 +
external/fs/unfs3-0.9.22/backend.h | 16 +
external/fs/unfs3-0.9.22/backend_unix.h | 84 +
external/fs/unfs3-0.9.22/backend_win32.h | 83 +
external/fs/unfs3-0.9.22/bootstrap | 2 +
external/fs/unfs3-0.9.22/config.h.in | 119 +
external/fs/unfs3-0.9.22/configure | 6835 ++++++++++++++++++++
external/fs/unfs3-0.9.22/configure.ac | 37 +
.../fs/unfs3-0.9.22/contrib/nfsotpclient/README | 3 +
.../contrib/nfsotpclient/mountclient/__init__.py | 6 +
.../nfsotpclient/mountclient/mountconstants.py | 48 +
.../nfsotpclient/mountclient/mountpacker.py | 113 +
.../contrib/nfsotpclient/mountclient/mounttypes.py | 232 +
.../contrib/nfsotpclient/nfsotpclient.py | 78 +
.../fs/unfs3-0.9.22/contrib/nfsotpclient/rpc.py | 1050 +++
external/fs/unfs3-0.9.22/contrib/rpcproxy/rpcproxy | 378 ++
external/fs/unfs3-0.9.22/daemon.c | 974 +++
external/fs/unfs3-0.9.22/daemon.h | 49 +
external/fs/unfs3-0.9.22/doc/README.win | 51 +
external/fs/unfs3-0.9.22/doc/TODO | 12 +
external/fs/unfs3-0.9.22/doc/kirch1.txt | 271 +
external/fs/unfs3-0.9.22/doc/passwords.txt | 46 +
external/fs/unfs3-0.9.22/error.c | 280 +
external/fs/unfs3-0.9.22/error.h | 29 +
external/fs/unfs3-0.9.22/fd_cache.c | 398 ++
external/fs/unfs3-0.9.22/fd_cache.h | 29 +
external/fs/unfs3-0.9.22/fh.c | 473 ++
external/fs/unfs3-0.9.22/fh.h | 62 +
external/fs/unfs3-0.9.22/fh_cache.c | 347 +
external/fs/unfs3-0.9.22/fh_cache.h | 23 +
external/fs/unfs3-0.9.22/indent-all | 5 +
external/fs/unfs3-0.9.22/install-sh | 251 +
external/fs/unfs3-0.9.22/locate.c | 171 +
external/fs/unfs3-0.9.22/locate.h | 13 +
external/fs/unfs3-0.9.22/md5.c | 379 ++
external/fs/unfs3-0.9.22/md5.h | 91 +
external/fs/unfs3-0.9.22/mount.c | 289 +
external/fs/unfs3-0.9.22/mount.h | 97 +
external/fs/unfs3-0.9.22/nfs.c | 1083 ++++
external/fs/unfs3-0.9.22/nfs.h | 1007 +++
external/fs/unfs3-0.9.22/password.c | 116 +
external/fs/unfs3-0.9.22/password.h | 13 +
external/fs/unfs3-0.9.22/readdir.c | 215 +
external/fs/unfs3-0.9.22/readdir.h | 14 +
external/fs/unfs3-0.9.22/unfs3.spec | 38 +
external/fs/unfs3-0.9.22/unfsd.8 | 394 ++
external/fs/unfs3-0.9.22/unfsd.init | 71 +
external/fs/unfs3-0.9.22/user.c | 293 +
external/fs/unfs3-0.9.22/user.h | 29 +
external/fs/unfs3-0.9.22/winsupport.c | 1062 +++
external/fs/unfs3-0.9.22/winsupport.h | 131 +
external/fs/unfs3-0.9.22/xdr.c | 1656 +++++
external/fs/unfs3-0.9.22/xdr.h | 165 +
fs/nfs/nfs.cc | 84 +
fs/nfs/nfs.hh | 70 +
fs/nfs/nfs_null_vfsops.cc | 36 +
fs/nfs/nfs_vfsops.cc | 79 +
fs/nfs/nfs_vnops.cc | 612 ++
fs/vfs/vfs_conf.cc | 3 +
include/osv/mount.h | 2 +-
modules/tests/Makefile | 8 +-
scripts/test.py | 39 +-
tests-nfs/fsx-linux.c | 1064 +++
tests-nfs/tst-nfs.cc | 316 +
90 files changed, 29078 insertions(+), 8 deletions(-)
create mode 160000 external/fs/libnfs
create mode 160000 external/fs/nfs-ganesha
create mode 100644 external/fs/unfs3-0.9.22/BRANCHES
create mode 100644 external/fs/unfs3-0.9.22/CREDITS
create mode 100644 external/fs/unfs3-0.9.22/Config/Makefile.in
create mode 100644 external/fs/unfs3-0.9.22/Config/exports.h
create mode 100644 external/fs/unfs3-0.9.22/Config/exports.l
create mode 100644 external/fs/unfs3-0.9.22/Config/exports.y
create mode 100644 external/fs/unfs3-0.9.22/Config/lex.yy.c
create mode 100644 external/fs/unfs3-0.9.22/Config/y.tab.c
create mode 100644 external/fs/unfs3-0.9.22/Config/y.tab.h
create mode 100644 external/fs/unfs3-0.9.22/Extras/Makefile.in
create mode 100644 external/fs/unfs3-0.9.22/Extras/cluster.c
create mode 100644 external/fs/unfs3-0.9.22/Extras/cluster.h
create mode 100644 external/fs/unfs3-0.9.22/Extras/tags.7
create mode 100644 external/fs/unfs3-0.9.22/LICENSE
create mode 100644 external/fs/unfs3-0.9.22/Makefile.in
create mode 100644 external/fs/unfs3-0.9.22/NEWS
create mode 100644 external/fs/unfs3-0.9.22/README
create mode 100644 external/fs/unfs3-0.9.22/README.nfsroot
create mode 100644 external/fs/unfs3-0.9.22/aclocal.m4
create mode 100644 external/fs/unfs3-0.9.22/attr.c
create mode 100644 external/fs/unfs3-0.9.22/attr.h
create mode 100644 external/fs/unfs3-0.9.22/backend.h
create mode 100644 external/fs/unfs3-0.9.22/backend_unix.h
create mode 100644 external/fs/unfs3-0.9.22/backend_win32.h
create mode 100755 external/fs/unfs3-0.9.22/bootstrap
create mode 100644 external/fs/unfs3-0.9.22/config.h.in
create mode 100755 external/fs/unfs3-0.9.22/configure
create mode 100644 external/fs/unfs3-0.9.22/configure.ac
create mode 100644 external/fs/unfs3-0.9.22/contrib/nfsotpclient/README
create mode 100644 external/fs/unfs3-0.9.22/contrib/nfsotpclient/mountclient/__init__.py
create mode 100644 external/fs/unfs3-0.9.22/contrib/nfsotpclient/mountclient/mountconstants.py
create mode 100644 external/fs/unfs3-0.9.22/contrib/nfsotpclient/mountclient/mountpacker.py
create mode 100644 external/fs/unfs3-0.9.22/contrib/nfsotpclient/mountclient/mounttypes.py
create mode 100755 external/fs/unfs3-0.9.22/contrib/nfsotpclient/nfsotpclient.py
create mode 100644 external/fs/unfs3-0.9.22/contrib/nfsotpclient/rpc.py
create mode 100755 external/fs/unfs3-0.9.22/contrib/rpcproxy/rpcproxy
create mode 100644 external/fs/unfs3-0.9.22/daemon.c
create mode 100644 external/fs/unfs3-0.9.22/daemon.h
create mode 100644 external/fs/unfs3-0.9.22/doc/README.win
create mode 100644 external/fs/unfs3-0.9.22/doc/TODO
create mode 100644 external/fs/unfs3-0.9.22/doc/kirch1.txt
create mode 100644 external/fs/unfs3-0.9.22/doc/passwords.txt
create mode 100644 external/fs/unfs3-0.9.22/error.c
create mode 100644 external/fs/unfs3-0.9.22/error.h
create mode 100644 external/fs/unfs3-0.9.22/fd_cache.c
create mode 100644 external/fs/unfs3-0.9.22/fd_cache.h
create mode 100644 external/fs/unfs3-0.9.22/fh.c
create mode 100644 external/fs/unfs3-0.9.22/fh.h
create mode 100644 external/fs/unfs3-0.9.22/fh_cache.c
create mode 100644 external/fs/unfs3-0.9.22/fh_cache.h
create mode 100755 external/fs/unfs3-0.9.22/indent-all
create mode 100755 external/fs/unfs3-0.9.22/install-sh
create mode 100644 external/fs/unfs3-0.9.22/locate.c
create mode 100644 external/fs/unfs3-0.9.22/locate.h
create mode 100644 external/fs/unfs3-0.9.22/md5.c
create mode 100644 external/fs/unfs3-0.9.22/md5.h
create mode 100644 external/fs/unfs3-0.9.22/mount.c
create mode 100644 external/fs/unfs3-0.9.22/mount.h
create mode 100644 external/fs/unfs3-0.9.22/nfs.c
create mode 100644 external/fs/unfs3-0.9.22/nfs.h
create mode 100644 external/fs/unfs3-0.9.22/password.c
create mode 100644 external/fs/unfs3-0.9.22/password.h
create mode 100644 external/fs/unfs3-0.9.22/readdir.c
create mode 100644 external/fs/unfs3-0.9.22/readdir.h
create mode 100644 external/fs/unfs3-0.9.22/unfs3.spec
create mode 100644 external/fs/unfs3-0.9.22/unfsd.8
create mode 100755 external/fs/unfs3-0.9.22/unfsd.init
create mode 100644 external/fs/unfs3-0.9.22/user.c
create mode 100644 external/fs/unfs3-0.9.22/user.h
create mode 100644 external/fs/unfs3-0.9.22/winsupport.c
create mode 100644 external/fs/unfs3-0.9.22/winsupport.h
create mode 100644 external/fs/unfs3-0.9.22/xdr.c
create mode 100644 external/fs/unfs3-0.9.22/xdr.h
create mode 100644 fs/nfs/nfs.cc
create mode 100644 fs/nfs/nfs.hh
create mode 100644 fs/nfs/nfs_null_vfsops.cc
create mode 100644 fs/nfs/nfs_vfsops.cc
create mode 100644 fs/nfs/nfs_vnops.cc
create mode 100644 tests-nfs/fsx-linux.c
create mode 100644 tests-nfs/tst-nfs.cc

--
2.6.2

Benoît Canet

unread,
Nov 26, 2015, 3:22:53 PM11/26/15
to osv...@googlegroups.com, Benoît Canet
It was just plain wrong probably because nobody
ever used it.

Signed-off-by: Benoît Canet <ben...@scylladb.com>
---
include/osv/mount.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/include/osv/mount.h b/include/osv/mount.h
index ffbf58a..7268d8c 100755
--- a/include/osv/mount.h
+++ b/include/osv/mount.h
@@ -120,7 +120,7 @@ struct vfsops {
};

typedef int (*vfsop_mount_t)(struct mount *, const char *, int, const void *);
-typedef int (*vfsop_umount_t)(struct mount *);
+typedef int (*vfsop_umount_t)(struct mount *, int flags);
typedef int (*vfsop_sync_t)(struct mount *);
typedef int (*vfsop_vget_t)(struct mount *, struct vnode *);
typedef int (*vfsop_statfs_t)(struct mount *, struct statfs *);
--
2.6.2

Benoît Canet

unread,
Nov 26, 2015, 3:22:54 PM11/26/15
to osv...@googlegroups.com, Benoît Canet
libnfs is an LGPL licensed nfs client implementation
that will be handy to implement the OSv nfs client
required by HLRS.

Most HPC use cases require an NFS mount to
regularly save data.

To build it do:

make NFS=true

Signed-off-by: Benoît Canet <ben...@scylladb.com>
---
.gitmodules | 3 +++
Makefile | 29 ++++++++++++++++++++++++++---
external/fs/libnfs | 1 +
3 files changed, 30 insertions(+), 3 deletions(-)
create mode 160000 external/fs/libnfs

diff --git a/.gitmodules b/.gitmodules
index ea8f06f..c0cfc52 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -48,3 +48,6 @@
[submodule "modules/httpserver/osv-gui"]
path = modules/httpserver/osv-gui
url = ../../cloudius-systems/osv-gui.git
+[submodule "external/fs/libnfs"]
+ path = external/fs/libnfs
+ url = https://github.com/sahlberg/libnfs.git
diff --git a/Makefile b/Makefile
index b6ce8f7..5488aee 100644
--- a/Makefile
+++ b/Makefile
@@ -144,10 +144,25 @@ check:
./scripts/build check
.PHONY: check

+libnfs-path = $(shell pwd)/external/fs/libnfs/
+
+$(out)/libnfs.a:
+ cd $(libnfs-path) && \
+ $(call quiet, $(libnfs-path)/bootstrap) && \
+ $(call quiet, $(libnfs-path)/configure --enable-shared=no --enable-static=yes --enable-silent-rules) && \
+ $(call quiet, make -f $(libnfs-path)/Makefile)
+ $(call quiet, cp -a $(libnfs-path)/lib/.libs/libnfs.a $(out)/libnfs.a)
+
+clean-libnfs:
+ if [ -f $(out)/libnfs.a ] ; then \
+ cd $(libnfs-path) && \
+ make distclean; \
+ fi
+
# Remember that "make clean" needs the same parameters that set $(out) in
# the first place, so to clean the output of "make mode=debug" you need to
# do "make mode=debug clean".
-clean:
+clean: clean-libnfs
rm -rf $(out)
rm -f $(outlink) $(outlink2)
.PHONY: clean
@@ -481,7 +496,6 @@ endif # aarch64
$(out)/bsd/sys/crypto/sha2/sha2.o: CFLAGS+=-Wno-strict-aliasing
$(out)/bsd/sys/crypto/rijndael/rijndael-api-fst.o: CFLAGS+=-Wno-strict-aliasing

-
bsd = bsd/init.o
bsd += bsd/net.o
bsd += bsd/$(arch)/machine/in_cksum.o
@@ -1319,6 +1333,7 @@ libc += network/h_errno.o
musl += network/getservbyname_r.o
musl += network/getservbyname.o
musl += network/getservbyport_r.o
+musl += network/getservbyport.o
musl += network/getifaddrs.o
musl += network/if_nameindex.o
musl += network/if_freenameindex.o
@@ -1756,6 +1771,13 @@ endif
boost-libs := $(boost-lib-dir)/libboost_program_options$(boost-mt).a \
$(boost-lib-dir)/libboost_system$(boost-mt).a

+nfs-lib =
+ifeq ($(NFS), true)
+ nfs-lib += $(out)/libnfs.a
+endif
+
+nfs-library: $(nfs-lib)
+
# ld has a known bug (https://sourceware.org/bugzilla/show_bug.cgi?id=6468)
# where if the executable doesn't use shared libraries, its .dynamic section
# is dropped, even when we use the "--export-dynamic" (which is silently
@@ -1763,13 +1785,14 @@ boost-libs := $(boost-lib-dir)/libboost_program_options$(boost-mt).a \
$(out)/dummy-shlib.so: $(out)/dummy-shlib.o
$(call quiet, $(CXX) -nodefaultlibs -shared $(gcc-sysroot) -o $@ $^, LINK $@)

-$(out)/loader.elf: $(out)/arch/$(arch)/boot.o arch/$(arch)/loader.ld $(out)/loader.o $(out)/runtime.o $(drivers:%=$(out)/%) $(objects:%=$(out)/%) $(out)/bootfs.bin $(out)/dummy-shlib.so
+$(out)/loader.elf: $(out)/arch/$(arch)/boot.o arch/$(arch)/loader.ld $(out)/loader.o $(out)/runtime.o $(drivers:%=$(out)/%) $(objects:%=$(out)/%) $(out)/bootfs.bin $(out)/dummy-shlib.so $(nfs-lib)
$(call quiet, $(LD) -o $@ --defsym=OSV_KERNEL_BASE=$(kernel_base) \
-Bdynamic --export-dynamic --eh-frame-hdr --enable-new-dtags \
$(filter-out %.bin, $(^:%.ld=-T %.ld)) \
--whole-archive \
$(libstdc++.a) $(libgcc.a) $(libgcc_eh.a) \
$(boost-libs) \
+ $(nfs-lib) \
--no-whole-archive, \
LINK loader.elf)
@# Build libosv.so matching this loader.elf. This is not a separate
diff --git a/external/fs/libnfs b/external/fs/libnfs
new file mode 160000
index 0000000..dc8d866
--- /dev/null
+++ b/external/fs/libnfs
@@ -0,0 +1 @@
+Subproject commit dc8d86628d2f67cb4b7a9e5e5d7a1259f065b3c7
--
2.6.2

Benoît Canet

unread,
Nov 26, 2015, 3:22:56 PM11/26/15
to osv...@googlegroups.com, Benoît Canet
---
73 files changed, 26699 insertions(+)
diff --git a/external/fs/unfs3-0.9.22/BRANCHES b/external/fs/unfs3-0.9.22/BRANCHES
new file mode 100644
index 0000000..f16282a
--- /dev/null
+++ b/external/fs/unfs3-0.9.22/BRANCHES
@@ -0,0 +1,21 @@
+uidmapping
+----------
+Unused.
+
+
+removable-fsidhash
+------------------
+This branch has been used for work on removable support. All changes
+has been merged with the HEAD branch now.
+
+
+removable-support
+-----------------
+Experimental ASCII-filehandles work. These changes will probably not
+be merged with HEAD; they are pretty much obsoleted by the work on the
+"removable-fsidhash" branch.
+
+
+pharao90
+--------
+Main vendor branch.
diff --git a/external/fs/unfs3-0.9.22/CREDITS b/external/fs/unfs3-0.9.22/CREDITS
new file mode 100644
index 0000000..9f44fd1
--- /dev/null
+++ b/external/fs/unfs3-0.9.22/CREDITS
@@ -0,0 +1,37 @@
+CREDITS
+=======
+
+The design of unfs3's filehandle code owes much to the original NFSv2
+universal user-space NFS server. Thanks to Mark Shand and Don Becker
+for coming up with those concepts.
+
+We also give credit to Gregory R. Warnes for the idea of file
+tagging as used by ClusterNFS and the unfs3 cluster extension.
+
+People who contributed ideas, suggestions, or code to UNFS3:
+
+- Bernd Schubert <bernd-s...@web.de>
+- Avery Pennarun <apen...@nit.ca>
+- Juergen Brendel <jue...@brendel.com>
+- Peter Astrand <ast...@cendio.se>
+- Igor Durdanovic <idurd...@comcast.net>
+- Jan P. Springer <js...@users.sourceforge.net>
+- Thomas Schwinge <schw...@nic-nac-project.de>
+- Simon Matter <si...@users.sourceforge.net>
+- Brian <bohal...@users.sourceforge.net>
+- Jean Aumont <JeanA...@videotron.ca>
+- Constantin Scheder <sch...@nirvanastorage.com>
+- Sam Sharma <sam.s...@gat.com>
+- Holger Wolf <Holge...@de.ibm.com>
+- Frank v Waveren <f...@var.cx>
+- Matthew Bloch <mat...@bytemark.co.uk>
+- Nick S. Grechukh <g...@altlinux.org>
+- Michael Shigorin <mi...@osdn.org.ua>
+- Tim Weippert <tim.we...@tds.de>
+- Hanpen-san <han...@lopox.com>
+- Sergey Bolshakov <sbols...@altlinux.ru>
+- Phill Bertolus <phi...@webwombat.com>
+- Brent A Nelson <br...@phys.ufl.edu>
+- Garrett Cooper <garr...@cisco.com>
+- Wesley Shields <w...@FreeBSD.org>
+- Bernhard Duebi <Bernhar...@telekurs.com>
diff --git a/external/fs/unfs3-0.9.22/Config/Makefile.in b/external/fs/unfs3-0.9.22/Config/Makefile.in
new file mode 100644
index 0000000..45c56e7
--- /dev/null
+++ b/external/fs/unfs3-0.9.22/Config/Makefile.in
@@ -0,0 +1,33 @@
+CC = @CC@
+CFLAGS = @CFLAGS@
+AR = ar
+RM = rm -f
+LEX = @LEX@
+YACC = @YACC@
+
+OBJS = @LEX_OUTPUT_ROOT@.o y.tab.o
+
+all: lib.a
+
+lib.a: $(OBJS)
+ $(AR) crs lib.a $(OBJS)
+
+y.tab.h y.tab.c: exports.y
+ $(YACC) -d exports.y
+
+y.tab.o: y.tab.c exports.h ../nfs.h ../mount.h ../daemon.h
+
+@LEX_OUTPUT_ROOT@.c: exports.l
+ $(LEX) exports.l
+
+@LEX_OUTPUT_ROOT@.o: @LEX_OUTPUT_ROOT@.c y.tab.h ../nfs.h
+
+dep:
+ :
+
+clean:
+ $(RM) $(OBJS) lib.a
+ $(RM) @LEX_OUTPUT_ROOT@.c y.tab.h y.tab.c
+
+distclean:
+ $(RM) Makefile
diff --git a/external/fs/unfs3-0.9.22/Config/exports.h b/external/fs/unfs3-0.9.22/Config/exports.h
new file mode 100644
index 0000000..2c5edec
--- /dev/null
+++ b/external/fs/unfs3-0.9.22/Config/exports.h
@@ -0,0 +1,45 @@
+/*
+ * UNFS3 export controls
+ * (C) 2003, Pascal Schmidt
+ * see file LICENSE for license details
+ */
+
+#ifndef UNFS3_EXPORTS_H
+#define UNFS3_EXPORTS_H
+
+#include "../mount.h" /* exports type */
+
+#define OPT_NO_ROOT_SQUASH 1
+#define OPT_ALL_SQUASH 2
+#define OPT_RW 4
+#define OPT_REMOVABLE 8
+#define OPT_INSECURE 16
+
+#define PASSWORD_MAXLEN 64
+
+#define ANON_NOTSPECIAL 0xffffffff
+
+extern exports exports_nfslist;
+/* Options cache */
+extern int exports_opts;
+const char *export_path;
+extern uint32 export_fsid;
+extern uint32 export_password_hash;
+
+extern unsigned char password[PASSWORD_MAXLEN+1];
+
+int exports_parse(void);
+int exports_options(const char *path, struct svc_req *rqstp, char **password, uint32 *fsid);
+int export_point(const char *path);
+char *export_point_from_fsid(uint32 fsid, time_t **last_mtime, uint32 **dir_hash);
+nfsstat3 exports_compat(const char *path, struct svc_req *rqstp);
+nfsstat3 exports_rw(void);
+uint32 exports_anonuid(void);
+uint32 exports_anongid(void);
+uint32 fnv1a_32(const char *str, uint32 hval);
+#ifdef WIN32
+uint32 wfnv1a_32(const wchar_t *str, uint32 hval);
+#endif /* WIN32 */
+char *normpath(const char *path, char *normpath);
+
+#endif
diff --git a/external/fs/unfs3-0.9.22/Config/exports.l b/external/fs/unfs3-0.9.22/Config/exports.l
new file mode 100644
index 0000000..8a2d6d1
--- /dev/null
+++ b/external/fs/unfs3-0.9.22/Config/exports.l
@@ -0,0 +1,70 @@
+%{
+/*
+ * UNFS3 exports lexer
+ * (C) 2003, Pascal Schmidt
+ * see file LICENSE for license details
+ */
+#include "../config.h"
+
+#include <rpc/rpc.h>
+#include <string.h>
+
+#include "../nfs.h"
+#include "y.tab.h"
+
+#define YY_NO_UNPUT
+
+YYSTYPE yylval;
+extern int e_error;
+
+/*
+ * copy matching text to yylval.text
+ */
+static void copy_text(const char *from, int leng)
+{
+ int len;
+
+ /* check length to prevent buffer overflow */
+ if (leng + 1 > NFS_MAXPATHLEN) {
+ len = NFS_MAXPATHLEN - 1;
+ e_error = 1;
+ } else
+ len = leng;
+
+ memcpy(yylval.text, from, len);
+ yylval.text[len] = 0;
+}
+%}
+
+WHITE [ \t]
+NOWHITE [^ \n\t]
+PATH "/"{NOWHITE}*
+ID [a-z][\.\-_a-z0-9]*
+OPTVALUE [^ \n\t,)]*
+
+IPCOMP [0-9]{1,3}
+IP {IPCOMP}"."{IPCOMP}"."{IPCOMP}"."{IPCOMP}
+NETCOMP [0-9]{1,2}
+NET {IP}"/"{NETCOMP}
+OLDNET {IP}"/"{IP}
+
+%%
+
+^{WHITE}*\n { /* eat empty line */ }
+^{WHITE}* { /* eat whitespace at beginning of line */ }
+"\\"\n { /* eat escaped newline */ }
+^{WHITE}*"#".*\n { /* eat one-line comment */ }
+{WHITE}*"#".* { /* eat trailing comment */ }
+
+{IP} { copy_text(yytext, yyleng); return IP; }
+{NET} { copy_text(yytext, yyleng); return NET; }
+{OLDNET} { copy_text(yytext, yyleng); return OLDNET; }
+"\"".*"\"" { copy_text(yytext+1, yyleng-2); return PATH; }
+"="{OPTVALUE} { copy_text(yytext+1, yyleng-1); return OPTVALUE; }
+{PATH} { copy_text(yytext, yyleng); return PATH; }
+{WHITE}+ { copy_text(yytext, yyleng); return WHITE; }
+{ID} { copy_text(yytext, yyleng); return ID; }
+
+. { return *yytext; }
+\n { return '\n'; }
+
\ No newline at end of file
diff --git a/external/fs/unfs3-0.9.22/Config/exports.y b/external/fs/unfs3-0.9.22/Config/exports.y
new file mode 100644
index 0000000..f30e8af
--- /dev/null
+++ b/external/fs/unfs3-0.9.22/Config/exports.y
@@ -0,0 +1,848 @@
+%{
+/*
+ * UNFS3 exports parser and export controls
+ * (C) 2004, Pascal Schmidt
+ * see file LICENSE for license details
+ */
+#include "../config.h"
+
+#include <rpc/rpc.h>
+#include <limits.h>
+
+#ifdef WIN32
+#include "../winsupport.h"
+#else
+#include <netdb.h>
+#include <syslog.h>
+#include <unistd.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#endif /* WIN32 */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "../nfs.h"
+#include "../mount.h"
+#include "../daemon.h"
+#include "../backend.h"
+#include "exports.h"
+
+#ifndef PATH_MAX
+# define PATH_MAX 4096
+#endif
+
+/* for lack of a better place */
+#ifdef __GNUC__
+#define U(x) x __attribute__ ((unused))
+#else
+#define U(x) x
+#endif
+
+/* lexer stuff, to avoid compiler warnings */
+int yylex(void);
+extern FILE *yyin;
+
+/*
+ * C code used by yacc parser
+ */
+
+typedef struct {
+ char orig[NFS_MAXPATHLEN];
+ int options;
+ char password[PASSWORD_MAXLEN+1];
+ uint32 password_hash;
+ struct in_addr addr;
+ struct in_addr mask;
+ uint32 anonuid;
+ uint32 anongid;
+ struct e_host *next;
+} e_host;
+
+typedef struct {
+ char path[NFS_MAXPATHLEN];
+ char orig[NFS_MAXPATHLEN];
+ e_host *hosts;
+ uint32 fsid; /* export point fsid (for removables) */
+ time_t last_mtime; /* Last returned mtime (for removables) */
+ uint32 dir_hash; /* Hash of dir contents (for removables) */
+ struct e_item *next;
+} e_item;
+
+/* export list, item, and host filled during parse */
+static e_item *e_list = NULL;
+static e_item cur_item;
+static e_host cur_host;
+
+/* last looked-up anonuid and anongid */
+static uint32 last_anonuid = ANON_NOTSPECIAL;
+static uint32 last_anongid = ANON_NOTSPECIAL;
+
+/* mount protocol compatible variants */
+static exports ne_list = NULL;
+static struct exportnode ne_item;
+static struct groupnode ne_host;
+
+/* error status of last parse */
+int e_error = FALSE;
+
+/*
+ * The FNV1a-32 hash algorithm
+ * (http://www.isthe.com/chongo/tech/comp/fnv/)
+ */
+uint32 fnv1a_32(const char *str, uint32 hval)
+{
+ static const uint32 fnv_32_prime = 0x01000193;
+
+ while (*str) {
+ hval ^= *str++;
+ hval *= fnv_32_prime;
+ }
+ return hval;
+}
+
+#ifdef WIN32
+uint32 wfnv1a_32(const wchar_t *str, uint32 hval)
+{
+ static const uint32 fnv_32_prime = 0x01000193;
+
+ while (*str) {
+ hval ^= *str++;
+ hval *= fnv_32_prime;
+ }
+ return hval;
+}
+#endif
+
+/*
+ * get static fsid, for use with removable media export points
+ */
+static uint32 get_free_fsid(const char *path)
+{
+ uint32 hval;
+
+ /* The 32:th bit is set to one on all special filehandles. The
+ last 31 bits are hashed from the export point path. */
+ hval = fnv1a_32(path, 0);
+ hval |= 0x80000000;
+ return hval;
+}
+
+
+/*
+ * clear current host
+ */
+static void clear_host(void)
+{
+ memset(&cur_host, 0, sizeof(e_host));
+ strcpy(cur_host.orig, "<anon clnt>");
+ memset(&ne_host, 0, sizeof(struct groupnode));
+
+ cur_host.anonuid =
+ cur_host.anongid = ANON_NOTSPECIAL;
+}
+
+/*
+ * clear current item
+ */
+static void clear_item(void)
+{
+ memset(&cur_item, 0, sizeof(e_item));
+ memset(&ne_item, 0, sizeof(struct exportnode));
+}
+
+/*
+ * add current host to current export item
+ */
+static void add_host(void)
+{
+ e_host *new;
+ e_host *iter;
+
+ groups ne_new;
+ groups ne_iter;
+
+ new = malloc(sizeof(e_host));
+ ne_new = malloc(sizeof(struct groupnode));
+ if (!new || !ne_new) {
+ logmsg(LOG_EMERG, "out of memory, aborting");
+ daemon_exit(CRISIS);
+ }
+
+ *new = cur_host;
+ *ne_new = ne_host;
+ ne_new->gr_name = new->orig;
+
+ /* internal list */
+ if (cur_item.hosts) {
+ iter = cur_item.hosts;
+ while (iter->next)
+ iter = (e_host *) iter->next;
+ iter->next = (struct e_host *) new;
+ } else
+ cur_item.hosts = new;
+
+ /* matching mount protocol list */
+ if (ne_item.ex_groups) {
+ ne_iter = ne_item.ex_groups;
+ while (ne_iter->gr_next)
+ ne_iter = (groups) ne_iter->gr_next;
+ ne_iter->gr_next = ne_new;
+ } else
+ ne_item.ex_groups = ne_new;
+
+ clear_host();
+}
+
+/*
+ Normalize path, eliminating double slashes, etc. To be used instead
+ of realpath, when realpath is not possible. Normalizing export
+ points is important. Otherwise, mount requests might fail, since
+ /x/y is not a prefix of ///x///y/ etc.
+*/
+char *normpath(const char *path, char *normpath)
+{
+ char *n;
+ const char *p;
+
+ /* Copy path to normpath, and replace blocks of slashes with
+ single slash */
+ p = path;
+ n = normpath;
+ while (*p) {
+ /* Skip over multiple slashes */
+ if (*p == '/' && *(p+1) == '/') {
+ p++;
+ continue;
+ }
+ *n++ = *p++;
+ }
+ *n = '\0';
+
+ /* Remove trailing slash, if any. */
+ if ((n - normpath) > 1 && *(n-1) == '/')
+ *(n-1) = '\0';
+
+ return normpath;
+}
+
+/*
+ * add current item to current export list
+ */
+static void add_item(const char *path)
+{
+ char buf[PATH_MAX];
+ e_item *new;
+ e_item *iter;
+ e_host *host;
+ /* Is this item marked as removable for all hosts? */
+ int removable_for_all = 1;
+
+ exports ne_new;
+ exports ne_iter;
+
+ new = malloc(sizeof(e_item));
+ ne_new = malloc(sizeof(struct exportnode));
+ if (!new || !ne_new) {
+ logmsg(LOG_EMERG, "out of memory, aborting");
+ daemon_exit(CRISIS);
+ }
+
+ /* Loop over all hosts and check if marked as removable. */
+ host = cur_item.hosts;
+ while (host) {
+ if (!(host->options & OPT_REMOVABLE))
+ removable_for_all = 0;
+ host = (e_host *) host->next;
+ }
+
+ if (removable_for_all) {
+ /* If marked as removable for all hosts, don't try
+ realpath. */
+ normpath(path, buf);
+ } else if (!backend_realpath(path, buf)) {
+ logmsg(LOG_CRIT, "realpath for %s failed", path);
+ e_error = TRUE;
+ free(new);
+ free(ne_new);
+ clear_item();
+ return;
+ }
+
+ if (strlen(buf) + 1 > NFS_MAXPATHLEN) {
+ logmsg(LOG_CRIT, "attempted to export too long path");
+ e_error = TRUE;
+ free(new);
+ free(ne_new);
+ clear_item();
+ return;
+ }
+
+ /* if no hosts listed, list default host */
+ if (!cur_item.hosts)
+ add_host();
+
+ *new = cur_item;
+ strcpy(new->path, buf);
+ strcpy(new->orig, path);
+ new->fsid = get_free_fsid(path);
+ new->last_mtime = 0;
+ new->dir_hash = 0;
+
+ *ne_new = ne_item;
+ ne_new->ex_dir = new->orig;
+
+ /* internal list */
+ if (e_list) {
+ iter = e_list;
+ while (iter->next)
+ iter = (e_item *) iter->next;
+ iter->next = (struct e_item *) new;
+ } else
+ e_list = new;
+
+ /* matching mount protocol list */
+ if (ne_list) {
+ ne_iter = ne_list;
+ while (ne_iter->ex_next)
+ ne_iter = (exports) ne_iter->ex_next;
+ ne_iter->ex_next = ne_new;
+ } else
+ ne_list = ne_new;
+
+ clear_item();
+}
+
+/*
+ * fill current host's address given a hostname
+ */
+static void set_hostname(const char *name)
+{
+ struct hostent *ent;
+
+ if (strlen(name) + 1 > NFS_MAXPATHLEN) {
+ e_error = TRUE;
+ return;
+ }
+ strcpy(cur_host.orig, name);
+
+ ent = gethostbyname(name);
+
+ if (ent) {
+ memcpy(&cur_host.addr, ent->h_addr_list[0],
+ sizeof(struct in_addr));
+ cur_host.mask.s_addr = ~0UL;
+ } else {
+ logmsg(LOG_CRIT, "could not resolve hostname '%s'", name);
+ e_error = TRUE;
+ }
+}
+
+/*
+ * fill current host's address given an IP address
+ */
+static void set_ipaddr(const char *addr)
+{
+ strcpy(cur_host.orig, addr);
+
+ if (!inet_aton(addr, &cur_host.addr))
+ e_error = TRUE;
+ cur_host.mask.s_addr = ~0UL;
+}
+
+/*
+ * compute network bitmask
+ */
+static unsigned long make_netmask(int bits) {
+ unsigned long buf = 0;
+ int i;
+
+ for (i=0; i<bits; i++)
+ buf = (buf << 1) + 1;
+ for (; i < 32; i++)
+ buf = (buf << 1);
+ return htonl(buf);
+}
+
+/*
+ * fill current host's address given IP address and netmask
+ */
+static void set_ipnet(char *addr, int new)
+{
+ char *pos, *net;
+
+ pos = strchr(addr, '/');
+ net = pos + 1;
+ *pos = 0;
+
+ set_ipaddr(addr);
+
+ if (new)
+ cur_host.mask.s_addr = make_netmask(atoi(net));
+ else
+ if (!inet_aton(net, &cur_host.mask))
+ e_error = TRUE;
+
+ *pos = '/';
+ strcpy(cur_host.orig, addr);
+}
+
+/*
+ * add an option bit to the current host
+ */
+static void add_option(const char *opt)
+{
+ if (strcmp(opt,"no_root_squash") == 0)
+ cur_host.options |= OPT_NO_ROOT_SQUASH;
+ else if (strcmp(opt,"root_squash") == 0)
+ cur_host.options &= ~OPT_NO_ROOT_SQUASH;
+ else if (strcmp(opt,"all_squash") == 0)
+ cur_host.options |= OPT_ALL_SQUASH;
+ else if (strcmp(opt,"no_all_squash") == 0)
+ cur_host.options &= ~OPT_ALL_SQUASH;
+ else if (strcmp(opt,"rw") == 0)
+ cur_host.options |= OPT_RW;
+ else if (strcmp(opt,"ro") == 0)
+ cur_host.options &= ~OPT_RW;
+ else if (strcmp(opt,"removable") == 0) {
+ cur_host.options |= OPT_REMOVABLE;
+ } else if (strcmp(opt,"fixed") == 0)
+ cur_host.options &= ~OPT_REMOVABLE;
+ else if (strcmp(opt,"insecure") == 0)
+ cur_host.options |= OPT_INSECURE;
+ else if (strcmp(opt,"secure") == 0)
+ cur_host.options &= ~OPT_INSECURE;
+ else
+ logmsg(LOG_WARNING, "Warning: unknown exports option `%s' ignored",
+ opt);
+}
+
+static void add_option_with_value(const char *opt, const char *val)
+{
+ if (strcmp(opt,"password") == 0) {
+ if (strlen(val) > PASSWORD_MAXLEN) {
+ logmsg(LOG_WARNING, "Warning: password for export %s truncated to 64 chars",
+ cur_item.orig);
+ }
+ strncpy(cur_host.password, val, sizeof(password));
+ cur_host.password[PASSWORD_MAXLEN] = '\0';
+ /* Calculate hash */
+ cur_host.password_hash = fnv1a_32(cur_host.password, 0);
+ } else if (strcmp(opt,"anonuid") == 0) {
+ cur_host.anonuid = atoi(val);
+ } else if (strcmp(opt,"anongid") == 0) {
+ cur_host.anongid = atoi(val);
+ } else {
+ logmsg(LOG_WARNING, "Warning: unknown exports option `%s' ignored",
+ opt);
+ }
+}
+
+/*
+ * dummy error function
+ */
+void yyerror(U(char *s))
+{
+ e_error = TRUE;
+ return;
+}
+
+%}
+
+%union {
+ char text[NFS_MAXPATHLEN];
+};
+
+%token <text> PATH
+%token <text> ID
+%token <text> OPTVALUE
+%token <text> WHITE
+%token <text> IP
+%token <text> NET
+%token <text> OLDNET
+
+%%
+
+exports:
+ export
+ | export '\n' exports
+ |
+ ;
+
+export:
+ PATH { add_item($1); }
+ | PATH WHITE hosts { add_item($1); }
+ | PATH WHITE { add_item($1); }
+ ;
+
+hosts:
+ host
+ | host WHITE hosts
+ | host WHITE
+ ;
+
+host:
+ name { add_host(); }
+ | name '(' opts ')' { add_host(); }
+ | '(' opts ')' { add_host(); }
+ ;
+
+name:
+ ID { set_hostname($1); }
+ | IP { set_ipaddr($1); }
+ | NET { set_ipnet($1, TRUE); }
+ | OLDNET { set_ipnet($1, FALSE); }
+ ;
+
+opts:
+ opt
+ | opt ',' opts
+ |
+ ;
+
+opt:
+ ID { add_option($1); }
+ | ID OPTVALUE { add_option_with_value($1,$2); }
+ ;
+%%
+
+/*
+ * C code using yacc parser + access code for exports list
+ */
+
+/* effective export list and access flag */
+static e_item *export_list = NULL;
+static volatile int exports_access = FALSE;
+
+/* mount protocol compatible exports list */
+exports exports_nfslist = NULL;
+
+/*
+ * free NFS groups list
+ */
+void free_nfsgroups(groups group)
+{
+ groups list, next;
+
+ list = group;
+ while (list) {
+ next = (groups) list->gr_next;
+ free(list);
+ list = next;
+ }
+}
+
+/*
+ * free NFS exports list
+ */
+void free_nfslist(exports elist)
+{
+ exports list, next;
+
+ list = elist;
+ while(list) {
+ next = (exports) list->ex_next;
+ free_nfsgroups(list->ex_groups);
+ free(list);
+ list = next;
+ }
+}
+
+/*
+ * free list of host structures
+ */
+static void free_hosts(e_item *item)
+{
+ e_host *host, *cur;
+
+ host = item->hosts;
+ while (host) {
+ cur = host;
+ host = (e_host *) host->next;
+ free(cur);
+ }
+}
+
+/*
+ * free list of export items
+ */
+static void free_list(e_item *item)
+{
+ e_item *cur;
+
+ while (item) {
+ free_hosts(item);
+ cur = item;
+ item = (e_item *) item->next;
+ free(cur);
+ }
+}
+
+/*
+ * print out the current exports list (for debugging)
+ */
+void print_list(void)
+{
+ char addrbuf[16], maskbuf[16];
+
+ e_item *item;
+ e_host *host;
+
+ item = e_list;
+
+ while (item) {
+ host = item->hosts;
+ while (host) {
+ /* inet_ntoa returns static buffer */
+ strcpy(addrbuf, inet_ntoa(host->addr));
+ strcpy(maskbuf, inet_ntoa(host->mask));
+ printf("%s: ip %s mask %s options %i\n",
+ item->path, addrbuf, maskbuf,
+ host->options);
+ host = (e_host *) host->next;
+ }
+ item = (e_item *) item->next;
+ }
+}
+
+/*
+ * clear current parse state
+ */
+static void clear_cur(void)
+{
+ e_list = NULL;
+ ne_list = NULL;
+ e_error = FALSE;
+ clear_host();
+ clear_item();
+}
+
+/*
+ * parse an exports file
+ */
+int exports_parse(void)
+{
+ FILE *efile;
+
+ /*
+ * if we are in the SIGHUP handler, a may_mount or get_options
+ * may currently be accessing the list
+ */
+ if (exports_access) {
+ logmsg(LOG_CRIT, "export list is being traversed, no reload\n");
+ return FALSE;
+ }
+
+ efile = fopen(opt_exports, "r");
+ if (!efile) {
+ logmsg(LOG_CRIT, "could not open '%s', exporting nothing",
+ opt_exports);
+ free_list(export_list);
+ free_nfslist(exports_nfslist);
+ export_list = NULL;
+ exports_nfslist = NULL;
+ return FALSE;
+ }
+
+ yyin = efile;
+ clear_cur();
+ yyparse();
+ fclose(efile);
+
+ if (e_error) {
+ logmsg(LOG_CRIT, "syntax error in '%s', exporting nothing",
+ opt_exports);
+ free_list(export_list);
+ free_nfslist(exports_nfslist);
+ export_list = NULL;
+ exports_nfslist = NULL;
+ return FALSE;
+ }
+
+ /* print out new list for debugging */
+ if (!opt_detach)
+ print_list();
+
+ free_list(export_list);
+ free_nfslist(exports_nfslist);
+ export_list = e_list;
+ exports_nfslist = ne_list;
+ return TRUE;
+}
+
+/*
+ * find a given host inside a host list, return options
+ */
+static e_host* find_host(struct in_addr remote, e_item *item,
+ char **password, uint32 *password_hash)
+{
+ e_host *host;
+
+ host = item->hosts;
+ while (host) {
+ if ((remote.s_addr & host->mask.s_addr) == host->addr.s_addr) {
+ if (password != NULL)
+ *password = host->password;
+ if (password_hash != NULL)
+ *password_hash = host->password_hash;
+ return host;
+ }
+ host = (e_host *) host->next;
+ }
+ return NULL;
+}
+
+/* options cache */
+int exports_opts = -1;
+const char *export_path = NULL;
+uint32 export_fsid = 0;
+uint32 export_password_hash = 0;
+
+/*
+ * given a path, return client's effective options
+ */
+int exports_options(const char *path, struct svc_req *rqstp,
+ char **password, uint32 *fsid)
+{
+ e_item *list;
+ struct in_addr remote;
+ unsigned int last_len = 0;
+
+ exports_opts = -1;
+ export_path = NULL;
+ export_fsid = 0;
+ last_anonuid = ANON_NOTSPECIAL;
+ last_anongid = ANON_NOTSPECIAL;
+
+ /* check for client attempting to use invalid pathname */
+ if (!path || strstr(path, "/../"))
+ return exports_opts;
+
+ remote = get_remote(rqstp);
+
+ /* protect against SIGHUP reloading the list */
+ exports_access = TRUE;
+
+ list = export_list;
+ while (list) {
+ /* longest matching prefix wins */
+ if (strlen(list->path) > last_len &&
+#ifndef WIN32
+ strstr(path, list->path) == path) {
+#else
+ !win_utf8ncasecmp(path, list->path, strlen(list->path))) {
+#endif
+ e_host* cur_host = find_host(remote, list, password, &export_password_hash);
+
+ if (fsid != NULL)
+ *fsid = list->fsid;
+ if (cur_host) {
+ exports_opts = cur_host->options;
+ export_path = list->path;
+ export_fsid = list->fsid;
+ last_len = strlen(list->path);
+ last_anonuid = cur_host->anonuid;
+ last_anongid = cur_host->anongid;
+ }
+ }
+ list = (e_item *) list->next;
+ }
+ exports_access = FALSE;
+ return exports_opts;
+}
+
+/*
+ * check whether path is an export point
+ */
+int export_point(const char *path)
+{
+ e_item *list;
+
+ exports_access = TRUE;
+ list = export_list;
+
+ while (list) {
+ if (strcmp(path, list->path) == 0) {
+ exports_access = FALSE;
+ return TRUE;
+ }
+ list = (e_item *) list->next;
+ }
+ exports_access = FALSE;
+ return FALSE;
+}
+
+/*
+ * return exported path from static fsid
+ */
+char *export_point_from_fsid(uint32 fsid, time_t **last_mtime, uint32 **dir_hash)
+{
+ e_item *list;
+
+ exports_access = TRUE;
+ list = export_list;
+
+ while (list) {
+ if (list->fsid == fsid) {
+ if (last_mtime != NULL)
+ *last_mtime = &list->last_mtime;
+ if (dir_hash != NULL)
+ *dir_hash = &list->dir_hash;
+ exports_access = FALSE;
+ return list->path;
+ }
+ list = (e_item *) list->next;
+ }
+ exports_access = FALSE;
+ return NULL;
+}
+
+
+/*
+ * check whether export options of a path match with last set of options
+ */
+nfsstat3 exports_compat(const char *path, struct svc_req *rqstp)
+{
+ int prev;
+ uint32 prev_anonuid, prev_anongid;
+
+ prev = exports_opts;
+ prev_anonuid = last_anonuid;
+ prev_anongid = last_anongid;
+
+ if (exports_options(path, rqstp, NULL, NULL) == prev &&
+ last_anonuid == prev_anonuid &&
+ last_anongid == prev_anongid)
+ return NFS3_OK;
+ else if (exports_opts == -1)
+ return NFS3ERR_ACCES;
+ else
+ return NFS3ERR_XDEV;
+}
+
+/*
+ * check whether options indicate rw mount
+ */
+nfsstat3 exports_rw(void)
+{
+ if (exports_opts != -1 && (exports_opts & OPT_RW))
+ return NFS3_OK;
+ else
+ return NFS3ERR_ROFS;
+}
+
+/*
+ * returns the last looked-up anonuid for a mount (ANON_NOTSPECIAL means none in effect)
+ */
+uint32 exports_anonuid(void)
+{
+ return last_anonuid;
+}
+
+/*
+ * returns the last looked-up anongid for a mount (ANON_NOTSPECIAL means none in effect)
+ */
+uint32 exports_anongid(void)
+{
+ return last_anongid;
+}
diff --git a/external/fs/unfs3-0.9.22/Config/lex.yy.c b/external/fs/unfs3-0.9.22/Config/lex.yy.c
new file mode 100644
index 0000000..ef61cc2
--- /dev/null
+++ b/external/fs/unfs3-0.9.22/Config/lex.yy.c
@@ -0,0 +1,1664 @@
+/* A lexical scanner generated by flex */
+
+/* Scanner skeleton version:
+ * $Header: /home/daffy/u0/vern/flex/RCS/flex.skl,v 2.91 96/09/10 16:58:48 vern Exp $
+ */
+
+#define FLEX_SCANNER
+#define YY_FLEX_MAJOR_VERSION 2
+#define YY_FLEX_MINOR_VERSION 5
+
+#include <stdio.h>
+#include <errno.h>
+
+/* cfront 1.2 defines "c_plusplus" instead of "__cplusplus" */
+#ifdef c_plusplus
+#ifndef __cplusplus
+#define __cplusplus
+#endif
+#endif
+
+
+#ifdef __cplusplus
+
+#include <stdlib.h>
+#ifndef _WIN32
+#include <unistd.h>
+#endif
+
+/* Use prototypes in function declarations. */
+#define YY_USE_PROTOS
+
+/* The "const" storage-class-modifier is valid. */
+#define YY_USE_CONST
+
+#else /* ! __cplusplus */
+
+#if __STDC__
+
+#define YY_USE_PROTOS
+#define YY_USE_CONST
+
+#endif /* __STDC__ */
+#endif /* ! __cplusplus */
+
+#ifdef __TURBOC__
+ #pragma warn -rch
+ #pragma warn -use
+#include <io.h>
+#include <stdlib.h>
+#define YY_USE_CONST
+#define YY_USE_PROTOS
+#endif
+
+#ifdef YY_USE_CONST
+#define yyconst const
+#else
+#define yyconst
+#endif
+
+
+#ifdef YY_USE_PROTOS
+#define YY_PROTO(proto) proto
+#else
+#define YY_PROTO(proto) ()
+#endif
+
+
+/* Returned upon end-of-file. */
+#define YY_NULL 0
+
+/* Promotes a possibly negative, possibly signed char to an unsigned
+ * integer for use as an array index. If the signed char is negative,
+ * we want to instead treat it as an 8-bit unsigned char, hence the
+ * double cast.
+ */
+#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c)
+
+/* Enter a start condition. This macro really ought to take a parameter,
+ * but we do it the disgusting crufty way forced on us by the ()-less
+ * definition of BEGIN.
+ */
+#define BEGIN yy_start = 1 + 2 *
+
+/* Translate the current start state into a value that can be later handed
+ * to BEGIN to return to the state. The YYSTATE alias is for lex
+ * compatibility.
+ */
+#define YY_START ((yy_start - 1) / 2)
+#define YYSTATE YY_START
+
+/* Action number for EOF rule of a given start state. */
+#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
+
+/* Special action meaning "start processing a new file". */
+#define YY_NEW_FILE yyrestart( yyin )
+
+#define YY_END_OF_BUFFER_CHAR 0
+
+/* Size of default input buffer. */
+#define YY_BUF_SIZE 16384
+
+typedef struct yy_buffer_state *YY_BUFFER_STATE;
+
+extern int yyleng;
+extern FILE *yyin, *yyout;
+
+#define EOB_ACT_CONTINUE_SCAN 0
+#define EOB_ACT_END_OF_FILE 1
+#define EOB_ACT_LAST_MATCH 2
+
+/* The funky do-while in the following #define is used to turn the definition
+ * int a single C statement (which needs a semi-colon terminator). This
+ * avoids problems with code like:
+ *
+ * if ( condition_holds )
+ * yyless( 5 );
+ * else
+ * do_something_else();
+ *
+ * Prior to using the do-while the compiler would get upset at the
+ * "else" because it interpreted the "if" statement as being all
+ * done when it reached the ';' after the yyless() call.
+ */
+
+/* Return all but the first 'n' matched characters back to the input stream. */
+
+#define yyless(n) \
+ do \
+ { \
+ /* Undo effects of setting up yytext. */ \
+ *yy_cp = yy_hold_char; \
+ YY_RESTORE_YY_MORE_OFFSET \
+ yy_c_buf_p = yy_cp = yy_bp + n - YY_MORE_ADJ; \
+ YY_DO_BEFORE_ACTION; /* set up yytext again */ \
+ } \
+ while ( 0 )
+
+#define unput(c) yyunput( c, yytext_ptr )
+
+/* The following is because we cannot portably get our hands on size_t
+ * (without autoconf's help, which isn't available because we want
+ * flex-generated scanners to compile on their own).
+ */
+typedef unsigned int yy_size_t;
+
+
+struct yy_buffer_state
+ {
+ FILE *yy_input_file;
+
+ char *yy_ch_buf; /* input buffer */
+ char *yy_buf_pos; /* current position in input buffer */
+
+ /* Size of input buffer in bytes, not including room for EOB
+ * characters.
+ */
+ yy_size_t yy_buf_size;
+
+ /* Number of characters read into yy_ch_buf, not including EOB
+ * characters.
+ */
+ int yy_n_chars;
+
+ /* Whether we "own" the buffer - i.e., we know we created it,
+ * and can realloc() it to grow it, and should free() it to
+ * delete it.
+ */
+ int yy_is_our_buffer;
+
+ /* Whether this is an "interactive" input source; if so, and
+ * if we're using stdio for input, then we want to use getc()
+ * instead of fread(), to make sure we stop fetching input after
+ * each newline.
+ */
+ int yy_is_interactive;
+
+ /* Whether we're considered to be at the beginning of a line.
+ * If so, '^' rules will be active on the next match, otherwise
+ * not.
+ */
+ int yy_at_bol;
+
+ /* Whether to try to fill the input buffer when we reach the
+ * end of it.
+ */
+ int yy_fill_buffer;
+
+ int yy_buffer_status;
+#define YY_BUFFER_NEW 0
+#define YY_BUFFER_NORMAL 1
+ /* When an EOF's been seen but there's still some text to process
+ * then we mark the buffer as YY_EOF_PENDING, to indicate that we
+ * shouldn't try reading from the input source any more. We might
+ * still have a bunch of tokens to match, though, because of
+ * possible backing-up.
+ *
+ * When we actually see the EOF, we change the status to "new"
+ * (via yyrestart()), so that the user can continue scanning by
+ * just pointing yyin at a new input file.
+ */
+#define YY_BUFFER_EOF_PENDING 2
+ };
+
+static YY_BUFFER_STATE yy_current_buffer = 0;
+
+/* We provide macros for accessing buffer states in case in the
+ * future we want to put the buffer states in a more general
+ * "scanner state".
+ */
+#define YY_CURRENT_BUFFER yy_current_buffer
+
+
+/* yy_hold_char holds the character lost when yytext is formed. */
+static char yy_hold_char;
+
+static int yy_n_chars; /* number of characters read into yy_ch_buf */
+
+
+int yyleng;
+
+/* Points to current character in buffer. */
+static char *yy_c_buf_p = (char *) 0;
+static int yy_init = 1; /* whether we need to initialize */
+static int yy_start = 0; /* start state number */
+
+/* Flag which is used to allow yywrap()'s to do buffer switches
+ * instead of setting up a fresh yyin. A bit of a hack ...
+ */
+static int yy_did_buffer_switch_on_eof;
+
+void yyrestart YY_PROTO(( FILE *input_file ));
+
+void yy_switch_to_buffer YY_PROTO(( YY_BUFFER_STATE new_buffer ));
+void yy_load_buffer_state YY_PROTO(( void ));
+YY_BUFFER_STATE yy_create_buffer YY_PROTO(( FILE *file, int size ));
+void yy_delete_buffer YY_PROTO(( YY_BUFFER_STATE b ));
+void yy_init_buffer YY_PROTO(( YY_BUFFER_STATE b, FILE *file ));
+void yy_flush_buffer YY_PROTO(( YY_BUFFER_STATE b ));
+#define YY_FLUSH_BUFFER yy_flush_buffer( yy_current_buffer )
+
+YY_BUFFER_STATE yy_scan_buffer YY_PROTO(( char *base, yy_size_t size ));
+YY_BUFFER_STATE yy_scan_string YY_PROTO(( yyconst char *yy_str ));
+YY_BUFFER_STATE yy_scan_bytes YY_PROTO(( yyconst char *bytes, int len ));
+
+static void *yy_flex_alloc YY_PROTO(( yy_size_t ));
+static void *yy_flex_realloc YY_PROTO(( void *, yy_size_t ));
+static void yy_flex_free YY_PROTO(( void * ));
+
+#define yy_new_buffer yy_create_buffer
+
+#define yy_set_interactive(is_interactive) \
+ { \
+ if ( ! yy_current_buffer ) \
+ yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \
+ yy_current_buffer->yy_is_interactive = is_interactive; \
+ }
+
+#define yy_set_bol(at_bol) \
+ { \
+ if ( ! yy_current_buffer ) \
+ yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \
+ yy_current_buffer->yy_at_bol = at_bol; \
+ }
+
+#define YY_AT_BOL() (yy_current_buffer->yy_at_bol)
+
+typedef unsigned char YY_CHAR;
+FILE *yyin = (FILE *) 0, *yyout = (FILE *) 0;
+typedef int yy_state_type;
+extern char *yytext;
+#define yytext_ptr yytext
+
+static yy_state_type yy_get_previous_state YY_PROTO(( void ));
+static yy_state_type yy_try_NUL_trans YY_PROTO(( yy_state_type current_state ));
+static int yy_get_next_buffer YY_PROTO(( void ));
+static void yy_fatal_error YY_PROTO(( yyconst char msg[] ));
+
+/* Done after the current pattern has been matched and before the
+ * corresponding action - sets up yytext.
+ */
+#define YY_DO_BEFORE_ACTION \
+ yytext_ptr = yy_bp; \
+ yyleng = (int) (yy_cp - yy_bp); \
+ yy_hold_char = *yy_cp; \
+ *yy_cp = '\0'; \
+ yy_c_buf_p = yy_cp;
+
+#define YY_NUM_RULES 16
+#define YY_END_OF_BUFFER 17
+static yyconst short int yy_accept[62] =
+ { 0,
+ 0, 2, 17, 14, 12, 15, 14, 5, 11, 14,
+ 10, 14, 13, 2, 1, 5, 12, 5, 0, 9,
+ 5, 11, 0, 0, 10, 3, 13, 2, 1, 5,
+ 5, 4, 0, 0, 0, 0, 0, 0, 0, 0,
+ 6, 0, 0, 6, 7, 6, 0, 7, 0, 0,
+ 0, 0, 0, 0, 0, 0, 8, 0, 8, 8,
+ 0
+ } ;
+
+static yyconst int yy_ec[256] =
+ { 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 2, 3,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 2, 1, 4, 5, 1, 1, 1, 1, 1,
+ 6, 1, 1, 6, 7, 8, 9, 10, 10, 10,
+ 10, 10, 10, 10, 10, 10, 10, 1, 1, 1,
+ 11, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 12, 1, 1, 7, 1, 13, 13, 13, 13,
+
+ 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+ 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+ 13, 13, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1
+ } ;
+
+static yyconst int yy_meta[14] =
+ { 0,
+ 1, 2, 3, 1, 1, 4, 5, 5, 1, 5,
+ 1, 1, 5
+ } ;
+
+static yyconst short int yy_base[68] =
+ { 0,
+ 0, 12, 85, 86, 16, 86, 80, 0, 0, 14,
+ 0, 80, 0, 23, 86, 79, 0, 0, 77, 76,
+ 0, 0, 69, 68, 0, 86, 0, 0, 86, 74,
+ 73, 86, 21, 67, 64, 63, 24, 64, 61, 54,
+ 26, 55, 52, 48, 29, 48, 43, 38, 32, 36,
+ 31, 28, 35, 25, 20, 17, 13, 12, 9, 86,
+ 86, 45, 50, 55, 60, 11, 65
+ } ;
+
+static yyconst short int yy_def[68] =
+ { 0,
+ 61, 1, 61, 61, 61, 61, 62, 63, 64, 61,
+ 65, 61, 66, 61, 61, 67, 5, 63, 62, 62,
+ 63, 64, 61, 10, 65, 61, 66, 14, 61, 67,
+ 67, 61, 61, 61, 61, 33, 61, 61, 61, 37,
+ 61, 61, 61, 41, 61, 61, 61, 45, 61, 61,
+ 61, 49, 61, 61, 61, 53, 61, 61, 61, 61,
+ 0, 61, 61, 61, 61, 61, 61
+ } ;
+
+static yyconst short int yy_nxt[100] =
+ { 0,
+ 4, 5, 6, 7, 8, 4, 4, 4, 9, 10,
+ 11, 12, 13, 14, 15, 27, 16, 17, 60, 55,
+ 18, 23, 59, 24, 28, 29, 58, 30, 35, 57,
+ 36, 39, 51, 40, 43, 44, 47, 54, 48, 51,
+ 53, 52, 55, 47, 56, 19, 19, 50, 19, 19,
+ 21, 21, 49, 21, 21, 22, 43, 46, 22, 22,
+ 25, 45, 39, 42, 25, 31, 31, 31, 31, 31,
+ 41, 35, 38, 37, 23, 32, 32, 34, 33, 20,
+ 20, 32, 26, 20, 61, 3, 61, 61, 61, 61,
+ 61, 61, 61, 61, 61, 61, 61, 61, 61
+
+ } ;
+
+static yyconst short int yy_chk[100] =
+ { 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 2, 2, 66, 2, 5, 59, 58,
+ 5, 10, 57, 10, 14, 14, 56, 14, 33, 55,
+ 33, 37, 54, 37, 41, 41, 45, 52, 45, 49,
+ 51, 49, 53, 50, 53, 62, 62, 48, 62, 62,
+ 63, 63, 47, 63, 63, 64, 46, 44, 64, 64,
+ 65, 43, 42, 40, 65, 67, 67, 67, 67, 67,
+ 39, 38, 36, 35, 34, 31, 30, 24, 23, 20,
+ 19, 16, 12, 7, 3, 61, 61, 61, 61, 61,
+ 61, 61, 61, 61, 61, 61, 61, 61, 61
+
+ } ;
+
+static yy_state_type yy_last_accepting_state;
+static char *yy_last_accepting_cpos;
+
+/* The intent behind this definition is that it'll catch
+ * any uses of REJECT which flex missed.
+ */
+#define REJECT reject_used_but_not_detected
+#define yymore() yymore_used_but_not_detected
+#define YY_MORE_ADJ 0
+#define YY_RESTORE_YY_MORE_OFFSET
+char *yytext;
+#line 1 "exports.l"
+#define INITIAL 0
+#line 2 "exports.l"
+/*
+ * UNFS3 exports lexer
+ * (C) 2003, Pascal Schmidt
+ * see file LICENSE for license details
+ */
+#include "../config.h"
+
+#include <rpc/rpc.h>
+#include <string.h>
+
+#include "../nfs.h"
+#include "y.tab.h"
+
+#define YY_NO_UNPUT
+
+YYSTYPE yylval;
+extern int e_error;
+
+/*
+ * copy matching text to yylval.text
+ */
+static void copy_text(const char *from, int leng)
+{
+ int len;
+
+ /* check length to prevent buffer overflow */
+ if (leng + 1 > NFS_MAXPATHLEN) {
+ len = NFS_MAXPATHLEN - 1;
+ e_error = 1;
+ } else
+ len = leng;
+
+ memcpy(yylval.text, from, len);
+ yylval.text[len] = 0;
+}
+#line 441 "lex.yy.c"
+
+/* Macros after this point can all be overridden by user definitions in
+ * section 1.
+ */
+
+#ifndef YY_SKIP_YYWRAP
+#ifdef __cplusplus
+extern "C" int yywrap YY_PROTO(( void ));
+#else
+extern int yywrap YY_PROTO(( void ));
+#endif
+#endif
+
+#ifndef YY_NO_UNPUT
+static void yyunput YY_PROTO(( int c, char *buf_ptr ));
+#endif
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy YY_PROTO(( char *, yyconst char *, int ));
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen YY_PROTO(( yyconst char * ));
+#endif
+
+#ifndef YY_NO_INPUT
+#ifdef __cplusplus
+static int yyinput YY_PROTO(( void ));
+#else
+static int input YY_PROTO(( void ));
+#endif
+#endif
+
+#if YY_STACK_USED
+static int yy_start_stack_ptr = 0;
+static int yy_start_stack_depth = 0;
+static int *yy_start_stack = 0;
+#ifndef YY_NO_PUSH_STATE
+static void yy_push_state YY_PROTO(( int new_state ));
+#endif
+#ifndef YY_NO_POP_STATE
+static void yy_pop_state YY_PROTO(( void ));
+#endif
+#ifndef YY_NO_TOP_STATE
+static int yy_top_state YY_PROTO(( void ));
+#endif
+
+#else
+#define YY_NO_PUSH_STATE 1
+#define YY_NO_POP_STATE 1
+#define YY_NO_TOP_STATE 1
+#endif
+
+#ifdef YY_MALLOC_DECL
+YY_MALLOC_DECL
+#else
+#if __STDC__
+#ifndef __cplusplus
+#include <stdlib.h>
+#endif
+#else
+/* Just try to get by without declaring the routines. This will fail
+ * miserably on non-ANSI systems for which sizeof(size_t) != sizeof(int)
+ * or sizeof(void*) != sizeof(int).
+ */
+#endif
+#endif
+
+/* Amount of stuff to slurp up with each read. */
+#ifndef YY_READ_BUF_SIZE
+#define YY_READ_BUF_SIZE 8192
+#endif
+
+/* Copy whatever the last rule matched to the standard output. */
+
+#ifndef ECHO
+/* This used to be an fputs(), but since the string might contain NUL's,
+ * we now use fwrite().
+ */
+#define ECHO (void) fwrite( yytext, yyleng, 1, yyout )
+#endif
+
+/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL,
+ * is returned in "result".
+ */
+#ifndef YY_INPUT
+#define YY_INPUT(buf,result,max_size) \
+ if ( yy_current_buffer->yy_is_interactive ) \
+ { \
+ int c = '*', n; \
+ for ( n = 0; n < max_size && \
+ (c = getc( yyin )) != EOF && c != '\n'; ++n ) \
+ buf[n] = (char) c; \
+ if ( c == '\n' ) \
+ buf[n++] = (char) c; \
+ if ( c == EOF && ferror( yyin ) ) \
+ YY_FATAL_ERROR( "input in flex scanner failed" ); \
+ result = n; \
+ } \
+ else \
+ { \
+ errno=0; \
+ while ( (result = fread(buf, 1, max_size, yyin))==0 && ferror(yyin)) \
+ { \
+ if( errno != EINTR) \
+ { \
+ YY_FATAL_ERROR( "input in flex scanner failed" ); \
+ break; \
+ } \
+ errno=0; \
+ clearerr(yyin); \
+ } \
+ }
+#endif
+
+/* No semi-colon after return; correct usage is to write "yyterminate();" -
+ * we don't want an extra ';' after the "return" because that will cause
+ * some compilers to complain about unreachable statements.
+ */
+#ifndef yyterminate
+#define yyterminate() return YY_NULL
+#endif
+
+/* Number of entries by which start-condition stack grows. */
+#ifndef YY_START_STACK_INCR
+#define YY_START_STACK_INCR 25
+#endif
+
+/* Report a fatal error. */
+#ifndef YY_FATAL_ERROR
+#define YY_FATAL_ERROR(msg) yy_fatal_error( msg )
+#endif
+
+/* Default declaration of generated scanner - a define so the user can
+ * easily add parameters.
+ */
+#ifndef YY_DECL
+#define YY_DECL int yylex YY_PROTO(( void ))
+#endif
+
+/* Code executed at the beginning of each rule, after yytext and yyleng
+ * have been set up.
+ */
+#ifndef YY_USER_ACTION
+#define YY_USER_ACTION
+#endif
+
+/* Code executed at the end of each rule. */
+#ifndef YY_BREAK
+#define YY_BREAK break;
+#endif
+
+#define YY_RULE_SETUP \
+ if ( yyleng > 0 ) \
+ yy_current_buffer->yy_at_bol = \
+ (yytext[yyleng - 1] == '\n'); \
+ YY_USER_ACTION
+
+YY_DECL
+ {
+ register yy_state_type yy_current_state;
+ register char *yy_cp, *yy_bp;
+ register int yy_act;
+
+#line 51 "exports.l"
+
+
+#line 609 "lex.yy.c"
+
+ if ( yy_init )
+ {
+ yy_init = 0;
+
+#ifdef YY_USER_INIT
+ YY_USER_INIT;
+#endif
+
+ if ( ! yy_start )
+ yy_start = 1; /* first start state */
+
+ if ( ! yyin )
+ yyin = stdin;
+
+ if ( ! yyout )
+ yyout = stdout;
+
+ if ( ! yy_current_buffer )
+ yy_current_buffer =
+ yy_create_buffer( yyin, YY_BUF_SIZE );
+
+ yy_load_buffer_state();
+ }
+
+ while ( 1 ) /* loops until end-of-file is reached */
+ {
+ yy_cp = yy_c_buf_p;
+
+ /* Support of yytext. */
+ *yy_cp = yy_hold_char;
+
+ /* yy_bp points to the position in yy_ch_buf of the start of
+ * the current run.
+ */
+ yy_bp = yy_cp;
+
+ yy_current_state = yy_start;
+ yy_current_state += YY_AT_BOL();
+yy_match:
+ do
+ {
+ register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)];
+ if ( yy_accept[yy_current_state] )
+ {
+ yy_last_accepting_state = yy_current_state;
+ yy_last_accepting_cpos = yy_cp;
+ }
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+ if ( yy_current_state >= 62 )
+ yy_c = yy_meta[(unsigned int) yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+ ++yy_cp;
+ }
+ while ( yy_base[yy_current_state] != 86 );
+
+yy_find_action:
+ yy_act = yy_accept[yy_current_state];
+ if ( yy_act == 0 )
+ { /* have to back up */
+ yy_cp = yy_last_accepting_cpos;
+ yy_current_state = yy_last_accepting_state;
+ yy_act = yy_accept[yy_current_state];
+ }
+
+ YY_DO_BEFORE_ACTION;
+
+
+do_action: /* This label is used only to access EOF actions. */
+
+
+ switch ( yy_act )
+ { /* beginning of action switch */
+ case 0: /* must back up */
+ /* undo the effects of YY_DO_BEFORE_ACTION */
+ *yy_cp = yy_hold_char;
+ yy_cp = yy_last_accepting_cpos;
+ yy_current_state = yy_last_accepting_state;
+ goto yy_find_action;
+
+case 1:
+YY_RULE_SETUP
+#line 53 "exports.l"
+{ /* eat empty line */ }
+ YY_BREAK
+case 2:
+YY_RULE_SETUP
+#line 54 "exports.l"
+{ /* eat whitespace at beginning of line */ }
+ YY_BREAK
+case 3:
+YY_RULE_SETUP
+#line 55 "exports.l"
+{ /* eat escaped newline */ }
+ YY_BREAK
+case 4:
+YY_RULE_SETUP
+#line 56 "exports.l"
+{ /* eat one-line comment */ }
+ YY_BREAK
+case 5:
+YY_RULE_SETUP
+#line 57 "exports.l"
+{ /* eat trailing comment */ }
+ YY_BREAK
+case 6:
+YY_RULE_SETUP
+#line 59 "exports.l"
+{ copy_text(yytext, yyleng); return IP; }
+ YY_BREAK
+case 7:
+YY_RULE_SETUP
+#line 60 "exports.l"
+{ copy_text(yytext, yyleng); return NET; }
+ YY_BREAK
+case 8:
+YY_RULE_SETUP
+#line 61 "exports.l"
+{ copy_text(yytext, yyleng); return OLDNET; }
+ YY_BREAK
+case 9:
+YY_RULE_SETUP
+#line 62 "exports.l"
+{ copy_text(yytext+1, yyleng-2); return PATH; }
+ YY_BREAK
+case 10:
+YY_RULE_SETUP
+#line 63 "exports.l"
+{ copy_text(yytext+1, yyleng-1); return OPTVALUE; }
+ YY_BREAK
+case 11:
+YY_RULE_SETUP
+#line 64 "exports.l"
+{ copy_text(yytext, yyleng); return PATH; }
+ YY_BREAK
+case 12:
+YY_RULE_SETUP
+#line 65 "exports.l"
+{ copy_text(yytext, yyleng); return WHITE; }
+ YY_BREAK
+case 13:
+YY_RULE_SETUP
+#line 66 "exports.l"
+{ copy_text(yytext, yyleng); return ID; }
+ YY_BREAK
+case 14:
+YY_RULE_SETUP
+#line 68 "exports.l"
+{ return *yytext; }
+ YY_BREAK
+case 15:
+YY_RULE_SETUP
+#line 69 "exports.l"
+{ return '\n'; }
+ YY_BREAK
+case 16:
+YY_RULE_SETUP
+#line 70 "exports.l"
+ECHO;
+ YY_BREAK
+#line 773 "lex.yy.c"
+case YY_STATE_EOF(INITIAL):
+ yyterminate();
+
+ case YY_END_OF_BUFFER:
+ {
+ /* Amount of text matched not including the EOB char. */
+ int yy_amount_of_matched_text = (int) (yy_cp - yytext_ptr) - 1;
+
+ /* Undo the effects of YY_DO_BEFORE_ACTION. */
+ *yy_cp = yy_hold_char;
+ YY_RESTORE_YY_MORE_OFFSET
+
+ if ( yy_current_buffer->yy_buffer_status == YY_BUFFER_NEW )
+ {
+ /* We're scanning a new file or input source. It's
+ * possible that this happened because the user
+ * just pointed yyin at a new source and called
+ * yylex(). If so, then we have to assure
+ * consistency between yy_current_buffer and our
+ * globals. Here is the right place to do so, because
+ * this is the first action (other than possibly a
+ * back-up) that will match for the new input source.
+ */
+ yy_n_chars = yy_current_buffer->yy_n_chars;
+ yy_current_buffer->yy_input_file = yyin;
+ yy_current_buffer->yy_buffer_status = YY_BUFFER_NORMAL;
+ }
+
+ /* Note that here we test for yy_c_buf_p "<=" to the position
+ * of the first EOB in the buffer, since yy_c_buf_p will
+ * already have been incremented past the NUL character
+ * (since all states make transitions on EOB to the
+ * end-of-buffer state). Contrast this with the test
+ * in input().
+ */
+ if ( yy_c_buf_p <= &yy_current_buffer->yy_ch_buf[yy_n_chars] )
+ { /* This was really a NUL. */
+ yy_state_type yy_next_state;
+
+ yy_c_buf_p = yytext_ptr + yy_amount_of_matched_text;
+
+ yy_current_state = yy_get_previous_state();
+
+ /* Okay, we're now positioned to make the NUL
+ * transition. We couldn't have
+ * yy_get_previous_state() go ahead and do it
+ * for us because it doesn't know how to deal
+ * with the possibility of jamming (and we don't
+ * want to build jamming into it because then it
+ * will run more slowly).
+ */
+
+ yy_next_state = yy_try_NUL_trans( yy_current_state );
+
+ yy_bp = yytext_ptr + YY_MORE_ADJ;
+
+ if ( yy_next_state )
+ {
+ /* Consume the NUL. */
+ yy_cp = ++yy_c_buf_p;
+ yy_current_state = yy_next_state;
+ goto yy_match;
+ }
+
+ else
+ {
+ yy_cp = yy_c_buf_p;
+ goto yy_find_action;
+ }
+ }
+
+ else switch ( yy_get_next_buffer() )
+ {
+ case EOB_ACT_END_OF_FILE:
+ {
+ yy_did_buffer_switch_on_eof = 0;
+
+ if ( yywrap() )
+ {
+ /* Note: because we've taken care in
+ * yy_get_next_buffer() to have set up
+ * yytext, we can now set up
+ * yy_c_buf_p so that if some total
+ * hoser (like flex itself) wants to
+ * call the scanner after we return the
+ * YY_NULL, it'll still work - another
+ * YY_NULL will get returned.
+ */
+ yy_c_buf_p = yytext_ptr + YY_MORE_ADJ;
+
+ yy_act = YY_STATE_EOF(YY_START);
+ goto do_action;
+ }
+
+ else
+ {
+ if ( ! yy_did_buffer_switch_on_eof )
+ YY_NEW_FILE;
+ }
+ break;
+ }
+
+ case EOB_ACT_CONTINUE_SCAN:
+ yy_c_buf_p =
+ yytext_ptr + yy_amount_of_matched_text;
+
+ yy_current_state = yy_get_previous_state();
+
+ yy_cp = yy_c_buf_p;
+ yy_bp = yytext_ptr + YY_MORE_ADJ;
+ goto yy_match;
+
+ case EOB_ACT_LAST_MATCH:
+ yy_c_buf_p =
+ &yy_current_buffer->yy_ch_buf[yy_n_chars];
+
+ yy_current_state = yy_get_previous_state();
+
+ yy_cp = yy_c_buf_p;
+ yy_bp = yytext_ptr + YY_MORE_ADJ;
+ goto yy_find_action;
+ }
+ break;
+ }
+
+ default:
+ YY_FATAL_ERROR(
+ "fatal flex scanner internal error--no action found" );
+ } /* end of action switch */
+ } /* end of scanning one token */
+ } /* end of yylex */
+
+
+/* yy_get_next_buffer - try to read in a new buffer
+ *
+ * Returns a code representing an action:
+ * EOB_ACT_LAST_MATCH -
+ * EOB_ACT_CONTINUE_SCAN - continue scanning from current position
+ * EOB_ACT_END_OF_FILE - end of file
+ */
+
+static int yy_get_next_buffer()
+ {
+ register char *dest = yy_current_buffer->yy_ch_buf;
+ register char *source = yytext_ptr;
+ register int number_to_move, i;
+ int ret_val;
+
+ if ( yy_c_buf_p > &yy_current_buffer->yy_ch_buf[yy_n_chars + 1] )
+ YY_FATAL_ERROR(
+ "fatal flex scanner internal error--end of buffer missed" );
+
+ if ( yy_current_buffer->yy_fill_buffer == 0 )
+ { /* Don't try to fill the buffer, so this is an EOF. */
+ if ( yy_c_buf_p - yytext_ptr - YY_MORE_ADJ == 1 )
+ {
+ /* We matched a single character, the EOB, so
+ * treat this as a final EOF.
+ */
+ return EOB_ACT_END_OF_FILE;
+ }
+
+ else
+ {
+ /* We matched some text prior to the EOB, first
+ * process it.
+ */
+ return EOB_ACT_LAST_MATCH;
+ }
+ }
+
+ /* Try to read more data. */
+
+ /* First move last chars to start of buffer. */
+ number_to_move = (int) (yy_c_buf_p - yytext_ptr) - 1;
+
+ for ( i = 0; i < number_to_move; ++i )
+ *(dest++) = *(source++);
+
+ if ( yy_current_buffer->yy_buffer_status == YY_BUFFER_EOF_PENDING )
+ /* don't do the read, it's not guaranteed to return an EOF,
+ * just force an EOF
+ */
+ yy_current_buffer->yy_n_chars = yy_n_chars = 0;
+
+ else
+ {
+ int num_to_read =
+ yy_current_buffer->yy_buf_size - number_to_move - 1;
+
+ while ( num_to_read <= 0 )
+ { /* Not enough room in the buffer - grow it. */
+#ifdef YY_USES_REJECT
+ YY_FATAL_ERROR(
+"input buffer overflow, can't enlarge buffer because scanner uses REJECT" );
+#else
+
+ /* just a shorter name for the current buffer */
+ YY_BUFFER_STATE b = yy_current_buffer;
+
+ int yy_c_buf_p_offset =
+ (int) (yy_c_buf_p - b->yy_ch_buf);
+
+ if ( b->yy_is_our_buffer )
+ {
+ int new_size = b->yy_buf_size * 2;
+
+ if ( new_size <= 0 )
+ b->yy_buf_size += b->yy_buf_size / 8;
+ else
+ b->yy_buf_size *= 2;
+
+ b->yy_ch_buf = (char *)
+ /* Include room in for 2 EOB chars. */
+ yy_flex_realloc( (void *) b->yy_ch_buf,
+ b->yy_buf_size + 2 );
+ }
+ else
+ /* Can't grow it, we don't own it. */
+ b->yy_ch_buf = 0;
+
+ if ( ! b->yy_ch_buf )
+ YY_FATAL_ERROR(
+ "fatal error - scanner input buffer overflow" );
+
+ yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset];
+
+ num_to_read = yy_current_buffer->yy_buf_size -
+ number_to_move - 1;
+#endif
+ }
+
+ if ( num_to_read > YY_READ_BUF_SIZE )
+ num_to_read = YY_READ_BUF_SIZE;
+
+ /* Read in more data. */
+ YY_INPUT( (&yy_current_buffer->yy_ch_buf[number_to_move]),
+ yy_n_chars, num_to_read );
+
+ yy_current_buffer->yy_n_chars = yy_n_chars;
+ }
+
+ if ( yy_n_chars == 0 )
+ {
+ if ( number_to_move == YY_MORE_ADJ )
+ {
+ ret_val = EOB_ACT_END_OF_FILE;
+ yyrestart( yyin );
+ }
+
+ else
+ {
+ ret_val = EOB_ACT_LAST_MATCH;
+ yy_current_buffer->yy_buffer_status =
+ YY_BUFFER_EOF_PENDING;
+ }
+ }
+
+ else
+ ret_val = EOB_ACT_CONTINUE_SCAN;
+
+ yy_n_chars += number_to_move;
+ yy_current_buffer->yy_ch_buf[yy_n_chars] = YY_END_OF_BUFFER_CHAR;
+ yy_current_buffer->yy_ch_buf[yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR;
+
+ yytext_ptr = &yy_current_buffer->yy_ch_buf[0];
+
+ return ret_val;
+ }
+
+
+/* yy_get_previous_state - get the state just before the EOB char was reached */
+
+static yy_state_type yy_get_previous_state()
+ {
+ register yy_state_type yy_current_state;
+ register char *yy_cp;
+
+ yy_current_state = yy_start;
+ yy_current_state += YY_AT_BOL();
+
+ for ( yy_cp = yytext_ptr + YY_MORE_ADJ; yy_cp < yy_c_buf_p; ++yy_cp )
+ {
+ register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1);
+ if ( yy_accept[yy_current_state] )
+ {
+ yy_last_accepting_state = yy_current_state;
+ yy_last_accepting_cpos = yy_cp;
+ }
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+ if ( yy_current_state >= 62 )
+ yy_c = yy_meta[(unsigned int) yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+ }
+
+ return yy_current_state;
+ }
+
+
+/* yy_try_NUL_trans - try to make a transition on the NUL character
+ *
+ * synopsis
+ * next_state = yy_try_NUL_trans( current_state );
+ */
+
+#ifdef YY_USE_PROTOS
+static yy_state_type yy_try_NUL_trans( yy_state_type yy_current_state )
+#else
+static yy_state_type yy_try_NUL_trans( yy_current_state )
+yy_state_type yy_current_state;
+#endif
+ {
+ register int yy_is_jam;
+ register char *yy_cp = yy_c_buf_p;
+
+ register YY_CHAR yy_c = 1;
+ if ( yy_accept[yy_current_state] )
+ {
+ yy_last_accepting_state = yy_current_state;
+ yy_last_accepting_cpos = yy_cp;
+ }
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+ if ( yy_current_state >= 62 )
+ yy_c = yy_meta[(unsigned int) yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+ yy_is_jam = (yy_current_state == 61);
+
+ return yy_is_jam ? 0 : yy_current_state;
+ }
+
+
+#ifndef YY_NO_UNPUT
+#ifdef YY_USE_PROTOS
+static void yyunput( int c, register char *yy_bp )
+#else
+static void yyunput( c, yy_bp )
+int c;
+register char *yy_bp;
+#endif
+ {
+ register char *yy_cp = yy_c_buf_p;
+
+ /* undo effects of setting up yytext */
+ *yy_cp = yy_hold_char;
+
+ if ( yy_cp < yy_current_buffer->yy_ch_buf + 2 )
+ { /* need to shift things up to make room */
+ /* +2 for EOB chars. */
+ register int number_to_move = yy_n_chars + 2;
+ register char *dest = &yy_current_buffer->yy_ch_buf[
+ yy_current_buffer->yy_buf_size + 2];
+ register char *source =
+ &yy_current_buffer->yy_ch_buf[number_to_move];
+
+ while ( source > yy_current_buffer->yy_ch_buf )
+ *--dest = *--source;
+
+ yy_cp += (int) (dest - source);
+ yy_bp += (int) (dest - source);
+ yy_current_buffer->yy_n_chars =
+ yy_n_chars = yy_current_buffer->yy_buf_size;
+
+ if ( yy_cp < yy_current_buffer->yy_ch_buf + 2 )
+ YY_FATAL_ERROR( "flex scanner push-back overflow" );
+ }
+
+ *--yy_cp = (char) c;
+
+
+ yytext_ptr = yy_bp;
+ yy_hold_char = *yy_cp;
+ yy_c_buf_p = yy_cp;
+ }
+#endif /* ifndef YY_NO_UNPUT */
+
+
+#ifdef __cplusplus
+static int yyinput()
+#else
+static int input()
+#endif
+ {
+ int c;
+
+ *yy_c_buf_p = yy_hold_char;
+
+ if ( *yy_c_buf_p == YY_END_OF_BUFFER_CHAR )
+ {
+ /* yy_c_buf_p now points to the character we want to return.
+ * If this occurs *before* the EOB characters, then it's a
+ * valid NUL; if not, then we've hit the end of the buffer.
+ */
+ if ( yy_c_buf_p < &yy_current_buffer->yy_ch_buf[yy_n_chars] )
+ /* This was really a NUL. */
+ *yy_c_buf_p = '\0';
+
+ else
+ { /* need more input */
+ int offset = yy_c_buf_p - yytext_ptr;
+ ++yy_c_buf_p;
+
+ switch ( yy_get_next_buffer() )
+ {
+ case EOB_ACT_LAST_MATCH:
+ /* This happens because yy_g_n_b()
+ * sees that we've accumulated a
+ * token and flags that we need to
+ * try matching the token before
+ * proceeding. But for input(),
+ * there's no matching to consider.
+ * So convert the EOB_ACT_LAST_MATCH
+ * to EOB_ACT_END_OF_FILE.
+ */
+
+ /* Reset buffer status. */
+ yyrestart( yyin );
+
+ /* fall through */
+
+ case EOB_ACT_END_OF_FILE:
+ {
+ if ( yywrap() )
+ return EOF;
+
+ if ( ! yy_did_buffer_switch_on_eof )
+ YY_NEW_FILE;
+#ifdef __cplusplus
+ return yyinput();
+#else
+ return input();
+#endif
+ }
+
+ case EOB_ACT_CONTINUE_SCAN:
+ yy_c_buf_p = yytext_ptr + offset;
+ break;
+ }
+ }
+ }
+
+ c = *(unsigned char *) yy_c_buf_p; /* cast for 8-bit char's */
+ *yy_c_buf_p = '\0'; /* preserve yytext */
+ yy_hold_char = *++yy_c_buf_p;
+
+ yy_current_buffer->yy_at_bol = (c == '\n');
+
+ return c;
+ }
+
+
+#ifdef YY_USE_PROTOS
+void yyrestart( FILE *input_file )
+#else
+void yyrestart( input_file )
+FILE *input_file;
+#endif
+ {
+ if ( ! yy_current_buffer )
+ yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE );
+
+ yy_init_buffer( yy_current_buffer, input_file );
+ yy_load_buffer_state();
+ }
+
+
+#ifdef YY_USE_PROTOS
+void yy_switch_to_buffer( YY_BUFFER_STATE new_buffer )
+#else
+void yy_switch_to_buffer( new_buffer )
+YY_BUFFER_STATE new_buffer;
+#endif
+ {
+ if ( yy_current_buffer == new_buffer )
+ return;
+
+ if ( yy_current_buffer )
+ {
+ /* Flush out information for old buffer. */
+ *yy_c_buf_p = yy_hold_char;
+ yy_current_buffer->yy_buf_pos = yy_c_buf_p;
+ yy_current_buffer->yy_n_chars = yy_n_chars;
+ }
+
+ yy_current_buffer = new_buffer;
+ yy_load_buffer_state();
+
+ /* We don't actually know whether we did this switch during
+ * EOF (yywrap()) processing, but the only time this flag
+ * is looked at is after yywrap() is called, so it's safe
+ * to go ahead and always set it.
+ */
+ yy_did_buffer_switch_on_eof = 1;
+ }
+
+
+#ifdef YY_USE_PROTOS
+void yy_load_buffer_state( void )
+#else
+void yy_load_buffer_state()
+#endif
+ {
+ yy_n_chars = yy_current_buffer->yy_n_chars;
+ yytext_ptr = yy_c_buf_p = yy_current_buffer->yy_buf_pos;
+ yyin = yy_current_buffer->yy_input_file;
+ yy_hold_char = *yy_c_buf_p;
+ }
+
+
+#ifdef YY_USE_PROTOS
+YY_BUFFER_STATE yy_create_buffer( FILE *file, int size )
+#else
+YY_BUFFER_STATE yy_create_buffer( file, size )
+FILE *file;
+int size;
+#endif
+ {
+ YY_BUFFER_STATE b;
+
+ b = (YY_BUFFER_STATE) yy_flex_alloc( sizeof( struct yy_buffer_state ) );
+ if ( ! b )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
+
+ b->yy_buf_size = size;
+
+ /* yy_ch_buf has to be 2 characters longer than the size given because
+ * we need to put in 2 end-of-buffer characters.
+ */
+ b->yy_ch_buf = (char *) yy_flex_alloc( b->yy_buf_size + 2 );
+ if ( ! b->yy_ch_buf )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
+
+ b->yy_is_our_buffer = 1;
+
+ yy_init_buffer( b, file );
+
+ return b;
+ }
+
+
+#ifdef YY_USE_PROTOS
+void yy_delete_buffer( YY_BUFFER_STATE b )
+#else
+void yy_delete_buffer( b )
+YY_BUFFER_STATE b;
+#endif
+ {
+ if ( ! b )
+ return;
+
+ if ( b == yy_current_buffer )
+ yy_current_buffer = (YY_BUFFER_STATE) 0;
+
+ if ( b->yy_is_our_buffer )
+ yy_flex_free( (void *) b->yy_ch_buf );
+
+ yy_flex_free( (void *) b );
+ }
+
+
+#ifndef _WIN32
+#include <unistd.h>
+#else
+#ifndef YY_ALWAYS_INTERACTIVE
+#ifndef YY_NEVER_INTERACTIVE
+extern int isatty YY_PROTO(( int ));
+#endif
+#endif
+#endif
+
+#ifdef YY_USE_PROTOS
+void yy_init_buffer( YY_BUFFER_STATE b, FILE *file )
+#else
+void yy_init_buffer( b, file )
+YY_BUFFER_STATE b;
+FILE *file;
+#endif
+
+
+ {
+ yy_flush_buffer( b );
+
+ b->yy_input_file = file;
+ b->yy_fill_buffer = 1;
+
+#if YY_ALWAYS_INTERACTIVE
+ b->yy_is_interactive = 1;
+#else
+#if YY_NEVER_INTERACTIVE
+ b->yy_is_interactive = 0;
+#else
+ b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0;
+#endif
+#endif
+ }
+
+
+#ifdef YY_USE_PROTOS
+void yy_flush_buffer( YY_BUFFER_STATE b )
+#else
+void yy_flush_buffer( b )
+YY_BUFFER_STATE b;
+#endif
+
+ {
+ if ( ! b )
+ return;
+
+ b->yy_n_chars = 0;
+
+ /* We always need two end-of-buffer characters. The first causes
+ * a transition to the end-of-buffer state. The second causes
+ * a jam in that state.
+ */
+ b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR;
+ b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR;
+
+ b->yy_buf_pos = &b->yy_ch_buf[0];
+
+ b->yy_at_bol = 1;
+ b->yy_buffer_status = YY_BUFFER_NEW;
+
+ if ( b == yy_current_buffer )
+ yy_load_buffer_state();
+ }
+
+
+#ifndef YY_NO_SCAN_BUFFER
+#ifdef YY_USE_PROTOS
+YY_BUFFER_STATE yy_scan_buffer( char *base, yy_size_t size )
+#else
+YY_BUFFER_STATE yy_scan_buffer( base, size )
+char *base;
+yy_size_t size;
+#endif
+ {
+ YY_BUFFER_STATE b;
+
+ if ( size < 2 ||
+ base[size-2] != YY_END_OF_BUFFER_CHAR ||
+ base[size-1] != YY_END_OF_BUFFER_CHAR )
+ /* They forgot to leave room for the EOB's. */
+ return 0;
+
+ b = (YY_BUFFER_STATE) yy_flex_alloc( sizeof( struct yy_buffer_state ) );
+ if ( ! b )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" );
+
+ b->yy_buf_size = size - 2; /* "- 2" to take care of EOB's */
+ b->yy_buf_pos = b->yy_ch_buf = base;
+ b->yy_is_our_buffer = 0;
+ b->yy_input_file = 0;
+ b->yy_n_chars = b->yy_buf_size;
+ b->yy_is_interactive = 0;
+ b->yy_at_bol = 1;
+ b->yy_fill_buffer = 0;
+ b->yy_buffer_status = YY_BUFFER_NEW;
+
+ yy_switch_to_buffer( b );
+
+ return b;
+ }
+#endif
+
+
+#ifndef YY_NO_SCAN_STRING
+#ifdef YY_USE_PROTOS
+YY_BUFFER_STATE yy_scan_string( yyconst char *yy_str )
+#else
+YY_BUFFER_STATE yy_scan_string( yy_str )
+yyconst char *yy_str;
+#endif
+ {
+ int len;
+ for ( len = 0; yy_str[len]; ++len )
+ ;
+
+ return yy_scan_bytes( yy_str, len );
+ }
+#endif
+
+
+#ifndef YY_NO_SCAN_BYTES
+#ifdef YY_USE_PROTOS
+YY_BUFFER_STATE yy_scan_bytes( yyconst char *bytes, int len )
+#else
+YY_BUFFER_STATE yy_scan_bytes( bytes, len )
+yyconst char *bytes;
+int len;
+#endif
+ {
+ YY_BUFFER_STATE b;
+ char *buf;
+ yy_size_t n;
+ int i;
+
+ /* Get memory for full buffer, including space for trailing EOB's. */
+ n = len + 2;
+ buf = (char *) yy_flex_alloc( n );
+ if ( ! buf )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" );
+
+ for ( i = 0; i < len; ++i )
+ buf[i] = bytes[i];
+
+ buf[len] = buf[len+1] = YY_END_OF_BUFFER_CHAR;
+
+ b = yy_scan_buffer( buf, n );
+ if ( ! b )
+ YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" );
+
+ /* It's okay to grow etc. this buffer, and we should throw it
+ * away when we're done.
+ */
+ b->yy_is_our_buffer = 1;
+
+ return b;
+ }
+#endif
+
+
+#ifndef YY_NO_PUSH_STATE
+#ifdef YY_USE_PROTOS
+static void yy_push_state( int new_state )
+#else
+static void yy_push_state( new_state )
+int new_state;
+#endif
+ {
+ if ( yy_start_stack_ptr >= yy_start_stack_depth )
+ {
+ yy_size_t new_size;
+
+ yy_start_stack_depth += YY_START_STACK_INCR;
+ new_size = yy_start_stack_depth * sizeof( int );
+
+ if ( ! yy_start_stack )
+ yy_start_stack = (int *) yy_flex_alloc( new_size );
+
+ else
+ yy_start_stack = (int *) yy_flex_realloc(
+ (void *) yy_start_stack, new_size );
+
+ if ( ! yy_start_stack )
+ YY_FATAL_ERROR(
+ "out of memory expanding start-condition stack" );
+ }
+
+ yy_start_stack[yy_start_stack_ptr++] = YY_START;
+
+ BEGIN(new_state);
+ }
+#endif
+
+
+#ifndef YY_NO_POP_STATE
+static void yy_pop_state()
+ {
+ if ( --yy_start_stack_ptr < 0 )
+ YY_FATAL_ERROR( "start-condition stack underflow" );
+
+ BEGIN(yy_start_stack[yy_start_stack_ptr]);
+ }
+#endif
+
+
+#ifndef YY_NO_TOP_STATE
+static int yy_top_state()
+ {
+ return yy_start_stack[yy_start_stack_ptr - 1];
+ }
+#endif
+
+#ifndef YY_EXIT_FAILURE
+#define YY_EXIT_FAILURE 2
+#endif
+
+#ifdef YY_USE_PROTOS
+static void yy_fatal_error( yyconst char msg[] )
+#else
+static void yy_fatal_error( msg )
+char msg[];
+#endif
+ {
+ (void) fprintf( stderr, "%s\n", msg );
+ exit( YY_EXIT_FAILURE );
+ }
+
+
+
+/* Redefine yyless() so it works in section 3 code. */
+
+#undef yyless
+#define yyless(n) \
+ do \
+ { \
+ /* Undo effects of setting up yytext. */ \
+ yytext[yyleng] = yy_hold_char; \
+ yy_c_buf_p = yytext + n; \
+ yy_hold_char = *yy_c_buf_p; \
+ *yy_c_buf_p = '\0'; \
+ yyleng = n; \
+ } \
+ while ( 0 )
+
+
+/* Internal utility routines. */
+
+#ifndef yytext_ptr
+#ifdef YY_USE_PROTOS
+static void yy_flex_strncpy( char *s1, yyconst char *s2, int n )
+#else
+static void yy_flex_strncpy( s1, s2, n )
+char *s1;
+yyconst char *s2;
+int n;
+#endif
+ {
+ register int i;
+ for ( i = 0; i < n; ++i )
+ s1[i] = s2[i];
+ }
+#endif
+
+#ifdef YY_NEED_STRLEN
+#ifdef YY_USE_PROTOS
+static int yy_flex_strlen( yyconst char *s )
+#else
+static int yy_flex_strlen( s )
+yyconst char *s;
+#endif
+ {
+ register int n;
+ for ( n = 0; s[n]; ++n )
+ ;
+
+ return n;
+ }
+#endif
+
+
+#ifdef YY_USE_PROTOS
+static void *yy_flex_alloc( yy_size_t size )
+#else
+static void *yy_flex_alloc( size )
+yy_size_t size;
+#endif
+ {
+ return (void *) malloc( size );
+ }
+
+#ifdef YY_USE_PROTOS
+static void *yy_flex_realloc( void *ptr, yy_size_t size )
+#else
+static void *yy_flex_realloc( ptr, size )
+void *ptr;
+yy_size_t size;
+#endif
+ {
+ /* The cast to (char *) in the following accommodates both
+ * implementations that use char* generic pointers, and those
+ * that use void* generic pointers. It works with the latter
+ * because both ANSI C and C++ allow castless assignment from
+ * any pointer type to void*, and deal with argument conversions
+ * as though doing an assignment.
+ */
+ return (void *) realloc( (char *) ptr, size );
+ }
+
+#ifdef YY_USE_PROTOS
+static void yy_flex_free( void *ptr )
+#else
+static void yy_flex_free( ptr )
+void *ptr;
+#endif
+ {
+ free( ptr );
+ }
+
+#if YY_MAIN
+int main()
+ {
+ yylex();
+ return 0;
+ }
+#endif
+#line 70 "exports.l"
diff --git a/external/fs/unfs3-0.9.22/Config/y.tab.c b/external/fs/unfs3-0.9.22/Config/y.tab.c
new file mode 100644
index 0000000..b0761f4
--- /dev/null
+++ b/external/fs/unfs3-0.9.22/Config/y.tab.c
@@ -0,0 +1,2403 @@
+/* A Bison parser, made by GNU Bison 2.3. */
+
+/* Skeleton implementation for Bison's Yacc-like parsers in C
+
+ Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
+ Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA. */
+
+/* As a special exception, you may create a larger work that contains
+ part or all of the Bison parser skeleton and distribute that work
+ under terms of your choice, so long as that work isn't itself a
+ parser generator using the skeleton or a modified version thereof
+ as a parser skeleton. Alternatively, if you modify or redistribute
+ the parser skeleton itself, you may (at your option) remove this
+ special exception, which will cause the skeleton and the resulting
+ Bison output files to be licensed under the GNU General Public
+ License without this special exception.
+
+ This special exception was added by the Free Software Foundation in
+ version 2.2 of Bison. */
+
+/* C LALR(1) parser skeleton written by Richard Stallman, by
+ simplifying the original so-called "semantic" parser. */
+
+/* All symbols defined below should begin with yy or YY, to avoid
+ infringing on user name space. This should be done even for local
+ variables, as they might otherwise be expanded by user macros.
+ There are some unavoidable exceptions within include files to
+ define necessary library symbols; they are noted "INFRINGES ON
+ USER NAME SPACE" below. */
+
+/* Identify Bison output. */
+#define YYBISON 1
+
+/* Bison version. */
+#define YYBISON_VERSION "2.3"
+
+/* Skeleton name. */
+#define YYSKELETON_NAME "yacc.c"
+
+/* Pure parsers. */
+#define YYPURE 0
+
+/* Using locations. */
+#define YYLSP_NEEDED 0
+
+
+
+/* Tokens. */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+ /* Put the tokens into the symbol table, so that GDB and other debuggers
+ know about them. */
+ enum yytokentype {
+ PATH = 258,
+ ID = 259,
+ OPTVALUE = 260,
+ WHITE = 261,
+ IP = 262,
+ NET = 263,
+ OLDNET = 264
+ };
+#endif
+/* Tokens. */
+#define PATH 258
+#define ID 259
+#define OPTVALUE 260
+#define WHITE 261
+#define IP 262
+#define NET 263
+#define OLDNET 264
+
+
+
+
+/* Copy the first part of user declarations. */
+#line 1 "exports.y"
+
+/*
+ * UNFS3 exports parser and export controls
+ * (C) 2004, Pascal Schmidt
+ * see file LICENSE for license details
+ */
+#include "../config.h"
+
+#include <rpc/rpc.h>
+#include <limits.h>
+
+#ifdef WIN32
+#include "../winsupport.h"
+#else
+#include <netdb.h>
+#include <syslog.h>
+#include <unistd.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#endif /* WIN32 */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "../nfs.h"
+#include "../mount.h"
+#include "../daemon.h"
+#include "../backend.h"
+#include "exports.h"
+
+#ifndef PATH_MAX
+# define PATH_MAX 4096
+#endif
+
+/* for lack of a better place */
+#ifdef __GNUC__
+#define U(x) x __attribute__ ((unused))
+#else
+#define U(x) x
+#endif
+
+/* lexer stuff, to avoid compiler warnings */
+int yylex(void);
+extern FILE *yyin;
+
+/*
+ * C code used by yacc parser
+ */
+
+typedef struct {
+ char orig[NFS_MAXPATHLEN];
+ int options;
+ char password[PASSWORD_MAXLEN+1];
+ uint32 password_hash;
+ struct in_addr addr;
+ struct in_addr mask;
+ uint32 anonuid;
+ uint32 anongid;
+ struct e_host *next;
+} e_host;
+
+typedef struct {
+ char path[NFS_MAXPATHLEN];
+ char orig[NFS_MAXPATHLEN];
+ e_host *hosts;
+ uint32 fsid; /* export point fsid (for removables) */
+ time_t last_mtime; /* Last returned mtime (for removables) */
+ uint32 dir_hash; /* Hash of dir contents (for removables) */
+ struct e_item *next;
+} e_item;
+
+/* export list, item, and host filled during parse */
+static e_item *e_list = NULL;
+static e_item cur_item;
+static e_host cur_host;
+
+/* last looked-up anonuid and anongid */
+static uint32 last_anonuid = ANON_NOTSPECIAL;
+static uint32 last_anongid = ANON_NOTSPECIAL;
+
+/* mount protocol compatible variants */
+static exports ne_list = NULL;
+static struct exportnode ne_item;
+static struct groupnode ne_host;
+
+/* error status of last parse */
+int e_error = FALSE;
+
+/*
+ * The FNV1a-32 hash algorithm
+ * (http://www.isthe.com/chongo/tech/comp/fnv/)
+ */
+uint32 fnv1a_32(const char *str, uint32 hval)
+{
+ static const uint32 fnv_32_prime = 0x01000193;
+
+ while (*str) {
+ hval ^= *str++;
+ hval *= fnv_32_prime;
+ }
+ return hval;
+}
+
+#ifdef WIN32
+uint32 wfnv1a_32(const wchar_t *str, uint32 hval)
+{
+ static const uint32 fnv_32_prime = 0x01000193;
+
+ while (*str) {
+ hval ^= *str++;
+ hval *= fnv_32_prime;
+ }
+ return hval;
+}
+#endif
+
+/*
+ * get static fsid, for use with removable media export points
+ */
+static uint32 get_free_fsid(const char *path)
+{
+ uint32 hval;
+
+ /* The 32:th bit is set to one on all special filehandles. The
+ last 31 bits are hashed from the export point path. */
+ hval = fnv1a_32(path, 0);
+ hval |= 0x80000000;
+ return hval;
+}
+
+
+/*
+ * clear current host
+ */
+static void clear_host(void)
+{
+ memset(&cur_host, 0, sizeof(e_host));
+ strcpy(cur_host.orig, "<anon clnt>");
+ memset(&ne_host, 0, sizeof(struct groupnode));
+
+ cur_host.anonuid =
+ cur_host.anongid = ANON_NOTSPECIAL;
+}
+
+/*
+ * clear current item
+ */
+static void clear_item(void)
+{
+ memset(&cur_item, 0, sizeof(e_item));
+ memset(&ne_item, 0, sizeof(struct exportnode));
+}
+
+/*
+ * add current host to current export item
+ */
+static void add_host(void)
+{
+ e_host *new;
+ e_host *iter;
+
+ groups ne_new;
+ groups ne_iter;
+
+ new = malloc(sizeof(e_host));
+ ne_new = malloc(sizeof(struct groupnode));
+ if (!new || !ne_new) {
+ logmsg(LOG_EMERG, "out of memory, aborting");
+ daemon_exit(CRISIS);
+ }
+
+ *new = cur_host;
+ *ne_new = ne_host;
+ ne_new->gr_name = new->orig;
+
+ /* internal list */
+ if (cur_item.hosts) {
+ iter = cur_item.hosts;
+ while (iter->next)
+ iter = (e_host *) iter->next;
+ iter->next = (struct e_host *) new;
+ } else
+ cur_item.hosts = new;
+
+ /* matching mount protocol list */
+ if (ne_item.ex_groups) {
+ ne_iter = ne_item.ex_groups;
+ while (ne_iter->gr_next)
+ ne_iter = (groups) ne_iter->gr_next;
+ ne_iter->gr_next = ne_new;
+ } else
+ ne_item.ex_groups = ne_new;
+
+ clear_host();
+}
+
+/*
+ Normalize path, eliminating double slashes, etc. To be used instead
+ of realpath, when realpath is not possible. Normalizing export
+ points is important. Otherwise, mount requests might fail, since
+ /x/y is not a prefix of ///x///y/ etc.
+*/
+char *normpath(const char *path, char *normpath)
+{
+ char *n;
+ const char *p;
+
+ /* Copy path to normpath, and replace blocks of slashes with
+ single slash */
+ p = path;
+ n = normpath;
+ while (*p) {
+ /* Skip over multiple slashes */
+ if (*p == '/' && *(p+1) == '/') {
+ p++;
+ continue;
+ }
+ *n++ = *p++;
+ }
+ *n = '\0';
+
+ /* Remove trailing slash, if any. */
+ if ((n - normpath) > 1 && *(n-1) == '/')
+ *(n-1) = '\0';
+
+ return normpath;
+}
+
+/*
+ * add current item to current export list
+ */
+static void add_item(const char *path)
+{
+ char buf[PATH_MAX];
+ e_item *new;
+ e_item *iter;
+ e_host *host;
+ /* Is this item marked as removable for all hosts? */
+ int removable_for_all = 1;
+
+ exports ne_new;
+ exports ne_iter;
+
+ new = malloc(sizeof(e_item));
+ ne_new = malloc(sizeof(struct exportnode));
+ if (!new || !ne_new) {
+ logmsg(LOG_EMERG, "out of memory, aborting");
+ daemon_exit(CRISIS);
+ }
+
+ /* Loop over all hosts and check if marked as removable. */
+ host = cur_item.hosts;
+ while (host) {
+ if (!(host->options & OPT_REMOVABLE))
+ removable_for_all = 0;
+ host = (e_host *) host->next;
+ }
+
+ if (removable_for_all) {
+ /* If marked as removable for all hosts, don't try
+ realpath. */
+ normpath(path, buf);
+ } else if (!backend_realpath(path, buf)) {
+ logmsg(LOG_CRIT, "realpath for %s failed", path);
+ e_error = TRUE;
+ free(new);
+ free(ne_new);
+ clear_item();
+ return;
+ }
+
+ if (strlen(buf) + 1 > NFS_MAXPATHLEN) {
+ logmsg(LOG_CRIT, "attempted to export too long path");
+ e_error = TRUE;
+ free(new);
+ free(ne_new);
+ clear_item();
+ return;
+ }
+
+ /* if no hosts listed, list default host */
+ if (!cur_item.hosts)
+ add_host();
+
+ *new = cur_item;
+ strcpy(new->path, buf);
+ strcpy(new->orig, path);
+ new->fsid = get_free_fsid(path);
+ new->last_mtime = 0;
+ new->dir_hash = 0;
+
+ *ne_new = ne_item;
+ ne_new->ex_dir = new->orig;
+
+ /* internal list */
+ if (e_list) {
+ iter = e_list;
+ while (iter->next)
+ iter = (e_item *) iter->next;
+ iter->next = (struct e_item *) new;
+ } else
+ e_list = new;
+
+ /* matching mount protocol list */
+ if (ne_list) {
+ ne_iter = ne_list;
+ while (ne_iter->ex_next)
+ ne_iter = (exports) ne_iter->ex_next;
+ ne_iter->ex_next = ne_new;
+ } else
+ ne_list = ne_new;
+
+ clear_item();
+}
+
+/*
+ * fill current host's address given a hostname
+ */
+static void set_hostname(const char *name)
+{
+ struct hostent *ent;
+
+ if (strlen(name) + 1 > NFS_MAXPATHLEN) {
+ e_error = TRUE;
+ return;
+ }
+ strcpy(cur_host.orig, name);
+
+ ent = gethostbyname(name);
+
+ if (ent) {
+ memcpy(&cur_host.addr, ent->h_addr_list[0],
+ sizeof(struct in_addr));
+ cur_host.mask.s_addr = ~0UL;
+ } else {
+ logmsg(LOG_CRIT, "could not resolve hostname '%s'", name);
+ e_error = TRUE;
+ }
+}
+
+/*
+ * fill current host's address given an IP address
+ */
+static void set_ipaddr(const char *addr)
+{
+ strcpy(cur_host.orig, addr);
+
+ if (!inet_aton(addr, &cur_host.addr))
+ e_error = TRUE;
+ cur_host.mask.s_addr = ~0UL;
+}
+
+/*
+ * compute network bitmask
+ */
+static unsigned long make_netmask(int bits) {
+ unsigned long buf = 0;
+ int i;
+
+ for (i=0; i<bits; i++)
+ buf = (buf << 1) + 1;
+ for (; i < 32; i++)
+ buf = (buf << 1);
+ return htonl(buf);
+}
+
+/*
+ * fill current host's address given IP address and netmask
+ */
+static void set_ipnet(char *addr, int new)
+{
+ char *pos, *net;
+
+ pos = strchr(addr, '/');
+ net = pos + 1;
+ *pos = 0;
+
+ set_ipaddr(addr);
+
+ if (new)
+ cur_host.mask.s_addr = make_netmask(atoi(net));
+ else
+ if (!inet_aton(net, &cur_host.mask))
+ e_error = TRUE;
+
+ *pos = '/';
+ strcpy(cur_host.orig, addr);
+}
+
+/*
+ * add an option bit to the current host
+ */
+static void add_option(const char *opt)
+{
+ if (strcmp(opt,"no_root_squash") == 0)
+ cur_host.options |= OPT_NO_ROOT_SQUASH;
+ else if (strcmp(opt,"root_squash") == 0)
+ cur_host.options &= ~OPT_NO_ROOT_SQUASH;
+ else if (strcmp(opt,"all_squash") == 0)
+ cur_host.options |= OPT_ALL_SQUASH;
+ else if (strcmp(opt,"no_all_squash") == 0)
+ cur_host.options &= ~OPT_ALL_SQUASH;
+ else if (strcmp(opt,"rw") == 0)
+ cur_host.options |= OPT_RW;
+ else if (strcmp(opt,"ro") == 0)
+ cur_host.options &= ~OPT_RW;
+ else if (strcmp(opt,"removable") == 0) {
+ cur_host.options |= OPT_REMOVABLE;
+ } else if (strcmp(opt,"fixed") == 0)
+ cur_host.options &= ~OPT_REMOVABLE;
+ else if (strcmp(opt,"insecure") == 0)
+ cur_host.options |= OPT_INSECURE;
+ else if (strcmp(opt,"secure") == 0)
+ cur_host.options &= ~OPT_INSECURE;
+ else
+ logmsg(LOG_WARNING, "Warning: unknown exports option `%s' ignored",
+ opt);
+}
+
+static void add_option_with_value(const char *opt, const char *val)
+{
+ if (strcmp(opt,"password") == 0) {
+ if (strlen(val) > PASSWORD_MAXLEN) {
+ logmsg(LOG_WARNING, "Warning: password for export %s truncated to 64 chars",
+ cur_item.orig);
+ }
+ strncpy(cur_host.password, val, sizeof(password));
+ cur_host.password[PASSWORD_MAXLEN] = '\0';
+ /* Calculate hash */
+ cur_host.password_hash = fnv1a_32(cur_host.password, 0);
+ } else if (strcmp(opt,"anonuid") == 0) {
+ cur_host.anonuid = atoi(val);
+ } else if (strcmp(opt,"anongid") == 0) {
+ cur_host.anongid = atoi(val);
+ } else {
+ logmsg(LOG_WARNING, "Warning: unknown exports option `%s' ignored",
+ opt);
+ }
+}
+
+/*
+ * dummy error function
+ */
+void yyerror(U(char *s))
+{
+ e_error = TRUE;
+ return;
+}
+
+
+
+/* Enabling traces. */
+#ifndef YYDEBUG
+# define YYDEBUG 0
+#endif
+
+/* Enabling verbose error messages. */
+#ifdef YYERROR_VERBOSE
+# undef YYERROR_VERBOSE
+# define YYERROR_VERBOSE 1
+#else
+# define YYERROR_VERBOSE 0
+#endif
+
+/* Enabling the token table. */
+#ifndef YYTOKEN_TABLE
+# define YYTOKEN_TABLE 0
+#endif
+
+#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+typedef union YYSTYPE
+#line 452 "exports.y"
+{
+ char text[NFS_MAXPATHLEN];
+}
+/* Line 187 of yacc.c. */
+#line 569 "y.tab.c"
+ YYSTYPE;
+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+# define YYSTYPE_IS_DECLARED 1
+# define YYSTYPE_IS_TRIVIAL 1
+#endif
+
+
+
+/* Copy the second part of user declarations. */
+
+
+/* Line 216 of yacc.c. */
+#line 582 "y.tab.c"
+
+#ifdef short
+# undef short
+#endif
+
+#ifdef YYTYPE_UINT8
+typedef YYTYPE_UINT8 yytype_uint8;
+#else
+typedef unsigned char yytype_uint8;
+#endif
+
+#ifdef YYTYPE_INT8
+typedef YYTYPE_INT8 yytype_int8;
+#elif (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+typedef signed char yytype_int8;
+#else
+typedef short int yytype_int8;
+#endif
+
+#ifdef YYTYPE_UINT16
+typedef YYTYPE_UINT16 yytype_uint16;
+#else
+typedef unsigned short int yytype_uint16;
+#endif
+
+#ifdef YYTYPE_INT16
+typedef YYTYPE_INT16 yytype_int16;
+#else
+typedef short int yytype_int16;
+#endif
+
+#ifndef YYSIZE_T
+# ifdef __SIZE_TYPE__
+# define YYSIZE_T __SIZE_TYPE__
+# elif defined size_t
+# define YYSIZE_T size_t
+# elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+# include <stddef.h> /* INFRINGES ON USER NAME SPACE */
+# define YYSIZE_T size_t
+# else
+# define YYSIZE_T unsigned int
+# endif
+#endif
+
+#define YYSIZE_MAXIMUM ((YYSIZE_T) -1)
+
+#ifndef YY_
+# if YYENABLE_NLS
+# if ENABLE_NLS
+# include <libintl.h> /* INFRINGES ON USER NAME SPACE */
+# define YY_(msgid) dgettext ("bison-runtime", msgid)
+# endif
+# endif
+# ifndef YY_
+# define YY_(msgid) msgid
+# endif
+#endif
+
+/* Suppress unused-variable warnings by "using" E. */
+#if ! defined lint || defined __GNUC__
+# define YYUSE(e) ((void) (e))
+#else
+# define YYUSE(e) /* empty */
+#endif
+
+/* Identity function, used to suppress warnings about constant conditions. */
+#ifndef lint
+# define YYID(n) (n)
+#else
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static int
+YYID (int i)
+#else
+static int
+YYID (i)
+ int i;
+#endif
+{
+ return i;
+}
+#endif
+
+#if ! defined yyoverflow || YYERROR_VERBOSE
+
+/* The parser invokes alloca or malloc; define the necessary symbols. */
+
+# ifdef YYSTACK_USE_ALLOCA
+# if YYSTACK_USE_ALLOCA
+# ifdef __GNUC__
+# define YYSTACK_ALLOC __builtin_alloca
+# elif defined __BUILTIN_VA_ARG_INCR
+# include <alloca.h> /* INFRINGES ON USER NAME SPACE */
+# elif defined _AIX
+# define YYSTACK_ALLOC __alloca
+# elif defined _MSC_VER
+# include <malloc.h> /* INFRINGES ON USER NAME SPACE */
+# define alloca _alloca
+# else
+# define YYSTACK_ALLOC alloca
+# if ! defined _ALLOCA_H && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+# ifndef _STDLIB_H
+# define _STDLIB_H 1
+# endif
+# endif
+# endif
+# endif
+# endif
+
+# ifdef YYSTACK_ALLOC
+ /* Pacify GCC's `empty if-body' warning. */
+# define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0))
+# ifndef YYSTACK_ALLOC_MAXIMUM
+ /* The OS might guarantee only one guard page at the bottom of the stack,
+ and a page size can be as small as 4096 bytes. So we cannot safely
+ invoke alloca (N) if N exceeds 4096. Use a slightly smaller number
+ to allow for a few compiler-allocated temporary stack slots. */
+# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */
+# endif
+# else
+# define YYSTACK_ALLOC YYMALLOC
+# define YYSTACK_FREE YYFREE
+# ifndef YYSTACK_ALLOC_MAXIMUM
+# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM
+# endif
+# if (defined __cplusplus && ! defined _STDLIB_H \
+ && ! ((defined YYMALLOC || defined malloc) \
+ && (defined YYFREE || defined free)))
+# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+# ifndef _STDLIB_H
+# define _STDLIB_H 1
+# endif
+# endif
+# ifndef YYMALLOC
+# define YYMALLOC malloc
+# if ! defined malloc && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */
+# endif
+# endif
+# ifndef YYFREE
+# define YYFREE free
+# if ! defined free && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+void free (void *); /* INFRINGES ON USER NAME SPACE */
+# endif
+# endif
+# endif
+#endif /* ! defined yyoverflow || YYERROR_VERBOSE */
+
+
+#if (! defined yyoverflow \
+ && (! defined __cplusplus \
+ || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL)))
+
+/* A type that is properly aligned for any stack member. */
+union yyalloc
+{
+ yytype_int16 yyss;
+ YYSTYPE yyvs;
+ };
+
+/* The size of the maximum gap between one aligned stack and the next. */
+# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1)
+
+/* The size of an array large to enough to hold all stacks, each with
+ N elements. */
+# define YYSTACK_BYTES(N) \
+ ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \
+ + YYSTACK_GAP_MAXIMUM)
+
+/* Copy COUNT objects from FROM to TO. The source and destination do
+ not overlap. */
+# ifndef YYCOPY
+# if defined __GNUC__ && 1 < __GNUC__
+# define YYCOPY(To, From, Count) \
+ __builtin_memcpy (To, From, (Count) * sizeof (*(From)))
+# else
+# define YYCOPY(To, From, Count) \
+ do \
+ { \
+ YYSIZE_T yyi; \
+ for (yyi = 0; yyi < (Count); yyi++) \
+ (To)[yyi] = (From)[yyi]; \
+ } \
+ while (YYID (0))
+# endif
+# endif
+
+/* Relocate STACK from its old location to the new one. The
+ local variables YYSIZE and YYSTACKSIZE give the old and new number of
+ elements in the stack, and YYPTR gives the new location of the
+ stack. Advance YYPTR to a properly aligned location for the next
+ stack. */
+# define YYSTACK_RELOCATE(Stack) \
+ do \
+ { \
+ YYSIZE_T yynewbytes; \
+ YYCOPY (&yyptr->Stack, Stack, yysize); \
+ Stack = &yyptr->Stack; \
+ yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
+ yyptr += yynewbytes / sizeof (*yyptr); \
+ } \
+ while (YYID (0))
+
+#endif
+
+/* YYFINAL -- State number of the termination state. */
+#define YYFINAL 5
+/* YYLAST -- Last index in YYTABLE. */
+#define YYLAST 21
+
+/* YYNTOKENS -- Number of terminals. */
+#define YYNTOKENS 14
+/* YYNNTS -- Number of nonterminals. */
+#define YYNNTS 8
+/* YYNRULES -- Number of rules. */
+#define YYNRULES 22
+/* YYNRULES -- Number of states. */
+#define YYNSTATES 28
+
+/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */
+#define YYUNDEFTOK 2
+#define YYMAXUTOK 264
+
+#define YYTRANSLATE(YYX) \
+ ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
+
+/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */
+static const yytype_uint8 yytranslate[] =
+{
+ 0, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 10, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 11, 12, 2, 2, 13, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 1, 2, 3, 4,
+ 5, 6, 7, 8, 9
+};
+
+#if YYDEBUG
+/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in
+ YYRHS. */
+static const yytype_uint8 yyprhs[] =
+{
+ 0, 0, 3, 5, 9, 10, 12, 16, 19, 21,
+ 25, 28, 30, 35, 39, 41, 43, 45, 47, 49,
+ 53, 54, 56
+};
+
+/* YYRHS -- A `-1'-separated list of the rules' RHS. */
+static const yytype_int8 yyrhs[] =
+{
+ 15, 0, -1, 16, -1, 16, 10, 15, -1, -1,
+ 3, -1, 3, 6, 17, -1, 3, 6, -1, 18,
+ -1, 18, 6, 17, -1, 18, 6, -1, 19, -1,
+ 19, 11, 20, 12, -1, 11, 20, 12, -1, 4,
+ -1, 7, -1, 8, -1, 9, -1, 21, -1, 21,
+ 13, 20, -1, -1, 4, -1, 4, 5, -1
+};
+
+/* YYRLINE[YYN] -- source line where rule number YYN was defined. */
+static const yytype_uint16 yyrline[] =
+{
+ 0, 467, 467, 468, 469, 473, 474, 475, 479, 480,
+ 481, 485, 486, 487, 491, 492, 493, 494, 498, 499,
+ 500, 504, 505
+};
+#endif
+
+#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE
+/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
+ First, the terminals, then, starting at YYNTOKENS, nonterminals. */
+static const char *const yytname[] =
+{
+ "$end", "error", "$undefined", "PATH", "ID", "OPTVALUE", "WHITE", "IP",
+ "NET", "OLDNET", "'\\n'", "'('", "')'", "','", "$accept", "exports",
+ "export", "hosts", "host", "name", "opts", "opt", 0
+};
+#endif
+
+# ifdef YYPRINT
+/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to
+ token YYLEX-NUM. */
+static const yytype_uint16 yytoknum[] =
+{
+ 0, 256, 257, 258, 259, 260, 261, 262, 263, 264,
+ 10, 40, 41, 44
+};
+# endif
+
+/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */
+static const yytype_uint8 yyr1[] =
+{
+ 0, 14, 15, 15, 15, 16, 16, 16, 17, 17,
+ 17, 18, 18, 18, 19, 19, 19, 19, 20, 20,
+ 20, 21, 21
+};
+
+/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */
+static const yytype_uint8 yyr2[] =
+{
+ 0, 2, 1, 3, 0, 1, 3, 2, 1, 3,
+ 2, 1, 4, 3, 1, 1, 1, 1, 1, 3,
+ 0, 1, 2
+};
+
+/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state
+ STATE-NUM when YYTABLE doesn't specify something else to do. Zero
+ means the default is an error. */
+static const yytype_uint8 yydefact[] =
+{
+ 4, 5, 0, 2, 7, 1, 4, 14, 15, 16,
+ 17, 20, 6, 8, 11, 3, 21, 0, 18, 10,
+ 20, 22, 13, 20, 9, 0, 19, 12
+};
+
+/* YYDEFGOTO[NTERM-NUM]. */
+static const yytype_int8 yydefgoto[] =
+{
+ -1, 2, 3, 12, 13, 14, 17, 18
+};
+
+/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
+ STATE-NUM. */
+#define YYPACT_NINF -15
+static const yytype_int8 yypact[] =
+{
+ -2, 2, 10, -8, -4, -15, -2, -15, -15, -15,
+ -15, 7, -15, 6, 3, -15, 8, 4, 5, -4,
+ 7, -15, -15, 7, -15, 9, -15, -15
+};
+
+/* YYPGOTO[NTERM-NUM]. */
+static const yytype_int8 yypgoto[] =
+{
+ -15, 11, -15, 0, -15, -15, -14, -15
+};
+
+/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If
+ positive, shift that token. If negative, reduce the rule which
+ number is the opposite. If zero, do what YYDEFACT says.
+ If YYTABLE_NINF, syntax error. */
+#define YYTABLE_NINF -1
+static const yytype_uint8 yytable[] =
+{
+ 7, 1, 6, 8, 9, 10, 25, 11, 4, 26,
+ 5, 16, 19, 21, 20, 0, 22, 15, 23, 24,
+ 0, 27
+};
+
+static const yytype_int8 yycheck[] =
+{
+ 4, 3, 10, 7, 8, 9, 20, 11, 6, 23,
+ 0, 4, 6, 5, 11, -1, 12, 6, 13, 19,
+ -1, 12
+};
+
+/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
+ symbol of state STATE-NUM. */
+static const yytype_uint8 yystos[] =
+{
+ 0, 3, 15, 16, 6, 0, 10, 4, 7, 8,
+ 9, 11, 17, 18, 19, 15, 4, 20, 21, 6,
+ 11, 5, 12, 13, 17, 20, 20, 12
+};
+
+#define yyerrok (yyerrstatus = 0)
+#define yyclearin (yychar = YYEMPTY)
+#define YYEMPTY (-2)
+#define YYEOF 0
+
+#define YYACCEPT goto yyacceptlab
+#define YYABORT goto yyabortlab
+#define YYERROR goto yyerrorlab
+
+
+/* Like YYERROR except do call yyerror. This remains here temporarily
+ to ease the transition to the new meaning of YYERROR, for GCC.
+ Once GCC version 2 has supplanted version 1, this can go. */
+
+#define YYFAIL goto yyerrlab
+
+#define YYRECOVERING() (!!yyerrstatus)
+
+#define YYBACKUP(Token, Value) \
+do \
+ if (yychar == YYEMPTY && yylen == 1) \
+ { \
+ yychar = (Token); \
+ yylval = (Value); \
+ yytoken = YYTRANSLATE (yychar); \
+ YYPOPSTACK (1); \
+ goto yybackup; \
+ } \
+ else \
+ { \
+ yyerror (YY_("syntax error: cannot back up")); \
+ YYERROR; \
+ } \
+while (YYID (0))
+
+
+#define YYTERROR 1
+#define YYERRCODE 256
+
+
+/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N].
+ If N is 0, then set CURRENT to the empty location which ends
+ the previous symbol: RHS[0] (always defined). */
+
+#define YYRHSLOC(Rhs, K) ((Rhs)[K])
+#ifndef YYLLOC_DEFAULT
+# define YYLLOC_DEFAULT(Current, Rhs, N) \
+ do \
+ if (YYID (N)) \
+ { \
+ (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \
+ (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \
+ (Current).last_line = YYRHSLOC (Rhs, N).last_line; \
+ (Current).last_column = YYRHSLOC (Rhs, N).last_column; \
+ } \
+ else \
+ { \
+ (Current).first_line = (Current).last_line = \
+ YYRHSLOC (Rhs, 0).last_line; \
+ (Current).first_column = (Current).last_column = \
+ YYRHSLOC (Rhs, 0).last_column; \
+ } \
+ while (YYID (0))
+#endif
+
+
+/* YY_LOCATION_PRINT -- Print the location on the stream.
+ This macro was not mandated originally: define only if we know
+ we won't break user code: when these are the locations we know. */
+
+#ifndef YY_LOCATION_PRINT
+# if YYLTYPE_IS_TRIVIAL
+# define YY_LOCATION_PRINT(File, Loc) \
+ fprintf (File, "%d.%d-%d.%d", \
+ (Loc).first_line, (Loc).first_column, \
+ (Loc).last_line, (Loc).last_column)
+# else
+# define YY_LOCATION_PRINT(File, Loc) ((void) 0)
+# endif
+#endif
+
+
+/* YYLEX -- calling `yylex' with the right arguments. */
+
+#ifdef YYLEX_PARAM
+# define YYLEX yylex (YYLEX_PARAM)
+#else
+# define YYLEX yylex ()
+#endif
+
+/* Enable debugging if requested. */
+#if YYDEBUG
+
+# ifndef YYFPRINTF
+# include <stdio.h> /* INFRINGES ON USER NAME SPACE */
+# define YYFPRINTF fprintf
+# endif
+
+# define YYDPRINTF(Args) \
+do { \
+ if (yydebug) \
+ YYFPRINTF Args; \
+} while (YYID (0))
+
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \
+do { \
+ if (yydebug) \
+ { \
+ YYFPRINTF (stderr, "%s ", Title); \
+ yy_symbol_print (stderr, \
+ Type, Value); \
+ YYFPRINTF (stderr, "\n"); \
+ } \
+} while (YYID (0))
+
+
+/*--------------------------------.
+| Print this symbol on YYOUTPUT. |
+`--------------------------------*/
+
+/*ARGSUSED*/
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep)
+#else
+static void
+yy_symbol_value_print (yyoutput, yytype, yyvaluep)
+ FILE *yyoutput;
+ int yytype;
+ YYSTYPE const * const yyvaluep;
+#endif
+{
+ if (!yyvaluep)
+ return;
+# ifdef YYPRINT
+ if (yytype < YYNTOKENS)
+ YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
+# else
+ YYUSE (yyoutput);
+# endif
+ switch (yytype)
+ {
+ default:
+ break;
+ }
+}
+
+
+/*--------------------------------.
+| Print this symbol on YYOUTPUT. |
+`--------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep)
+#else
+static void
+yy_symbol_print (yyoutput, yytype, yyvaluep)
+ FILE *yyoutput;
+ int yytype;
+ YYSTYPE const * const yyvaluep;
+#endif
+{
+ if (yytype < YYNTOKENS)
+ YYFPRINTF (yyoutput, "token %s (", yytname[yytype]);
+ else
+ YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]);
+
+ yy_symbol_value_print (yyoutput, yytype, yyvaluep);
+ YYFPRINTF (yyoutput, ")");
+}
+
+/*------------------------------------------------------------------.
+| yy_stack_print -- Print the state stack from its BOTTOM up to its |
+| TOP (included). |
+`------------------------------------------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yy_stack_print (yytype_int16 *bottom, yytype_int16 *top)
+#else
+static void
+yy_stack_print (bottom, top)
+ yytype_int16 *bottom;
+ yytype_int16 *top;
+#endif
+{
+ YYFPRINTF (stderr, "Stack now");
+ for (; bottom <= top; ++bottom)
+ YYFPRINTF (stderr, " %d", *bottom);
+ YYFPRINTF (stderr, "\n");
+}
+
+# define YY_STACK_PRINT(Bottom, Top) \
+do { \
+ if (yydebug) \
+ yy_stack_print ((Bottom), (Top)); \
+} while (YYID (0))
+
+
+/*------------------------------------------------.
+| Report that the YYRULE is going to be reduced. |
+`------------------------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yy_reduce_print (YYSTYPE *yyvsp, int yyrule)
+#else
+static void
+yy_reduce_print (yyvsp, yyrule)
+ YYSTYPE *yyvsp;
+ int yyrule;
+#endif
+{
+ int yynrhs = yyr2[yyrule];
+ int yyi;
+ unsigned long int yylno = yyrline[yyrule];
+ YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n",
+ yyrule - 1, yylno);
+ /* The symbols being reduced. */
+ for (yyi = 0; yyi < yynrhs; yyi++)
+ {
+ fprintf (stderr, " $%d = ", yyi + 1);
+ yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi],
+ &(yyvsp[(yyi + 1) - (yynrhs)])
+ );
+ fprintf (stderr, "\n");
+ }
+}
+
+# define YY_REDUCE_PRINT(Rule) \
+do { \
+ if (yydebug) \
+ yy_reduce_print (yyvsp, Rule); \
+} while (YYID (0))
+
+/* Nonzero means print parse trace. It is left uninitialized so that
+ multiple parsers can coexist. */
+int yydebug;
+#else /* !YYDEBUG */
+# define YYDPRINTF(Args)
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location)
+# define YY_STACK_PRINT(Bottom, Top)
+# define YY_REDUCE_PRINT(Rule)
+#endif /* !YYDEBUG */
+
+
+/* YYINITDEPTH -- initial size of the parser's stacks. */
+#ifndef YYINITDEPTH
+# define YYINITDEPTH 200
+#endif
+
+/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only
+ if the built-in stack extension method is used).
+
+ Do not make this value too large; the results are undefined if
+ YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH)
+ evaluated with infinite-precision integer arithmetic. */
+
+#ifndef YYMAXDEPTH
+# define YYMAXDEPTH 10000
+#endif
+
+
+
+#if YYERROR_VERBOSE
+
+# ifndef yystrlen
+# if defined __GLIBC__ && defined _STRING_H
+# define yystrlen strlen
+# else
+/* Return the length of YYSTR. */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static YYSIZE_T
+yystrlen (const char *yystr)
+#else
+static YYSIZE_T
+yystrlen (yystr)
+ const char *yystr;
+#endif
+{
+ YYSIZE_T yylen;
+ for (yylen = 0; yystr[yylen]; yylen++)
+ continue;
+ return yylen;
+}
+# endif
+# endif
+
+# ifndef yystpcpy
+# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE
+# define yystpcpy stpcpy
+# else
+/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
+ YYDEST. */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static char *
+yystpcpy (char *yydest, const char *yysrc)
+#else
+static char *
+yystpcpy (yydest, yysrc)
+ char *yydest;
+ const char *yysrc;
+#endif
+{
+ char *yyd = yydest;
+ const char *yys = yysrc;
+
+ while ((*yyd++ = *yys++) != '\0')
+ continue;
+
+ return yyd - 1;
+}
+# endif
+# endif
+
+# ifndef yytnamerr
+/* Copy to YYRES the contents of YYSTR after stripping away unnecessary
+ quotes and backslashes, so that it's suitable for yyerror. The
+ heuristic is that double-quoting is unnecessary unless the string
+ contains an apostrophe, a comma, or backslash (other than
+ backslash-backslash). YYSTR is taken from yytname. If YYRES is
+ null, do not copy; instead, return the length of what the result
+ would have been. */
+static YYSIZE_T
+yytnamerr (char *yyres, const char *yystr)
+{
+ if (*yystr == '"')
+ {
+ YYSIZE_T yyn = 0;
+ char const *yyp = yystr;
+
+ for (;;)
+ switch (*++yyp)
+ {
+ case '\'':
+ case ',':
+ goto do_not_strip_quotes;
+
+ case '\\':
+ if (*++yyp != '\\')
+ goto do_not_strip_quotes;
+ /* Fall through. */
+ default:
+ if (yyres)
+ yyres[yyn] = *yyp;
+ yyn++;
+ break;
+
+ case '"':
+ if (yyres)
+ yyres[yyn] = '\0';
+ return yyn;
+ }
+ do_not_strip_quotes: ;
+ }
+
+ if (! yyres)
+ return yystrlen (yystr);
+
+ return yystpcpy (yyres, yystr) - yyres;
+}
+# endif
+
+/* Copy into YYRESULT an error message about the unexpected token
+ YYCHAR while in state YYSTATE. Return the number of bytes copied,
+ including the terminating null byte. If YYRESULT is null, do not
+ copy anything; just return the number of bytes that would be
+ copied. As a special case, return 0 if an ordinary "syntax error"
+ message will do. Return YYSIZE_MAXIMUM if overflow occurs during
+ size calculation. */
+static YYSIZE_T
+yysyntax_error (char *yyresult, int yystate, int yychar)
+{
+ int yyn = yypact[yystate];
+
+ if (! (YYPACT_NINF < yyn && yyn <= YYLAST))
+ return 0;
+ else
+ {
+ int yytype = YYTRANSLATE (yychar);
+ YYSIZE_T yysize0 = yytnamerr (0, yytname[yytype]);
+ YYSIZE_T yysize = yysize0;
+ YYSIZE_T yysize1;
+ int yysize_overflow = 0;
+ enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 };
+ char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM];
+ int yyx;
+
+# if 0
+ /* This is so xgettext sees the translatable formats that are
+ constructed on the fly. */
+ YY_("syntax error, unexpected %s");
+ YY_("syntax error, unexpected %s, expecting %s");
+ YY_("syntax error, unexpected %s, expecting %s or %s");
+ YY_("syntax error, unexpected %s, expecting %s or %s or %s");
+ YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s");
+# endif
+ char *yyfmt;
+ char const *yyf;
+ static char const yyunexpected[] = "syntax error, unexpected %s";
+ static char const yyexpecting[] = ", expecting %s";
+ static char const yyor[] = " or %s";
+ char yyformat[sizeof yyunexpected
+ + sizeof yyexpecting - 1
+ + ((YYERROR_VERBOSE_ARGS_MAXIMUM - 2)
+ * (sizeof yyor - 1))];
+ char const *yyprefix = yyexpecting;
+
+ /* Start YYX at -YYN if negative to avoid negative indexes in
+ YYCHECK. */
+ int yyxbegin = yyn < 0 ? -yyn : 0;
+
+ /* Stay within bounds of both yycheck and yytname. */
+ int yychecklim = YYLAST - yyn + 1;
+ int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
+ int yycount = 1;
+
+ yyarg[0] = yytname[yytype];
+ yyfmt = yystpcpy (yyformat, yyunexpected);
+
+ for (yyx = yyxbegin; yyx < yyxend; ++yyx)
+ if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR)
+ {
+ if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM)
+ {
+ yycount = 1;
+ yysize = yysize0;
+ yyformat[sizeof yyunexpected - 1] = '\0';
+ break;
+ }
+ yyarg[yycount++] = yytname[yyx];
+ yysize1 = yysize + yytnamerr (0, yytname[yyx]);
+ yysize_overflow |= (yysize1 < yysize);
+ yysize = yysize1;
+ yyfmt = yystpcpy (yyfmt, yyprefix);
+ yyprefix = yyor;
+ }
+
+ yyf = YY_(yyformat);
+ yysize1 = yysize + yystrlen (yyf);
+ yysize_overflow |= (yysize1 < yysize);
+ yysize = yysize1;
+
+ if (yysize_overflow)
+ return YYSIZE_MAXIMUM;
+
+ if (yyresult)
+ {
+ /* Avoid sprintf, as that infringes on the user's name space.
+ Don't have undefined behavior even if the translation
+ produced a string with the wrong number of "%s"s. */
+ char *yyp = yyresult;
+ int yyi = 0;
+ while ((*yyp = *yyf) != '\0')
+ {
+ if (*yyp == '%' && yyf[1] == 's' && yyi < yycount)
+ {
+ yyp += yytnamerr (yyp, yyarg[yyi++]);
+ yyf += 2;
+ }
+ else
+ {
+ yyp++;
+ yyf++;
+ }
+ }
+ }
+ return yysize;
+ }
+}
+#endif /* YYERROR_VERBOSE */
+
+
+/*-----------------------------------------------.
+| Release the memory associated to this symbol. |
+`-----------------------------------------------*/
+
+/*ARGSUSED*/
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep)
+#else
+static void
+yydestruct (yymsg, yytype, yyvaluep)
+ const char *yymsg;
+ int yytype;
+ YYSTYPE *yyvaluep;
+#endif
+{
+ YYUSE (yyvaluep);
+
+ if (!yymsg)
+ yymsg = "Deleting";
+ YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp);
+
+ switch (yytype)
+ {
+
+ default:
+ break;
+ }
+}
+
+
+/* Prevent warnings from -Wmissing-prototypes. */
+
+#ifdef YYPARSE_PARAM
+#if defined __STDC__ || defined __cplusplus
+int yyparse (void *YYPARSE_PARAM);
+#else
+int yyparse ();
+#endif
+#else /* ! YYPARSE_PARAM */
+#if defined __STDC__ || defined __cplusplus
+int yyparse (void);
+#else
+int yyparse ();
+#endif
+#endif /* ! YYPARSE_PARAM */
+
+
+
+/* The look-ahead symbol. */
+int yychar;
+
+/* The semantic value of the look-ahead symbol. */
+YYSTYPE yylval;
+
+/* Number of syntax errors so far. */
+int yynerrs;
+
+
+
+/*----------.
+| yyparse. |
+`----------*/
+
+#ifdef YYPARSE_PARAM
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+int
+yyparse (void *YYPARSE_PARAM)
+#else
+int
+yyparse (YYPARSE_PARAM)
+ void *YYPARSE_PARAM;
+#endif
+#else /* ! YYPARSE_PARAM */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+int
+yyparse (void)
+#else
+int
+yyparse ()
+
+#endif
+#endif
+{
+
+ int yystate;
+ int yyn;
+ int yyresult;
+ /* Number of tokens to shift before error messages enabled. */
+ int yyerrstatus;
+ /* Look-ahead token as an internal (translated) token number. */
+ int yytoken = 0;
+#if YYERROR_VERBOSE
+ /* Buffer for error messages, and its allocated size. */
+ char yymsgbuf[128];
+ char *yymsg = yymsgbuf;
+ YYSIZE_T yymsg_alloc = sizeof yymsgbuf;
+#endif
+
+ /* Three stacks and their tools:
+ `yyss': related to states,
+ `yyvs': related to semantic values,
+ `yyls': related to locations.
+
+ Refer to the stacks thru separate pointers, to allow yyoverflow
+ to reallocate them elsewhere. */
+
+ /* The state stack. */
+ yytype_int16 yyssa[YYINITDEPTH];
+ yytype_int16 *yyss = yyssa;
+ yytype_int16 *yyssp;
+
+ /* The semantic value stack. */
+ YYSTYPE yyvsa[YYINITDEPTH];
+ YYSTYPE *yyvs = yyvsa;
+ YYSTYPE *yyvsp;
+
+
+
+#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N))
+
+ YYSIZE_T yystacksize = YYINITDEPTH;
+
+ /* The variables used to return semantic value and location from the
+ action routines. */
+ YYSTYPE yyval;
+
+
+ /* The number of symbols on the RHS of the reduced rule.
+ Keep to zero when no symbol should be popped. */
+ int yylen = 0;
+
+ YYDPRINTF ((stderr, "Starting parse\n"));
+
+ yystate = 0;
+ yyerrstatus = 0;
+ yynerrs = 0;
+ yychar = YYEMPTY; /* Cause a token to be read. */
+
+ /* Initialize stack pointers.
+ Waste one element of value and location stack
+ so that they stay on the same level as the state stack.
+ The wasted elements are never initialized. */
+
+ yyssp = yyss;
+ yyvsp = yyvs;
+
+ goto yysetstate;
+
+/*------------------------------------------------------------.
+| yynewstate -- Push a new state, which is found in yystate. |
+`------------------------------------------------------------*/
+ yynewstate:
+ /* In all cases, when you get here, the value and location stacks
+ have just been pushed. So pushing a state here evens the stacks. */
+ yyssp++;
+
+ yysetstate:
+ *yyssp = yystate;
+
+ if (yyss + yystacksize - 1 <= yyssp)
+ {
+ /* Get the current used size of the three stacks, in elements. */
+ YYSIZE_T yysize = yyssp - yyss + 1;
+
+#ifdef yyoverflow
+ {
+ /* Give user a chance to reallocate the stack. Use copies of
+ these so that the &'s don't force the real ones into
+ memory. */
+ YYSTYPE *yyvs1 = yyvs;
+ yytype_int16 *yyss1 = yyss;
+
+
+ /* Each stack pointer address is followed by the size of the
+ data in use in that stack, in bytes. This used to be a
+ conditional around just the two extra args, but that might
+ be undefined if yyoverflow is a macro. */
+ yyoverflow (YY_("memory exhausted"),
+ &yyss1, yysize * sizeof (*yyssp),
+ &yyvs1, yysize * sizeof (*yyvsp),
+
+ &yystacksize);
+
+ yyss = yyss1;
+ yyvs = yyvs1;
+ }
+#else /* no yyoverflow */
+# ifndef YYSTACK_RELOCATE
+ goto yyexhaustedlab;
+# else
+ /* Extend the stack our own way. */
+ if (YYMAXDEPTH <= yystacksize)
+ goto yyexhaustedlab;
+ yystacksize *= 2;
+ if (YYMAXDEPTH < yystacksize)
+ yystacksize = YYMAXDEPTH;
+
+ {
+ yytype_int16 *yyss1 = yyss;
+ union yyalloc *yyptr =
+ (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
+ if (! yyptr)
+ goto yyexhaustedlab;
+ YYSTACK_RELOCATE (yyss);
+ YYSTACK_RELOCATE (yyvs);
+
+# undef YYSTACK_RELOCATE
+ if (yyss1 != yyssa)
+ YYSTACK_FREE (yyss1);
+ }
+# endif
+#endif /* no yyoverflow */
+
+ yyssp = yyss + yysize - 1;
+ yyvsp = yyvs + yysize - 1;
+
+
+ YYDPRINTF ((stderr, "Stack size increased to %lu\n",
+ (unsigned long int) yystacksize));
+
+ if (yyss + yystacksize - 1 <= yyssp)
+ YYABORT;
+ }
+
+ YYDPRINTF ((stderr, "Entering state %d\n", yystate));
+
+ goto yybackup;
+
+/*-----------.
+| yybackup. |
+`-----------*/
+yybackup:
+
+ /* Do appropriate processing given the current state. Read a
+ look-ahead token if we need one and don't already have one. */
+
+ /* First try to decide what to do without reference to look-ahead token. */
+ yyn = yypact[yystate];
+ if (yyn == YYPACT_NINF)
+ goto yydefault;
+
+ /* Not known => get a look-ahead token if don't already have one. */
+
+ /* YYCHAR is either YYEMPTY or YYEOF or a valid look-ahead symbol. */
+ if (yychar == YYEMPTY)
+ {
+ YYDPRINTF ((stderr, "Reading a token: "));
+ yychar = YYLEX;
+ }
+
+ if (yychar <= YYEOF)
+ {
+ yychar = yytoken = YYEOF;
+ YYDPRINTF ((stderr, "Now at end of input.\n"));
+ }
+ else
+ {
+ yytoken = YYTRANSLATE (yychar);
+ YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc);
+ }
+
+ /* If the proper action on seeing token YYTOKEN is to reduce or to
+ detect an error, take that action. */
+ yyn += yytoken;
+ if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken)
+ goto yydefault;
+ yyn = yytable[yyn];
+ if (yyn <= 0)
+ {
+ if (yyn == 0 || yyn == YYTABLE_NINF)
+ goto yyerrlab;
+ yyn = -yyn;
+ goto yyreduce;
+ }
+
+ if (yyn == YYFINAL)
+ YYACCEPT;
+
+ /* Count tokens shifted since error; after three, turn off error
+ status. */
+ if (yyerrstatus)
+ yyerrstatus--;
+
+ /* Shift the look-ahead token. */
+ YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc);
+
+ /* Discard the shifted token unless it is eof. */
+ if (yychar != YYEOF)
+ yychar = YYEMPTY;
+
+ yystate = yyn;
+ *++yyvsp = yylval;
+
+ goto yynewstate;
+
+
+/*-----------------------------------------------------------.
+| yydefault -- do the default action for the current state. |
+`-----------------------------------------------------------*/
+yydefault:
+ yyn = yydefact[yystate];
+ if (yyn == 0)
+ goto yyerrlab;
+ goto yyreduce;
+
+
+/*-----------------------------.
+| yyreduce -- Do a reduction. |
+`-----------------------------*/
+yyreduce:
+ /* yyn is the number of a rule to reduce with. */
+ yylen = yyr2[yyn];
+
+ /* If YYLEN is nonzero, implement the default value of the action:
+ `$$ = $1'.
+
+ Otherwise, the following line sets YYVAL to garbage.
+ This behavior is undocumented and Bison
+ users should not rely upon it. Assigning to YYVAL
+ unconditionally makes the parser a bit smaller, and it avoids a
+ GCC warning that YYVAL may be used uninitialized. */
+ yyval = yyvsp[1-yylen];
+
+
+ YY_REDUCE_PRINT (yyn);
+ switch (yyn)
+ {
+ case 5:
+#line 473 "exports.y"
+ { add_item((yyvsp[(1) - (1)].text)); }
+ break;
+
+ case 6:
+#line 474 "exports.y"
+ { add_item((yyvsp[(1) - (3)].text)); }
+ break;
+
+ case 7:
+#line 475 "exports.y"
+ { add_item((yyvsp[(1) - (2)].text)); }
+ break;
+
+ case 11:
+#line 485 "exports.y"
+ { add_host(); }
+ break;
+
+ case 12:
+#line 486 "exports.y"
+ { add_host(); }
+ break;
+
+ case 13:
+#line 487 "exports.y"
+ { add_host(); }
+ break;
+
+ case 14:
+#line 491 "exports.y"
+ { set_hostname((yyvsp[(1) - (1)].text)); }
+ break;
+
+ case 15:
+#line 492 "exports.y"
+ { set_ipaddr((yyvsp[(1) - (1)].text)); }
+ break;
+
+ case 16:
+#line 493 "exports.y"
+ { set_ipnet((yyvsp[(1) - (1)].text), TRUE); }
+ break;
+
+ case 17:
+#line 494 "exports.y"
+ { set_ipnet((yyvsp[(1) - (1)].text), FALSE); }
+ break;
+
+ case 21:
+#line 504 "exports.y"
+ { add_option((yyvsp[(1) - (1)].text)); }
+ break;
+
+ case 22:
+#line 505 "exports.y"
+ { add_option_with_value((yyvsp[(1) - (2)].text),(yyvsp[(2) - (2)].text)); }
+ break;
+
+
+/* Line 1267 of yacc.c. */
+#line 1847 "y.tab.c"
+ default: break;
+ }
+ YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
+
+ YYPOPSTACK (yylen);
+ yylen = 0;
+ YY_STACK_PRINT (yyss, yyssp);
+
+ *++yyvsp = yyval;
+
+
+ /* Now `shift' the result of the reduction. Determine what state
+ that goes to, based on the state we popped back to and the rule
+ number reduced by. */
+
+ yyn = yyr1[yyn];
+
+ yystate = yypgoto[yyn - YYNTOKENS] + *yyssp;
+ if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp)
+ yystate = yytable[yystate];
+ else
+ yystate = yydefgoto[yyn - YYNTOKENS];
+
+ goto yynewstate;
+
+
+/*------------------------------------.
+| yyerrlab -- here on detecting error |
+`------------------------------------*/
+yyerrlab:
+ /* If not already recovering from an error, report this error. */
+ if (!yyerrstatus)
+ {
+ ++yynerrs;
+#if ! YYERROR_VERBOSE
+ yyerror (YY_("syntax error"));
+#else
+ {
+ YYSIZE_T yysize = yysyntax_error (0, yystate, yychar);
+ if (yymsg_alloc < yysize && yymsg_alloc < YYSTACK_ALLOC_MAXIMUM)
+ {
+ YYSIZE_T yyalloc = 2 * yysize;
+ if (! (yysize <= yyalloc && yyalloc <= YYSTACK_ALLOC_MAXIMUM))
+ yyalloc = YYSTACK_ALLOC_MAXIMUM;
+ if (yymsg != yymsgbuf)
+ YYSTACK_FREE (yymsg);
+ yymsg = (char *) YYSTACK_ALLOC (yyalloc);
+ if (yymsg)
+ yymsg_alloc = yyalloc;
+ else
+ {
+ yymsg = yymsgbuf;
+ yymsg_alloc = sizeof yymsgbuf;
+ }
+ }
+
+ if (0 < yysize && yysize <= yymsg_alloc)
+ {
+ (void) yysyntax_error (yymsg, yystate, yychar);
+ yyerror (yymsg);
+ }
+ else
+ {
+ yyerror (YY_("syntax error"));
+ if (yysize != 0)
+ goto yyexhaustedlab;
+ }
+ }
+#endif
+ }
+
+
+
+ if (yyerrstatus == 3)
+ {
+ /* If just tried and failed to reuse look-ahead token after an
+ error, discard it. */
+
+ if (yychar <= YYEOF)
+ {
+ /* Return failure if at end of input. */
+ if (yychar == YYEOF)
+ YYABORT;
+ }
+ else
+ {
+ yydestruct ("Error: discarding",
+ yytoken, &yylval);
+ yychar = YYEMPTY;
+ }
+ }
+
+ /* Else will try to reuse look-ahead token after shifting the error
+ token. */
+ goto yyerrlab1;
+
+
+/*---------------------------------------------------.
+| yyerrorlab -- error raised explicitly by YYERROR. |
+`---------------------------------------------------*/
+yyerrorlab:
+
+ /* Pacify compilers like GCC when the user code never invokes
+ YYERROR and the label yyerrorlab therefore never appears in user
+ code. */
+ if (/*CONSTCOND*/ 0)
+ goto yyerrorlab;
+
+ /* Do not reclaim the symbols of the rule which action triggered
+ this YYERROR. */
+ YYPOPSTACK (yylen);
+ yylen = 0;
+ YY_STACK_PRINT (yyss, yyssp);
+ yystate = *yyssp;
+ goto yyerrlab1;
+
+
+/*-------------------------------------------------------------.
+| yyerrlab1 -- common code for both syntax error and YYERROR. |
+`-------------------------------------------------------------*/
+yyerrlab1:
+ yyerrstatus = 3; /* Each real token shifted decrements this. */
+
+ for (;;)
+ {
+ yyn = yypact[yystate];
+ if (yyn != YYPACT_NINF)
+ {
+ yyn += YYTERROR;
+ if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
+ {
+ yyn = yytable[yyn];
+ if (0 < yyn)
+ break;
+ }
+ }
+
+ /* Pop the current state because it cannot handle the error token. */
+ if (yyssp == yyss)
+ YYABORT;
+
+
+ yydestruct ("Error: popping",
+ yystos[yystate], yyvsp);
+ YYPOPSTACK (1);
+ yystate = *yyssp;
+ YY_STACK_PRINT (yyss, yyssp);
+ }
+
+ if (yyn == YYFINAL)
+ YYACCEPT;
+
+ *++yyvsp = yylval;
+
+
+ /* Shift the error token. */
+ YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp);
+
+ yystate = yyn;
+ goto yynewstate;
+
+
+/*-------------------------------------.
+| yyacceptlab -- YYACCEPT comes here. |
+`-------------------------------------*/
+yyacceptlab:
+ yyresult = 0;
+ goto yyreturn;
+
+/*-----------------------------------.
+| yyabortlab -- YYABORT comes here. |
+`-----------------------------------*/
+yyabortlab:
+ yyresult = 1;
+ goto yyreturn;
+
+#ifndef yyoverflow
+/*-------------------------------------------------.
+| yyexhaustedlab -- memory exhaustion comes here. |
+`-------------------------------------------------*/
+yyexhaustedlab:
+ yyerror (YY_("memory exhausted"));
+ yyresult = 2;
+ /* Fall through. */
+#endif
+
+yyreturn:
+ if (yychar != YYEOF && yychar != YYEMPTY)
+ yydestruct ("Cleanup: discarding lookahead",
+ yytoken, &yylval);
+ /* Do not reclaim the symbols of the rule which action triggered
+ this YYABORT or YYACCEPT. */
+ YYPOPSTACK (yylen);
+ YY_STACK_PRINT (yyss, yyssp);
+ while (yyssp != yyss)
+ {
+ yydestruct ("Cleanup: popping",
+ yystos[*yyssp], yyvsp);
+ YYPOPSTACK (1);
+ }
+#ifndef yyoverflow
+ if (yyss != yyssa)
+ YYSTACK_FREE (yyss);
+#endif
+#if YYERROR_VERBOSE
+ if (yymsg != yymsgbuf)
+ YYSTACK_FREE (yymsg);
+#endif
+ /* Make sure YYID is used. */
+ return YYID (yyresult);
+}
+
+
+#line 507 "exports.y"
+
+
+/*
+ * C code using yacc parser + access code for exports list
+ */
+
+/* effective export list and access flag */
+static e_item *export_list = NULL;
+static volatile int exports_access = FALSE;
+
+/* mount protocol compatible exports list */
+exports exports_nfslist = NULL;
+
+/*
+ * free NFS groups list
+ */
+void free_nfsgroups(groups group)
+{
+ groups list, next;
+
+ list = group;
+ while (list) {
+ next = (groups) list->gr_next;
+ free(list);
+ list = next;
+ }
+}
+
+/*
+ * free NFS exports list
+ */
+void free_nfslist(exports elist)
+{
+ exports list, next;
+
+ list = elist;
+ while(list) {
+ next = (exports) list->ex_next;
+ free_nfsgroups(list->ex_groups);
+ free(list);
+ list = next;
+ }
+}
+
+/*
+ * free list of host structures
+ */
+static void free_hosts(e_item *item)
+{
+ e_host *host, *cur;
+
+ host = item->hosts;
+ while (host) {
+ cur = host;
+ host = (e_host *) host->next;
+ free(cur);
+ }
+}
+
+/*
+ * free list of export items
+ */
+static void free_list(e_item *item)
+{
+ e_item *cur;
+
+ while (item) {
+ free_hosts(item);
+ cur = item;
+ item = (e_item *) item->next;
+ free(cur);
+ }
+}
+
+/*
+ * print out the current exports list (for debugging)
+ */
+void print_list(void)
+{
+ char addrbuf[16], maskbuf[16];
+
+ e_item *item;
+ e_host *host;
+
+ item = e_list;
+
+ while (item) {
+ host = item->hosts;
+ while (host) {
+ /* inet_ntoa returns static buffer */
+ strcpy(addrbuf, inet_ntoa(host->addr));
+ strcpy(maskbuf, inet_ntoa(host->mask));
+ printf("%s: ip %s mask %s options %i\n",
+ item->path, addrbuf, maskbuf,
+ host->options);
+ host = (e_host *) host->next;
+ }
+ item = (e_item *) item->next;
+ }
+}
+
+/*
+ * clear current parse state
+ */
+static void clear_cur(void)
+{
+ e_list = NULL;
+ ne_list = NULL;
+ e_error = FALSE;
+ clear_host();
+ clear_item();
+}
+
+/*
+ * parse an exports file
+ */
+int exports_parse(void)
+{
+ FILE *efile;
+
+ /*
+ * if we are in the SIGHUP handler, a may_mount or get_options
+ * may currently be accessing the list
+ */
+ if (exports_access) {
+ logmsg(LOG_CRIT, "export list is being traversed, no reload\n");
+ return FALSE;
+ }
+
+ efile = fopen(opt_exports, "r");
+ if (!efile) {
+ logmsg(LOG_CRIT, "could not open '%s', exporting nothing",
+ opt_exports);
+ free_list(export_list);
+ free_nfslist(exports_nfslist);
+ export_list = NULL;
+ exports_nfslist = NULL;
+ return FALSE;
+ }
+
+ yyin = efile;
+ clear_cur();
+ yyparse();
+ fclose(efile);
+
+ if (e_error) {
+ logmsg(LOG_CRIT, "syntax error in '%s', exporting nothing",
+ opt_exports);
+ free_list(export_list);
+ free_nfslist(exports_nfslist);
+ export_list = NULL;
+ exports_nfslist = NULL;
+ return FALSE;
+ }
+
+ /* print out new list for debugging */
+ if (!opt_detach)
+ print_list();
+
+ free_list(export_list);
+ free_nfslist(exports_nfslist);
+ export_list = e_list;
+ exports_nfslist = ne_list;
+ return TRUE;
+}
+
+/*
+ * find a given host inside a host list, return options
+ */
+static e_host* find_host(struct in_addr remote, e_item *item,
+ char **password, uint32 *password_hash)
+{
+ e_host *host;
+
+ host = item->hosts;
+ while (host) {
+ if ((remote.s_addr & host->mask.s_addr) == host->addr.s_addr) {
+ if (password != NULL)
+ *password = host->password;
+ if (password_hash != NULL)
+ *password_hash = host->password_hash;
+ return host;
+ }
+ host = (e_host *) host->next;
+ }
+ return NULL;
+}
+
+/* options cache */
+int exports_opts = -1;
+const char *export_path = NULL;
+uint32 export_fsid = 0;
+uint32 export_password_hash = 0;
+
+/*
+ * given a path, return client's effective options
+ */
+int exports_options(const char *path, struct svc_req *rqstp,
+ char **password, uint32 *fsid)
+{
+ e_item *list;
+ struct in_addr remote;
+ unsigned int last_len = 0;
+
+ exports_opts = -1;
+ export_path = NULL;
+ export_fsid = 0;
+ last_anonuid = ANON_NOTSPECIAL;
+ last_anongid = ANON_NOTSPECIAL;
+
+ /* check for client attempting to use invalid pathname */
+ if (!path || strstr(path, "/../"))
+ return exports_opts;
+
+ remote = get_remote(rqstp);
+
+ /* protect against SIGHUP reloading the list */
+ exports_access = TRUE;
+
+ list = export_list;
+ while (list) {
+ /* longest matching prefix wins */
+ if (strlen(list->path) > last_len &&
+#ifndef WIN32
+ strstr(path, list->path) == path) {
+#else
+ !win_utf8ncasecmp(path, list->path, strlen(list->path))) {
+#endif
+ e_host* cur_host = find_host(remote, list, password, &export_password_hash);
+
+ if (fsid != NULL)
+ *fsid = list->fsid;
+ if (cur_host) {
+ exports_opts = cur_host->options;
+ export_path = list->path;
+ export_fsid = list->fsid;
+ last_len = strlen(list->path);
+ last_anonuid = cur_host->anonuid;
+ last_anongid = cur_host->anongid;
+ }
+ }
+ list = (e_item *) list->next;
+ }
+ exports_access = FALSE;
+ return exports_opts;
+}
+
+/*
+ * check whether path is an export point
+ */
+int export_point(const char *path)
+{
+ e_item *list;
+
+ exports_access = TRUE;
+ list = export_list;
+
+ while (list) {
+ if (strcmp(path, list->path) == 0) {
+ exports_access = FALSE;
+ return TRUE;
+ }
+ list = (e_item *) list->next;
+ }
+ exports_access = FALSE;
+ return FALSE;
+}
+
+/*
+ * return exported path from static fsid
+ */
+char *export_point_from_fsid(uint32 fsid, time_t **last_mtime, uint32 **dir_hash)
+{
+ e_item *list;
+
+ exports_access = TRUE;
+ list = export_list;
+
+ while (list) {
+ if (list->fsid == fsid) {
+ if (last_mtime != NULL)
+ *last_mtime = &list->last_mtime;
+ if (dir_hash != NULL)
+ *dir_hash = &list->dir_hash;
+ exports_access = FALSE;
+ return list->path;
+ }
+ list = (e_item *) list->next;
+ }
+ exports_access = FALSE;
+ return NULL;
+}
+
+
+/*
+ * check whether export options of a path match with last set of options
+ */
+nfsstat3 exports_compat(const char *path, struct svc_req *rqstp)
+{
+ int prev;
+ uint32 prev_anonuid, prev_anongid;
+
+ prev = exports_opts;
+ prev_anonuid = last_anonuid;
+ prev_anongid = last_anongid;
+
+ if (exports_options(path, rqstp, NULL, NULL) == prev &&
+ last_anonuid == prev_anonuid &&
+ last_anongid == prev_anongid)
+ return NFS3_OK;
+ else if (exports_opts == -1)
+ return NFS3ERR_ACCES;
+ else
+ return NFS3ERR_XDEV;
+}
+
+/*
+ * check whether options indicate rw mount
+ */
+nfsstat3 exports_rw(void)
+{
+ if (exports_opts != -1 && (exports_opts & OPT_RW))
+ return NFS3_OK;
+ else
+ return NFS3ERR_ROFS;
+}
+
+/*
+ * returns the last looked-up anonuid for a mount (ANON_NOTSPECIAL means none in effect)
+ */
+uint32 exports_anonuid(void)
+{
+ return last_anonuid;
+}
+
+/*
+ * returns the last looked-up anongid for a mount (ANON_NOTSPECIAL means none in effect)
+ */
+uint32 exports_anongid(void)
+{
+ return last_anongid;
+}
+
diff --git a/external/fs/unfs3-0.9.22/Config/y.tab.h b/external/fs/unfs3-0.9.22/Config/y.tab.h
new file mode 100644
index 0000000..42ebab1
--- /dev/null
+++ b/external/fs/unfs3-0.9.22/Config/y.tab.h
@@ -0,0 +1,78 @@
+/* A Bison parser, made by GNU Bison 2.3. */
+
+/* Skeleton interface for Bison's Yacc-like parsers in C
+
+ Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
+ Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA. */
+
+/* As a special exception, you may create a larger work that contains
+ part or all of the Bison parser skeleton and distribute that work
+ under terms of your choice, so long as that work isn't itself a
+ parser generator using the skeleton or a modified version thereof
+ as a parser skeleton. Alternatively, if you modify or redistribute
+ the parser skeleton itself, you may (at your option) remove this
+ special exception, which will cause the skeleton and the resulting
+ Bison output files to be licensed under the GNU General Public
+ License without this special exception.
+
+ This special exception was added by the Free Software Foundation in
+ version 2.2 of Bison. */
+
+/* Tokens. */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+ /* Put the tokens into the symbol table, so that GDB and other debuggers
+ know about them. */
+ enum yytokentype {
+ PATH = 258,
+ ID = 259,
+ OPTVALUE = 260,
+ WHITE = 261,
+ IP = 262,
+ NET = 263,
+ OLDNET = 264
+ };
+#endif
+/* Tokens. */
+#define PATH 258
+#define ID 259
+#define OPTVALUE 260
+#define WHITE 261
+#define IP 262
+#define NET 263
+#define OLDNET 264
+
+
+
+
+#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+typedef union YYSTYPE
+#line 452 "exports.y"
+{
+ char text[NFS_MAXPATHLEN];
+}
+/* Line 1489 of yacc.c. */
+#line 71 "y.tab.h"
+ YYSTYPE;
+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+# define YYSTYPE_IS_DECLARED 1
+# define YYSTYPE_IS_TRIVIAL 1
+#endif
+
+extern YYSTYPE yylval;
+
diff --git a/external/fs/unfs3-0.9.22/Extras/Makefile.in b/external/fs/unfs3-0.9.22/Extras/Makefile.in
new file mode 100644
index 0000000..038f10c
--- /dev/null
+++ b/external/fs/unfs3-0.9.22/Extras/Makefile.in
@@ -0,0 +1,23 @@
+CC = @CC@
+CFLAGS = @CFLAGS@
+AR = ar
+RM = rm -f
+
+SOURCES = cluster.c
+OBJS = cluster.o
+
+all: lib.a
+
+lib.a: $(OBJS)
+ $(AR) crs lib.a $(OBJS)
+
+dep: $(SOURCES)
+ $(CC) $(CFLAGS) -MM $(SOURCES) >> Makefile
+
+clean:
+ $(RM) $(OBJS) lib.a
+
+distclean:
+ $(RM) Makefile
+
+# automatically generated dependencies follow
diff --git a/external/fs/unfs3-0.9.22/Extras/cluster.c b/external/fs/unfs3-0.9.22/Extras/cluster.c
new file mode 100644
index 0000000..3dd5628
--- /dev/null
+++ b/external/fs/unfs3-0.9.22/Extras/cluster.c
@@ -0,0 +1,512 @@
+
+/*
+ * UNFS3 cluster support
+ * (C) 2004, Pascal Schmidt
+ * see file LICENSE for license details
+ */
+
+#include "../config.h"
+
+#ifdef WANT_CLUSTER
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <rpc/rpc.h>
+#include <dirent.h>
+#include <errno.h>
+#include <libgen.h>
+#include <netdb.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include "../nfs.h"
+#include "../daemon.h"
+#include "../backend.h"
+#include "cluster.h"
+
+/* array of dirents prefixed with master file name */
+static char **cluster_dirents = NULL;
+
+/* number of dirents in above array */
+static int cluster_count = -1;
+
+/*
+ * check whether given pathname is in clustering path
+ */
+int want_cluster(const char *path)
+{
+ char buf[NFS_MAXPATHLEN];
+ char *last, *next;
+
+ /* if path is too long, play it safe */
+ if (strlen(opt_cluster_path) + 1 > NFS_MAXPATHLEN)
+ return TRUE;
+
+ strcpy(buf, opt_cluster_path);
+ last = buf;
+
+ /* iterate over colon-seperated list */
+ do {
+ next = strchr(last, ':');
+ if (next)
+ *next = 0;
+
+ if (strstr(path, last) == path)
+ return TRUE;
+
+ if (next) {
+ last = next + 1;
+ if (strlen(last) == 0)
+ last = NULL;
+ } else {
+ last = NULL;
+ }
+ } while (last);
+
+ return FALSE;
+}
+
+/*
+ * get name of remote machine
+ */
+static char *get_host(struct in_addr remote)
+{
+ static char buf[NFS_MAXPATHLEN];
+ struct hostent *entry;
+ char *dot;
+
+ entry = gethostbyaddr((char *) &remote, sizeof(struct in_addr), AF_INET);
+
+ if (entry) {
+ strcpy(buf, entry->h_name);
+
+ /* have the name string end at the first dot */
+ dot = strchr(buf, '.');
+ if (dot)
+ *dot = 0;
+
+ return buf;
+ }
+
+ return NULL;
+}
+
+/*
+ * check whether name is already host tagged name
+ */
+int is_host(const char *name)
+{
+ return (int) (strstr(name, "$$HOST=") && name[strlen(name) - 1] == '$' &&
+ name[strlen(name) - 2] == '$');
+}
+
+/*
+ * check whether a hostname matches a dirent
+ */
+char *match_host(const char *hname, const char *entry)
+{
+ char buf[NFS_MAXPATHLEN];
+ static char *part;
+
+ /* check for presence of hostname tag */
+ if (!is_host(entry))
+ return NULL;
+
+ part = strstr(entry, "$$HOST=");
+
+ /* copy hostname part of host tag */
+ memcpy(buf, part + 7, strlen(part) - 8);
+ buf[strlen(part) - 9] = 0;
+
+ /* exact match? */
+ if (strcmp(buf, hname) == 0)
+ return part;
+
+ /* wildcard pattern? */
+ if (buf[strlen(buf) - 1] != '*')
+ return NULL;
+
+ /* if wildcard, check for matching prefix */
+ buf[strlen(buf) - 1] = 0;
+ if (strstr(hname, buf) == hname)
+ return part;
+
+ return NULL;
+}
+
+/*
+ * better dirname providing internal buffer
+ */
+char *cluster_dirname(const char *path)
+{
+ static char buf[NFS_MAXPATHLEN];
+
+ strcpy(buf, path);
+ return dirname(buf);
+}
+
+/*
+ * better basename providing internal buffer
+ */
+char *cluster_basename(const char *path)
+{
+ static char buf[NFS_MAXPATHLEN];
+
+ strcpy(buf, path);
+ return basename(buf);
+}
+
+/*
+ * free dirent array
+ */
+void cluster_freedir(void)
+{
+ /* only if it was really allocated before */
+ if (cluster_dirents) {
+ while (cluster_count--)
+ free(cluster_dirents[cluster_count]);
+ free(cluster_dirents);
+ cluster_dirents = NULL;
+ }
+}
+
+/*
+ * compare function for qsort'ing the scandir list
+ */
+int compar(const void *x, const void *y)
+{
+ return strcmp(*(const char **) x, *(const char **) y);
+}
+
+/*
+ * reset euid/egid to specific values
+ */
+static void reset_ids(uid_t euid, gid_t egid)
+{
+ if (backend_setegid(egid) || backend_seteuid(euid)) {
+ logmsg(LOG_EMERG, "euid/egid switching failed, aborting");
+ daemon_exit(CRISIS);
+ }
+}
+
+/*
+ * scan directory for filenames beginning with master name as prefix
+ */
+void cluster_scandir(const char *path)
+{
+ char prefix[NFS_MAXPATHLEN];
+ DIR *scan;
+ struct dirent *entry;
+ char **new, *name;
+ uid_t euid;
+ gid_t egid;
+
+ strcpy(prefix, cluster_basename(path));
+
+ /*
+ * need to read directory as root, temporarily switch back
+ */
+ euid = backend_geteuid();
+ egid = backend_getegid();
+ backend_setegid(0);
+ backend_seteuid(0);
+
+ scan = backend_opendir(cluster_dirname(path));
+ if (!scan) {
+ cluster_count = -1;
+ reset_ids(euid, egid);
+ return;
+ }
+
+ cluster_count = 0;
+ while ((entry = backend_readdir(scan))) {
+ if (strstr(entry->d_name, prefix) != entry->d_name &&
+ strcmp(entry->d_name, "$$CREATE=IP$$") != 0 &&
+ strcmp(entry->d_name, "$$CREATE=CLIENT$$") != 0 &&
+ strcmp(entry->d_name, "$$ALWAYS=IP$$") != 0 &&
+ strcmp(entry->d_name, "$$ALWAYS=CLIENT$$") != 0)
+ continue;
+
+ name = malloc(strlen(entry->d_name) + 1);
+ new = realloc(cluster_dirents, (cluster_count + 1) * sizeof(char *));
+ if (!new || !name) {
+ cluster_freedir();
+ cluster_count = -1;
+ free(new);
+ free(name);
+ backend_closedir(scan);
+ reset_ids(euid, egid);
+ return;
+ }
+
+ strcpy(name, entry->d_name);
+ cluster_dirents = new;
+ cluster_dirents[cluster_count] = name;
+ cluster_count++;
+ }
+
+ backend_closedir(scan);
+ reset_ids(euid, egid);
+
+ /* list needs to be sorted for cluster_lookup_lowlevel to work */
+ qsort(cluster_dirents, cluster_count, sizeof(char *), compar);
+}
+
+/*
+ * check whether master name + suffix matches with a string
+ */
+int match_suffix(const char *master, const char *suffix, const char *entry)
+{
+ char obj[NFS_MAXPATHLEN];
+
+ sprintf(obj, "%s%s", master, suffix);
+
+ if (strcmp(entry, obj) == 0)
+ return CLU_SLAVE;
+ else
+ return FALSE;
+}
+
+/*
+ * create string version of a netmask
+ * buf: where to put string
+ * remote: full IP address of remote machine
+ * n: number of dots to keep
+ */
+void cluster_netmask(char *buf, const char *remote, int n)
+{
+ int i;
+
+ sprintf(buf, "$$IP=%s", remote);
+
+ /* skip to desired dot position */
+ for (i = 0; i < n; i++)
+ buf = strchr(buf, '.') + 1;
+
+ *buf-- = 0;
+
+ /* append trailer of netmask string */
+ switch (n) {
+ case 3:
+ strcat(buf, "0_24$$");
+ break;
+ case 2:
+ strcat(buf, "0.0_16$$");
+ break;
+ case 1:
+ strcat(buf, "0.0.0_8$$");
+ break;
+ }
+}
+
+/*
+ * look up cluster name, defaulting to master name if no slave name found
+ */
+int cluster_lookup_lowlevel(char *path, struct svc_req *rqstp)
+{
+ struct in_addr raddr;
+ char *remote, *hname, *master, *entry, *match;
+ char buf[NFS_MAXPATHLEN];
+ int i, res = CLU_MASTER;
+
+ cluster_freedir();
+ cluster_scandir(path);
+
+ if (cluster_count == -1)
+ return CLU_IO;
+ else if (cluster_count == 0)
+ return CLU_MASTER;
+
+ raddr = get_remote(rqstp); /* remote IP address */
+ master = cluster_basename(path); /* master file name */
+ remote = inet_ntoa(raddr); /* remote IP address string */
+ hname = get_host(raddr); /* remote hostname */
+
+ /*
+ * traversal in reverse alphanumerical order, so that
+ * IP is encountered before HOST, HOST before CLIENT,
+ * CLIENT before ALWAYS, and also subnets are encountered
+ * in the right order
+ */
+ i = cluster_count;
+ while (i--) {
+ entry = cluster_dirents[i];
+
+ /* match specific IP address */
+ sprintf(buf, "$$IP=%s$$", remote);
+ if ((res = match_suffix(master, buf, entry)))
+ break;
+
+ /* always match IP file */
+ if ((res = match_suffix(master, "$$ALWAYS=IP$$", entry)))
+ break;
+ if (strcmp("$$ALWAYS=IP$$", entry) == 0) {
+ res = CLU_SLAVE;
+ break;
+ }
+
+ /* match all clients */
+ strcpy(buf, "$$CLIENT$$");
+ if ((res = match_suffix(master, buf, entry)))
+ break;
+
+ /* always match CLIENT file */
+ if ((res = match_suffix(master, "$$ALWAYS=CLIENT$$", entry)))
+ break;
+ if (strcmp("$$ALWAYS=CLIENT$$", entry) == 0) {
+ res = CLU_SLAVE;
+ break;
+ }
+
+ /* match 24 bit network address */
+ cluster_netmask(buf, remote, 3);
+ if ((res = match_suffix(master, buf, entry)))
+ break;
+
+ /* match 16 bit network address */
+ cluster_netmask(buf, remote, 2);
+ if ((res = match_suffix(master, buf, entry)))
+ break;
+
+ /* match 8 bit network address */
+ cluster_netmask(buf, remote, 1);
+ if ((res = match_suffix(master, buf, entry)))
+ break;
+
+ /* match hostname pattern */
+ if (!is_host(master)) {
+ match = match_host(hname, entry);
+ if (match) {
+ res = CLU_SLAVE;
+ strcpy(buf, match);
+ break;
+ }
+ }
+ }
+
+ /* append suffix if possible */
+ if (res == CLU_SLAVE) {
+ if (strlen(path) + strlen(buf) + 1 < NFS_MAXPATHLEN)
+ strcat(path, buf);
+ else
+ res = CLU_TOOLONG;
+ } else {
+ /* res will be 0 after above loop */
+ res = CLU_MASTER;
+ }
+
+ /*
+ * dirent array not freed here since cluster_create may need
+ * to look at it afterwards
+ */
+
+ return res;
+}
+
+/*
+ * substitute slave filename if possible
+ */
+void cluster_lookup(char *path, struct svc_req *rqstp, nfsstat3 * nstat)
+{
+ int res;
+
+ if (!opt_cluster)
+ return;
+
+ if (!path)
+ return;
+
+ if (*nstat != NFS3_OK)
+ return;
+
+ if (!want_cluster(path))
+ return;
+
+ res = strlen(path);
+ if (strstr(path, "$$$$") == path + res - 4) {
+ *(path + res - 4) = 0;
+ return;
+ }
+
+ res = cluster_lookup_lowlevel(path, rqstp);
+ if (res == CLU_TOOLONG)
+ *nstat = NFS3ERR_NAMETOOLONG;
+ else if (res == CLU_IO)
+ *nstat = NFS3ERR_IO;
+}
+
+/*
+ * substitute slave filename if possible, for create operations
+ */
+void cluster_create(char *path, struct svc_req *rqstp, nfsstat3 * nstat)
+{
+ int i, res;
+ char buf[NFS_MAXPATHLEN];
+ char *master, *entry;
+
+ if (!opt_cluster)
+ return;
+
+ if (*nstat != NFS3_OK)
+ return;
+
+ if (!want_cluster(path))
+ return;
+
+ res = cluster_lookup_lowlevel(path, rqstp);
+
+ if (res == CLU_TOOLONG) {
+ *nstat = NFS3ERR_NAMETOOLONG;
+ return;
+ } else if (res == CLU_IO) {
+ *nstat = NFS3ERR_IO;
+ return;
+ } else if (res == CLU_SLAVE)
+ return;
+
+ master = cluster_basename(path);
+
+ /* look for create tag */
+ i = cluster_count;
+ while (i--) {
+ entry = cluster_dirents[i];
+
+ /* always create IP file */
+ sprintf(buf, "$$IP=%s$$", inet_ntoa(get_remote(rqstp)));
+ if ((res = match_suffix(master, "$$CREATE=IP$$", entry)) ||
+ (res = match_suffix(master, "$$ALWAYS=IP$$", entry)))
+ break;
+ if ((strcmp("$$CREATE=IP$$", entry) == 0) ||
+ (strcmp("$$ALWAYS=IP$$", entry) == 0)) {
+ res = CLU_SLAVE;
+ break;
+ }
+
+ /* always create CLIENT file */
+ sprintf(buf, "$$CLIENT$$");
+ if ((res = match_suffix(master, "$$CREATE=CLIENT$$", entry)) ||
+ (res = match_suffix(master, "$$ALWAYS=CLIENT$$", entry)))
+ break;
+ if ((strcmp("$$CREATE=CLIENT$$", entry) == 0) ||
+ (strcmp("$$ALWAYS=CLIENT$$", entry) == 0)) {
+ res = CLU_SLAVE;
+ break;
+ }
+ }
+
+ if (res != CLU_SLAVE)
+ return;
+
+ /* append suffix if possible */
+ if (strlen(path) + strlen(buf) + 1 < NFS_MAXPATHLEN)
+ strcat(path, buf);
+ else
+ *nstat = NFS3ERR_NAMETOOLONG;
+}
+
+#endif
diff --git a/external/fs/unfs3-0.9.22/Extras/cluster.h b/external/fs/unfs3-0.9.22/Extras/cluster.h
new file mode 100644
index 0000000..d892e2e
--- /dev/null
+++ b/external/fs/unfs3-0.9.22/Extras/cluster.h
@@ -0,0 +1,27 @@
+/*
+ * UNFS3 cluster extensions
+ * (C) 2003, Pascal Schmidt
+ * see file LICENSE for license details
+ */
+
+#ifndef UNFS3_CLUSTER_H
+#define UNFS3_CLUSTER_H
+
+#ifdef WANT_CLUSTER
+
+#define CLU_TOOLONG 0 /* name got too long */
+#define CLU_SLAVE 1 /* slave file matched */
+#define CLU_MASTER 2 /* master file matched */
+#define CLU_IO 3 /* I/O error */
+
+void cluster_lookup(char *path, struct svc_req *rqstp, nfsstat3 *nstat);
+void cluster_create(char *path, struct svc_req *rqstp, nfsstat3 *nstat);
+
+#else
+
+#define cluster_lookup(x,y,z)
+#define cluster_create(x,y,z)
+
+#endif
+
+#endif
diff --git a/external/fs/unfs3-0.9.22/Extras/tags.7 b/external/fs/unfs3-0.9.22/Extras/tags.7
new file mode 100644
index 0000000..b95c2f3
--- /dev/null
+++ b/external/fs/unfs3-0.9.22/Extras/tags.7
@@ -0,0 +1,123 @@
+.\"
+.\" (C) 2004, Pascal Schmidt
+.\"
+.TH tags 7 "04 Jan 2004"
+.SH NAME
+tags \- tagged files used for clustering extensions
+.SH DESCRIPTION
+Tagged files are used by
+.B ClusterNFS
+and
+.B unfs3
+to support NFS exporting directories like
+.I /etc
+and
+.I /var
+to a cluster of client machines. The problem at hand is that different
+files need to be served to different clients. Tagged files provide a
+way to specify which file should be served to which client(s).
+.P
+Tags are appended to the end of a filename and are seperated from the
+rest of the name by beginning and ending with $$. For each file, there
+can be multiple tagged variants. The normal file, without a tag, is
+only served to clients by default when no tagged file matching the client is
+found. The following tags exist:
+.TP
+.B file$$$$
+If a client attempts to access this file, it will be redirected to the
+normal file instead, no matter what other tagged files exist. This
+is mainly useful for use inside symlinks that need to point to a normal
+file although other access to the normal file should be redirected. In
+this special case, the tagged file
+.B file$$$$
+does not even need to exist (the symlink will then seem to be dangling
+on the server).
+.TP
+.B file$$IP=a.b.c.d$$
+If a client with an IP address of
+.I a.b.c.d
+attempts to access the normal file,
+it will be redirected to this file instead.
+.TP
+.B file$$IP=a.b.c.d_n$$
+If a client with an IP adress in the network
+.I a.b.c.d/n
+attempts to
+access the normal file, it will be redirected to this file instead. Note that
+.B unfs3
+only supports 8, 16, and 24 as values for
+.BR n .
+.TP
+.B file$$HOST=name$$
+If a client with the hostname
+.I name
+attempts to access the normal file, it will be redirected to this file instead.
+.TP
+.B file$$HOST=name*$$
+If a client whose hostname begins with the string
+.I name
+attempts to access the normal file, it will be redirected to this file instead.
+.TP
+.B file$$CLIENT$$
+If any client attempts to access the normal file, it will be redirected to this
+file instead.
+.TP
+.B file$$ALWAYS=IP$$
+If any client attempts to access or create the normal file, it will be redirected to
+.B file$$IP=a.b.c.d$$
+instead, where
+.I a.b.c.d
+is the IP address of the client. It does not matter whether the target
+tagged file exists or not.
+.TP
+.B file$$ALWAYS=CLIENT$$
+If any client attempts to access or create the normal file, it will be redirected to
+.B file$$CLIENT$$
+instead. It does not matter whether that file exists or not.
+.TP
+.B $$ALWAYS=CLIENT$$
+Like above, but effective for all files in the directory where it is found.
+.TP
+.B $$ALWAYS=IP$$
+Like above, but effective for all files in the directory where it is found.
+.PP
+Note that the ALWAYS tag can lead to file not found errors on clients
+if the tagged files it redirects to does not exist on the server. For
+example,
+.BR ls (1)
+can suffer from this problem. Furthermore, this tag is a
+.B unfs3
+extension and does not exist in
+.BR ClusterNFS .
+When this tags exists, it prevents all access to the normal file by any
+client.
+.TP
+.B file$$CREATE=IP$$
+If any client attempts to create the normal file,
+.B file$$IP=a.b.c.d$$
+will be created instead, where
+.I a.b.c.d
+is the IP address of the client.
+.TP
+.B file$$CREATE=CLIENT$$
+If any client attempts to create the normal file,
+.B file$$CLIENT$$
+will be created instead.
+.TP
+.B $$CREATE=IP$$
+Like above, but effective for all files in the directory where it is found.
+.TP
+.B $$CREATE=CLIENT$$
+Like above, but effective for all files in the directory where it is found.
+.PP
+Tags work for all kinds of named filesystem objects.
+If multiple tagged files
+are found for a normal file, they are considered in the order they are
+given above, starting at the top. Processing stops once a match is found.
+In
+.BR ClusterNFS ", but not in " unfs3 ,
+only files accessible and readable by a client are considered matches.
+.SH AUTHOR
+Pascal Schmidt
+.SH "SEE ALSO"
+.BR unfsd (8)
diff --git a/external/fs/unfs3-0.9.22/LICENSE b/external/fs/unfs3-0.9.22/LICENSE
new file mode 100644
index 0000000..7f2b53f
--- /dev/null
+++ b/external/fs/unfs3-0.9.22/LICENSE
@@ -0,0 +1,24 @@
+UNFS3 user-space NFSv3 server
+(C) 2003, Pascal Schmidt <unfs3-...@ewetel.net>
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+3. The name of the author may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/external/fs/unfs3-0.9.22/Makefile.in b/external/fs/unfs3-0.9.22/Makefile.in
new file mode 100644
index 0000000..551aa22
--- /dev/null
+++ b/external/fs/unfs3-0.9.22/Makefile.in
@@ -0,0 +1,158 @@
+CC = @CC@
+CFLAGS = @CFLAGS@ -D_GNU_SOURCE
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+VERSION = @PACKAGE_VERSION@
+RM = rm -f
+MAKE = make
+
+SOURCES = attr.c daemon.c error.c fd_cache.c fh.c fh_cache.c locate.c \
+ md5.c mount.c nfs.c password.c readdir.c user.c xdr.c winsupport.c
+OBJS = attr.o daemon.o error.o fd_cache.o fh.o fh_cache.o locate.o \
+ md5.o mount.o nfs.o password.o readdir.o user.o xdr.o winsupport.o
+CONFOBJ = Config/lib.a
+EXTRAOBJ = @EXTRAOBJ@
+LDFLAGS = @LDFLAGS@ @LIBS@ @LEXLIB@
+EXEEXT = @EXEEXT@
+
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+sbindir = @sbindir@
+mandir = @mandir@
+datarootdir = @datarootdir@
+
+SUBDIRS = Config @SUBDIRS@
+
+DESTDIR =
+
+all: subdirs unfsd$(EXEEXT)
+
+unfsd$(EXEEXT): $(OBJS) $(CONFOBJ) $(EXTRAOBJ)
+ $(CC) -o $@ $(OBJS) $(CONFOBJ) $(EXTRAOBJ) $(LDFLAGS)
+
+subdirs:
+ for i in $(SUBDIRS); do cd $$i; $(MAKE) all; cd ..; done
+
+install: unfsd$(EXEEXT)
+ $(INSTALL) -d $(DESTDIR)$(sbindir)
+ $(INSTALL) -d $(DESTDIR)$(mandir)/man7
+ $(INSTALL) -d $(DESTDIR)$(mandir)/man8
+ $(INSTALL) unfsd$(EXEEXT) $(DESTDIR)$(sbindir)/unfsd$(EXEEXT)
+ $(INSTALL_DATA) Extras/tags.7 $(DESTDIR)$(mandir)/man7/tags.7
+ $(INSTALL_DATA) unfsd.8 $(DESTDIR)$(mandir)/man8/unfsd.8
+
+# Not installed by default, since it installs files outside prefix
+install-init: unfsd.init
+ $(INSTALL) -d $(DESTDIR)/etc/init.d
+ $(INSTALL) unfsd.init $(DESTDIR)/etc/init.d/unfsd
+
+install-strip: install
+ strip $(DESTDIR)$(sbindir)/unfsd$(EXEEXT)
+
+uninstall:
+ $(RM) $(DESTDIR)$(sbindir)/unfsd$(EXEEXT)
+ $(RM) $(DESTDIR)$(mandir)/man7/tags.7
+ $(RM) $(DESTDIR)$(mandir)/man8/unfsd.8
+
+clean:
+ for i in $(SUBDIRS); do cd $$i; $(MAKE) clean; cd ..; done
+ $(RM) $(OBJS)
+ $(RM) unfsd$(EXEEXT)
+ $(RM) unfs3-$(VERSION).tar.gz
+
+distclean: clean
+ for i in $(SUBDIRS); do cd $$i; $(MAKE) distclean; cd ..; done
+ $(RM) Makefile config.h
+ $(RM) config.log config.status
+
+maintainer-clean: distclean
+ $(RM) config.h.in configure
+ $(RM) -rf autom4te.cache
+
+dep: $(SOURCES)
+ for i in $(SUBDIRS); do cd $$i; $(MAKE) dep; cd ..; done
+ $(CC) $(CFLAGS) -MM $(SOURCES) >> Makefile
+
+.PHONY: dist unfs3-$(VERSION).tar.gz
+
+dist: unfs3-$(VERSION).tar.gz
+
+unfs3-$(VERSION).tar.gz:
+ rm -rf /tmp/unfs3-make-dist-dir
+ mkdir /tmp/unfs3-make-dist-dir
+ ln -sf `pwd` /tmp/unfs3-make-dist-dir/unfs3-$(VERSION)
+ (cd /tmp/unfs3-make-dist-dir; \
+ tar zcf unfs3-$(VERSION)/unfs3-$(VERSION).tar.gz \
+ unfs3-$(VERSION)/fd_cache.c \
+ unfs3-$(VERSION)/md5.h \
+ unfs3-$(VERSION)/xdr.h \
+ unfs3-$(VERSION)/attr.c \
+ unfs3-$(VERSION)/README \
+ unfs3-$(VERSION)/backend.h \
+ unfs3-$(VERSION)/password.c \
+ unfs3-$(VERSION)/README.nfsroot \
+ unfs3-$(VERSION)/error.c \
+ unfs3-$(VERSION)/winsupport.c \
+ unfs3-$(VERSION)/fh_cache.h \
+ unfs3-$(VERSION)/user.c \
+ unfs3-$(VERSION)/unfs3.spec \
+ unfs3-$(VERSION)/winsupport.h \
+ unfs3-$(VERSION)/readdir.h \
+ unfs3-$(VERSION)/nfs.c \
+ unfs3-$(VERSION)/configure \
+ unfs3-$(VERSION)/xdr.c \
+ unfs3-$(VERSION)/install-sh \
+ unfs3-$(VERSION)/mount.c \
+ unfs3-$(VERSION)/password.h \
+ unfs3-$(VERSION)/Extras/Makefile.in \
+ unfs3-$(VERSION)/Extras/cluster.c \
+ unfs3-$(VERSION)/Extras/tags.7 \
+ unfs3-$(VERSION)/Extras/cluster.h \
+ unfs3-$(VERSION)/NEWS \
+ unfs3-$(VERSION)/CREDITS \
+ unfs3-$(VERSION)/aclocal.m4 \
+ unfs3-$(VERSION)/daemon.h \
+ unfs3-$(VERSION)/doc/TODO \
+ unfs3-$(VERSION)/doc/README.win \
+ unfs3-$(VERSION)/doc/kirch1.txt \
+ unfs3-$(VERSION)/doc/passwords.txt \
+ unfs3-$(VERSION)/unfsd.8 \
+ unfs3-$(VERSION)/Makefile.in \
+ unfs3-$(VERSION)/unfsd.init \
+ unfs3-$(VERSION)/backend_win32.h \
+ unfs3-$(VERSION)/indent-all \
+ unfs3-$(VERSION)/backend_unix.h \
+ unfs3-$(VERSION)/nfs.h \
+ unfs3-$(VERSION)/locate.c \
+ unfs3-$(VERSION)/BRANCHES \
+ unfs3-$(VERSION)/fd_cache.h \
+ unfs3-$(VERSION)/daemon.c \
+ unfs3-$(VERSION)/error.h \
+ unfs3-$(VERSION)/contrib/nfsotpclient/README \
+ unfs3-$(VERSION)/contrib/nfsotpclient/mountclient \
+ unfs3-$(VERSION)/contrib/nfsotpclient/mountclient/__init__.py \
+ unfs3-$(VERSION)/contrib/nfsotpclient/mountclient/mountpacker.py \
+ unfs3-$(VERSION)/contrib/nfsotpclient/mountclient/mountconstants.py \
+ unfs3-$(VERSION)/contrib/nfsotpclient/mountclient/mounttypes.py \
+ unfs3-$(VERSION)/contrib/nfsotpclient/nfsotpclient.py \
+ unfs3-$(VERSION)/contrib/nfsotpclient/rpc.py \
+ unfs3-$(VERSION)/contrib/rpcproxy/rpcproxy \
+ unfs3-$(VERSION)/LICENSE \
+ unfs3-$(VERSION)/fh.h \
+ unfs3-$(VERSION)/fh.c \
+ unfs3-$(VERSION)/Config/exports.y \
+ unfs3-$(VERSION)/Config/exports.l \
+ unfs3-$(VERSION)/Config/exports.h \
+ unfs3-$(VERSION)/Config/Makefile.in \
+ unfs3-$(VERSION)/locate.h \
+ unfs3-$(VERSION)/md5.c \
+ unfs3-$(VERSION)/fh_cache.c \
+ unfs3-$(VERSION)/config.h.in \
+ unfs3-$(VERSION)/attr.h \
+ unfs3-$(VERSION)/configure.ac \
+ unfs3-$(VERSION)/mount.h \
+ unfs3-$(VERSION)/readdir.c \
+ unfs3-$(VERSION)/user.h)
+ rm -rf /tmp/unfs3-make-dist-dir
+
+# automatically generated dependencies follow
diff --git a/external/fs/unfs3-0.9.22/NEWS b/external/fs/unfs3-0.9.22/NEWS
new file mode 100644
index 0000000..231eaad
--- /dev/null
+++ b/external/fs/unfs3-0.9.22/NEWS
@@ -0,0 +1,242 @@
+What's new or changed in 0.9.22
+===============================
+
+Garrett Cooper reported that Andy Levine found a bug
+where the "no_all_squash" option is unusable due to a
+spelling mistake in the options parser. This is fixed now.
+
+Wesley Shields reported build problems on more recent
+FreeBSD systems which are fixed now.
+
+Bernhard Duebi reported problems with filesystem size
+reporting when using a Solaris Zone. This is fixed now.
+
+The BUGS section of the manpage has been updated to
+explicitly list the permissions that UNFS3 will need
+for exported directories and the parents of exported
+directories.
+
+
+ChangeLog
+=========
+
+Version 0.9.22
+
+ - fix spelling mistake in "no_all_squash" export option parsing
+ - fix build on more recent FreeBSD systems
+ - fix filesystem size reporting for Solaris Zones and others
+ - document permission needs for exported directories
+
+Version 0.9.21
+
+ - avoid returning large fileids on Windows, for better compatibility
+ with clients such as Linux 2.6.24
+ - try to prevent races between READDIR and removal of files
+
+Version 0.9.20
+
+ - fix LOOKUP permission reporting on execute-bit-only directories
+ - fix writing of files opened for writing with intervening chmod -w
+ - fix reading of files opened for reading with intervening chmod -r
+
+Version 0.9.19
+
+ - fix chown operation on symbolic links
+ - fix auxiliary group support
+
+Version 0.9.18
+
+ - add support for writing a pid file with the -i option
+ - fix atomic_attr() to respect uid/gid squashing
+ - add -T option for doing test parse of the exports file
+
+Version 0.9.17
+
+ - add support for 64 bit inode numbers
+ - the returned "fileid" is now equal to the file's real inode number
+ - fix ACCESS and read_executable to stop adding permissions when user or
+ group matches
+ - report unreadable executables as unreadable unless -r is used
+ - support for using larger read and write sizes: up to 32K for UDP and
+ 512K for TCP
+ - add support for "anonuid" and "anongid" export options
+ - add Windows support
+ - improve error reporting for WRITE and COMMIT requests
+ - improve file descriptor cache to not keep files open forever
+
+Version 0.9.16
+
+ - add support for "insecure" and "secure" export options
+ - do not abort daemon on RPC or XDR failures
+
+Version 0.9.15
+
+ - only allow mount requests from source ports below 1024
+
+Version 0.9.14
+
+ - accept SET_TO_SERVER_TIME in object creation calls
+ - update maintainer email address
+
+Version 0.9.13
+
+ - add support for CREATE EXCLUSIVE procedure call
+ - fix some minor compiler warnings
+
+Version 0.9.12
+
+ - add option for binding to a specified interface
+ - lots of compile fixes for Solaris/AIX/Irix/Mac OS X
+ - make redirection of operating system calls possible
+ - fix READDIR error reporting
+ - fix handling of . and .. lookups for Irix clients
+
+Version 0.9.11
+
+ - handle case where a tagged file exists but the master file doesn't
+ - make clustering work in non-readable directories
+ - make filehandle resolution work on non-readable directories
+ - fix file creation by Solaris NFS clients
+
+Version 0.9.10
+
+ - fix building with gcc 2.95.x or 2.96
+ - make ALWAYS cluster tag take effect for file creations
+ - fix possible use-after-free bug in fh.c:fh_rec
+
+Version 0.9.9
+
+ - add support for mount passwords, for use with secure links
+ - make exports parser accept dashes in hostnames and leading whitespace
+ - fix debug mode to use line buffering, useful for redirections
+ - make exporting of (automounted) removable media possible
+
+Version 0.9.8
+
+ - fix cache LRU algorithm, could lead to unreliable operations once
+ the filehandle cache filled up
+
+Version 0.9.7
+
+ - make renames across directories not cause stale filehandles
+ - allow clients to read files they only have execute permission for
+ - lift restrictions on attribute setting
+ - fix bug in special-casing of root directory filehandles
+ - add file$$$$ tag to clustering extensions
+
+Version 0.9.6
+
+ - run the source through indent to improve style consistency
+ - fix bug in READDIR that resulted in truncated replies
+ - add options to specify which ports and protocols to use
+
+Version 0.9.5
+
+ - code cleanups, remove now impossible cases (stale filehandles)
+ - fix bug in READDIR that could return EOF one entry too early
+
+Version 0.9.4
+
+ - support the DUMP and EXPORT mount protocol procedures
+ - use a simple counter instead of the system time for cache LRU
+ - document tagged files in a seperate manpage, tags(7)
+ - introduce a new ALWAYS tag for forced redirection
+
+Version 0.9.3
+
+ - fix mount handler not properly initializing return status
+ - send messages to syslog for some mount problems
+ - make it possible to export and mount symlinks to directories
+ - fix cluster extensions breakage from 0.9.1 code merge
+ - prevent filehandle cache from storing redundant information
+
+Version 0.9.2
+
+ - clean up lots of duplicate code in nfs.c
+ - move configuration parser and cluster extensions into subdirectories
+ - use real write verifier in WRITE and COMMIT
+
+Version 0.9.1
+
+ - add -d option to prevent forking into background (for debugging)
+ - merge in lots of cleaner code from the experimental branch
+ - merge nfsd and mountd into one program
+ - better /etc/exports parser using lex and yacc
+
+Version 0.9.0
+
+ - check for clients attempting to use invalid pathnames
+ - include cluster extensions (optional at compile and run time)
+
+Version 0.8.8
+
+ - fix ACCESS compatibility problem affecting HP-UX clients
+
+Version 0.8.7
+
+ - fixed chmod handling to make us pass the Connectathon 2003 NFS
+ testsuite's "basic" and "general" tests
+ - improve filehandle integrity checking
+
+Version 0.8.6
+
+ - use inode generation numbers only in SETATTR and fd cache because
+ it is a huge performance hit everywhere else
+ - use 32 bit device and inode numbers to save space in filehandles
+ - have nfsd bind to port number 2049 (nfs) by default
+
+Version 0.8.5
+
+ - undo refusal to use "." and ".." since it confuses NetBSD clients
+ - include inode generation number in filehandles whenever possible
+
+Version 0.8.4
+
+ - handle export of the root directory correctly
+ - return XDEV error in RENAME and LINK if export options for given
+ objects do not match (needed for squash options differences)
+ - prevent the use of "." and ".." as names
+ - use largefile API to enable access to files greater than 2 GB
+ - check filehandles for integrity before using them
+ - we no longer need GNU make
+
+Version 0.8.3
+
+ - use shorter filehandles whenever possible
+ - use stat cache in unfs3_readdir()
+ - switch filehandle cache to use static allocation of entries
+ - make unfs3_readdir() account for XDR overhead correctly
+
+Version 0.8.2
+
+ - simplify and speed up low-level filehandle routines
+ - fix a serious bug in READDIR, cookie == 0 was handled incorrectly
+ - make it build and run on NetBSD 1.6.1/i386
+
+Version 0.8.1
+
+ - use svc_getcaller instead of our own hack (well, duh)
+ - don't attempt to service v1 mount calls, only v1 umount
+ - check incoming object names for validity
+
+Version 0.8
+
+ - support for export controls via /etc/exports
+ - introduce caching of stat() results to improve performance
+ - explicitly check for gcc in the configure script
+ - make user/group id squashing be based on export options
+ - remove the now obsolete -r and -a nfsd options
+
+Version 0.7
+
+ - attempt at race protection/detection code for many NFS procedures
+ - add comments to all error code paths
+
+Version 0.6.1
+
+ - document possible races with local fs activity on server
+ - minor fix in LOOKUP error handling
+
+Version 0.6
+
+ - initial public release
diff --git a/external/fs/unfs3-0.9.22/README b/external/fs/unfs3-0.9.22/README
new file mode 100644
index 0000000..d8a7059
--- /dev/null
+++ b/external/fs/unfs3-0.9.22/README
@@ -0,0 +1,89 @@
+UNFS3 (User-Space NFSv3 Server)
+(C) 2003-2006, Pascal Schmidt <unfs3-...@ewetel.net>
+
+
+INTRODUCTION
+============
+
+UNFS3 is a user-space implementation of the NFSv3 server
+specification.
+
+UNFS3 supports all NFSv3 procedures with the exception of the
+READDIRPLUS procedure. It tries to provide as much information
+to NFS clients as possible, within the limits possible from
+user-space.
+
+See the unfsd(8) manpage for restrictions imposed on NFS
+operations (section RESTRICTIONS) and for possible races
+with local file system activity (section BUGS).
+
+It is not possible to export to netgroups or wildcard hostnames
+via /etc/exports, all other addressing methods should work. The
+following options are recognized in the exports file: ro, rw,
+root_squash, all_squash, no_root_squash, no_all_squash. If
+other options are present, they are ignored.
+
+Cluster extensions compatible to the older ClusterNFS project
+are supported when the source is configured with --enable-cluster.
+
+
+SUPPORTED SYSTEMS
+=================
+
+Linux: compiles and runs, passes Connectathon 2003 NFS
+ testsuite's "basic" and "general" tests, survives
+ fsx stress testing
+
+Solaris: compiles and runs, survives light testing
+
+NetBSD: compiles and runs, but there are compatibility
+ problems with the in-kernel NFS client
+
+AIX: compiles
+
+Irix: compiles (with gcc and native compiler)
+
+OS X: compiles
+
+Note that only Linux support is checked for all releases. If unfs3
+breaks on other platforms, a bug report is appreciated.
+
+
+INSTALLATION
+============
+
+You will need gcc, lex (flex), and yacc (bison) to compile UNFS3.
+
+ ./configure
+ make
+ make install
+
+Please read the manpage for information about command-line
+options.
+
+ man 8 unfsd
+
+If you decide to modify the code yourself, you can run
+
+ make dep
+
+to append dependency information to the Makefile, so that make
+knows which files depend on each other and recompiles all the
+necessary files on changes.
+
+
+CVS REPOSITORY
+==============
+
+The unfs3 CVS repository is accessible via anonymous CVS. The source
+can be checked out with:
+
+ cvs -d:pserver:anon...@cvs.lysator.liu.se:/cvsroot/unfs3 login
+ cvs -d:pserver:anon...@cvs.lysator.liu.se:/cvsroot/unfs3 co unfs3
+
+You can also use the web-based CVS repository viewer at:
+
+ http://cvs.lysator.liu.se/viewcvs/viewcvs.cgi/?cvsroot=unfs3
+
+In the HEAD branch, you will find a file called "BRANCHES", which
+describes the different branches in this repository.
diff --git a/external/fs/unfs3-0.9.22/README.nfsroot b/external/fs/unfs3-0.9.22/README.nfsroot
new file mode 100644
index 0000000..6b2fb1b
--- /dev/null
+++ b/external/fs/unfs3-0.9.22/README.nfsroot
@@ -0,0 +1,44 @@
+Using UNFS3 for Linux nfsroot
+=============================
+
+General information about Linux nfsroot can be found in the
+Linux kernel source, in the file Documentation/nfsroot.txt.
+
+If you want the use the Linux kernel's "nfsroot=" boot option
+to use a root directory on an NFS server and use UNFS3 in the
+role of the NFS server for that, you need to remember that UNFS3
+only supports NFSv3, not NFSv2. The kernel, on the other hand,
+always defaults to using NFSv2. Thus, you need to modify the
+nfsroot boot option to force the kernel to use NFSv3. If you do
+not do this, an error message like this will appear on the
+client machine:
+
+ Looking up port of RPC 1000003/2 on 172.16.100.100
+ Root-NFS: Portmapper on server returned 2049 as nfsd port
+ Looking up port of RPC 1000005/1 on 172.16.100.100
+ Root-NFS: mounted port is 2049
+ NFS: nfs_mount (ac106464:/nfsroot)
+ RPC: call_verify: programm 100003 version 2 unsupported by server
+ nfs_get_root: getattr error = 5
+ nfs_read_super: get root inode failed
+ VFS: Unable to mount root fs via NFS trying floppy
+
+To fix this problem, append the "v3" NFS option to the nfsroot
+boot option. Assuming your NFS server's IP address is 192.168.2.72
+and the path you need to mount is /tftpboot/nfsroot, the boot
+option should look like this:
+
+ nfsroot=192.168.2.72:/tftpboot/nfsroot,v3
+
+You can add more options to the end, seperated by commas. If you
+use DHCP to pass the NFS server configuration to the client, you
+need to use a line like this in the /etc/dhcpd.conf settings
+for the client machine:
+
+ option root-path "/tftpboot/nfsroot,v3";
+
+As above, more options can be added to the end, sepereated by
+commas.
+
+Thanks go to Jean Aumont <JeanA...@videotron.ca> for suggesting
+this bit of information to be documented.
diff --git a/external/fs/unfs3-0.9.22/aclocal.m4 b/external/fs/unfs3-0.9.22/aclocal.m4
new file mode 100644
index 0000000..1a2845e
--- /dev/null
+++ b/external/fs/unfs3-0.9.22/aclocal.m4
@@ -0,0 +1,25 @@
+dnl Special rpc library for Solaris
+dnl
+AC_DEFUN([UNFS3_SOLARIS_RPC],[
+ AC_CHECK_FUNC(svc_tli_create, [
+ # On Solaris, you must link with librpcsoc, or the binaries won't work.
+ LDFLAGS="-L/usr/ucblib -R/usr/ucblib $LDFLAGS"
+ AC_CHECK_LIB(rpcsoc, svctcp_create,
+ [ LIBS="-lrpcsoc $LIBS" ],
+ [ AC_MSG_WARN([*** Cannot find librpcsoc. On Solaris, install package SUNWscpu. ***]) ]
+ )
+ ])
+])
+dnl PORTMAP define needed for Solaris
+dnl
+AC_DEFUN([UNFS3_PORTMAP_DEFINE],[
+ AC_DEFINE([PORTMAP], [], [Define to an empty value if you use Solaris.])
+])
+dnl Set compiler warnings for gcc
+dnl
+AC_DEFUN([UNFS3_COMPILE_WARNINGS],[
+ if test "$GCC" = "yes"
+ then
+ CFLAGS="$CFLAGS -Wall -W"
+ fi
+])
diff --git a/external/fs/unfs3-0.9.22/attr.c b/external/fs/unfs3-0.9.22/attr.c
new file mode 100644
index 0000000..2653ed0
--- /dev/null
+++ b/external/fs/unfs3-0.9.22/attr.c
@@ -0,0 +1,496 @@
+
+/*
+ * UNFS3 attribute handling
+ * (C) 2004, Pascal Schmidt
+ * see file LICENSE for license details
+ */
+
+#include "config.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <rpc/rpc.h>
+#include <fcntl.h>
+#include <time.h>
+#ifndef WIN32
+#include <unistd.h>
+#endif
+#include <utime.h>
+#include <errno.h>
+
+#include "backend.h"
+#include "nfs.h"
+#include "attr.h"
+#include "error.h"
+#include "fh.h"
+#include "fh_cache.h"
+#include "daemon.h"
+#include "user.h"
+#include "Config/exports.h"
+
+/*
+ * check whether stat_cache is for a regular file
+ *
+ * fh_decomp must be called before to fill the stat cache
+ */
+nfsstat3 is_reg(void)
+{
+ if (!st_cache_valid)
+ return NFS3ERR_STALE;
+ else if (S_ISREG(st_cache.st_mode))
+ return NFS3_OK;
+ else
+ return NFS3ERR_INVAL;
+}
+
+/*
+ * find stat bit corresponding to given NFS file type
+ */
+mode_t type_to_mode(ftype3 ftype)
+{
+ switch (ftype) {
+ case NF3REG:
+ return S_IFREG;
+ case NF3DIR:
+ return S_IFDIR;
+ case NF3LNK:
+ return S_IFLNK;
+ case NF3CHR:
+ return S_IFCHR;
+ case NF3BLK:
+ return S_IFBLK;
+ case NF3FIFO:
+ return S_IFIFO;
+ case NF3SOCK:
+ return S_IFSOCK;
+ }
+
+ /* fix gcc warning */
+ return 0;
+}
+
+/*
+ * post_op_attr for error returns
+ */
+#ifdef __GNUC__
+static post_op_attr error_attr = {.attributes_follow = FALSE };
+#else
+static post_op_attr error_attr = { FALSE };
+#endif
+
+/*
+ * return pre-operation attributes
+ *
+ * fh_decomp must be called before to fill the stat cache
+ */
+pre_op_attr get_pre_cached(void)
+{
+ pre_op_attr result;
+
+ if (!st_cache_valid) {
+ result.attributes_follow = FALSE;
+ return result;
+ }
+
+ result.attributes_follow = TRUE;
+
+ result.pre_op_attr_u.attributes.size = st_cache.st_size;
+ result.pre_op_attr_u.attributes.mtime.seconds = st_cache.st_mtime;
+ result.pre_op_attr_u.attributes.mtime.nseconds = 0;
+ result.pre_op_attr_u.attributes.ctime.seconds = st_cache.st_ctime;
+ result.pre_op_attr_u.attributes.ctime.nseconds = 0;
+
+ return result;
+}
+
+/*
+ * compute post-operation attributes given a stat buffer
+ */
+post_op_attr get_post_buf(backend_statstruct buf, struct svc_req * req)
+{
+ post_op_attr result;
+
+ result.attributes_follow = TRUE;
+
+ if (S_ISDIR(buf.st_mode))
+ result.post_op_attr_u.attributes.type = NF3DIR;
+ else if (S_ISBLK(buf.st_mode))
+ result.post_op_attr_u.attributes.type = NF3BLK;
+ else if (S_ISCHR(buf.st_mode))
+ result.post_op_attr_u.attributes.type = NF3CHR;
+#ifdef S_ISLNK
+ else if (S_ISLNK(buf.st_mode))
+ result.post_op_attr_u.attributes.type = NF3LNK;
+#endif /* S_ISLNK */
+#ifdef S_ISSOCK
+ else if (S_ISSOCK(buf.st_mode))
+ result.post_op_attr_u.attributes.type = NF3SOCK;
+#endif /* S_ISSOCK */
+ else if (S_ISFIFO(buf.st_mode))
+ result.post_op_attr_u.attributes.type = NF3FIFO;
+ else
+ result.post_op_attr_u.attributes.type = NF3REG;
+
+ /* adapt permissions for executable files */
+ if (opt_readable_executables && S_ISREG(buf.st_mode)) {
+ if (buf.st_mode & S_IXUSR)
+ buf.st_mode |= S_IRUSR;
+ if (buf.st_mode & S_IXGRP)
+ buf.st_mode |= S_IRGRP;
+ if (buf.st_mode & S_IXOTH)
+ buf.st_mode |= S_IROTH;
+ }
+
+ result.post_op_attr_u.attributes.mode = buf.st_mode & 0xFFFF;
+ result.post_op_attr_u.attributes.nlink = buf.st_nlink;
+
+ /* If -s, translate uids */
+ if (opt_singleuser) {
+ unsigned int req_uid = 0;
+ unsigned int req_gid = 0;
+ struct authunix_parms *auth = (void *) req->rq_clntcred;
+ uid_t ruid = backend_getuid();
+
+ if (req->rq_cred.oa_flavor == AUTH_UNIX) {
+ req_uid = auth->aup_uid;
+ req_gid = auth->aup_gid;
+ }
+
+ if ((buf.st_uid == ruid) || (ruid == 0))
+ result.post_op_attr_u.attributes.uid = req_uid;
+ else
+ result.post_op_attr_u.attributes.uid = 0;
+
+ if ((buf.st_gid == backend_getgid()) || (ruid == 0))
+ result.post_op_attr_u.attributes.gid = req_gid;
+ else
+ result.post_op_attr_u.attributes.gid = 0;
+ } else {
+ /* Normal case */
+ result.post_op_attr_u.attributes.uid = buf.st_uid;
+ result.post_op_attr_u.attributes.gid = buf.st_gid;
+ }
+
+ result.post_op_attr_u.attributes.size = buf.st_size;
+ result.post_op_attr_u.attributes.used = buf.st_blocks * 512;
+ result.post_op_attr_u.attributes.rdev.specdata1 =
+ (buf.st_rdev >> 8) & 0xFF;
+ result.post_op_attr_u.attributes.rdev.specdata2 = buf.st_rdev & 0xFF;
+ result.post_op_attr_u.attributes.fsid = buf.st_dev;
+
+ /* If this is a removable export point, we should return the preset fsid
+ for all objects which resides in the same file system as the exported
+ directory */
+ if (exports_opts & OPT_REMOVABLE) {
+ backend_statstruct epbuf;
+
+ if (backend_lstat(export_path, &epbuf) != -1 &&
+ buf.st_dev == epbuf.st_dev) {
+ result.post_op_attr_u.attributes.fsid = export_fsid;
+ }
+ }
+#ifdef WIN32
+ /* Recent Linux kernels (2.6.24 and newer) exposes large fileids even to
+ non-LFS 32-bit applications, unless kernel parameter
+ nfs.enable_ino64=0. This means that applications will fail with
+ EOVERFLOW. On Windows, we always have large st_ino:s. To avoid
+ trouble, we truncate to 32 bits */
+ result.post_op_attr_u.attributes.fileid =
+ (buf.st_ino >> 32) ^ (buf.st_ino & 0xffffffff);
+#else
+ result.post_op_attr_u.attributes.fileid = buf.st_ino;
+#endif
+ result.post_op_attr_u.attributes.atime.seconds = buf.st_atime;
+ result.post_op_attr_u.attributes.atime.nseconds = 0;
+ result.post_op_attr_u.attributes.mtime.seconds = buf.st_mtime;
+ result.post_op_attr_u.attributes.mtime.nseconds = 0;
+ result.post_op_attr_u.attributes.ctime.seconds = buf.st_ctime;
+ result.post_op_attr_u.attributes.ctime.nseconds = 0;
+
+ return result;
+}
+
+/*
+ * lowlevel routine for getting post-operation attributes
+ */
+static post_op_attr get_post_ll(const char *path, uint32 dev, uint64 ino,
+ struct svc_req *req)
+{
+ backend_statstruct buf;
+ int res;
+
+ if (!path)
+ return error_attr;
+
+ res = backend_lstat(path, &buf);
+ if (res == -1)
+ return error_attr;
+
+ /* protect against local fs race */
+ if (dev != buf.st_dev || ino != buf.st_ino)
+ return error_attr;
+
+ return get_post_buf(buf, req);
+}
+
+/*
+ * return post-operation attributes, using fh for old dev/ino
+ */
+post_op_attr get_post_attr(const char *path, nfs_fh3 nfh,
+ struct svc_req * req)
+{
+ unfs3_fh_t *fh = (void *) nfh.data.data_val;
+
+ return get_post_ll(path, fh->dev, fh->ino, req);
+}
+
+/*
+ * return post-operation attributes, using stat cache for old dev/ino
+ */
+post_op_attr get_post_stat(const char *path, struct svc_req * req)
+{
+ return get_post_ll(path, st_cache.st_dev, st_cache.st_ino, req);
+}
+
+/*
+ * return post-operation attributes using stat cache
+ *
+ * fd_decomp must be called before to fill the stat cache
+ */
+post_op_attr get_post_cached(struct svc_req * req)
+{
+ if (!st_cache_valid)
+ return error_attr;
+
+ return get_post_buf(st_cache, req);
+}
+
+/*
+ * setting of time, races with local filesystem
+ *
+ * there is no futimes() function in POSIX or Linux
+ */
+static nfsstat3 set_time(const char *path, backend_statstruct buf, sattr3 new)
+{
+ time_t new_atime, new_mtime;
+ struct utimbuf utim;
+ int res;
+
+ /* set atime and mtime */
+ if (new.atime.set_it != DONT_CHANGE || new.mtime.set_it != DONT_CHANGE) {
+
+ /* compute atime to set */
+ if (new.atime.set_it == SET_TO_SERVER_TIME)
+ new_atime = time(NULL);
+ else if (new.atime.set_it == SET_TO_CLIENT_TIME)
+ new_atime = new.atime.set_atime_u.atime.seconds;
+ else /* DONT_CHANGE */
+ new_atime = buf.st_atime;
+
+ /* compute mtime to set */
+ if (new.mtime.set_it == SET_TO_SERVER_TIME)
+ new_mtime = time(NULL);
+ else if (new.mtime.set_it == SET_TO_CLIENT_TIME)
+ new_mtime = new.mtime.set_mtime_u.mtime.seconds;
+ else /* DONT_CHANGE */
+ new_mtime = buf.st_mtime;
+
+ utim.actime = new_atime;
+ utim.modtime = new_mtime;
+
+ res = backend_utime(path, &utim);
+ if (res == -1)
+ return setattr_err();
+ }
+
+ return NFS3_OK;
+}
+
+/*
+ * race unsafe setting of attributes
+ */
+static nfsstat3 set_attr_unsafe(const char *path, nfs_fh3 nfh, sattr3 new)
+{
+ unfs3_fh_t *fh = (void *) nfh.data.data_val;
+ uid_t new_uid;
+ gid_t new_gid;
+ backend_statstruct buf;
+ int res;
+
+ res = backend_lstat(path, &buf);
+ if (res != 0)
+ return NFS3ERR_STALE;
+
+ /* check local fs race */
+ if (buf.st_dev != fh->dev || buf.st_ino != fh->ino)
+ return NFS3ERR_STALE;
+
+ /* set file size */
+ if (new.size.set_it == TRUE) {
+ res = backend_truncate(path, new.size.set_size3_u.size);
+ if (res == -1)
+ return setattr_err();
+ }
+
+ /* set uid and gid */
+ if (new.uid.set_it == TRUE || new.gid.set_it == TRUE) {
+ if (new.uid.set_it == TRUE)
+ new_uid = new.uid.set_uid3_u.uid;
+ else
+ new_uid = -1;
+ if (new_uid == buf.st_uid)
+ new_uid = -1;
+
+ if (new.gid.set_it == TRUE)
+ new_gid = new.gid.set_gid3_u.gid;
+ else
+ new_gid = -1;
+
+ res = backend_lchown(path, new_uid, new_gid);
+ if (res == -1)
+ return setattr_err();
+ }
+
+ /* set mode */
+ if (new.mode.set_it == TRUE) {
+ res = backend_chmod(path, new.mode.set_mode3_u.mode);
+ if (res == -1)
+ return setattr_err();
+ }
+
+ return set_time(path, buf, new);
+}
+
+/*
+ * set attributes of an object
+ */
+nfsstat3 set_attr(const char *path, nfs_fh3 nfh, sattr3 new)
+{
+ unfs3_fh_t *fh = (void *) nfh.data.data_val;
+ int res, fd;
+ uid_t new_uid;
+ gid_t new_gid;
+ backend_statstruct buf;
+
+ res = backend_lstat(path, &buf);
+ if (res != 0)
+ return NFS3ERR_STALE;
+
+ /*
+ * don't open(2) device nodes, it could trigger
+ * module loading on the server
+ */
+ if (S_ISBLK(buf.st_mode) || S_ISCHR(buf.st_mode))
+ return set_attr_unsafe(path, nfh, new);
+
+#ifdef S_ISLNK
+ /*
+ * opening a symlink would open the underlying file,
+ * don't try to do that
+ */
+ if (S_ISLNK(buf.st_mode))
+ return set_attr_unsafe(path, nfh, new);
+#endif
+
+ /*
+ * open object for atomic setting of attributes
+ */
+ fd = backend_open(path, O_WRONLY | O_NONBLOCK);
+ if (fd == -1)
+ fd = backend_open(path, O_RDONLY | O_NONBLOCK);
+
+ if (fd == -1)
+ return set_attr_unsafe(path, nfh, new);
+
+ res = backend_fstat(fd, &buf);
+ if (res == -1) {
+ backend_close(fd);
+ return NFS3ERR_STALE;
+ }
+
+ /* check local fs race */
+ if (fh->dev != buf.st_dev || fh->ino != buf.st_ino ||
+ fh->gen != backend_get_gen(buf, fd, path)) {
+ backend_close(fd);
+ return NFS3ERR_STALE;
+ }
+
+ /* set file size */
+ if (new.size.set_it == TRUE) {
+ res = backend_ftruncate(fd, new.size.set_size3_u.size);
+ if (res == -1) {
+ backend_close(fd);
+ return setattr_err();
+ }
+ }
+
+ /* set uid and gid */
+ if (new.uid.set_it == TRUE || new.gid.set_it == TRUE) {
+ if (new.uid.set_it == TRUE)
+ new_uid = new.uid.set_uid3_u.uid;
+ else
+ new_uid = -1;
+ if (new_uid == buf.st_uid)
+ new_uid = -1;
+
+ if (new.gid.set_it == TRUE)
+ new_gid = new.gid.set_gid3_u.gid;
+ else
+ new_gid = -1;
+
+ res = backend_fchown(fd, new_uid, new_gid);
+ if (res == -1) {
+ backend_close(fd);
+ return setattr_err();
+ }
+ }
+
+ /* set mode */
+ if (new.mode.set_it == TRUE) {
+ res = backend_fchmod(fd, new.mode.set_mode3_u.mode);
+ if (res == -1) {
+ backend_close(fd);
+ return setattr_err();
+ }
+ }
+
+ res = backend_close(fd);
+ if (res == -1) {
+ /* error on close probably means attributes didn't make it */
+ return NFS3ERR_IO;
+ }
+
+ /* finally, set times */
+ return set_time(path, buf, new);
+}
+
+/*
+ * deduce mode from given settable attributes
+ * default to rwxrwxr-x if no mode given
+ */
+mode_t create_mode(sattr3 new)
+{
+ if (new.mode.set_it == TRUE)
+ return new.mode.set_mode3_u.mode;
+ else
+ return S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IWGRP | S_IXGRP |
+ S_IROTH | S_IXOTH;
+}
+
+/*
+ * check whether an sattr3 is settable atomically on a create op
+ */
+nfsstat3 atomic_attr(sattr3 attr)
+{
+ uid_t used_uid = mangle_uid(attr.uid.set_uid3_u.uid);
+ gid_t used_gid = mangle_gid(attr.gid.set_gid3_u.gid);
+
+ if ((attr.uid.set_it == TRUE && used_uid != backend_geteuid()) ||
+ (attr.gid.set_it == TRUE && used_gid != backend_getegid()) ||
+ (attr.size.set_it == TRUE && attr.size.set_size3_u.size != 0) ||
+ attr.atime.set_it == SET_TO_CLIENT_TIME ||
+ attr.mtime.set_it == SET_TO_CLIENT_TIME)
+ return NFS3ERR_INVAL;
+ else
+ return NFS3_OK;
+}
diff --git a/external/fs/unfs3-0.9.22/attr.h b/external/fs/unfs3-0.9.22/attr.h
new file mode 100644
index 0000000..4b2b0bc
--- /dev/null
+++ b/external/fs/unfs3-0.9.22/attr.h
@@ -0,0 +1,26 @@
+/*
+ * UNFS3 attribute handling
+ * (C) 2004, Pascal Schmidt
+ * see file LICENSE for license details
+ */
+
+#ifndef NFS_ATTR_H
+#define NFS_ATTR_H
+
+nfsstat3 is_reg(void);
+
+mode_t type_to_mode(ftype3 ftype);
+
+post_op_attr get_post_attr(const char *path, nfs_fh3 fh, struct svc_req *req);
+post_op_attr get_post_stat(const char *path, struct svc_req *req);
+post_op_attr get_post_cached(struct svc_req *req);
+post_op_attr get_post_buf(backend_statstruct buf, struct svc_req *req);
+pre_op_attr get_pre_cached(void);
+
+nfsstat3 set_attr(const char *path, nfs_fh3 fh, sattr3 sattr);
+
+mode_t create_mode(sattr3 sattr);
+
+nfsstat3 atomic_attr(sattr3 sattr);
+
+#endif
diff --git a/external/fs/unfs3-0.9.22/backend.h b/external/fs/unfs3-0.9.22/backend.h
new file mode 100644
index 0000000..d3c595d
--- /dev/null
+++ b/external/fs/unfs3-0.9.22/backend.h
@@ -0,0 +1,16 @@
+/*
+ * UNFS3 low-level filesystem calls
+ * (C) 2004, Pascal Schmidt
+ * see file LICENSE for license details
+ */
+
+#ifndef UNFS3_BACKEND_H
+#define UNFS3_BACKEND_H
+
+#ifdef WIN32
+#include "backend_win32.h"
+#else
+#include "backend_unix.h"
+#endif /* WIN32 */
+
+#endif
diff --git a/external/fs/unfs3-0.9.22/backend_unix.h b/external/fs/unfs3-0.9.22/backend_unix.h
new file mode 100644
index 0000000..713288d
--- /dev/null
+++ b/external/fs/unfs3-0.9.22/backend_unix.h
@@ -0,0 +1,84 @@
+/*
+ * UNFS3 low-level filesystem calls for Unix
+ * (C) 2004, Pascal Schmidt
+ * see file LICENSE for license details
+ */
+
+#ifndef UNFS3_BACKEND_UNIX_H
+#define UNFS3_BACKEND_UNIX_H
+
+/*
+ * backend init and shutdown
+ */
+#define backend_init() 1
+#define backend_shutdown() do { } while (0)
+
+/*
+ * unfs3 functions
+ */
+#define backend_get_gen get_gen
+#define backend_mksocket mksocket
+#define backend_locate_file locate_file
+
+/*
+ * system calls
+ */
+#define backend_chmod chmod
+#define backend_chown chown
+#define backend_close close
+#define backend_closedir closedir
+#define backend_fchmod fchmod
+#define backend_fchown fchown
+#define backend_fstat fstat
+#define backend_fsync fsync
+#define backend_ftruncate ftruncate
+#define backend_getegid getegid
+#define backend_geteuid geteuid
+#define backend_getgid getgid
+#define backend_getuid getuid
+#define backend_link link
+#define backend_lseek lseek
+#define backend_lstat lstat
+#define backend_mkdir mkdir
+#define backend_mkfifo mkfifo
+#define backend_mknod mknod
+#define backend_open open
+#define backend_open_create open
+#define backend_opendir opendir
+#define backend_pread pread
+#define backend_pwrite pwrite
+#define backend_readdir readdir
+#define backend_readlink readlink
+#define backend_realpath realpath
+#define backend_remove remove
+#define backend_rename rename
+#define backend_rmdir rmdir
+#define backend_setegid setegid
+#define backend_seteuid seteuid
+#define backend_setgroups setgroups
+#define backend_stat stat
+#define backend_statvfs statvfs
+#define backend_symlink symlink
+#define backend_truncate truncate
+#define backend_utime utime
+#define backend_statstruct struct stat
+#define backend_dirstream DIR
+#define backend_statvfsstruct struct statvfs
+#define backend_fsinfo_properties FSF3_LINK | FSF3_SYMLINK | FSF3_HOMOGENEOUS | FSF3_CANSETTIME;
+#define backend_time_delta_seconds 1
+#define backend_pathconf_case_insensitive FALSE
+#define backend_passwdstruct struct passwd
+#define backend_getpwnam getpwnam
+#define backend_gen_nonce gen_nonce
+#define backend_flock flock
+#define backend_getpid getpid
+#define backend_store_create_verifier store_create_verifier
+#define backend_check_create_verifier check_create_verifier
+
+#if HAVE_LCHOWN == 1
+#define backend_lchown lchown
+#else
+#define backend_lchown chown
+#endif
+
+#endif
diff --git a/external/fs/unfs3-0.9.22/backend_win32.h b/external/fs/unfs3-0.9.22/backend_win32.h
new file mode 100644
index 0000000..03878a3
--- /dev/null
+++ b/external/fs/unfs3-0.9.22/backend_win32.h
@@ -0,0 +1,83 @@
+/*
+ * UNFS3 low-level filesystem calls for Win32
+ * (C) 2006, Peter Åstrand
+ * see file LICENSE for license details
+ */
+
+#ifndef UNFS3_BACKEND_WIN32_H
+#define UNFS3_BACKEND_WIN32_H
+
+#include "winsupport.h"
+
+/*
+ * backend init and shutdown
+ */
+#define backend_shutdown() do { } while (0)
+
+/*
+ * unfs3 functions
+ */
+#define backend_get_gen get_gen
+#define backend_mksocket win_mkfifo
+#define backend_locate_file locate_file
+
+/*
+ * system calls
+ */
+#define backend_chmod win_chmod
+#define backend_chown win_chown
+#define backend_close win_close
+#define backend_closedir win_closedir
+#define backend_fchmod win_fchmod
+#define backend_fchown win_fchown
+#define backend_fstat win_fstat
+#define backend_fsync _commit
+#define backend_ftruncate chsize
+#define backend_getegid() 0
+#define backend_geteuid() 0
+#define backend_getgid() 0
+#define backend_getuid() 0
+#define backend_lchown win_chown
+#define backend_link win_link
+#define backend_lseek lseek
+#define backend_lstat win_stat
+#define backend_mkdir win_mkdir
+#define backend_mkfifo win_mkfifo
+#define backend_mknod win_mknod
+#define backend_open win_open
+#define backend_open_create win_open
+#define backend_opendir win_opendir
+#define backend_pread pread
+#define backend_pwrite pwrite
+#define backend_readdir win_readdir
+#define backend_readlink win_readlink
+#define backend_realpath win_realpath
+#define backend_remove win_remove
+#define backend_rename win_rename
+#define backend_rmdir win_rmdir
+#define backend_setegid win_setegid
+#define backend_seteuid win_seteuid
+#define backend_setgroups(size, groups) 0
+#define backend_stat win_stat
+#define backend_statvfs win_statvfs
+#define backend_symlink win_symlink
+#define backend_truncate win_truncate
+#define backend_utime win_utime
+#define backend_init win_init
+#define backend_dirstream UNFS3_WIN_DIR
+#define backend_fsinfo_properties FSF3_HOMOGENEOUS | FSF3_CANSETTIME;
+/*
+ Note: FAT has different granularities for different times: 1 day for
+ atime, 2 seconds for mtime and 10ms för CreationTime. time_delta
+ only applies to atime/mtime. We are choosing 2 seconds.
+*/
+#define backend_time_delta_seconds 2
+#define backend_pathconf_case_insensitive TRUE
+#define backend_getpwnam(name) NULL
+#define backend_gen_nonce win_gen_nonce
+#define backend_flock flock(fd, op) (-1)
+#define backend_getpid getpid
+#define backend_store_create_verifier win_store_create_verifier
+#define backend_check_create_verifier win_check_create_verifier
+
+#endif
diff --git a/external/fs/unfs3-0.9.22/bootstrap b/external/fs/unfs3-0.9.22/bootstrap
new file mode 100755
index 0000000..68f4a17
--- /dev/null
+++ b/external/fs/unfs3-0.9.22/bootstrap
@@ -0,0 +1,2 @@
+#!/bin/sh
+autoreconf -i
diff --git a/external/fs/unfs3-0.9.22/config.h.in b/external/fs/unfs3-0.9.22/config.h.in
new file mode 100644
index 0000000..f50dddd
--- /dev/null
+++ b/external/fs/unfs3-0.9.22/config.h.in
@@ -0,0 +1,119 @@
+/* config.h.in. Generated from configure.ac by autoheader. */
+
+/* Define to 1 if the system has the type `int32'. */
+#undef HAVE_INT32
+
+/* Define to 1 if the system has the type `int64'. */
+#undef HAVE_INT64
+
+/* Define to 1 if you have the `lchown' function. */
+#undef HAVE_LCHOWN
+
+/* Define to 1 if you have the <linux/ext2_fs.h> header file. */
+#undef HAVE_LINUX_EXT2_FS_H
+
+/* Define to 1 if you have the <mntent.h> header file. */
+#undef HAVE_MNTENT_H
+
+/* Define to 1 if you have the <rpc/svc_soc.h> header file. */
+#undef HAVE_RPC_SVC_SOC_H
+
+/* Define to 1 if you have the `setegid' function. */
+#undef HAVE_SETEGID
+
+/* Define to 1 if you have the `seteuid' function. */
+#undef HAVE_SETEUID
+
+/* Define to 1 if you have the `setgroups' function. */
+#undef HAVE_SETGROUPS
+
+/* Define to 1 if you have the `setresgid' function. */
+#undef HAVE_SETRESGID
+
+/* Define to 1 if you have the `setresuid' function. */
+#undef HAVE_SETRESUID
+
+/* Define to 1 if you have the `statvfs' function. */
+#undef HAVE_STATVFS
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#undef HAVE_STDINT_H
+
+/* Define to 1 if `st_gen' is member of `struct stat'. */
+#undef HAVE_STRUCT_STAT_ST_GEN
+
+/* Define to 1 if `xp_fd' is member of `struct __rpc_svcxprt'. */
+#undef HAVE_STRUCT___RPC_SVCXPRT_XP_FD
+
+/* Define to 1 if you have the <sys/mnttab.h> header file. */
+#undef HAVE_SYS_MNTTAB_H
+
+/* Define to 1 if you have the <sys/mount.h> header file. */
+#undef HAVE_SYS_MOUNT_H
+
+/* Define to 1 if you have the <sys/vmount.h> header file. */
+#undef HAVE_SYS_VMOUNT_H
+
+/* Define to 1 if the system has the type `uint32'. */
+#undef HAVE_UINT32
+
+/* Define to 1 if the system has the type `uint64'. */
+#undef HAVE_UINT64
+
+/* Define to 1 if you have the `vsyslog' function. */
+#undef HAVE_VSYSLOG
+
+/* Define to 1 if you have the `xdr_int32' function. */
+#undef HAVE_XDR_INT32
+
+/* Define to 1 if you have the `xdr_long' function. */
+#undef HAVE_XDR_LONG
+
+/* Define to 1 if you have the `xdr_uint32' function. */
+#undef HAVE_XDR_UINT32
+
+/* Define to 1 if you have the `xdr_uint64' function. */
+#undef HAVE_XDR_UINT64
+
+/* Define to 1 if you have the `xdr_uint64_t' function. */
+#undef HAVE_XDR_UINT64_T
+
+/* Define to 1 if you have the `xdr_u_int64_t' function. */
+#undef HAVE_XDR_U_INT64_T
+
+/* Define to 1 if you have the `xdr_u_long' function. */
+#undef HAVE_XDR_U_LONG
+
+/* Define to the address where bug reports for this package should be sent. */
+#undef PACKAGE_BUGREPORT
+
+/* Define to the full name of this package. */
+#undef PACKAGE_NAME
+
+/* Define to the full name and version of this package. */
+#undef PACKAGE_STRING
+
+/* Define to the one symbol short name of this package. */
+#undef PACKAGE_TARNAME
+
+/* Define to the version of this package. */
+#undef PACKAGE_VERSION
+
+/* Define to an empty value if you use Solaris. */
+#undef PORTMAP
+
+/* Define to 1 if you have the ANSI C header files. */
+#undef STDC_HEADERS
+
+/* Cluster extensions */
+#undef WANT_CLUSTER
+
+/* Define to 1 if `lex' declares `yytext' as a `char *' by default, not a
+ `char[]'. */
+#undef YYTEXT_POINTER
+
+/* Number of bits in a file offset, on hosts where this is settable. */
+#undef _FILE_OFFSET_BITS
+
+/* Define for large files, on AIX-style hosts. */
+#undef _LARGE_FILES
diff --git a/external/fs/unfs3-0.9.22/configure b/external/fs/unfs3-0.9.22/configure
new file mode 100755
index 0000000..07ec5cd
--- /dev/null
+++ b/external/fs/unfs3-0.9.22/configure
@@ -0,0 +1,6835 @@
+#! /bin/sh
+# Guess values for system-dependent variables and create Makefiles.
+# Generated by GNU Autoconf 2.61 for unfs3 0.9.22.
+#
+# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
+# 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
+# This configure script is free software; the Free Software Foundation
+# gives unlimited permission to copy, distribute and modify it.
+## --------------------- ##
+## M4sh Initialization. ##
+## --------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
+ emulate sh
+ NULLCMD=:
+ # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+ setopt NO_GLOB_SUBST
+else
+ case `(set -o) 2>/dev/null` in
+ *posix*) set -o posix ;;
+esac
+
+fi
+
+
+
+
+# PATH needs CR
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ echo "#! /bin/sh" >conf$$.sh
+ echo "exit 0" >>conf$$.sh
+ chmod +x conf$$.sh
+ if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then
+ PATH_SEPARATOR=';'
+ else
+ PATH_SEPARATOR=:
+ fi
+ rm -f conf$$.sh
+fi
+
+# Support unset when possible.
+if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then
+ as_unset=unset
+else
+ as_unset=false
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order. Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+as_nl='
+'
+IFS=" "" $as_nl"
+
+# Find who we are. Look in the path if we contain no directory separator.
+case $0 in
+ *[\\/]* ) as_myself=$0 ;;
+ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+done
+IFS=$as_save_IFS
+
+ ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+ as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+ echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+ { (exit 1); exit 1; }
+fi
+
+# Work around bugs in pre-3.0 UWIN ksh.
+for as_var in ENV MAIL MAILPATH
+do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+for as_var in \
+ LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \
+ LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \
+ LC_TELEPHONE LC_TIME
+do
+ if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then
+ eval $as_var=C; export $as_var
+ else
+ ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var
+ fi
+done
+
+# Required to use basename.
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+ test "X`expr 00001 : '.*\(...\)'`" = X001; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+ as_basename=basename
+else
+ as_basename=false
+fi
+
+
+# Name of the executable.
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+
+# CDPATH.
+$as_unset CDPATH
+
+
+if test "x$CONFIG_SHELL" = x; then
+ if (eval ":") 2>/dev/null; then
+ as_have_required=yes
+else
+ as_have_required=no
+fi
+
+ if test $as_have_required = yes && (eval ":
+(as_func_return () {
+ (exit \$1)
+}
+as_func_success () {
+ as_func_return 0
+}
+as_func_failure () {
+ as_func_return 1
+}
+as_func_ret_success () {
+ return 0
+}
+as_func_ret_failure () {
+ return 1
+}
+
+exitcode=0
+if as_func_success; then
+ :
+else
+ exitcode=1
+ echo as_func_success failed.
+fi
+
+if as_func_failure; then
+ exitcode=1
+ echo as_func_failure succeeded.
+fi
+
+if as_func_ret_success; then
+ :
+else
+ exitcode=1
+ echo as_func_ret_success failed.
+fi
+
+if as_func_ret_failure; then
+ exitcode=1
+ echo as_func_ret_failure succeeded.
+fi
+
+if ( set x; as_func_ret_success y && test x = \"\$1\" ); then
+ :
+else
+ exitcode=1
+ echo positional parameters were not saved.
+fi
+
+test \$exitcode = 0) || { (exit 1); exit 1; }
+
+(
+ as_lineno_1=\$LINENO
+ as_lineno_2=\$LINENO
+ test \"x\$as_lineno_1\" != \"x\$as_lineno_2\" &&
+ test \"x\`expr \$as_lineno_1 + 1\`\" = \"x\$as_lineno_2\") || { (exit 1); exit 1; }
+") 2> /dev/null; then
+ :
+else
+ as_candidate_shells=
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ case $as_dir in
+ /*)
+ for as_base in sh bash ksh sh5; do
+ as_candidate_shells="$as_candidate_shells $as_dir/$as_base"
+ done;;
+ esac
+done
+IFS=$as_save_IFS
+
+
+ for as_shell in $as_candidate_shells $SHELL; do
+ # Try only shells that exist, to save several forks.
+ if { test -f "$as_shell" || test -f "$as_shell.exe"; } &&
+ { ("$as_shell") 2> /dev/null <<\_ASEOF
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
+ emulate sh
+ NULLCMD=:
+ # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+ setopt NO_GLOB_SUBST
+else
+ case `(set -o) 2>/dev/null` in
+ *posix*) set -o posix ;;
+esac
+
+fi
+
+
+:
+_ASEOF
+}; then
+ CONFIG_SHELL=$as_shell
+ as_have_required=yes
+ if { "$as_shell" 2> /dev/null <<\_ASEOF
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
+ emulate sh
+ NULLCMD=:
+ # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+ setopt NO_GLOB_SUBST
+else
+ case `(set -o) 2>/dev/null` in
+ *posix*) set -o posix ;;
+esac
+
+fi
+
+
+:
+(as_func_return () {
+ (exit $1)
+}
+as_func_success () {
+ as_func_return 0
+}
+as_func_failure () {
+ as_func_return 1
+}
+as_func_ret_success () {
+ return 0
+}
+as_func_ret_failure () {
+ return 1
+}
+
+exitcode=0
+if as_func_success; then
+ :
+else
+ exitcode=1
+ echo as_func_success failed.
+fi
+
+if as_func_failure; then
+ exitcode=1
+ echo as_func_failure succeeded.
+fi
+
+if as_func_ret_success; then
+ :
+else
+ exitcode=1
+ echo as_func_ret_success failed.
+fi
+
+if as_func_ret_failure; then
+ exitcode=1
+ echo as_func_ret_failure succeeded.
+fi
+
+if ( set x; as_func_ret_success y && test x = "$1" ); then
+ :
+else
+ exitcode=1
+ echo positional parameters were not saved.
+fi
+
+test $exitcode = 0) || { (exit 1); exit 1; }
+
+(
+ as_lineno_1=$LINENO
+ as_lineno_2=$LINENO
+ test "x$as_lineno_1" != "x$as_lineno_2" &&
+ test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2") || { (exit 1); exit 1; }
+
+_ASEOF
+}; then
+ break
+fi
+
+fi
+
+ done
+
+ if test "x$CONFIG_SHELL" != x; then
+ for as_var in BASH_ENV ENV
+ do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var
+ done
+ export CONFIG_SHELL
+ exec "$CONFIG_SHELL" "$as_myself" ${1+"$@"}
+fi
+
+
+ if test $as_have_required = no; then
+ echo This script requires a shell more modern than all the
+ echo shells that I found on your system. Please install a
+ echo modern shell, or manually run the script under such a
+ echo shell if you do have one.
+ { (exit 1); exit 1; }
+fi
+
+
+fi
+
+fi
+
+
+
+(eval "as_func_return () {
+ (exit \$1)
+}
+as_func_success () {
+ as_func_return 0
+}
+as_func_failure () {
+ as_func_return 1
+}
+as_func_ret_success () {
+ return 0
+}
+as_func_ret_failure () {
+ return 1
+}
+
+exitcode=0
+if as_func_success; then
+ :
+else
+ exitcode=1
+ echo as_func_success failed.
+fi
+
+if as_func_failure; then
+ exitcode=1
+ echo as_func_failure succeeded.
+fi
+
+if as_func_ret_success; then
+ :
+else
+ exitcode=1
+ echo as_func_ret_success failed.
+fi
+
+if as_func_ret_failure; then
+ exitcode=1
+ echo as_func_ret_failure succeeded.
+fi
+
+if ( set x; as_func_ret_success y && test x = \"\$1\" ); then
+ :
+else
+ exitcode=1
+ echo positional parameters were not saved.
+fi
+
+test \$exitcode = 0") || {
+ echo No shell found that supports shell functions.
+ echo Please tell auto...@gnu.org about your system,
+ echo including any error possibly output before this
+ echo message
+}
+
+
+
+ as_lineno_1=$LINENO
+ as_lineno_2=$LINENO
+ test "x$as_lineno_1" != "x$as_lineno_2" &&
+ test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2" || {
+
+ # Create $as_me.lineno as a copy of $as_myself, but with $LINENO
+ # uniformly replaced by the line number. The first 'sed' inserts a
+ # line-number line after each line using $LINENO; the second 'sed'
+ # does the real work. The second script uses 'N' to pair each
+ # line-number line with the line containing $LINENO, and appends
+ # trailing '-' during substitution so that $LINENO is not a special
+ # case at line end.
+ # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the
+ # scripts with optimization help from Paolo Bonzini. Blame Lee
+ # E. McMahon (1931-1989) for sed's syntax. :-)
+ sed -n '
+ p
+ /[$]LINENO/=
+ ' <$as_myself |
+ sed '
+ s/[$]LINENO.*/&-/
+ t lineno
+ b
+ :lineno
+ N
+ :loop
+ s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/
+ t loop
+ s/-\n.*//
+ ' >$as_me.lineno &&
+ chmod +x "$as_me.lineno" ||
+ { echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2
+ { (exit 1); exit 1; }; }
+
+ # Don't try to exec as it changes $[0], causing all sort of problems
+ # (the dirname of $[0] is not the place where we might find the
+ # original and so on. Autoconf is especially sensitive to this).
+ . "./$as_me.lineno"
+ # Exit status is that of the last command.
+ exit
+}
+
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+ as_dirname=dirname
+else
+ as_dirname=false
+fi
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in
+-n*)
+ case `echo 'x\c'` in
+ *c*) ECHO_T=' ';; # ECHO_T is single tab character.
+ *) ECHO_C='\c';;
+ esac;;
+*)
+ ECHO_N='-n';;
+esac
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+ test "X`expr 00001 : '.*\(...\)'`" = X001; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+ rm -f conf$$.dir/conf$$.file
+else
+ rm -f conf$$.dir
+ mkdir conf$$.dir
+fi
+echo >conf$$.file
+if ln -s conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s='ln -s'
+ # ... but there are two gotchas:
+ # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+ # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+ # In both cases, we have to default to `cp -p'.
+ ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+ as_ln_s='cp -p'
+elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+else
+ as_ln_s='cp -p'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+if mkdir -p . 2>/dev/null; then
+ as_mkdir_p=:
+else
+ test -d ./-p && rmdir ./-p
+ as_mkdir_p=false
+fi
+
+if test -x / >/dev/null 2>&1; then
+ as_test_x='test -x'
+else
+ if ls -dL / >/dev/null 2>&1; then
+ as_ls_L_option=L
+ else
+ as_ls_L_option=
+ fi
+ as_test_x='
+ eval sh -c '\''
+ if test -d "$1"; then
+ test -d "$1/.";
+ else
+ case $1 in
+ -*)set "./$1";;
+ esac;
+ case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in
+ ???[sx]*):;;*)false;;esac;fi
+ '\'' sh
+ '
+fi
+as_executable_p=$as_test_x
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+
+exec 7<&0 </dev/null 6>&1
+
+# Name of the host.
+# hostname on some systems (SVR3.2, Linux) returns a bogus exit status,
+# so uname gets run too.
+ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q`
+
+#
+# Initializations.
+#
+ac_default_prefix=/usr/local
+ac_clean_files=
+ac_config_libobj_dir=.
+LIBOBJS=
+cross_compiling=no
+subdirs=
+MFLAGS=
+MAKEFLAGS=
+SHELL=${CONFIG_SHELL-/bin/sh}
+
+# Identity of this package.
+PACKAGE_NAME='unfs3'
+PACKAGE_TARNAME='unfs3'
+PACKAGE_VERSION='0.9.22'
+PACKAGE_STRING='unfs3 0.9.22'
+PACKAGE_BUGREPORT=''
+
+ac_subst_vars='SHELL
+PATH_SEPARATOR
+PACKAGE_NAME
+PACKAGE_TARNAME
+PACKAGE_VERSION
+PACKAGE_STRING
+PACKAGE_BUGREPORT
+exec_prefix
+prefix
+program_transform_name
+bindir
+sbindir
+libexecdir
+datarootdir
+datadir
+sysconfdir
+sharedstatedir
+localstatedir
+includedir
+oldincludedir
+docdir
+infodir
+htmldir
+dvidir
+pdfdir
+psdir
+libdir
+localedir
+mandir
+DEFS
+ECHO_C
+ECHO_N
+ECHO_T
+LIBS
+build_alias
+host_alias
+target_alias
+INSTALL_PROGRAM
+INSTALL_SCRIPT
+INSTALL_DATA
+CC
+CFLAGS
+LDFLAGS
+CPPFLAGS
+ac_ct_CC
+EXEEXT
+OBJEXT
+LEX
+LEX_OUTPUT_ROOT
+LEXLIB
+YACC
+YFLAGS
+CPP
+GREP
+EGREP
+SUBDIRS
+EXTRAOBJ
+LIBOBJS
+LTLIBOBJS'
+ac_subst_files=''
+ ac_precious_vars='build_alias
+host_alias
+target_alias
+CC
+CFLAGS
+LDFLAGS
+LIBS
+CPPFLAGS
+YACC
+YFLAGS
+CPP'
+
+
+# Initialize some variables set by options.
+ac_init_help=
+ac_init_version=false
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+cache_file=/dev/null
+exec_prefix=NONE
+no_create=
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+verbose=
+x_includes=NONE
+x_libraries=NONE
+
+# Installation directory options.
+# These are left unexpanded so users can "make install exec_prefix=/foo"
+# and all the variables that are supposed to be based on exec_prefix
+# by default will actually change.
+# Use braces instead of parens because sh, perl, etc. also accept them.
+# (The list follows the same order as the GNU Coding Standards.)
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datarootdir='${prefix}/share'
+datadir='${datarootdir}'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+docdir='${datarootdir}/doc/${PACKAGE_TARNAME}'
+infodir='${datarootdir}/info'
+htmldir='${docdir}'
+dvidir='${docdir}'
+pdfdir='${docdir}'
+psdir='${docdir}'
+libdir='${exec_prefix}/lib'
+localedir='${datarootdir}/locale'
+mandir='${datarootdir}/man'
+
+ac_prev=
+ac_dashdash=
+for ac_option
+do
+ # If the previous option needs an argument, assign it.
+ if test -n "$ac_prev"; then
+ eval $ac_prev=\$ac_option
+ ac_prev=
+ continue
+ fi
+
+ case $ac_option in
+ *=*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;;
+ *) ac_optarg=yes ;;
+ esac
+
+ # Accept the important Cygnus configure options, so we can diagnose typos.
+
+ case $ac_dashdash$ac_option in
+ --)
+ ac_dashdash=yes ;;
+
+ -bindir | --bindir | --bindi | --bind | --bin | --bi)
+ ac_prev=bindir ;;
+ -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+ bindir=$ac_optarg ;;
+
+ -build | --build | --buil | --bui | --bu)
+ ac_prev=build_alias ;;
+ -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+ build_alias=$ac_optarg ;;
+
+ -cache-file | --cache-file | --cache-fil | --cache-fi \
+ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+ ac_prev=cache_file ;;
+ -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+ cache_file=$ac_optarg ;;
+
+ --config-cache | -C)
+ cache_file=config.cache ;;
+
+ -datadir | --datadir | --datadi | --datad)
+ ac_prev=datadir ;;
+ -datadir=* | --datadir=* | --datadi=* | --datad=*)
+ datadir=$ac_optarg ;;
+
+ -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \
+ | --dataroo | --dataro | --datar)
+ ac_prev=datarootdir ;;
+ -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \
+ | --dataroot=* | --dataroo=* | --dataro=* | --datar=*)
+ datarootdir=$ac_optarg ;;
+
+ -disable-* | --disable-*)
+ ac_feature=`expr "x$ac_option" : 'x-*disable-\(.*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_feature" : ".*[^-._$as_cr_alnum]" >/dev/null &&
+ { echo "$as_me: error: invalid feature name: $ac_feature" >&2
+ { (exit 1); exit 1; }; }
+ ac_feature=`echo $ac_feature | sed 's/[-.]/_/g'`
+ eval enable_$ac_feature=no ;;
+
+ -docdir | --docdir | --docdi | --doc | --do)
+ ac_prev=docdir ;;
+ -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*)
+ docdir=$ac_optarg ;;
+
+ -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv)
+ ac_prev=dvidir ;;
+ -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*)
+ dvidir=$ac_optarg ;;
+
+ -enable-* | --enable-*)
+ ac_feature=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_feature" : ".*[^-._$as_cr_alnum]" >/dev/null &&
+ { echo "$as_me: error: invalid feature name: $ac_feature" >&2
+ { (exit 1); exit 1; }; }
+ ac_feature=`echo $ac_feature | sed 's/[-.]/_/g'`
+ eval enable_$ac_feature=\$ac_optarg ;;
+
+ -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+ | --exec | --exe | --ex)
+ ac_prev=exec_prefix ;;
+ -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+ | --exec=* | --exe=* | --ex=*)
+ exec_prefix=$ac_optarg ;;
+
+ -gas | --gas | --ga | --g)
+ # Obsolete; use --with-gas.
+ with_gas=yes ;;
+
+ -help | --help | --hel | --he | -h)
+ ac_init_help=long ;;
+ -help=r* | --help=r* | --hel=r* | --he=r* | -hr*)
+ ac_init_help=recursive ;;
+ -help=s* | --help=s* | --hel=s* | --he=s* | -hs*)
+ ac_init_help=short ;;
+
+ -host | --host | --hos | --ho)
+ ac_prev=host_alias ;;
+ -host=* | --host=* | --hos=* | --ho=*)
+ host_alias=$ac_optarg ;;
+
+ -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht)
+ ac_prev=htmldir ;;
+ -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \
+ | --ht=*)
+ htmldir=$ac_optarg ;;
+
+ -includedir | --includedir | --includedi | --included | --include \
+ | --includ | --inclu | --incl | --inc)
+ ac_prev=includedir ;;
+ -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+ | --includ=* | --inclu=* | --incl=* | --inc=*)
+ includedir=$ac_optarg ;;
+
+ -infodir | --infodir | --infodi | --infod | --info | --inf)
+ ac_prev=infodir ;;
+ -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+ infodir=$ac_optarg ;;
+
+ -libdir | --libdir | --libdi | --libd)
+ ac_prev=libdir ;;
+ -libdir=* | --libdir=* | --libdi=* | --libd=*)
+ libdir=$ac_optarg ;;
+
+ -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+ | --libexe | --libex | --libe)
+ ac_prev=libexecdir ;;
+ -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+ | --libexe=* | --libex=* | --libe=*)
+ libexecdir=$ac_optarg ;;
+
+ -localedir | --localedir | --localedi | --localed | --locale)
+ ac_prev=localedir ;;
+ -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*)
+ localedir=$ac_optarg ;;
+
+ -localstatedir | --localstatedir | --localstatedi | --localstated \
+ | --localstate | --localstat | --localsta | --localst | --locals)
+ ac_prev=localstatedir ;;
+ -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+ | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*)
+ localstatedir=$ac_optarg ;;
+
+ -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+ ac_prev=mandir ;;
+ -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+ mandir=$ac_optarg ;;
+
+ -nfp | --nfp | --nf)
+ # Obsolete; use --without-fp.
+ with_fp=no ;;
+
+ -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+ | --no-cr | --no-c | -n)
+ no_create=yes ;;
+
+ -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+ no_recursion=yes ;;
+
+ -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+ | --oldin | --oldi | --old | --ol | --o)
+ ac_prev=oldincludedir ;;
+ -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+ oldincludedir=$ac_optarg ;;
+
+ -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+ ac_prev=prefix ;;
+ -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+ prefix=$ac_optarg ;;
+
+ -program-prefix | --program-prefix | --program-prefi | --program-pref \
+ | --program-pre | --program-pr | --program-p)
+ ac_prev=program_prefix ;;
+ -program-prefix=* | --program-prefix=* | --program-prefi=* \
+ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+ program_prefix=$ac_optarg ;;
+
+ -program-suffix | --program-suffix | --program-suffi | --program-suff \
+ | --program-suf | --program-su | --program-s)
+ ac_prev=program_suffix ;;
+ -program-suffix=* | --program-suffix=* | --program-suffi=* \
+ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+ program_suffix=$ac_optarg ;;
+
+ -program-transform-name | --program-transform-name \
+ | --program-transform-nam | --program-transform-na \
+ | --program-transform-n | --program-transform- \
+ | --program-transform | --program-transfor \
+ | --program-transfo | --program-transf \
+ | --program-trans | --program-tran \
+ | --progr-tra | --program-tr | --program-t)
+ ac_prev=program_transform_name ;;
+ -program-transform-name=* | --program-transform-name=* \
+ | --program-transform-nam=* | --program-transform-na=* \
+ | --program-transform-n=* | --program-transform-=* \
+ | --program-transform=* | --program-transfor=* \
+ | --program-transfo=* | --program-transf=* \
+ | --program-trans=* | --program-tran=* \
+ | --progr-tra=* | --program-tr=* | --program-t=*)
+ program_transform_name=$ac_optarg ;;
+
+ -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd)
+ ac_prev=pdfdir ;;
+ -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*)
+ pdfdir=$ac_optarg ;;
+
+ -psdir | --psdir | --psdi | --psd | --ps)
+ ac_prev=psdir ;;
+ -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*)
+ psdir=$ac_optarg ;;
+
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ silent=yes ;;
+
+ -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+ ac_prev=sbindir ;;
+ -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+ | --sbi=* | --sb=*)
+ sbindir=$ac_optarg ;;
+
+ -sharedstatedir | --sharedstatedir | --sharedstatedi \
+ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+ | --sharedst | --shareds | --shared | --share | --shar \
+ | --sha | --sh)
+ ac_prev=sharedstatedir ;;
+ -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+ | --sha=* | --sh=*)
+ sharedstatedir=$ac_optarg ;;
+
+ -site | --site | --sit)
+ ac_prev=site ;;
+ -site=* | --site=* | --sit=*)
+ site=$ac_optarg ;;
+
+ -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+ ac_prev=srcdir ;;
+ -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+ srcdir=$ac_optarg ;;
+
+ -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+ | --syscon | --sysco | --sysc | --sys | --sy)
+ ac_prev=sysconfdir ;;
+ -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+ sysconfdir=$ac_optarg ;;
+
+ -target | --target | --targe | --targ | --tar | --ta | --t)
+ ac_prev=target_alias ;;
+ -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+ target_alias=$ac_optarg ;;
+
+ -v | -verbose | --verbose | --verbos | --verbo | --verb)
+ verbose=yes ;;
+
+ -version | --version | --versio | --versi | --vers | -V)
+ ac_init_version=: ;;
+
+ -with-* | --with-*)
+ ac_package=`expr "x$ac_option" : 'x-*with-\([^=]*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_package" : ".*[^-._$as_cr_alnum]" >/dev/null &&
+ { echo "$as_me: error: invalid package name: $ac_package" >&2
+ { (exit 1); exit 1; }; }
+ ac_package=`echo $ac_package | sed 's/[-.]/_/g'`
+ eval with_$ac_package=\$ac_optarg ;;
+
+ -without-* | --without-*)
+ ac_package=`expr "x$ac_option" : 'x-*without-\(.*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_package" : ".*[^-._$as_cr_alnum]" >/dev/null &&
+ { echo "$as_me: error: invalid package name: $ac_package" >&2
+ { (exit 1); exit 1; }; }
+ ac_package=`echo $ac_package | sed 's/[-.]/_/g'`
+ eval with_$ac_package=no ;;
+
+ --x)
+ # Obsolete; use --with-x.
+ with_x=yes ;;
+
+ -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+ | --x-incl | --x-inc | --x-in | --x-i)
+ ac_prev=x_includes ;;
+ -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+ x_includes=$ac_optarg ;;
+
+ -x-libraries | --x-libraries | --x-librarie | --x-librari \
+ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+ ac_prev=x_libraries ;;
+ -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+ x_libraries=$ac_optarg ;;
+
+ -*) { echo "$as_me: error: unrecognized option: $ac_option
+Try \`$0 --help' for more information." >&2
+ { (exit 1); exit 1; }; }
+ ;;
+
+ *=*)
+ ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_envvar" : ".*[^_$as_cr_alnum]" >/dev/null &&
+ { echo "$as_me: error: invalid variable name: $ac_envvar" >&2
+ { (exit 1); exit 1; }; }
+ eval $ac_envvar=\$ac_optarg
+ export $ac_envvar ;;
+
+ *)
+ # FIXME: should be removed in autoconf 3.0.
+ echo "$as_me: WARNING: you should use --build, --host, --target" >&2
+ expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null &&
+ echo "$as_me: WARNING: invalid host type: $ac_option" >&2
+ : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}
+ ;;
+
+ esac
+done
+
+if test -n "$ac_prev"; then
+ ac_option=--`echo $ac_prev | sed 's/_/-/g'`
+ { echo "$as_me: error: missing argument to $ac_option" >&2
+ { (exit 1); exit 1; }; }
+fi
+
+# Be sure to have absolute directory names.
+for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \
+ datadir sysconfdir sharedstatedir localstatedir includedir \
+ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
+ libdir localedir mandir
+do
+ eval ac_val=\$$ac_var
+ case $ac_val in
+ [\\/$]* | ?:[\\/]* ) continue;;
+ NONE | '' ) case $ac_var in *prefix ) continue;; esac;;
+ esac
+ { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2
+ { (exit 1); exit 1; }; }
+done
+
+# There might be people who depend on the old broken behavior: `$host'
+# used to hold the argument of --host etc.
+# FIXME: To remove some day.
+build=$build_alias
+host=$host_alias
+target=$target_alias
+
+# FIXME: To remove some day.
+if test "x$host_alias" != x; then
+ if test "x$build_alias" = x; then
+ cross_compiling=maybe
+ echo "$as_me: WARNING: If you wanted to set the --build type, don't use --host.
+ If a cross compiler is detected then cross compile mode will be used." >&2
+ elif test "x$build_alias" != "x$host_alias"; then
+ cross_compiling=yes
+ fi
+fi
+
+ac_tool_prefix=
+test -n "$host_alias" && ac_tool_prefix=$host_alias-
+
+test "$silent" = yes && exec 6>/dev/null
+
+
+ac_pwd=`pwd` && test -n "$ac_pwd" &&
+ac_ls_di=`ls -di .` &&
+ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` ||
+ { echo "$as_me: error: Working directory cannot be determined" >&2
+ { (exit 1); exit 1; }; }
+test "X$ac_ls_di" = "X$ac_pwd_ls_di" ||
+ { echo "$as_me: error: pwd does not report name of working directory" >&2
+ { (exit 1); exit 1; }; }
+
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+ ac_srcdir_defaulted=yes
+ # Try the directory containing this script, then the parent directory.
+ ac_confdir=`$as_dirname -- "$0" ||
+$as_expr X"$0" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$0" : 'X\(//\)[^/]' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+echo X"$0" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ srcdir=$ac_confdir
+ if test ! -r "$srcdir/$ac_unique_file"; then
+ srcdir=..
+ fi
+else
+ ac_srcdir_defaulted=no
+fi
+if test ! -r "$srcdir/$ac_unique_file"; then
+ test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .."
+ { echo "$as_me: error: cannot find sources ($ac_unique_file) in $srcdir" >&2
+ { (exit 1); exit 1; }; }
+fi
+ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work"
+ac_abs_confdir=`(
+ cd "$srcdir" && test -r "./$ac_unique_file" || { echo "$as_me: error: $ac_msg" >&2
+ { (exit 1); exit 1; }; }
+ pwd)`
+# When building in place, set srcdir=.
+if test "$ac_abs_confdir" = "$ac_pwd"; then
+ srcdir=.
+fi
+# Remove unnecessary trailing slashes from srcdir.
+# Double slashes in file names in object file debugging info
+# mess up M-x gdb in Emacs.
+case $srcdir in
+*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;;
+esac
+for ac_var in $ac_precious_vars; do
+ eval ac_env_${ac_var}_set=\${${ac_var}+set}
+ eval ac_env_${ac_var}_value=\$${ac_var}
+ eval ac_cv_env_${ac_var}_set=\${${ac_var}+set}
+ eval ac_cv_env_${ac_var}_value=\$${ac_var}
+done
+
+#
+# Report the --help message.
+#
+if test "$ac_init_help" = "long"; then
+ # Omit some internal or obsolete options to make the list less imposing.
+ # This message is too long to be a string in the A/UX 3.1 sh.
+ cat <<_ACEOF
+\`configure' configures unfs3 0.9.22 to adapt to many kinds of systems.
+
+Usage: $0 [OPTION]... [VAR=VALUE]...
+
+To assign environment variables (e.g., CC, CFLAGS...), specify them as
+VAR=VALUE. See below for descriptions of some of the useful variables.
+
+Defaults for the options are specified in brackets.
+
+Configuration:
+ -h, --help display this help and exit
+ --help=short display options specific to this package
+ --help=recursive display the short help of all the included packages
+ -V, --version display version information and exit
+ -q, --quiet, --silent do not print \`checking...' messages
+ --cache-file=FILE cache test results in FILE [disabled]
+ -C, --config-cache alias for \`--cache-file=config.cache'
+ -n, --no-create do not create output files
+ --srcdir=DIR find the sources in DIR [configure dir or \`..']
+
+Installation directories:
+ --prefix=PREFIX install architecture-independent files in PREFIX
+ [$ac_default_prefix]
+ --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
+ [PREFIX]
+
+By default, \`make install' will install all the files in
+\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify
+an installation prefix other than \`$ac_default_prefix' using \`--prefix',
+for instance \`--prefix=\$HOME'.
+
+For better control, use the options below.
+
+Fine tuning of the installation directories:
+ --bindir=DIR user executables [EPREFIX/bin]
+ --sbindir=DIR system admin executables [EPREFIX/sbin]
+ --libexecdir=DIR program executables [EPREFIX/libexec]
+ --sysconfdir=DIR read-only single-machine data [PREFIX/etc]
+ --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com]
+ --localstatedir=DIR modifiable single-machine data [PREFIX/var]
+ --libdir=DIR object code libraries [EPREFIX/lib]
+ --includedir=DIR C header files [PREFIX/include]
+ --oldincludedir=DIR C header files for non-gcc [/usr/include]
+ --datarootdir=DIR read-only arch.-independent data root [PREFIX/share]
+ --datadir=DIR read-only architecture-independent data [DATAROOTDIR]
+ --infodir=DIR info documentation [DATAROOTDIR/info]
+ --localedir=DIR locale-dependent data [DATAROOTDIR/locale]
+ --mandir=DIR man documentation [DATAROOTDIR/man]
+ --docdir=DIR documentation root [DATAROOTDIR/doc/unfs3]
+ --htmldir=DIR html documentation [DOCDIR]
+ --dvidir=DIR dvi documentation [DOCDIR]
+ --pdfdir=DIR pdf documentation [DOCDIR]
+ --psdir=DIR ps documentation [DOCDIR]
+_ACEOF
+
+ cat <<\_ACEOF
+_ACEOF
+fi
+
+if test -n "$ac_init_help"; then
+ case $ac_init_help in
+ short | recursive ) echo "Configuration of unfs3 0.9.22:";;
+ esac
+ cat <<\_ACEOF
+
+Optional Features:
+ --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no)
+ --enable-FEATURE[=ARG] include FEATURE [ARG=yes]
+ --disable-largefile omit support for large files
+ --enable-cluster include clustering extensions
+
+Some influential environment variables:
+ CC C compiler command
+ CFLAGS C compiler flags
+ LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a
+ nonstandard directory <lib dir>
+ LIBS libraries to pass to the linker, e.g. -l<library>
+ CPPFLAGS C/C++/Objective C preprocessor flags, e.g. -I<include dir> if
+ you have headers in a nonstandard directory <include dir>
+ YACC The `Yet Another C Compiler' implementation to use. Defaults to
+ the first program found out of: `bison -y', `byacc', `yacc'.
+ YFLAGS The list of arguments that will be passed by default to $YACC.
+ This script will default YFLAGS to the empty string to avoid a
+ default value of `-d' given by some make applications.
+ CPP C preprocessor
+
+Use these variables to override the choices made by `configure' or to help
+it to find libraries and programs with nonstandard names/locations.
+
+_ACEOF
+ac_status=$?
+fi
+
+if test "$ac_init_help" = "recursive"; then
+ # If there are subdirs, report their specific --help.
+ for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue
+ test -d "$ac_dir" || continue
+ ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+ ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'`
+ # A ".." for each directory in $ac_dir_suffix.
+ ac_top_builddir_sub=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,/..,g;s,/,,'`
+ case $ac_top_builddir_sub in
+ "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+ *) ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+ esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+ .) # We are building in place.
+ ac_srcdir=.
+ ac_top_srcdir=$ac_top_builddir_sub
+ ac_abs_top_srcdir=$ac_pwd ;;
+ [\\/]* | ?:[\\/]* ) # Absolute name.
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir
+ ac_abs_top_srcdir=$srcdir ;;
+ *) # Relative name.
+ ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_build_prefix$srcdir
+ ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+ cd "$ac_dir" || { ac_status=$?; continue; }
+ # Check for guested configure.
+ if test -f "$ac_srcdir/configure.gnu"; then
+ echo &&
+ $SHELL "$ac_srcdir/configure.gnu" --help=recursive
+ elif test -f "$ac_srcdir/configure"; then
+ echo &&
+ $SHELL "$ac_srcdir/configure" --help=recursive
+ else
+ echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2
+ fi || ac_status=$?
+ cd "$ac_pwd" || { ac_status=$?; break; }
+ done
+fi
+
+test -n "$ac_init_help" && exit $ac_status
+if $ac_init_version; then
+ cat <<\_ACEOF
+unfs3 configure 0.9.22
+generated by GNU Autoconf 2.61
+
+Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
+2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
+This configure script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it.
+_ACEOF
+ exit
+fi
+cat >config.log <<_ACEOF
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+
+It was created by unfs3 $as_me 0.9.22, which was
+generated by GNU Autoconf 2.61. Invocation command line was
+
+ $ $0 $@
+
+_ACEOF
+exec 5>>config.log
+{
+cat <<_ASUNAME
+## --------- ##
+## Platform. ##
+## --------- ##
+
+hostname = `(hostname || uname -n) 2>/dev/null | sed 1q`
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown`
+/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown`
+
+/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown`
+/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown`
+/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown`
+/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown`
+/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown`
+/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown`
+
+_ASUNAME
+
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ echo "PATH: $as_dir"
+done
+IFS=$as_save_IFS
+
+} >&5
+
+cat >&5 <<_ACEOF
+
+
+## ----------- ##
+## Core tests. ##
+## ----------- ##
+
+_ACEOF
+
+
+# Keep a trace of the command line.
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Strip out --silent because we don't want to record it for future runs.
+# Also quote any args containing shell meta-characters.
+# Make two passes to allow for proper duplicate-argument suppression.
+ac_configure_args=
+ac_configure_args0=
+ac_configure_args1=
+ac_must_keep_next=false
+for ac_pass in 1 2
+do
+ for ac_arg
+ do
+ case $ac_arg in
+ -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ continue ;;
+ *\'*)
+ ac_arg=`echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ esac
+ case $ac_pass in
+ 1) ac_configure_args0="$ac_configure_args0 '$ac_arg'" ;;
+ 2)
+ ac_configure_args1="$ac_configure_args1 '$ac_arg'"
+ if test $ac_must_keep_next = true; then
+ ac_must_keep_next=false # Got value, back to normal.
+ else
+ case $ac_arg in
+ *=* | --config-cache | -C | -disable-* | --disable-* \
+ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \
+ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \
+ | -with-* | --with-* | -without-* | --without-* | --x)
+ case "$ac_configure_args0 " in
+ "$ac_configure_args1"*" '$ac_arg' "* ) continue ;;
+ esac
+ ;;
+ -* ) ac_must_keep_next=true ;;
+ esac
+ fi
+ ac_configure_args="$ac_configure_args '$ac_arg'"
+ ;;
+ esac
+ done
+done
+$as_unset ac_configure_args0 || test "${ac_configure_args0+set}" != set || { ac_configure_args0=; export ac_configure_args0; }
+$as_unset ac_configure_args1 || test "${ac_configure_args1+set}" != set || { ac_configure_args1=; export ac_configure_args1; }
+
+# When interrupted or exit'd, cleanup temporary files, and complete
+# config.log. We remove comments because anyway the quotes in there
+# would cause problems or look ugly.
+# WARNING: Use '\'' to represent an apostrophe within the trap.
+# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug.
+trap 'exit_status=$?
+ # Save into config.log some information that might help in debugging.
+ {
+ echo
+
+ cat <<\_ASBOX
+## ---------------- ##
+## Cache variables. ##
+## ---------------- ##
+_ASBOX
+ echo
+ # The following way of writing the cache mishandles newlines in values,
+(
+ for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do
+ eval ac_val=\$$ac_var
+ case $ac_val in #(
+ *${as_nl}*)
+ case $ac_var in #(
+ *_cv_*) { echo "$as_me:$LINENO: WARNING: Cache variable $ac_var contains a newline." >&5
+echo "$as_me: WARNING: Cache variable $ac_var contains a newline." >&2;} ;;
+ esac
+ case $ac_var in #(
+ _ | IFS | as_nl) ;; #(
+ *) $as_unset $ac_var ;;
+ esac ;;
+ esac
+ done
+ (set) 2>&1 |
+ case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #(
+ *${as_nl}ac_space=\ *)
+ sed -n \
+ "s/'\''/'\''\\\\'\'''\''/g;
+ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p"
+ ;; #(
+ *)
+ sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+ ;;
+ esac |
+ sort
+)
+ echo
+
+ cat <<\_ASBOX
+## ----------------- ##
+## Output variables. ##
+## ----------------- ##
+_ASBOX
+ echo
+ for ac_var in $ac_subst_vars
+ do
+ eval ac_val=\$$ac_var
+ case $ac_val in
+ *\'\''*) ac_val=`echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+ esac
+ echo "$ac_var='\''$ac_val'\''"
+ done | sort
+ echo
+
+ if test -n "$ac_subst_files"; then
+ cat <<\_ASBOX
+## ------------------- ##
+## File substitutions. ##
+## ------------------- ##
+_ASBOX
+ echo
+ for ac_var in $ac_subst_files
+ do
+ eval ac_val=\$$ac_var
+ case $ac_val in
+ *\'\''*) ac_val=`echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+ esac
+ echo "$ac_var='\''$ac_val'\''"
+ done | sort
+ echo
+ fi
+
+ if test -s confdefs.h; then
+ cat <<\_ASBOX
+## ----------- ##
+## confdefs.h. ##
+## ----------- ##
+_ASBOX
+ echo
+ cat confdefs.h
+ echo
+ fi
+ test "$ac_signal" != 0 &&
+ echo "$as_me: caught signal $ac_signal"
+ echo "$as_me: exit $exit_status"
+ } >&5
+ rm -f core *.core core.conftest.* &&
+ rm -f -r conftest* confdefs* conf$$* $ac_clean_files &&
+ exit $exit_status
+' 0
+for ac_signal in 1 2 13 15; do
+ trap 'ac_signal='$ac_signal'; { (exit 1); exit 1; }' $ac_signal
+done
+ac_signal=0
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -f -r conftest* confdefs.h
+
+# Predefined preprocessor variables.
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_NAME "$PACKAGE_NAME"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_TARNAME "$PACKAGE_TARNAME"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_VERSION "$PACKAGE_VERSION"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_STRING "$PACKAGE_STRING"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT"
+_ACEOF
+
+
+# Let the site file select an alternate cache file if it wants to.
+# Prefer explicitly selected file to automatically selected ones.
+if test -n "$CONFIG_SITE"; then
+ set x "$CONFIG_SITE"
+elif test "x$prefix" != xNONE; then
+ set x "$prefix/share/config.site" "$prefix/etc/config.site"
+else
+ set x "$ac_default_prefix/share/config.site" \
+ "$ac_default_prefix/etc/config.site"
+fi
+shift
+for ac_site_file
+do
+ if test -r "$ac_site_file"; then
+ { echo "$as_me:$LINENO: loading site script $ac_site_file" >&5
+echo "$as_me: loading site script $ac_site_file" >&6;}
+ sed 's/^/| /' "$ac_site_file" >&5
+ . "$ac_site_file"
+ fi
+done
+
+if test -r "$cache_file"; then
+ # Some versions of bash will fail to source /dev/null (special
+ # files actually), so we avoid doing that.
+ if test -f "$cache_file"; then
+ { echo "$as_me:$LINENO: loading cache $cache_file" >&5
+echo "$as_me: loading cache $cache_file" >&6;}
+ case $cache_file in
+ [\\/]* | ?:[\\/]* ) . "$cache_file";;
+ *) . "./$cache_file";;
+ esac
+ fi
+else
+ { echo "$as_me:$LINENO: creating cache $cache_file" >&5
+echo "$as_me: creating cache $cache_file" >&6;}
+ >$cache_file
+fi
+
+# Check that the precious variables saved in the cache have kept the same
+# value.
+ac_cache_corrupted=false
+for ac_var in $ac_precious_vars; do
+ eval ac_old_set=\$ac_cv_env_${ac_var}_set
+ eval ac_new_set=\$ac_env_${ac_var}_set
+ eval ac_old_val=\$ac_cv_env_${ac_var}_value
+ eval ac_new_val=\$ac_env_${ac_var}_value
+ case $ac_old_set,$ac_new_set in
+ set,)
+ { echo "$as_me:$LINENO: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5
+echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,set)
+ { echo "$as_me:$LINENO: error: \`$ac_var' was not set in the previous run" >&5
+echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,);;
+ *)
+ if test "x$ac_old_val" != "x$ac_new_val"; then
+ { echo "$as_me:$LINENO: error: \`$ac_var' has changed since the previous run:" >&5
+echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;}
+ { echo "$as_me:$LINENO: former value: $ac_old_val" >&5
+echo "$as_me: former value: $ac_old_val" >&2;}
+ { echo "$as_me:$LINENO: current value: $ac_new_val" >&5
+echo "$as_me: current value: $ac_new_val" >&2;}
+ ac_cache_corrupted=:
+ fi;;
+ esac
+ # Pass precious variables to config.status.
+ if test "$ac_new_set" = set; then
+ case $ac_new_val in
+ *\'*) ac_arg=$ac_var=`echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;;
+ *) ac_arg=$ac_var=$ac_new_val ;;
+ esac
+ case " $ac_configure_args " in
+ *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy.
+ *) ac_configure_args="$ac_configure_args '$ac_arg'" ;;
+ esac
+ fi
+done
+if $ac_cache_corrupted; then
+ { echo "$as_me:$LINENO: error: changes in the environment can compromise the build" >&5
+echo "$as_me: error: changes in the environment can compromise the build" >&2;}
+ { { echo "$as_me:$LINENO: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&5
+echo "$as_me: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&2;}
+ { (exit 1); exit 1; }; }
+fi
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+ac_config_headers="$ac_config_headers config.h"
+
+ac_aux_dir=
+for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do
+ if test -f "$ac_dir/install-sh"; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/install-sh -c"
+ break
+ elif test -f "$ac_dir/install.sh"; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/install.sh -c"
+ break
+ elif test -f "$ac_dir/shtool"; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/shtool install -c"
+ break
+ fi
+done
+if test -z "$ac_aux_dir"; then
+ { { echo "$as_me:$LINENO: error: cannot find install-sh or install.sh in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" >&5
+echo "$as_me: error: cannot find install-sh or install.sh in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" >&2;}
+ { (exit 1); exit 1; }; }
+fi
+
+# These three variables are undocumented and unsupported,
+# and are intended to be withdrawn in a future Autoconf release.
+# They can cause serious problems if a builder's source tree is in a directory
+# whose full name contains unusual characters.
+ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var.
+ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var.
+ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var.
+
+
+# Find a good install program. We prefer a C program (faster),
+# so one script is as good as another. But avoid the broken or
+# incompatible versions:
+# SysV /etc/install, /usr/sbin/install
+# SunOS /usr/etc/install
+# IRIX /sbin/install
+# AIX /bin/install
+# AmigaOS /C/install, which installs bootblocks on floppy discs
+# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag
+# AFS /usr/afsws/bin/install, which mishandles nonexistent args
+# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
+# OS/2's system install, which has a completely different semantic
+# ./install, which can be erroneously created by make from ./install.sh.
+{ echo "$as_me:$LINENO: checking for a BSD-compatible install" >&5
+echo $ECHO_N "checking for a BSD-compatible install... $ECHO_C" >&6; }
+if test -z "$INSTALL"; then
+if test "${ac_cv_path_install+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ # Account for people who put trailing slashes in PATH elements.
+case $as_dir/ in
+ ./ | .// | /cC/* | \
+ /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \
+ ?:\\/os2\\/install\\/* | ?:\\/OS2\\/INSTALL\\/* | \
+ /usr/ucb/* ) ;;
+ *)
+ # OSF1 and SCO ODT 3.0 have their own names for install.
+ # Don't use installbsd from OSF since it installs stuff as root
+ # by default.
+ for ac_prog in ginstall scoinst install; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; }; then
+ if test $ac_prog = install &&
+ grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
+ # AIX install. It has an incompatible calling convention.
+ :
+ elif test $ac_prog = install &&
+ grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
+ # program-specific install script used by HP pwplus--don't use.
+ :
+ else
+ ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c"
+ break 3
+ fi
+ fi
+ done
+ done
+ ;;
+esac
+done
+IFS=$as_save_IFS
+
+
+fi
+ if test "${ac_cv_path_install+set}" = set; then
+ INSTALL=$ac_cv_path_install
+ else
+ # As a last resort, use the slow shell script. Don't cache a
+ # value for INSTALL within a source directory, because that will
+ # break other packages using the cache if that directory is
+ # removed, or if the value is a relative name.
+ INSTALL=$ac_install_sh
+ fi
+fi
+{ echo "$as_me:$LINENO: result: $INSTALL" >&5
+echo "${ECHO_T}$INSTALL" >&6; }
+
+# Use test -z because SunOS4 sh mishandles braces in ${var-val}.
+# It thinks the first close brace ends the variable substitution.
+test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'
+
+test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}'
+
+test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+if test -n "$ac_tool_prefix"; then
+ for ac_prog in gcc egcs kgcc cc
+ do
+ # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_prog_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_CC="$ac_tool_prefix$ac_prog"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6; }
+else
+ { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+
+ test -n "$CC" && break
+ done
+fi
+if test -z "$CC"; then
+ ac_ct_CC=$CC
+ for ac_prog in gcc egcs kgcc cc
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$ac_ct_CC"; then
+ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_ac_ct_CC="$ac_prog"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+ { echo "$as_me:$LINENO: result: $ac_ct_CC" >&5
+echo "${ECHO_T}$ac_ct_CC" >&6; }
+else
+ { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+
+ test -n "$ac_ct_CC" && break
+done
+
+ if test "x$ac_ct_CC" = x; then
+ CC=""
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools
+whose name does not start with the host triplet. If you think this
+configuration is useful to you, please write to auto...@gnu.org." >&5
+echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools
+whose name does not start with the host triplet. If you think this
+configuration is useful to you, please write to auto...@gnu.org." >&2;}
+ac_tool_warned=yes ;;
+esac
+ CC=$ac_ct_CC
+ fi
+fi
+
+
+test -z "$CC" && { { echo "$as_me:$LINENO: error: no acceptable C compiler found in \$PATH
+See \`config.log' for more details." >&5
+echo "$as_me: error: no acceptable C compiler found in \$PATH
+See \`config.log' for more details." >&2;}
+ { (exit 1); exit 1; }; }
+
+# Provide some information about the compiler.
+echo "$as_me:$LINENO: checking for C compiler version" >&5
+ac_compiler=`set X $ac_compile; echo $2`
+{ (ac_try="$ac_compiler --version >&5"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$ac_compiler --version >&5") 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }
+{ (ac_try="$ac_compiler -v >&5"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$ac_compiler -v >&5") 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }
+{ (ac_try="$ac_compiler -V >&5"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$ac_compiler -V >&5") 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }
+
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files a.out a.exe b.out"
+# Try to create an executable without -o first, disregard a.out.
+# It will help us diagnose broken compilers, and finding out an intuition
+# of exeext.
+{ echo "$as_me:$LINENO: checking for C compiler default output file name" >&5
+echo $ECHO_N "checking for C compiler default output file name... $ECHO_C" >&6; }
+ac_link_default=`echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'`
+#
+# List of possible output files, starting from the most likely.
+# The algorithm is not robust to junk in `.', hence go to wildcards (a.*)
+# only as a last resort. b.out is created by i960 compilers.
+ac_files='a_out.exe a.exe conftest.exe a.out conftest a.* conftest.* b.out'
+#
+# The IRIX 6 linker writes into existing files which may not be
+# executable, retaining their permissions. Remove them first so a
+# subsequent execution test works.
+ac_rmfiles=
+for ac_file in $ac_files
+do
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.o | *.obj ) ;;
+ * ) ac_rmfiles="$ac_rmfiles $ac_file";;
+ esac
+done
+rm -f $ac_rmfiles
+
+if { (ac_try="$ac_link_default"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$ac_link_default") 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; then
+ # Autoconf-2.13 could set the ac_cv_exeext variable to `no'.
+# So ignore a value of `no', otherwise this would lead to `EXEEXT = no'
+# in a Makefile. We should not override ac_cv_exeext if it was cached,
+# so that the user can short-circuit this test for compilers unknown to
+# Autoconf.
+for ac_file in $ac_files ''
+do
+ test -f "$ac_file" || continue
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.o | *.obj )
+ ;;
+ [ab].out )
+ # We found the default executable, but exeext='' is most
+ # certainly right.
+ break;;
+ *.* )
+ if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no;
+ then :; else
+ ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+ fi
+ # We set ac_cv_exeext here because the later test for it is not
+ # safe: cross compilers may not add the suffix if given an `-o'
+ # argument, so we may need to know it at that point already.
+ # Even if this section looks crufty: it has the advantage of
+ # actually working.
+ break;;
+ * )
+ break;;
+ esac
+done
+test "$ac_cv_exeext" = no && ac_cv_exeext=
+
+else
+ ac_file=''
+fi
+
+{ echo "$as_me:$LINENO: result: $ac_file" >&5
+echo "${ECHO_T}$ac_file" >&6; }
+if test -z "$ac_file"; then
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { echo "$as_me:$LINENO: error: C compiler cannot create executables
+See \`config.log' for more details." >&5
+echo "$as_me: error: C compiler cannot create executables
+See \`config.log' for more details." >&2;}
+ { (exit 77); exit 77; }; }
+fi
+
+ac_exeext=$ac_cv_exeext
+
+# Check that the compiler produces executables we can run. If not, either
+# the compiler is broken, or we cross compile.
+{ echo "$as_me:$LINENO: checking whether the C compiler works" >&5
+echo $ECHO_N "checking whether the C compiler works... $ECHO_C" >&6; }
+# FIXME: These cross compiler hacks should be removed for Autoconf 3.0
+# If not cross compiling, check that we can run a simple program.
+if test "$cross_compiling" != yes; then
+ if { ac_try='./$ac_file'
+ { (case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$ac_try") 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ cross_compiling=no
+ else
+ if test "$cross_compiling" = maybe; then
+ cross_compiling=yes
+ else
+ { { echo "$as_me:$LINENO: error: cannot run C compiled programs.
+If you meant to cross compile, use \`--host'.
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot run C compiled programs.
+If you meant to cross compile, use \`--host'.
+See \`config.log' for more details." >&2;}
+ { (exit 1); exit 1; }; }
+ fi
+ fi
+fi
+{ echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6; }
+
+rm -f a.out a.exe conftest$ac_cv_exeext b.out
+ac_clean_files=$ac_clean_files_save
+# Check that the compiler produces executables we can run. If not, either
+# the compiler is broken, or we cross compile.
+{ echo "$as_me:$LINENO: checking whether we are cross compiling" >&5
+echo $ECHO_N "checking whether we are cross compiling... $ECHO_C" >&6; }
+{ echo "$as_me:$LINENO: result: $cross_compiling" >&5
+echo "${ECHO_T}$cross_compiling" >&6; }
+
+{ echo "$as_me:$LINENO: checking for suffix of executables" >&5
+echo $ECHO_N "checking for suffix of executables... $ECHO_C" >&6; }
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$ac_link") 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; then
+ # If both `conftest.exe' and `conftest' are `present' (well, observable)
+# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will
+# work properly (i.e., refer to `conftest.exe'), while it won't with
+# `rm'.
+for ac_file in conftest.exe conftest conftest.*; do
+ test -f "$ac_file" || continue
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.o | *.obj ) ;;
+ *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+ break;;
+ * ) break;;
+ esac
+done
+else
+ { { echo "$as_me:$LINENO: error: cannot compute suffix of executables: cannot compile and link
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot compute suffix of executables: cannot compile and link
+See \`config.log' for more details." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+
+rm -f conftest$ac_cv_exeext
+{ echo "$as_me:$LINENO: result: $ac_cv_exeext" >&5
+echo "${ECHO_T}$ac_cv_exeext" >&6; }
+
+rm -f conftest.$ac_ext
+EXEEXT=$ac_cv_exeext
+ac_exeext=$EXEEXT
+{ echo "$as_me:$LINENO: checking for suffix of object files" >&5
+echo $ECHO_N "checking for suffix of object files... $ECHO_C" >&6; }
+if test "${ac_cv_objext+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.o conftest.obj
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$ac_compile") 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; then
+ for ac_file in conftest.o conftest.obj conftest.*; do
+ test -f "$ac_file" || continue;
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf ) ;;
+ *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'`
+ break;;
+ esac
+done
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { echo "$as_me:$LINENO: error: cannot compute suffix of object files: cannot compile
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot compute suffix of object files: cannot compile
+See \`config.log' for more details." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+
+rm -f conftest.$ac_cv_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_objext" >&5
+echo "${ECHO_T}$ac_cv_objext" >&6; }
+OBJEXT=$ac_cv_objext
+ac_objext=$OBJEXT
+{ echo "$as_me:$LINENO: checking whether we are using the GNU C compiler" >&5
+echo $ECHO_N "checking whether we are using the GNU C compiler... $ECHO_C" >&6; }
+if test "${ac_cv_c_compiler_gnu+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+int
+main ()
+{
+#ifndef __GNUC__
+ choke me
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$ac_compile") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest.$ac_objext; then
+ ac_compiler_gnu=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_compiler_gnu=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ac_cv_c_compiler_gnu=$ac_compiler_gnu
+
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_c_compiler_gnu" >&5
+echo "${ECHO_T}$ac_cv_c_compiler_gnu" >&6; }
+GCC=`test $ac_compiler_gnu = yes && echo yes`
+ac_test_CFLAGS=${CFLAGS+set}
+ac_save_CFLAGS=$CFLAGS
+{ echo "$as_me:$LINENO: checking whether $CC accepts -g" >&5
+echo $ECHO_N "checking whether $CC accepts -g... $ECHO_C" >&6; }
+if test "${ac_cv_prog_cc_g+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_save_c_werror_flag=$ac_c_werror_flag
+ ac_c_werror_flag=yes
+ ac_cv_prog_cc_g=no
+ CFLAGS="-g"
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$ac_compile") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest.$ac_objext; then
+ ac_cv_prog_cc_g=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ CFLAGS=""
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$ac_compile") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest.$ac_objext; then
+ :
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_c_werror_flag=$ac_save_c_werror_flag
+ CFLAGS="-g"
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$ac_compile") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest.$ac_objext; then
+ ac_cv_prog_cc_g=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ ac_c_werror_flag=$ac_save_c_werror_flag
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_prog_cc_g" >&5
+echo "${ECHO_T}$ac_cv_prog_cc_g" >&6; }
+if test "$ac_test_CFLAGS" = set; then
+ CFLAGS=$ac_save_CFLAGS
+elif test $ac_cv_prog_cc_g = yes; then
+ if test "$GCC" = yes; then
+ CFLAGS="-g -O2"
+ else
+ CFLAGS="-g"
+ fi
+else
+ if test "$GCC" = yes; then
+ CFLAGS="-O2"
+ else
+ CFLAGS=
+ fi
+fi
+{ echo "$as_me:$LINENO: checking for $CC option to accept ISO C89" >&5
+echo $ECHO_N "checking for $CC option to accept ISO C89... $ECHO_C" >&6; }
+if test "${ac_cv_prog_cc_c89+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_cv_prog_cc_c89=no
+ac_save_CC=$CC
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <stdarg.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */
+struct buf { int x; };
+FILE * (*rcsopen) (struct buf *, struct stat *, int);
+static char *e (p, i)
+ char **p;
+ int i;
+{
+ return p[i];
+}
+static char *f (char * (*g) (char **, int), char **p, ...)
+{
+ char *s;
+ va_list v;
+ va_start (v,p);
+ s = g (p, va_arg (v,int));
+ va_end (v);
+ return s;
+}
+
+/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has
+ function prototypes and stuff, but not '\xHH' hex character constants.
+ These don't provoke an error unfortunately, instead are silently treated
+ as 'x'. The following induces an error, until -std is added to get
+ proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an
+ array size at least. It's necessary to write '\x00'==0 to get something
+ that's true only with -std. */
+int osf4_cc_array ['\x00' == 0 ? 1 : -1];
+
+/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters
+ inside strings and character constants. */
+#define FOO(x) 'x'
+int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1];
+
+int test (int i, double x);
+struct s1 {int (*f) (int a);};
+struct s2 {int (*f) (double a);};
+int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int);
+int argc;
+char **argv;
+int
+main ()
+{
+return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1];
+ ;
+ return 0;
+}
+_ACEOF
+for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \
+ -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__"
+do
+ CC="$ac_save_CC $ac_arg"
+ rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$ac_compile") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest.$ac_objext; then
+ ac_cv_prog_cc_c89=$ac_arg
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext
+ test "x$ac_cv_prog_cc_c89" != "xno" && break
+done
+rm -f conftest.$ac_ext
+CC=$ac_save_CC
+
+fi
+# AC_CACHE_VAL
+case "x$ac_cv_prog_cc_c89" in
+ x)
+ { echo "$as_me:$LINENO: result: none needed" >&5
+echo "${ECHO_T}none needed" >&6; } ;;
+ xno)
+ { echo "$as_me:$LINENO: result: unsupported" >&5
+echo "${ECHO_T}unsupported" >&6; } ;;
+ *)
+ CC="$CC $ac_cv_prog_cc_c89"
+ { echo "$as_me:$LINENO: result: $ac_cv_prog_cc_c89" >&5
+echo "${ECHO_T}$ac_cv_prog_cc_c89" >&6; } ;;
+esac
+
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+for ac_prog in flex lex
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_prog_LEX+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$LEX"; then
+ ac_cv_prog_LEX="$LEX" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_LEX="$ac_prog"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+LEX=$ac_cv_prog_LEX
+if test -n "$LEX"; then
+ { echo "$as_me:$LINENO: result: $LEX" >&5
+echo "${ECHO_T}$LEX" >&6; }
+else
+ { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+
+ test -n "$LEX" && break
+done
+test -n "$LEX" || LEX=":"
+
+if test "x$LEX" != "x:"; then
+ cat >conftest.l <<_ACEOF
+%%
+a { ECHO; }
+b { REJECT; }
+c { yymore (); }
+d { yyless (1); }
+e { yyless (input () != 0); }
+f { unput (yytext[0]); }
+. { BEGIN INITIAL; }
+%%
+#ifdef YYTEXT_POINTER
+extern char *yytext;
+#endif
+int
+main (void)
+{
+ return ! yylex () + ! yywrap ();
+}
+_ACEOF
+{ (ac_try="$LEX conftest.l"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$LEX conftest.l") 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }
+{ echo "$as_me:$LINENO: checking lex output file root" >&5
+echo $ECHO_N "checking lex output file root... $ECHO_C" >&6; }
+if test "${ac_cv_prog_lex_root+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+if test -f lex.yy.c; then
+ ac_cv_prog_lex_root=lex.yy
+elif test -f lexyy.c; then
+ ac_cv_prog_lex_root=lexyy
+else
+ { { echo "$as_me:$LINENO: error: cannot find output from $LEX; giving up" >&5
+echo "$as_me: error: cannot find output from $LEX; giving up" >&2;}
+ { (exit 1); exit 1; }; }
+fi
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_prog_lex_root" >&5
+echo "${ECHO_T}$ac_cv_prog_lex_root" >&6; }
+LEX_OUTPUT_ROOT=$ac_cv_prog_lex_root
+
+if test -z "${LEXLIB+set}"; then
+ { echo "$as_me:$LINENO: checking lex library" >&5
+echo $ECHO_N "checking lex library... $ECHO_C" >&6; }
+if test "${ac_cv_lib_lex+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+ ac_save_LIBS=$LIBS
+ ac_cv_lib_lex='none needed'
+ for ac_lib in '' -lfl -ll; do
+ LIBS="$ac_lib $ac_save_LIBS"
+ cat >conftest.$ac_ext <<_ACEOF
+`cat $LEX_OUTPUT_ROOT.c`
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$ac_link") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest$ac_exeext &&
+ $as_test_x conftest$ac_exeext; then
+ ac_cv_lib_lex=$ac_lib
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+ conftest$ac_exeext conftest.$ac_ext
+ test "$ac_cv_lib_lex" != 'none needed' && break
+ done
+ LIBS=$ac_save_LIBS
+
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_lib_lex" >&5
+echo "${ECHO_T}$ac_cv_lib_lex" >&6; }
+ test "$ac_cv_lib_lex" != 'none needed' && LEXLIB=$ac_cv_lib_lex
+fi
+
+
+{ echo "$as_me:$LINENO: checking whether yytext is a pointer" >&5
+echo $ECHO_N "checking whether yytext is a pointer... $ECHO_C" >&6; }
+if test "${ac_cv_prog_lex_yytext_pointer+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ # POSIX says lex can declare yytext either as a pointer or an array; the
+# default is implementation-dependent. Figure out which it is, since
+# not all implementations provide the %pointer and %array declarations.
+ac_cv_prog_lex_yytext_pointer=no
+ac_save_LIBS=$LIBS
+LIBS="$LEXLIB $ac_save_LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+#define YYTEXT_POINTER 1
+`cat $LEX_OUTPUT_ROOT.c`
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$ac_link") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest$ac_exeext &&
+ $as_test_x conftest$ac_exeext; then
+ ac_cv_prog_lex_yytext_pointer=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_save_LIBS
+
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_prog_lex_yytext_pointer" >&5
+echo "${ECHO_T}$ac_cv_prog_lex_yytext_pointer" >&6; }
+if test $ac_cv_prog_lex_yytext_pointer = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define YYTEXT_POINTER 1
+_ACEOF
+
+fi
+rm -f conftest.l $LEX_OUTPUT_ROOT.c
+
+fi
+for ac_prog in 'bison -y' byacc
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_prog_YACC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$YACC"; then
+ ac_cv_prog_YACC="$YACC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_YACC="$ac_prog"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+YACC=$ac_cv_prog_YACC
+if test -n "$YACC"; then
+ { echo "$as_me:$LINENO: result: $YACC" >&5
+echo "${ECHO_T}$YACC" >&6; }
+else
+ { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+
+ test -n "$YACC" && break
+done
+test -n "$YACC" || YACC="yacc"
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+{ echo "$as_me:$LINENO: checking how to run the C preprocessor" >&5
+echo $ECHO_N "checking how to run the C preprocessor... $ECHO_C" >&6; }
+# On Suns, sometimes $CPP names a directory.
+if test -n "$CPP" && test -d "$CPP"; then
+ CPP=
+fi
+if test -z "$CPP"; then
+ if test "${ac_cv_prog_CPP+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ # Double quotes because CPP needs to be expanded
+ for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp"
+ do
+ ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+ # Use a header file that comes with gcc, so configuring glibc
+ # with a fresh cross-compiler works.
+ # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ # <limits.h> exists even on freestanding compilers.
+ # On the NeXT, cc -E runs the code through the compiler's parser,
+ # not just through cpp. "Syntax error" is here to catch this case.
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+ Syntax error
+_ACEOF
+if { (ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null && {
+ test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ }; then
+ :
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ # Broken: fails on valid input.
+continue
+fi
+
+rm -f conftest.err conftest.$ac_ext
+
+ # OK, works on sane cases. Now check whether nonexistent headers
+ # can be detected and how.
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <ac_nonexistent.h>
+_ACEOF
+if { (ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null && {
+ test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ }; then
+ # Broken: success on invalid input.
+continue
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+
+rm -f conftest.err conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then
+ break
+fi
+
+ done
+ ac_cv_prog_CPP=$CPP
+
+fi
+ CPP=$ac_cv_prog_CPP
+else
+ ac_cv_prog_CPP=$CPP
+fi
+{ echo "$as_me:$LINENO: result: $CPP" >&5
+echo "${ECHO_T}$CPP" >&6; }
+ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+ # Use a header file that comes with gcc, so configuring glibc
+ # with a fresh cross-compiler works.
+ # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ # <limits.h> exists even on freestanding compilers.
+ # On the NeXT, cc -E runs the code through the compiler's parser,
+ # not just through cpp. "Syntax error" is here to catch this case.
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+ Syntax error
+_ACEOF
+if { (ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null && {
+ test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ }; then
+ :
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ # Broken: fails on valid input.
+continue
+fi
+
+rm -f conftest.err conftest.$ac_ext
+
+ # OK, works on sane cases. Now check whether nonexistent headers
+ # can be detected and how.
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <ac_nonexistent.h>
+_ACEOF
+if { (ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null && {
+ test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ }; then
+ # Broken: success on invalid input.
+continue
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+
+rm -f conftest.err conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then
+ :
+else
+ { { echo "$as_me:$LINENO: error: C preprocessor \"$CPP\" fails sanity check
+See \`config.log' for more details." >&5
+echo "$as_me: error: C preprocessor \"$CPP\" fails sanity check
+See \`config.log' for more details." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+{ echo "$as_me:$LINENO: checking for grep that handles long lines and -e" >&5
+echo $ECHO_N "checking for grep that handles long lines and -e... $ECHO_C" >&6; }
+if test "${ac_cv_path_GREP+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ # Extract the first word of "grep ggrep" to use in msg output
+if test -z "$GREP"; then
+set dummy grep ggrep; ac_prog_name=$2
+if test "${ac_cv_path_GREP+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_path_GREP_found=false
+# Loop through the user's path and test for each of PROGNAME-LIST
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_prog in grep ggrep; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext"
+ { test -f "$ac_path_GREP" && $as_test_x "$ac_path_GREP"; } || continue
+ # Check for GNU ac_path_GREP and select it if it is found.
+ # Check for GNU $ac_path_GREP
+case `"$ac_path_GREP" --version 2>&1` in
+*GNU*)
+ ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;;
+*)
+ ac_count=0
+ echo $ECHO_N "0123456789$ECHO_C" >"conftest.in"
+ while :
+ do
+ cat "conftest.in" "conftest.in" >"conftest.tmp"
+ mv "conftest.tmp" "conftest.in"
+ cp "conftest.in" "conftest.nl"
+ echo 'GREP' >> "conftest.nl"
+ "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break
+ diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+ ac_count=`expr $ac_count + 1`
+ if test $ac_count -gt ${ac_path_GREP_max-0}; then
+ # Best one so far, save it but keep looking for a better one
+ ac_cv_path_GREP="$ac_path_GREP"
+ ac_path_GREP_max=$ac_count
+ fi
+ # 10*(2^10) chars as input seems more than enough
+ test $ac_count -gt 10 && break
+ done
+ rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+
+ $ac_path_GREP_found && break 3
+ done
+done
+
+done
+IFS=$as_save_IFS
+
+
+fi
+
+GREP="$ac_cv_path_GREP"
+if test -z "$GREP"; then
+ { { echo "$as_me:$LINENO: error: no acceptable $ac_prog_name could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&5
+echo "$as_me: error: no acceptable $ac_prog_name could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&2;}
+ { (exit 1); exit 1; }; }
+fi
+
+else
+ ac_cv_path_GREP=$GREP
+fi
+
+
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_path_GREP" >&5
+echo "${ECHO_T}$ac_cv_path_GREP" >&6; }
+ GREP="$ac_cv_path_GREP"
+
+
+{ echo "$as_me:$LINENO: checking for egrep" >&5
+echo $ECHO_N "checking for egrep... $ECHO_C" >&6; }
+if test "${ac_cv_path_EGREP+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if echo a | $GREP -E '(a|b)' >/dev/null 2>&1
+ then ac_cv_path_EGREP="$GREP -E"
+ else
+ # Extract the first word of "egrep" to use in msg output
+if test -z "$EGREP"; then
+set dummy egrep; ac_prog_name=$2
+if test "${ac_cv_path_EGREP+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_path_EGREP_found=false
+# Loop through the user's path and test for each of PROGNAME-LIST
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_prog in egrep; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext"
+ { test -f "$ac_path_EGREP" && $as_test_x "$ac_path_EGREP"; } || continue
+ # Check for GNU ac_path_EGREP and select it if it is found.
+ # Check for GNU $ac_path_EGREP
+case `"$ac_path_EGREP" --version 2>&1` in
+*GNU*)
+ ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;;
+*)
+ ac_count=0
+ echo $ECHO_N "0123456789$ECHO_C" >"conftest.in"
+ while :
+ do
+ cat "conftest.in" "conftest.in" >"conftest.tmp"
+ mv "conftest.tmp" "conftest.in"
+ cp "conftest.in" "conftest.nl"
+ echo 'EGREP' >> "conftest.nl"
+ "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break
+ diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+ ac_count=`expr $ac_count + 1`
+ if test $ac_count -gt ${ac_path_EGREP_max-0}; then
+ # Best one so far, save it but keep looking for a better one
+ ac_cv_path_EGREP="$ac_path_EGREP"
+ ac_path_EGREP_max=$ac_count
+ fi
+ # 10*(2^10) chars as input seems more than enough
+ test $ac_count -gt 10 && break
+ done
+ rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+
+ $ac_path_EGREP_found && break 3
+ done
+done
+
+done
+IFS=$as_save_IFS
+
+
+fi
+
+EGREP="$ac_cv_path_EGREP"
+if test -z "$EGREP"; then
+ { { echo "$as_me:$LINENO: error: no acceptable $ac_prog_name could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&5
+echo "$as_me: error: no acceptable $ac_prog_name could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&2;}
+ { (exit 1); exit 1; }; }
+fi
+
+else
+ ac_cv_path_EGREP=$EGREP
+fi
+
+
+ fi
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_path_EGREP" >&5
+echo "${ECHO_T}$ac_cv_path_EGREP" >&6; }
+ EGREP="$ac_cv_path_EGREP"
+
+
+{ echo "$as_me:$LINENO: checking for ANSI C header files" >&5
+echo $ECHO_N "checking for ANSI C header files... $ECHO_C" >&6; }
+if test "${ac_cv_header_stdc+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <float.h>
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$ac_compile") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest.$ac_objext; then
+ ac_cv_header_stdc=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_cv_header_stdc=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+if test $ac_cv_header_stdc = yes; then
+ # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <string.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "memchr" >/dev/null 2>&1; then
+ :
+else
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+ # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <stdlib.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "free" >/dev/null 2>&1; then
+ :
+else
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+ # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
+ if test "$cross_compiling" = yes; then
+ :
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <ctype.h>
+#include <stdlib.h>
+#if ((' ' & 0x0FF) == 0x020)
+# define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
+# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
+#else
+# define ISLOWER(c) \
+ (('a' <= (c) && (c) <= 'i') \
+ || ('j' <= (c) && (c) <= 'r') \
+ || ('s' <= (c) && (c) <= 'z'))
+# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c))
+#endif
+
+#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
+int
+main ()
+{
+ int i;
+ for (i = 0; i < 256; i++)
+ if (XOR (islower (i), ISLOWER (i))
+ || toupper (i) != TOUPPER (i))
+ return 2;
+ return 0;
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$ac_link") 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+ { (case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$ac_try") 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ :
+else
+ echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+ac_cv_header_stdc=no
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+
+
+fi
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_header_stdc" >&5
+echo "${ECHO_T}$ac_cv_header_stdc" >&6; }
+if test $ac_cv_header_stdc = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define STDC_HEADERS 1
+_ACEOF
+
+fi
+
+# Check whether --enable-largefile was given.
+if test "${enable_largefile+set}" = set; then
+ enableval=$enable_largefile;
+fi
+
+if test "$enable_largefile" != no; then
+
+ { echo "$as_me:$LINENO: checking for special C compiler options needed for large files" >&5
+echo $ECHO_N "checking for special C compiler options needed for large files... $ECHO_C" >&6; }
+if test "${ac_cv_sys_largefile_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_cv_sys_largefile_CC=no
+ if test "$GCC" != yes; then
+ ac_save_CC=$CC
+ while :; do
+ # IRIX 6.2 and later do not support large files by default,
+ # so use the C compiler's -n32 option if that helps.
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <sys/types.h>
+ /* Check that off_t can represent 2**63 - 1 correctly.
+ We can't simply define LARGE_OFF_T to be 9223372036854775807,
+ since some C++ compilers masquerading as C compilers
+ incorrectly reject 9223372036854775807. */
+#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62))
+ int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
+ && LARGE_OFF_T % 2147483647 == 1)
+ ? 1 : -1];
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+ rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$ac_compile") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest.$ac_objext; then
+ break
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext
+ CC="$CC -n32"
+ rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$ac_compile") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest.$ac_objext; then
+ ac_cv_sys_largefile_CC=' -n32'; break
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext
+ break
+ done
+ CC=$ac_save_CC
+ rm -f conftest.$ac_ext
+ fi
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_sys_largefile_CC" >&5
+echo "${ECHO_T}$ac_cv_sys_largefile_CC" >&6; }
+ if test "$ac_cv_sys_largefile_CC" != no; then
+ CC=$CC$ac_cv_sys_largefile_CC
+ fi
+
+ { echo "$as_me:$LINENO: checking for _FILE_OFFSET_BITS value needed for large files" >&5
+echo $ECHO_N "checking for _FILE_OFFSET_BITS value needed for large files... $ECHO_C" >&6; }
+if test "${ac_cv_sys_file_offset_bits+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ while :; do
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <sys/types.h>
+ /* Check that off_t can represent 2**63 - 1 correctly.
+ We can't simply define LARGE_OFF_T to be 9223372036854775807,
+ since some C++ compilers masquerading as C compilers
+ incorrectly reject 9223372036854775807. */
+#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62))
+ int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
+ && LARGE_OFF_T % 2147483647 == 1)
+ ? 1 : -1];
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$ac_compile") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest.$ac_objext; then
+ ac_cv_sys_file_offset_bits=no; break
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#define _FILE_OFFSET_BITS 64
+#include <sys/types.h>
+ /* Check that off_t can represent 2**63 - 1 correctly.
+ We can't simply define LARGE_OFF_T to be 9223372036854775807,
+ since some C++ compilers masquerading as C compilers
+ incorrectly reject 9223372036854775807. */
+#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62))
+ int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
+ && LARGE_OFF_T % 2147483647 == 1)
+ ? 1 : -1];
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$ac_compile") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest.$ac_objext; then
+ ac_cv_sys_file_offset_bits=64; break
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ ac_cv_sys_file_offset_bits=unknown
+ break
+done
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_sys_file_offset_bits" >&5
+echo "${ECHO_T}$ac_cv_sys_file_offset_bits" >&6; }
+case $ac_cv_sys_file_offset_bits in #(
+ no | unknown) ;;
+ *)
+cat >>confdefs.h <<_ACEOF
+#define _FILE_OFFSET_BITS $ac_cv_sys_file_offset_bits
+_ACEOF
+;;
+esac
+rm -f conftest*
+ if test $ac_cv_sys_file_offset_bits = unknown; then
+ { echo "$as_me:$LINENO: checking for _LARGE_FILES value needed for large files" >&5
+echo $ECHO_N "checking for _LARGE_FILES value needed for large files... $ECHO_C" >&6; }
+if test "${ac_cv_sys_large_files+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ while :; do
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <sys/types.h>
+ /* Check that off_t can represent 2**63 - 1 correctly.
+ We can't simply define LARGE_OFF_T to be 9223372036854775807,
+ since some C++ compilers masquerading as C compilers
+ incorrectly reject 9223372036854775807. */
+#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62))
+ int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
+ && LARGE_OFF_T % 2147483647 == 1)
+ ? 1 : -1];
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$ac_compile") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest.$ac_objext; then
+ ac_cv_sys_large_files=no; break
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#define _LARGE_FILES 1
+#include <sys/types.h>
+ /* Check that off_t can represent 2**63 - 1 correctly.
+ We can't simply define LARGE_OFF_T to be 9223372036854775807,
+ since some C++ compilers masquerading as C compilers
+ incorrectly reject 9223372036854775807. */
+#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62))
+ int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
+ && LARGE_OFF_T % 2147483647 == 1)
+ ? 1 : -1];
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$ac_compile") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest.$ac_objext; then
+ ac_cv_sys_large_files=1; break
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ ac_cv_sys_large_files=unknown
+ break
+done
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_sys_large_files" >&5
+echo "${ECHO_T}$ac_cv_sys_large_files" >&6; }
+case $ac_cv_sys_large_files in #(
+ no | unknown) ;;
+ *)
+cat >>confdefs.h <<_ACEOF
+#define _LARGE_FILES $ac_cv_sys_large_files
+_ACEOF
+;;
+esac
+rm -f conftest*
+ fi
+fi
+
+{ echo "$as_me:$LINENO: checking for library containing xdr_int" >&5
+echo $ECHO_N "checking for library containing xdr_int... $ECHO_C" >&6; }
+if test "${ac_cv_search_xdr_int+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_func_search_save_LIBS=$LIBS
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char xdr_int ();
+int
+main ()
+{
+return xdr_int ();
+ ;
+ return 0;
+}
+_ACEOF
+for ac_lib in '' nsl; do
+ if test -z "$ac_lib"; then
+ ac_res="none required"
+ else
+ ac_res=-l$ac_lib
+ LIBS="-l$ac_lib $ac_func_search_save_LIBS"
+ fi
+ rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$ac_link") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest$ac_exeext &&
+ $as_test_x conftest$ac_exeext; then
+ ac_cv_search_xdr_int=$ac_res
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+ conftest$ac_exeext
+ if test "${ac_cv_search_xdr_int+set}" = set; then
+ break
+fi
+done
+if test "${ac_cv_search_xdr_int+set}" = set; then
+ :
+else
+ ac_cv_search_xdr_int=no
+fi
+rm conftest.$ac_ext
+LIBS=$ac_func_search_save_LIBS
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_search_xdr_int" >&5
+echo "${ECHO_T}$ac_cv_search_xdr_int" >&6; }
+ac_res=$ac_cv_search_xdr_int
+if test "$ac_res" != no; then
+ test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
+
+fi
+
+{ echo "$as_me:$LINENO: checking for library containing socket" >&5
+echo $ECHO_N "checking for library containing socket... $ECHO_C" >&6; }
+if test "${ac_cv_search_socket+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_func_search_save_LIBS=$LIBS
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char socket ();
+int
+main ()
+{
+return socket ();
+ ;
+ return 0;
+}
+_ACEOF
+for ac_lib in '' socket; do
+ if test -z "$ac_lib"; then
+ ac_res="none required"
+ else
+ ac_res=-l$ac_lib
+ LIBS="-l$ac_lib $ac_func_search_save_LIBS"
+ fi
+ rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$ac_link") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest$ac_exeext &&
+ $as_test_x conftest$ac_exeext; then
+ ac_cv_search_socket=$ac_res
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+ conftest$ac_exeext
+ if test "${ac_cv_search_socket+set}" = set; then
+ break
+fi
+done
+if test "${ac_cv_search_socket+set}" = set; then
+ :
+else
+ ac_cv_search_socket=no
+fi
+rm conftest.$ac_ext
+LIBS=$ac_func_search_save_LIBS
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_search_socket" >&5
+echo "${ECHO_T}$ac_cv_search_socket" >&6; }
+ac_res=$ac_cv_search_socket
+if test "$ac_res" != no; then
+ test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
+
+fi
+
+{ echo "$as_me:$LINENO: checking for library containing inet_aton" >&5
+echo $ECHO_N "checking for library containing inet_aton... $ECHO_C" >&6; }
+if test "${ac_cv_search_inet_aton+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_func_search_save_LIBS=$LIBS
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char inet_aton ();
+int
+main ()
+{
+return inet_aton ();
+ ;
+ return 0;
+}
+_ACEOF
+for ac_lib in '' resolv; do
+ if test -z "$ac_lib"; then
+ ac_res="none required"
+ else
+ ac_res=-l$ac_lib
+ LIBS="-l$ac_lib $ac_func_search_save_LIBS"
+ fi
+ rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$ac_link") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest$ac_exeext &&
+ $as_test_x conftest$ac_exeext; then
+ ac_cv_search_inet_aton=$ac_res
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+ conftest$ac_exeext
+ if test "${ac_cv_search_inet_aton+set}" = set; then
+ break
+fi
+done
+if test "${ac_cv_search_inet_aton+set}" = set; then
+ :
+else
+ ac_cv_search_inet_aton=no
+fi
+rm conftest.$ac_ext
+LIBS=$ac_func_search_save_LIBS
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_search_inet_aton" >&5
+echo "${ECHO_T}$ac_cv_search_inet_aton" >&6; }
+ac_res=$ac_cv_search_inet_aton
+if test "$ac_res" != no; then
+ test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
+
+fi
+
+
+for ac_header in mntent.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+{ echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; }
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <stdio.h>
+
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$ac_compile") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest.$ac_objext; then
+ eval "$as_ac_Header=yes"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ eval "$as_ac_Header=no"
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+ac_res=`eval echo '${'$as_ac_Header'}'`
+ { echo "$as_me:$LINENO: result: $ac_res" >&5
+echo "${ECHO_T}$ac_res" >&6; }
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+for ac_header in stdint.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+{ echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; }
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <stdio.h>
+
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$ac_compile") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest.$ac_objext; then
+ eval "$as_ac_Header=yes"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ eval "$as_ac_Header=no"
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+ac_res=`eval echo '${'$as_ac_Header'}'`
+ { echo "$as_me:$LINENO: result: $ac_res" >&5
+echo "${ECHO_T}$ac_res" >&6; }
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+for ac_header in sys/mnttab.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+{ echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; }
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <stdio.h>
+
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$ac_compile") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest.$ac_objext; then
+ eval "$as_ac_Header=yes"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ eval "$as_ac_Header=no"
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+ac_res=`eval echo '${'$as_ac_Header'}'`
+ { echo "$as_me:$LINENO: result: $ac_res" >&5
+echo "${ECHO_T}$ac_res" >&6; }
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+for ac_header in sys/mount.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+{ echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; }
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <stdio.h>
+
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$ac_compile") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest.$ac_objext; then
+ eval "$as_ac_Header=yes"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ eval "$as_ac_Header=no"
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+ac_res=`eval echo '${'$as_ac_Header'}'`
+ { echo "$as_me:$LINENO: result: $ac_res" >&5
+echo "${ECHO_T}$ac_res" >&6; }
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+for ac_header in sys/vmount.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+{ echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; }
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <stdio.h>
+
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$ac_compile") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest.$ac_objext; then
+ eval "$as_ac_Header=yes"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ eval "$as_ac_Header=no"
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+ac_res=`eval echo '${'$as_ac_Header'}'`
+ { echo "$as_me:$LINENO: result: $ac_res" >&5
+echo "${ECHO_T}$ac_res" >&6; }
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+for ac_header in rpc/svc_soc.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+{ echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; }
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <rpc/rpc.h>
+
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$ac_compile") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest.$ac_objext; then
+ eval "$as_ac_Header=yes"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ eval "$as_ac_Header=no"
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+ac_res=`eval echo '${'$as_ac_Header'}'`
+ { echo "$as_me:$LINENO: result: $ac_res" >&5
+echo "${ECHO_T}$ac_res" >&6; }
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+for ac_header in linux/ext2_fs.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+{ echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; }
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <unistd.h>
+
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$ac_compile") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest.$ac_objext; then
+ eval "$as_ac_Header=yes"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ eval "$as_ac_Header=no"
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+ac_res=`eval echo '${'$as_ac_Header'}'`
+ { echo "$as_me:$LINENO: result: $ac_res" >&5
+echo "${ECHO_T}$ac_res" >&6; }
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+{ echo "$as_me:$LINENO: checking for int32" >&5
+echo $ECHO_N "checking for int32... $ECHO_C" >&6; }
+if test "${ac_cv_type_int32+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <sys/inttypes.h>
+
+typedef int32 ac__type_new_;
+int
+main ()
+{
+if ((ac__type_new_ *) 0)
+ return 0;
+if (sizeof (ac__type_new_))
+ return 0;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$ac_compile") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest.$ac_objext; then
+ ac_cv_type_int32=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_cv_type_int32=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_type_int32" >&5
+echo "${ECHO_T}$ac_cv_type_int32" >&6; }
+if test $ac_cv_type_int32 = yes; then
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_INT32 1
+_ACEOF
+
+
+fi
+
+{ echo "$as_me:$LINENO: checking for uint32" >&5
+echo $ECHO_N "checking for uint32... $ECHO_C" >&6; }
+if test "${ac_cv_type_uint32+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <sys/inttypes.h>
+
+typedef uint32 ac__type_new_;
+int
+main ()
+{
+if ((ac__type_new_ *) 0)
+ return 0;
+if (sizeof (ac__type_new_))
+ return 0;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$ac_compile") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest.$ac_objext; then
+ ac_cv_type_uint32=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_cv_type_uint32=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_type_uint32" >&5
+echo "${ECHO_T}$ac_cv_type_uint32" >&6; }
+if test $ac_cv_type_uint32 = yes; then
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_UINT32 1
+_ACEOF
+
+
+fi
+
+{ echo "$as_me:$LINENO: checking for int64" >&5
+echo $ECHO_N "checking for int64... $ECHO_C" >&6; }
+if test "${ac_cv_type_int64+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <sys/inttypes.h>
+
+typedef int64 ac__type_new_;
+int
+main ()
+{
+if ((ac__type_new_ *) 0)
+ return 0;
+if (sizeof (ac__type_new_))
+ return 0;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$ac_compile") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest.$ac_objext; then
+ ac_cv_type_int64=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_cv_type_int64=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_type_int64" >&5
+echo "${ECHO_T}$ac_cv_type_int64" >&6; }
+if test $ac_cv_type_int64 = yes; then
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_INT64 1
+_ACEOF
+
+
+fi
+
+{ echo "$as_me:$LINENO: checking for uint64" >&5
+echo $ECHO_N "checking for uint64... $ECHO_C" >&6; }
+if test "${ac_cv_type_uint64+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <sys/inttypes.h>
+
+typedef uint64 ac__type_new_;
+int
+main ()
+{
+if ((ac__type_new_ *) 0)
+ return 0;
+if (sizeof (ac__type_new_))
+ return 0;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$ac_compile") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest.$ac_objext; then
+ ac_cv_type_uint64=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_cv_type_uint64=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_type_uint64" >&5
+echo "${ECHO_T}$ac_cv_type_uint64" >&6; }
+if test $ac_cv_type_uint64 = yes; then
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_UINT64 1
+_ACEOF
+
+
+fi
+
+{ echo "$as_me:$LINENO: checking for struct stat.st_gen" >&5
+echo $ECHO_N "checking for struct stat.st_gen... $ECHO_C" >&6; }
+if test "${ac_cv_member_struct_stat_st_gen+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <sys/stat.h>
+
+int
+main ()
+{
+static struct stat ac_aggr;
+if (ac_aggr.st_gen)
+return 0;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$ac_compile") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest.$ac_objext; then
+ ac_cv_member_struct_stat_st_gen=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <sys/stat.h>
+
+int
+main ()
+{
+static struct stat ac_aggr;
+if (sizeof ac_aggr.st_gen)
+return 0;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$ac_compile") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest.$ac_objext; then
+ ac_cv_member_struct_stat_st_gen=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_cv_member_struct_stat_st_gen=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_member_struct_stat_st_gen" >&5
+echo "${ECHO_T}$ac_cv_member_struct_stat_st_gen" >&6; }
+if test $ac_cv_member_struct_stat_st_gen = yes; then
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_STRUCT_STAT_ST_GEN 1
+_ACEOF
+
+
+fi
+
+{ echo "$as_me:$LINENO: checking for struct __rpc_svcxprt.xp_fd" >&5
+echo $ECHO_N "checking for struct __rpc_svcxprt.xp_fd... $ECHO_C" >&6; }
+if test "${ac_cv_member_struct___rpc_svcxprt_xp_fd+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <rpc/rpc.h>
+
+int
+main ()
+{
+static struct __rpc_svcxprt ac_aggr;
+if (ac_aggr.xp_fd)
+return 0;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$ac_compile") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest.$ac_objext; then
+ ac_cv_member_struct___rpc_svcxprt_xp_fd=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <rpc/rpc.h>
+
+int
+main ()
+{
+static struct __rpc_svcxprt ac_aggr;
+if (sizeof ac_aggr.xp_fd)
+return 0;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$ac_compile") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest.$ac_objext; then
+ ac_cv_member_struct___rpc_svcxprt_xp_fd=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_cv_member_struct___rpc_svcxprt_xp_fd=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_member_struct___rpc_svcxprt_xp_fd" >&5
+echo "${ECHO_T}$ac_cv_member_struct___rpc_svcxprt_xp_fd" >&6; }
+if test $ac_cv_member_struct___rpc_svcxprt_xp_fd = yes; then
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_STRUCT___RPC_SVCXPRT_XP_FD 1
+_ACEOF
+
+
+fi
+
+
+
+
+
+for ac_func in xdr_long xdr_int32 xdr_u_long xdr_uint32
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+{ echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6; }
+if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $ac_func
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined __stub_$ac_func || defined __stub___$ac_func
+choke me
+#endif
+
+int
+main ()
+{
+return $ac_func ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$ac_link") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest$ac_exeext &&
+ $as_test_x conftest$ac_exeext; then
+ eval "$as_ac_var=yes"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ eval "$as_ac_var=no"
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+ac_res=`eval echo '${'$as_ac_var'}'`
+ { echo "$as_me:$LINENO: result: $ac_res" >&5
+echo "${ECHO_T}$ac_res" >&6; }
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
+
+
+
+for ac_func in xdr_uint64 xdr_uint64_t xdr_u_int64_t
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+{ echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6; }
+if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $ac_func
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined __stub_$ac_func || defined __stub___$ac_func
+choke me
+#endif
+
+int
+main ()
+{
+return $ac_func ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$ac_link") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest$ac_exeext &&
+ $as_test_x conftest$ac_exeext; then
+ eval "$as_ac_var=yes"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ eval "$as_ac_var=no"
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+ac_res=`eval echo '${'$as_ac_var'}'`
+ { echo "$as_me:$LINENO: result: $ac_res" >&5
+echo "${ECHO_T}$ac_res" >&6; }
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
+
+for ac_func in statvfs
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+{ echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6; }
+if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $ac_func
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined __stub_$ac_func || defined __stub___$ac_func
+choke me
+#endif
+
+int
+main ()
+{
+return $ac_func ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$ac_link") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest$ac_exeext &&
+ $as_test_x conftest$ac_exeext; then
+ eval "$as_ac_var=yes"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ eval "$as_ac_var=no"
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+ac_res=`eval echo '${'$as_ac_var'}'`
+ { echo "$as_me:$LINENO: result: $ac_res" >&5
+echo "${ECHO_T}$ac_res" >&6; }
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
+
+
+for ac_func in seteuid setegid
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+{ echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6; }
+if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $ac_func
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined __stub_$ac_func || defined __stub___$ac_func
+choke me
+#endif
+
+int
+main ()
+{
+return $ac_func ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$ac_link") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest$ac_exeext &&
+ $as_test_x conftest$ac_exeext; then
+ eval "$as_ac_var=yes"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ eval "$as_ac_var=no"
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+ac_res=`eval echo '${'$as_ac_var'}'`
+ { echo "$as_me:$LINENO: result: $ac_res" >&5
+echo "${ECHO_T}$ac_res" >&6; }
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
+
+
+for ac_func in setresuid setresgid
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+{ echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6; }
+if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $ac_func
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined __stub_$ac_func || defined __stub___$ac_func
+choke me
+#endif
+
+int
+main ()
+{
+return $ac_func ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$ac_link") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest$ac_exeext &&
+ $as_test_x conftest$ac_exeext; then
+ eval "$as_ac_var=yes"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ eval "$as_ac_var=no"
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+ac_res=`eval echo '${'$as_ac_var'}'`
+ { echo "$as_me:$LINENO: result: $ac_res" >&5
+echo "${ECHO_T}$ac_res" >&6; }
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
+
+for ac_func in vsyslog
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+{ echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6; }
+if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $ac_func
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined __stub_$ac_func || defined __stub___$ac_func
+choke me
+#endif
+
+int
+main ()
+{
+return $ac_func ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$ac_link") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest$ac_exeext &&
+ $as_test_x conftest$ac_exeext; then
+ eval "$as_ac_var=yes"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ eval "$as_ac_var=no"
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+ac_res=`eval echo '${'$as_ac_var'}'`
+ { echo "$as_me:$LINENO: result: $ac_res" >&5
+echo "${ECHO_T}$ac_res" >&6; }
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
+
+for ac_func in lchown
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+{ echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6; }
+if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $ac_func
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined __stub_$ac_func || defined __stub___$ac_func
+choke me
+#endif
+
+int
+main ()
+{
+return $ac_func ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$ac_link") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest$ac_exeext &&
+ $as_test_x conftest$ac_exeext; then
+ eval "$as_ac_var=yes"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ eval "$as_ac_var=no"
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+ac_res=`eval echo '${'$as_ac_var'}'`
+ { echo "$as_me:$LINENO: result: $ac_res" >&5
+echo "${ECHO_T}$ac_res" >&6; }
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
+
+for ac_func in setgroups
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+{ echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6; }
+if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $ac_func
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined __stub_$ac_func || defined __stub___$ac_func
+choke me
+#endif
+
+int
+main ()
+{
+return $ac_func ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$ac_link") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest$ac_exeext &&
+ $as_test_x conftest$ac_exeext; then
+ eval "$as_ac_var=yes"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ eval "$as_ac_var=no"
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+ac_res=`eval echo '${'$as_ac_var'}'`
+ { echo "$as_me:$LINENO: result: $ac_res" >&5
+echo "${ECHO_T}$ac_res" >&6; }
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
+
+ { echo "$as_me:$LINENO: checking for svc_tli_create" >&5
+echo $ECHO_N "checking for svc_tli_create... $ECHO_C" >&6; }
+if test "${ac_cv_func_svc_tli_create+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define svc_tli_create to an innocuous variant, in case <limits.h> declares svc_tli_create.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define svc_tli_create innocuous_svc_tli_create
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char svc_tli_create (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef svc_tli_create
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char svc_tli_create ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined __stub_svc_tli_create || defined __stub___svc_tli_create
+choke me
+#endif
+
+int
+main ()
+{
+return svc_tli_create ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$ac_link") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest$ac_exeext &&
+ $as_test_x conftest$ac_exeext; then
+ ac_cv_func_svc_tli_create=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_cv_func_svc_tli_create=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_func_svc_tli_create" >&5
+echo "${ECHO_T}$ac_cv_func_svc_tli_create" >&6; }
+if test $ac_cv_func_svc_tli_create = yes; then
+
+ # On Solaris, you must link with librpcsoc, or the binaries won't work.
+ LDFLAGS="-L/usr/ucblib -R/usr/ucblib $LDFLAGS"
+ { echo "$as_me:$LINENO: checking for svctcp_create in -lrpcsoc" >&5
+echo $ECHO_N "checking for svctcp_create in -lrpcsoc... $ECHO_C" >&6; }
+if test "${ac_cv_lib_rpcsoc_svctcp_create+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lrpcsoc $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char svctcp_create ();
+int
+main ()
+{
+return svctcp_create ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$ac_link") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest$ac_exeext &&
+ $as_test_x conftest$ac_exeext; then
+ ac_cv_lib_rpcsoc_svctcp_create=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_cv_lib_rpcsoc_svctcp_create=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_lib_rpcsoc_svctcp_create" >&5
+echo "${ECHO_T}$ac_cv_lib_rpcsoc_svctcp_create" >&6; }
+if test $ac_cv_lib_rpcsoc_svctcp_create = yes; then
+ LIBS="-lrpcsoc $LIBS"
+else
+ { echo "$as_me:$LINENO: WARNING: *** Cannot find librpcsoc. On Solaris, install package SUNWscpu. ***" >&5
+echo "$as_me: WARNING: *** Cannot find librpcsoc. On Solaris, install package SUNWscpu. ***" >&2;}
+
+fi
+
+
+fi
+
+
+
+
+cat >>confdefs.h <<\_ACEOF
+#define PORTMAP
+_ACEOF
+
+
+
+ if test "$GCC" = "yes"
+ then
+ CFLAGS="$CFLAGS -Wall -W"
+ fi
+
+# Check whether --enable-cluster was given.
+if test "${enable_cluster+set}" = set; then
+ enableval=$enable_cluster;
+cat >>confdefs.h <<\_ACEOF
+#define WANT_CLUSTER
+_ACEOF
+ SUBDIRS=Extras
+ EXTRAOBJ=Extras/lib.a
+
+fi
+
+ac_config_files="$ac_config_files Makefile Config/Makefile Extras/Makefile"
+
+cat >confcache <<\_ACEOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs, see configure's option --config-cache.
+# It is not useful on other systems. If it contains results you don't
+# want to keep, you may remove or edit it.
+#
+# config.status only pays attention to the cache file if you give it
+# the --recheck option to rerun configure.
+#
+# `ac_cv_env_foo' variables (set or unset) will be overridden when
+# loading this file, other *unset* `ac_cv_foo' will be assigned the
+# following values.
+
+_ACEOF
+
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, we kill variables containing newlines.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+(
+ for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do
+ eval ac_val=\$$ac_var
+ case $ac_val in #(
+ *${as_nl}*)
+ case $ac_var in #(
+ *_cv_*) { echo "$as_me:$LINENO: WARNING: Cache variable $ac_var contains a newline." >&5
+echo "$as_me: WARNING: Cache variable $ac_var contains a newline." >&2;} ;;
+ esac
+ case $ac_var in #(
+ _ | IFS | as_nl) ;; #(
+ *) $as_unset $ac_var ;;
+ esac ;;
+ esac
+ done
+
+ (set) 2>&1 |
+ case $as_nl`(ac_space=' '; set) 2>&1` in #(
+ *${as_nl}ac_space=\ *)
+ # `set' does not quote correctly, so add quotes (double-quote
+ # substitution turns \\\\ into \\, and sed turns \\ into \).
+ sed -n \
+ "s/'/'\\\\''/g;
+ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p"
+ ;; #(
+ *)
+ # `set' quotes correctly as required by POSIX, so do not add quotes.
+ sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+ ;;
+ esac |
+ sort
+) |
+ sed '
+ /^ac_cv_env_/b end
+ t clear
+ :clear
+ s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/
+ t end
+ s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/
+ :end' >>confcache
+if diff "$cache_file" confcache >/dev/null 2>&1; then :; else
+ if test -w "$cache_file"; then
+ test "x$cache_file" != "x/dev/null" &&
+ { echo "$as_me:$LINENO: updating cache $cache_file" >&5
+echo "$as_me: updating cache $cache_file" >&6;}
+ cat confcache >$cache_file
+ else
+ { echo "$as_me:$LINENO: not updating unwritable cache $cache_file" >&5
+echo "$as_me: not updating unwritable cache $cache_file" >&6;}
+ fi
+fi
+rm -f confcache
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+DEFS=-DHAVE_CONFIG_H
+
+ac_libobjs=
+ac_ltlibobjs=
+for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue
+ # 1. Remove the extension, and $U if already installed.
+ ac_script='s/\$U\././;s/\.o$//;s/\.obj$//'
+ ac_i=`echo "$ac_i" | sed "$ac_script"`
+ # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR
+ # will be set to the directory where LIBOBJS objects are built.
+ ac_libobjs="$ac_libobjs \${LIBOBJDIR}$ac_i\$U.$ac_objext"
+ ac_ltlibobjs="$ac_ltlibobjs \${LIBOBJDIR}$ac_i"'$U.lo'
+done
+LIBOBJS=$ac_libobjs
+
+LTLIBOBJS=$ac_ltlibobjs
+
+
+
+: ${CONFIG_STATUS=./config.status}
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files $CONFIG_STATUS"
+{ echo "$as_me:$LINENO: creating $CONFIG_STATUS" >&5
+echo "$as_me: creating $CONFIG_STATUS" >&6;}
+cat >$CONFIG_STATUS <<_ACEOF
+#! $SHELL
+# Generated by $as_me.
+# Run this file to recreate the current configuration.
+# Compiler output produced by configure, useful for debugging
+# configure, is in config.log if it exists.
+
+debug=false
+ac_cs_recheck=false
+ac_cs_silent=false
+SHELL=\${CONFIG_SHELL-$SHELL}
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+## --------------------- ##
+## M4sh Initialization. ##
+## --------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
+ emulate sh
+ NULLCMD=:
+ # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+ setopt NO_GLOB_SUBST
+else
+ case `(set -o) 2>/dev/null` in
+ *posix*) set -o posix ;;
+esac
+
+fi
+
+
+
+
+# PATH needs CR
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ echo "#! /bin/sh" >conf$$.sh
+ echo "exit 0" >>conf$$.sh
+ chmod +x conf$$.sh
+ if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then
+ PATH_SEPARATOR=';'
+ else
+ PATH_SEPARATOR=:
+ fi
+ rm -f conf$$.sh
+fi
+
+# Support unset when possible.
+if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then
+ as_unset=unset
+else
+ as_unset=false
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order. Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+as_nl='
+'
+IFS=" "" $as_nl"
+
+# Find who we are. Look in the path if we contain no directory separator.
+case $0 in
+ *[\\/]* ) as_myself=$0 ;;
+ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+done
+IFS=$as_save_IFS
+
+ ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+ as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+ echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+ { (exit 1); exit 1; }
+fi
+
+# Work around bugs in pre-3.0 UWIN ksh.
+for as_var in ENV MAIL MAILPATH
+do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+for as_var in \
+ LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \
+ LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \
+ LC_TELEPHONE LC_TIME
+do
+ if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then
+ eval $as_var=C; export $as_var
+ else
+ ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var
+ fi
+done
+
+# Required to use basename.
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+ test "X`expr 00001 : '.*\(...\)'`" = X001; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+ as_basename=basename
+else
+ as_basename=false
+fi
+
+
+# Name of the executable.
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+
+# CDPATH.
+$as_unset CDPATH
+
+
+
+ as_lineno_1=$LINENO
+ as_lineno_2=$LINENO
+ test "x$as_lineno_1" != "x$as_lineno_2" &&
+ test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2" || {
+
+ # Create $as_me.lineno as a copy of $as_myself, but with $LINENO
+ # uniformly replaced by the line number. The first 'sed' inserts a
+ # line-number line after each line using $LINENO; the second 'sed'
+ # does the real work. The second script uses 'N' to pair each
+ # line-number line with the line containing $LINENO, and appends
+ # trailing '-' during substitution so that $LINENO is not a special
+ # case at line end.
+ # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the
+ # scripts with optimization help from Paolo Bonzini. Blame Lee
+ # E. McMahon (1931-1989) for sed's syntax. :-)
+ sed -n '
+ p
+ /[$]LINENO/=
+ ' <$as_myself |
+ sed '
+ s/[$]LINENO.*/&-/
+ t lineno
+ b
+ :lineno
+ N
+ :loop
+ s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/
+ t loop
+ s/-\n.*//
+ ' >$as_me.lineno &&
+ chmod +x "$as_me.lineno" ||
+ { echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2
+ { (exit 1); exit 1; }; }
+
+ # Don't try to exec as it changes $[0], causing all sort of problems
+ # (the dirname of $[0] is not the place where we might find the
+ # original and so on. Autoconf is especially sensitive to this).
+ . "./$as_me.lineno"
+ # Exit status is that of the last command.
+ exit
+}
+
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+ as_dirname=dirname
+else
+ as_dirname=false
+fi
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in
+-n*)
+ case `echo 'x\c'` in
+ *c*) ECHO_T=' ';; # ECHO_T is single tab character.
+ *) ECHO_C='\c';;
+ esac;;
+*)
+ ECHO_N='-n';;
+esac
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+ test "X`expr 00001 : '.*\(...\)'`" = X001; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+ rm -f conf$$.dir/conf$$.file
+else
+ rm -f conf$$.dir
+ mkdir conf$$.dir
+fi
+echo >conf$$.file
+if ln -s conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s='ln -s'
+ # ... but there are two gotchas:
+ # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+ # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+ # In both cases, we have to default to `cp -p'.
+ ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+ as_ln_s='cp -p'
+elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+else
+ as_ln_s='cp -p'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+if mkdir -p . 2>/dev/null; then
+ as_mkdir_p=:
+else
+ test -d ./-p && rmdir ./-p
+ as_mkdir_p=false
+fi
+
+if test -x / >/dev/null 2>&1; then
+ as_test_x='test -x'
+else
+ if ls -dL / >/dev/null 2>&1; then
+ as_ls_L_option=L
+ else
+ as_ls_L_option=
+ fi
+ as_test_x='
+ eval sh -c '\''
+ if test -d "$1"; then
+ test -d "$1/.";
+ else
+ case $1 in
+ -*)set "./$1";;
+ esac;
+ case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in
+ ???[sx]*):;;*)false;;esac;fi
+ '\'' sh
+ '
+fi
+as_executable_p=$as_test_x
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+exec 6>&1
+
+# Save the log message, to keep $[0] and so on meaningful, and to
+# report actual input values of CONFIG_FILES etc. instead of their
+# values after options handling.
+ac_log="
+This file was extended by unfs3 $as_me 0.9.22, which was
+generated by GNU Autoconf 2.61. Invocation command line was
+
+ CONFIG_FILES = $CONFIG_FILES
+ CONFIG_HEADERS = $CONFIG_HEADERS
+ CONFIG_LINKS = $CONFIG_LINKS
+ CONFIG_COMMANDS = $CONFIG_COMMANDS
+ $ $0 $@
+
+on `(hostname || uname -n) 2>/dev/null | sed 1q`
+"
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<_ACEOF
+# Files that config.status was made for.
+config_files="$ac_config_files"
+config_headers="$ac_config_headers"
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+ac_cs_usage="\
+\`$as_me' instantiates files from templates according to the
+current configuration.
+
+Usage: $0 [OPTIONS] [FILE]...
+
+ -h, --help print this help, then exit
+ -V, --version print version number and configuration settings, then exit
+ -q, --quiet do not print progress messages
+ -d, --debug don't remove temporary files
+ --recheck update $as_me by reconfiguring in the same conditions
+ --file=FILE[:TEMPLATE]
+ instantiate the configuration file FILE
+ --header=FILE[:TEMPLATE]
+ instantiate the configuration header FILE
+
+Configuration files:
+$config_files
+
+Configuration headers:
+$config_headers
+
+Report bugs to <bug-au...@gnu.org>."
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF
+ac_cs_version="\\
+unfs3 config.status 0.9.22
+configured by $0, generated by GNU Autoconf 2.61,
+ with options \\"`echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\"
+
+Copyright (C) 2006 Free Software Foundation, Inc.
+This config.status script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it."
+
+ac_pwd='$ac_pwd'
+srcdir='$srcdir'
+INSTALL='$INSTALL'
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+# If no file are specified by the user, then we need to provide default
+# value. By we need to know if files were specified by the user.
+ac_need_defaults=:
+while test $# != 0
+do
+ case $1 in
+ --*=*)
+ ac_option=`expr "X$1" : 'X\([^=]*\)='`
+ ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'`
+ ac_shift=:
+ ;;
+ *)
+ ac_option=$1
+ ac_optarg=$2
+ ac_shift=shift
+ ;;
+ esac
+
+ case $ac_option in
+ # Handling of the options.
+ -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+ ac_cs_recheck=: ;;
+ --version | --versio | --versi | --vers | --ver | --ve | --v | -V )
+ echo "$ac_cs_version"; exit ;;
+ --debug | --debu | --deb | --de | --d | -d )
+ debug=: ;;
+ --file | --fil | --fi | --f )
+ $ac_shift
+ CONFIG_FILES="$CONFIG_FILES $ac_optarg"
+ ac_need_defaults=false;;
+ --header | --heade | --head | --hea )
+ $ac_shift
+ CONFIG_HEADERS="$CONFIG_HEADERS $ac_optarg"
+ ac_need_defaults=false;;
+ --he | --h)
+ # Conflict between --help and --header
+ { echo "$as_me: error: ambiguous option: $1
+Try \`$0 --help' for more information." >&2
+ { (exit 1); exit 1; }; };;
+ --help | --hel | -h )
+ echo "$ac_cs_usage"; exit ;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil | --si | --s)
+ ac_cs_silent=: ;;
+
+ # This is an error.
+ -*) { echo "$as_me: error: unrecognized option: $1
+Try \`$0 --help' for more information." >&2
+ { (exit 1); exit 1; }; } ;;
+
+ *) ac_config_targets="$ac_config_targets $1"
+ ac_need_defaults=false ;;
+
+ esac
+ shift
+done
+
+ac_configure_extra_args=
+
+if $ac_cs_silent; then
+ exec 6>/dev/null
+ ac_configure_extra_args="$ac_configure_extra_args --silent"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF
+if \$ac_cs_recheck; then
+ echo "running CONFIG_SHELL=$SHELL $SHELL $0 "$ac_configure_args \$ac_configure_extra_args " --no-create --no-recursion" >&6
+ CONFIG_SHELL=$SHELL
+ export CONFIG_SHELL
+ exec $SHELL "$0"$ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF
+exec 5>>config.log
+{
+ echo
+ sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
+## Running $as_me. ##
+_ASBOX
+ echo "$ac_log"
+} >&5
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+
+# Handling of arguments.
+for ac_config_target in $ac_config_targets
+do
+ case $ac_config_target in
+ "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;;
+ "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;;
+ "Config/Makefile") CONFIG_FILES="$CONFIG_FILES Config/Makefile" ;;
+ "Extras/Makefile") CONFIG_FILES="$CONFIG_FILES Extras/Makefile" ;;
+
+ *) { { echo "$as_me:$LINENO: error: invalid argument: $ac_config_target" >&5
+echo "$as_me: error: invalid argument: $ac_config_target" >&2;}
+ { (exit 1); exit 1; }; };;
+ esac
+done
+
+
+# If the user did not use the arguments to specify the items to instantiate,
+# then the envvar interface is used. Set only those that are not.
+# We use the long form for the default assignment because of an extremely
+# bizarre bug on SunOS 4.1.3.
+if $ac_need_defaults; then
+ test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files
+ test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers
+fi
+
+# Have a temporary directory for convenience. Make it in the build tree
+# simply because there is no reason against having it here, and in addition,
+# creating and moving files from /tmp can sometimes cause problems.
+# Hook for its removal unless debugging.
+# Note that there is a small window in which the directory will not be cleaned:
+# after its creation but before its name has been assigned to `$tmp'.
+$debug ||
+{
+ tmp=
+ trap 'exit_status=$?
+ { test -z "$tmp" || test ! -d "$tmp" || rm -fr "$tmp"; } && exit $exit_status
+' 0
+ trap '{ (exit 1); exit 1; }' 1 2 13 15
+}
+# Create a (secure) tmp directory for tmp files.
+
+{
+ tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` &&
+ test -n "$tmp" && test -d "$tmp"
+} ||
+{
+ tmp=./conf$$-$RANDOM
+ (umask 077 && mkdir "$tmp")
+} ||
+{
+ echo "$me: cannot create a temporary directory in ." >&2
+ { (exit 1); exit 1; }
+}
+
+#
+# Set up the sed scripts for CONFIG_FILES section.
+#
+
+# No need to generate the scripts if there are no CONFIG_FILES.
+# This happens for instance when ./config.status config.h
+if test -n "$CONFIG_FILES"; then
+
+_ACEOF
+
+
+
+ac_delim='%!_!# '
+for ac_last_try in false false false false false :; do
+ cat >conf$$subs.sed <<_ACEOF
+SHELL!$SHELL$ac_delim
+PATH_SEPARATOR!$PATH_SEPARATOR$ac_delim
+PACKAGE_NAME!$PACKAGE_NAME$ac_delim
+PACKAGE_TARNAME!$PACKAGE_TARNAME$ac_delim
+PACKAGE_VERSION!$PACKAGE_VERSION$ac_delim
+PACKAGE_STRING!$PACKAGE_STRING$ac_delim
+PACKAGE_BUGREPORT!$PACKAGE_BUGREPORT$ac_delim
+exec_prefix!$exec_prefix$ac_delim
+prefix!$prefix$ac_delim
+program_transform_name!$program_transform_name$ac_delim
+bindir!$bindir$ac_delim
+sbindir!$sbindir$ac_delim
+libexecdir!$libexecdir$ac_delim
+datarootdir!$datarootdir$ac_delim
+datadir!$datadir$ac_delim
+sysconfdir!$sysconfdir$ac_delim
+sharedstatedir!$sharedstatedir$ac_delim
+localstatedir!$localstatedir$ac_delim
+includedir!$includedir$ac_delim
+oldincludedir!$oldincludedir$ac_delim
+docdir!$docdir$ac_delim
+infodir!$infodir$ac_delim
+htmldir!$htmldir$ac_delim
+dvidir!$dvidir$ac_delim
+pdfdir!$pdfdir$ac_delim
+psdir!$psdir$ac_delim
+libdir!$libdir$ac_delim
+localedir!$localedir$ac_delim
+mandir!$mandir$ac_delim
+DEFS!$DEFS$ac_delim
+ECHO_C!$ECHO_C$ac_delim
+ECHO_N!$ECHO_N$ac_delim
+ECHO_T!$ECHO_T$ac_delim
+LIBS!$LIBS$ac_delim
+build_alias!$build_alias$ac_delim
+host_alias!$host_alias$ac_delim
+target_alias!$target_alias$ac_delim
+INSTALL_PROGRAM!$INSTALL_PROGRAM$ac_delim
+INSTALL_SCRIPT!$INSTALL_SCRIPT$ac_delim
+INSTALL_DATA!$INSTALL_DATA$ac_delim
+CC!$CC$ac_delim
+CFLAGS!$CFLAGS$ac_delim
+LDFLAGS!$LDFLAGS$ac_delim
+CPPFLAGS!$CPPFLAGS$ac_delim
+ac_ct_CC!$ac_ct_CC$ac_delim
+EXEEXT!$EXEEXT$ac_delim
+OBJEXT!$OBJEXT$ac_delim
+LEX!$LEX$ac_delim
+LEX_OUTPUT_ROOT!$LEX_OUTPUT_ROOT$ac_delim
+LEXLIB!$LEXLIB$ac_delim
+YACC!$YACC$ac_delim
+YFLAGS!$YFLAGS$ac_delim
+CPP!$CPP$ac_delim
+GREP!$GREP$ac_delim
+EGREP!$EGREP$ac_delim
+SUBDIRS!$SUBDIRS$ac_delim
+EXTRAOBJ!$EXTRAOBJ$ac_delim
+LIBOBJS!$LIBOBJS$ac_delim
+LTLIBOBJS!$LTLIBOBJS$ac_delim
+_ACEOF
+
+ if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 59; then
+ break
+ elif $ac_last_try; then
+ { { echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5
+echo "$as_me: error: could not make $CONFIG_STATUS" >&2;}
+ { (exit 1); exit 1; }; }
+ else
+ ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+ fi
+done
+
+ac_eof=`sed -n '/^CEOF[0-9]*$/s/CEOF/0/p' conf$$subs.sed`
+if test -n "$ac_eof"; then
+ ac_eof=`echo "$ac_eof" | sort -nru | sed 1q`
+ ac_eof=`expr $ac_eof + 1`
+fi
+
+cat >>$CONFIG_STATUS <<_ACEOF
+cat >"\$tmp/subs-1.sed" <<\CEOF$ac_eof
+/@[a-zA-Z_][a-zA-Z_0-9]*@/!b end
+_ACEOF
+sed '
+s/[,\\&]/\\&/g; s/@/@|#_!!_#|/g
+s/^/s,@/; s/!/@,|#_!!_#|/
+:n
+t n
+s/'"$ac_delim"'$/,g/; t
+s/$/\\/; p
+N; s/^.*\n//; s/[,\\&]/\\&/g; s/@/@|#_!!_#|/g; b n
+' >>$CONFIG_STATUS <conf$$subs.sed
+rm -f conf$$subs.sed
+cat >>$CONFIG_STATUS <<_ACEOF
+:end
+s/|#_!!_#|//g
+CEOF$ac_eof
+_ACEOF
+
+
+# VPATH may cause trouble with some makes, so we remove $(srcdir),
+# ${srcdir} and @srcdir@ from VPATH if srcdir is ".", strip leading and
+# trailing colons and then remove the whole line if VPATH becomes empty
+# (actually we leave an empty line to preserve line numbers).
+if test "x$srcdir" = x.; then
+ ac_vpsub='/^[ ]*VPATH[ ]*=/{
+s/:*\$(srcdir):*/:/
+s/:*\${srcdir}:*/:/
+s/:*@srcdir@:*/:/
+s/^\([^=]*=[ ]*\):*/\1/
+s/:*$//
+s/^[^=]*=[ ]*$//
+}'
+fi
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+fi # test -n "$CONFIG_FILES"
+
+
+for ac_tag in :F $CONFIG_FILES :H $CONFIG_HEADERS
+do
+ case $ac_tag in
+ :[FHLC]) ac_mode=$ac_tag; continue;;
+ esac
+ case $ac_mode$ac_tag in
+ :[FHL]*:*);;
+ :L* | :C*:*) { { echo "$as_me:$LINENO: error: Invalid tag $ac_tag." >&5
+echo "$as_me: error: Invalid tag $ac_tag." >&2;}
+ { (exit 1); exit 1; }; };;
+ :[FH]-) ac_tag=-:-;;
+ :[FH]*) ac_tag=$ac_tag:$ac_tag.in;;
+ esac
+ ac_save_IFS=$IFS
+ IFS=:
+ set x $ac_tag
+ IFS=$ac_save_IFS
+ shift
+ ac_file=$1
+ shift
+
+ case $ac_mode in
+ :L) ac_source=$1;;
+ :[FH])
+ ac_file_inputs=
+ for ac_f
+ do
+ case $ac_f in
+ -) ac_f="$tmp/stdin";;
+ *) # Look for the file first in the build tree, then in the source tree
+ # (if the path is not absolute). The absolute path cannot be DOS-style,
+ # because $ac_f cannot contain `:'.
+ test -f "$ac_f" ||
+ case $ac_f in
+ [\\/$]*) false;;
+ *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";;
+ esac ||
+ { { echo "$as_me:$LINENO: error: cannot find input file: $ac_f" >&5
+echo "$as_me: error: cannot find input file: $ac_f" >&2;}
+ { (exit 1); exit 1; }; };;
+ esac
+ ac_file_inputs="$ac_file_inputs $ac_f"
+ done
+
+ # Let's still pretend it is `configure' which instantiates (i.e., don't
+ # use $as_me), people would be surprised to read:
+ # /* config.h. Generated by config.status. */
+ configure_input="Generated from "`IFS=:
+ echo $* | sed 's|^[^:]*/||;s|:[^:]*/|, |g'`" by configure."
+ if test x"$ac_file" != x-; then
+ configure_input="$ac_file. $configure_input"
+ { echo "$as_me:$LINENO: creating $ac_file" >&5
+echo "$as_me: creating $ac_file" >&6;}
+ fi
+
+ case $ac_tag in
+ *:-:* | *:-) cat >"$tmp/stdin";;
+ esac
+ ;;
+ esac
+
+ ac_dir=`$as_dirname -- "$ac_file" ||
+$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$ac_file" : 'X\(//\)[^/]' \| \
+ X"$ac_file" : 'X\(//\)$' \| \
+ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null ||
+echo X"$ac_file" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ { as_dir="$ac_dir"
+ case $as_dir in #(
+ -*) as_dir=./$as_dir;;
+ esac
+ test -d "$as_dir" || { $as_mkdir_p && mkdir -p "$as_dir"; } || {
+ as_dirs=
+ while :; do
+ case $as_dir in #(
+ *\'*) as_qdir=`echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #(
+ *) as_qdir=$as_dir;;
+ esac
+ as_dirs="'$as_qdir' $as_dirs"
+ as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_dir" : 'X\(//\)[^/]' \| \
+ X"$as_dir" : 'X\(//\)$' \| \
+ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+echo X"$as_dir" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ test -d "$as_dir" && break
+ done
+ test -z "$as_dirs" || eval "mkdir $as_dirs"
+ } || test -d "$as_dir" || { { echo "$as_me:$LINENO: error: cannot create directory $as_dir" >&5
+echo "$as_me: error: cannot create directory $as_dir" >&2;}
+ { (exit 1); exit 1; }; }; }
+ ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+ ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'`
+ # A ".." for each directory in $ac_dir_suffix.
+ ac_top_builddir_sub=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,/..,g;s,/,,'`
+ case $ac_top_builddir_sub in
+ "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+ *) ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+ esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+ .) # We are building in place.
+ ac_srcdir=.
+ ac_top_srcdir=$ac_top_builddir_sub
+ ac_abs_top_srcdir=$ac_pwd ;;
+ [\\/]* | ?:[\\/]* ) # Absolute name.
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir
+ ac_abs_top_srcdir=$srcdir ;;
+ *) # Relative name.
+ ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_build_prefix$srcdir
+ ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+
+ case $ac_mode in
+ :F)
+ #
+ # CONFIG_FILE
+ #
+
+ case $INSTALL in
+ [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;;
+ *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;;
+ esac
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+# If the template does not know about datarootdir, expand it.
+# FIXME: This hack should be removed a few years after 2.60.
+ac_datarootdir_hack=; ac_datarootdir_seen=
+
+case `sed -n '/datarootdir/ {
+ p
+ q
+}
+/@datadir@/p
+/@docdir@/p
+/@infodir@/p
+/@localedir@/p
+/@mandir@/p
+' $ac_file_inputs` in
+*datarootdir*) ac_datarootdir_seen=yes;;
+*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*)
+ { echo "$as_me:$LINENO: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5
+echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;}
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF
+ ac_datarootdir_hack='
+ s&@datadir@&$datadir&g
+ s&@docdir@&$docdir&g
+ s&@infodir@&$infodir&g
+ s&@localedir@&$localedir&g
+ s&@mandir@&$mandir&g
+ s&\\\${datarootdir}&$datarootdir&g' ;;
+esac
+_ACEOF
+
+# Neutralize VPATH when `$srcdir' = `.'.
+# Shell code in configure.ac might set extrasub.
+# FIXME: do we really want to maintain this feature?
+cat >>$CONFIG_STATUS <<_ACEOF
+ sed "$ac_vpsub
+$extrasub
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF
+:t
+/@[a-zA-Z_][a-zA-Z_0-9]*@/!b
+s&@configure_input@&$configure_input&;t t
+s&@top_builddir@&$ac_top_builddir_sub&;t t
+s&@srcdir@&$ac_srcdir&;t t
+s&@abs_srcdir@&$ac_abs_srcdir&;t t
+s&@top_srcdir@&$ac_top_srcdir&;t t
+s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t
+s&@builddir@&$ac_builddir&;t t
+s&@abs_builddir@&$ac_abs_builddir&;t t
+s&@abs_top_builddir@&$ac_abs_top_builddir&;t t
+s&@INSTALL@&$ac_INSTALL&;t t
+$ac_datarootdir_hack
+" $ac_file_inputs | sed -f "$tmp/subs-1.sed" >$tmp/out
+
+test -z "$ac_datarootdir_hack$ac_datarootdir_seen" &&
+ { ac_out=`sed -n '/\${datarootdir}/p' "$tmp/out"`; test -n "$ac_out"; } &&
+ { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' "$tmp/out"`; test -z "$ac_out"; } &&
+ { echo "$as_me:$LINENO: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined. Please make sure it is defined." >&5
+echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined. Please make sure it is defined." >&2;}
+
+ rm -f "$tmp/stdin"
+ case $ac_file in
+ -) cat "$tmp/out"; rm -f "$tmp/out";;
+ *) rm -f "$ac_file"; mv "$tmp/out" $ac_file;;
+ esac
+ ;;
+ :H)
+ #
+ # CONFIG_HEADER
+ #
+_ACEOF
+
+# Transform confdefs.h into a sed script `conftest.defines', that
+# substitutes the proper values into config.h.in to produce config.h.
+rm -f conftest.defines conftest.tail
+# First, append a space to every undef/define line, to ease matching.
+echo 's/$/ /' >conftest.defines
+# Then, protect against being on the right side of a sed subst, or in
+# an unquoted here document, in config.status. If some macros were
+# called several times there might be several #defines for the same
+# symbol, which is useless. But do not sort them, since the last
+# AC_DEFINE must be honored.
+ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]*
+# These sed commands are passed to sed as "A NAME B PARAMS C VALUE D", where
+# NAME is the cpp macro being defined, VALUE is the value it is being given.
+# PARAMS is the parameter list in the macro definition--in most cases, it's
+# just an empty string.
+ac_dA='s,^\\([ #]*\\)[^ ]*\\([ ]*'
+ac_dB='\\)[ (].*,\\1define\\2'
+ac_dC=' '
+ac_dD=' ,'
+
+uniq confdefs.h |
+ sed -n '
+ t rset
+ :rset
+ s/^[ ]*#[ ]*define[ ][ ]*//
+ t ok
+ d
+ :ok
+ s/[\\&,]/\\&/g
+ s/^\('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/ '"$ac_dA"'\1'"$ac_dB"'\2'"${ac_dC}"'\3'"$ac_dD"'/p
+ s/^\('"$ac_word_re"'\)[ ]*\(.*\)/'"$ac_dA"'\1'"$ac_dB$ac_dC"'\2'"$ac_dD"'/p
+ ' >>conftest.defines
+
+# Remove the space that was appended to ease matching.
+# Then replace #undef with comments. This is necessary, for
+# example, in the case of _POSIX_SOURCE, which is predefined and required
+# on some systems where configure will not decide to define it.
+# (The regexp can be short, since the line contains either #define or #undef.)
+echo 's/ $//
+s,^[ #]*u.*,/* & */,' >>conftest.defines
+
+# Break up conftest.defines:
+ac_max_sed_lines=50
+
+# First sed command is: sed -f defines.sed $ac_file_inputs >"$tmp/out1"
+# Second one is: sed -f defines.sed "$tmp/out1" >"$tmp/out2"
+# Third one will be: sed -f defines.sed "$tmp/out2" >"$tmp/out1"
+# et cetera.
+ac_in='$ac_file_inputs'
+ac_out='"$tmp/out1"'
+ac_nxt='"$tmp/out2"'
+
+while :
+do
+ # Write a here document:
+ cat >>$CONFIG_STATUS <<_ACEOF
+ # First, check the format of the line:
+ cat >"\$tmp/defines.sed" <<\\CEOF
+/^[ ]*#[ ]*undef[ ][ ]*$ac_word_re[ ]*\$/b def
+/^[ ]*#[ ]*define[ ][ ]*$ac_word_re[( ]/b def
+b
+:def
+_ACEOF
+ sed ${ac_max_sed_lines}q conftest.defines >>$CONFIG_STATUS
+ echo 'CEOF
+ sed -f "$tmp/defines.sed"' "$ac_in >$ac_out" >>$CONFIG_STATUS
+ ac_in=$ac_out; ac_out=$ac_nxt; ac_nxt=$ac_in
+ sed 1,${ac_max_sed_lines}d conftest.defines >conftest.tail
+ grep . conftest.tail >/dev/null || break
+ rm -f conftest.defines
+ mv conftest.tail conftest.defines
+done
+rm -f conftest.defines conftest.tail
+
+echo "ac_result=$ac_in" >>$CONFIG_STATUS
+cat >>$CONFIG_STATUS <<\_ACEOF
+ if test x"$ac_file" != x-; then
+ echo "/* $configure_input */" >"$tmp/config.h"
+ cat "$ac_result" >>"$tmp/config.h"
+ if diff $ac_file "$tmp/config.h" >/dev/null 2>&1; then
+ { echo "$as_me:$LINENO: $ac_file is unchanged" >&5
+echo "$as_me: $ac_file is unchanged" >&6;}
+ else
+ rm -f $ac_file
+ mv "$tmp/config.h" $ac_file
+ fi
+ else
+ echo "/* $configure_input */"
+ cat "$ac_result"
+ fi
+ rm -f "$tmp/out12"
+ ;;
+
+
+ esac
+
+done # for ac_tag
+
+
+{ (exit 0); exit 0; }
+_ACEOF
+chmod +x $CONFIG_STATUS
+ac_clean_files=$ac_clean_files_save
+
+
+# configure is writing to config.log, and then calls config.status.
+# config.status does its own redirection, appending to config.log.
+# Unfortunately, on DOS this fails, as config.log is still kept open
+# by configure, so config.status won't be able to write to it; its
+# output is simply discarded. So we exec the FD to /dev/null,
+# effectively closing config.log, so it can be properly (re)opened and
+# appended to by config.status. When coming back to configure, we
+# need to make the FD available again.
+if test "$no_create" != yes; then
+ ac_cs_success=:
+ ac_config_status_args=
+ test "$silent" = yes &&
+ ac_config_status_args="$ac_config_status_args --quiet"
+ exec 5>/dev/null
+ $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false
+ exec 5>>config.log
+ # Use ||, not &&, to avoid exiting from the if with $? = 1, which
+ # would make configure fail if this is the last instruction.
+ $ac_cs_success || { (exit 1); exit 1; }
+fi
+
diff --git a/external/fs/unfs3-0.9.22/configure.ac b/external/fs/unfs3-0.9.22/configure.ac
new file mode 100644
index 0000000..023b296
--- /dev/null
+++ b/external/fs/unfs3-0.9.22/configure.ac
@@ -0,0 +1,37 @@
+AC_INIT(unfs3, 0.9.22)
+AC_CONFIG_HEADER(config.h)
+AC_PROG_INSTALL
+AC_PROG_CC([gcc egcs kgcc cc])
+AC_PROG_LEX
+AC_PROG_YACC
+AC_HEADER_STDC
+AC_SYS_LARGEFILE
+AC_SEARCH_LIBS(xdr_int, nsl)
+AC_SEARCH_LIBS(socket, socket)
+AC_SEARCH_LIBS(inet_aton, resolv)
+AC_CHECK_HEADERS(mntent.h,,,[#include <stdio.h>])
+AC_CHECK_HEADERS(stdint.h,,,[#include <stdio.h>])
+AC_CHECK_HEADERS(sys/mnttab.h,,,[#include <stdio.h>])
+AC_CHECK_HEADERS(sys/mount.h,,,[#include <stdio.h>])
+AC_CHECK_HEADERS(sys/vmount.h,,,[#include <stdio.h>])
+AC_CHECK_HEADERS(rpc/svc_soc.h,,,[#include <rpc/rpc.h>])
+AC_CHECK_HEADERS(linux/ext2_fs.h,,,[#include <unistd.h>])
+AC_CHECK_TYPES(int32,,,[#include <sys/inttypes.h>])
+AC_CHECK_TYPES(uint32,,,[#include <sys/inttypes.h>])
+AC_CHECK_TYPES(int64,,,[#include <sys/inttypes.h>])
+AC_CHECK_TYPES(uint64,,,[#include <sys/inttypes.h>])
+AC_CHECK_MEMBERS([struct stat.st_gen],,,[#include <sys/stat.h>])
+AC_CHECK_MEMBERS([struct __rpc_svcxprt.xp_fd],,,[#include <rpc/rpc.h>])
+AC_CHECK_FUNCS(xdr_long xdr_int32 xdr_u_long xdr_uint32)
+AC_CHECK_FUNCS(xdr_uint64 xdr_uint64_t xdr_u_int64_t)
+AC_CHECK_FUNCS(statvfs)
+AC_CHECK_FUNCS(seteuid setegid)
+AC_CHECK_FUNCS(setresuid setresgid)
+AC_CHECK_FUNCS(vsyslog)
+AC_CHECK_FUNCS(lchown)
+AC_CHECK_FUNCS(setgroups)
+UNFS3_SOLARIS_RPC
+UNFS3_PORTMAP_DEFINE
+UNFS3_COMPILE_WARNINGS
+AC_ARG_ENABLE(cluster,[ --enable-cluster include clustering extensions],[AC_DEFINE([WANT_CLUSTER], [], [Cluster extensions]) AC_SUBST([SUBDIRS],[Extras]) AC_SUBST([EXTRAOBJ],[Extras/lib.a])])
+AC_OUTPUT(Makefile Config/Makefile Extras/Makefile)
diff --git a/external/fs/unfs3-0.9.22/contrib/nfsotpclient/README b/external/fs/unfs3-0.9.22/contrib/nfsotpclient/README
new file mode 100644
index 0000000..5ad1f0e
--- /dev/null
+++ b/external/fs/unfs3-0.9.22/contrib/nfsotpclient/README
@@ -0,0 +1,3 @@
+
+This is a NFS one time password client. Read doc/passwords.txt for
+more information.
diff --git a/external/fs/unfs3-0.9.22/contrib/nfsotpclient/mountclient/__init__.py b/external/fs/unfs3-0.9.22/contrib/nfsotpclient/mountclient/__init__.py
new file mode 100644
index 0000000..88c0f92
--- /dev/null
+++ b/external/fs/unfs3-0.9.22/contrib/nfsotpclient/mountclient/__init__.py
@@ -0,0 +1,6 @@
+
+import mountconstants
+import mounttypes
+import mountpacker
+
+__all__ = ['mountconstants', 'mounttypes', 'mountpacker']
diff --git a/external/fs/unfs3-0.9.22/contrib/nfsotpclient/mountclient/mountconstants.py b/external/fs/unfs3-0.9.22/contrib/nfsotpclient/mountclient/mountconstants.py
new file mode 100644
index 0000000..e5b0628
--- /dev/null
+++ b/external/fs/unfs3-0.9.22/contrib/nfsotpclient/mountclient/mountconstants.py
@@ -0,0 +1,48 @@
+# Generated by rpcgen.py at Mon Mar 8 11:09:57 2004
+
+__all__ = ['MNTPATHLEN', 'MNTNAMLEN', 'FHSIZE2', 'FHSIZE3', 'MNT3_OK', 'MNT3ERR_PERM', 'MNT3ERR_NOENT', 'MNT3ERR_IO', 'MNT3ERR_ACCES', 'MNT3ERR_NOTDIR', 'MNT3ERR_INVAL', 'MNT3ERR_NAMETOOLONG', 'MNT3ERR_NOTSUPP', 'MNT3ERR_SERVERFAULT', 'mountstat3_id', 'MOUNTPROC_NULL', 'MOUNTPROC_MNT', 'MOUNTPROC_DUMP', 'MOUNTPROC_UMNT', 'MOUNTPROC_UMNTALL', 'MOUNTPROC_EXPORT', 'MOUNTPROC_EXPORTALL', 'MOUNT_V1', 'MOUNTPROC3_NULL', 'MOUNTPROC3_MNT', 'MOUNTPROC3_DUMP', 'MOUNTPROC3_UMNT', 'MOUNTPROC3_UMNTALL', 'MOUNTPROC3_EXPORT', 'MOUNT_V3', 'MOUNT_PROGRAM']
+
+FALSE = 0
+TRUE = 1
+MNTPATHLEN = 1024
+MNTNAMLEN = 255
+FHSIZE2 = 32
+FHSIZE3 = 64
+MNT3_OK = 0
+MNT3ERR_PERM = 1
+MNT3ERR_NOENT = 2
+MNT3ERR_IO = 5
+MNT3ERR_ACCES = 13
+MNT3ERR_NOTDIR = 20
+MNT3ERR_INVAL = 22
+MNT3ERR_NAMETOOLONG = 63
+MNT3ERR_NOTSUPP = 10004
+MNT3ERR_SERVERFAULT = 10006
+mountstat3_id = {
+ MNT3_OK: "MNT3_OK",
+ MNT3ERR_PERM: "MNT3ERR_PERM",
+ MNT3ERR_NOENT: "MNT3ERR_NOENT",
+ MNT3ERR_IO: "MNT3ERR_IO",
+ MNT3ERR_ACCES: "MNT3ERR_ACCES",
+ MNT3ERR_NOTDIR: "MNT3ERR_NOTDIR",
+ MNT3ERR_INVAL: "MNT3ERR_INVAL",
+ MNT3ERR_NAMETOOLONG: "MNT3ERR_NAMETOOLONG",
+ MNT3ERR_NOTSUPP: "MNT3ERR_NOTSUPP",
+ MNT3ERR_SERVERFAULT: "MNT3ERR_SERVERFAULT"
+ }
+MOUNTPROC_NULL = 0
+MOUNTPROC_MNT = 1
+MOUNTPROC_DUMP = 2
+MOUNTPROC_UMNT = 3
+MOUNTPROC_UMNTALL = 4
+MOUNTPROC_EXPORT = 5
+MOUNTPROC_EXPORTALL = 6
+MOUNT_V1 = 1
+MOUNTPROC3_NULL = 0
+MOUNTPROC3_MNT = 1
+MOUNTPROC3_DUMP = 2
+MOUNTPROC3_UMNT = 3
+MOUNTPROC3_UMNTALL = 4
+MOUNTPROC3_EXPORT = 5
+MOUNT_V3 = 3
+MOUNT_PROGRAM = 100005
diff --git a/external/fs/unfs3-0.9.22/contrib/nfsotpclient/mountclient/mountpacker.py b/external/fs/unfs3-0.9.22/contrib/nfsotpclient/mountclient/mountpacker.py
new file mode 100644
index 0000000..b6e1e1f
--- /dev/null
+++ b/external/fs/unfs3-0.9.22/contrib/nfsotpclient/mountclient/mountpacker.py
@@ -0,0 +1,113 @@
+# Generated by rpcgen.py at Mon Mar 8 11:09:57 2004
+
+import rpc
+import mounttypes
+import mountconstants
+import xdrlib
+
+__all__ = ['MOUNTPacker', 'MOUNTUnpacker']
+
+class MOUNTPacker(rpc.Packer):
+ def __init__(self, ncl):
+ xdrlib.Packer.__init__(self)
+ self.ncl = ncl
+
+ pack_hyper = rpc.Packer.pack_hyper
+
+ pack_string = rpc.Packer.pack_string
+
+ pack_enum = rpc.Packer.pack_enum
+
+ pack_opaque = rpc.Packer.pack_opaque
+
+ pack_int = rpc.Packer.pack_int
+
+ pack_double = rpc.Packer.pack_double
+
+ pack_float = rpc.Packer.pack_float
+
+ pack_unsigned = rpc.Packer.pack_uint
+
+ pack_quadruple = rpc.Packer.pack_double
+
+ pack_bool = rpc.Packer.pack_bool
+
+ pack_unsigned_int = rpc.Packer.pack_uint
+
+ pack_unsigned_hyper = rpc.Packer.pack_uhyper
+
+ def pack_fhandle2(self, data):
+ self.pack_fopaque(mountconstants.FHSIZE2, data)
+
+ def pack_fhandle3(self, data):
+ self.pack_opaque(data)
+
+ def pack_dirpath(self, data):
+ self.pack_string(data)
+
+ def pack_name(self, data):
+ self.pack_string(data)
+
+ pack_mountstat3 = pack_enum
+
+ def pack_mountlist(self, data):
+ mounttypes.pack_objarray(self, data)
+
+ def pack_groups(self, data):
+ mounttypes.pack_objarray(self, data)
+
+ def pack_exports(self, data):
+ mounttypes.pack_objarray(self, data)
+
+class MOUNTUnpacker(rpc.Unpacker):
+ def __init__(self, ncl, data=''):
+ xdrlib.Unpacker.__init__(self, data)
+ self.ncl = ncl
+
+ unpack_hyper = rpc.Unpacker.unpack_hyper
+
+ unpack_string = rpc.Unpacker.unpack_string
+
+ unpack_enum = rpc.Unpacker.unpack_enum
+
+ unpack_opaque = rpc.Unpacker.unpack_opaque
+
+ unpack_int = rpc.Unpacker.unpack_int
+
+ unpack_double = rpc.Unpacker.unpack_double
+
+ unpack_float = rpc.Unpacker.unpack_float
+
+ unpack_unsigned = rpc.Unpacker.unpack_uint
+
+ unpack_quadruple = rpc.Unpacker.unpack_double
+
+ unpack_bool = rpc.Unpacker.unpack_bool
+
+ unpack_unsigned_int = rpc.Unpacker.unpack_uint
+
+ unpack_unsigned_hyper = rpc.Unpacker.unpack_uhyper
+
+ def unpack_fhandle2(self):
+ return self.unpack_fopaque(mountconstants.FHSIZE2)
+
+ def unpack_fhandle3(self):
+ return self.unpack_opaque()
+
+ def unpack_dirpath(self):
+ return self.unpack_string()
+
+ def unpack_name(self):
+ return self.unpack_string()
+
+ unpack_mountstat3 = unpack_enum
+
+ def unpack_mountlist(self):
+ return mounttypes.unpack_objarray(self.ncl, mounttypes.mountbody)
+
+ def unpack_groups(self):
+ return mounttypes.unpack_objarray(self.ncl, mounttypes.groupnode)
+
+ def unpack_exports(self):
+ return mounttypes.unpack_objarray(self.ncl, mounttypes.exportnode)
+
diff --git a/external/fs/unfs3-0.9.22/contrib/nfsotpclient/mountclient/mounttypes.py b/external/fs/unfs3-0.9.22/contrib/nfsotpclient/mountclient/mounttypes.py
new file mode 100644
index 0000000..303462c
--- /dev/null
+++ b/external/fs/unfs3-0.9.22/contrib/nfsotpclient/mountclient/mounttypes.py
@@ -0,0 +1,232 @@
+# Generated by rpcgen.py at Mon Mar 8 11:09:57 2004
+
+from mountconstants import *
+from mountpacker import *
+import rpc
+
+__all__ = ['BadDiscriminant', 'fhstatus', 'mountres3_ok', 'mountres3', 'mountbody', 'groupnode', 'exportnode']
+
+def init_type_class(klass, ncl):
+ # Initilize type class
+ klass.ncl = ncl
+ klass.packer = ncl.packer
+ klass.unpacker = ncl.unpacker
+
+def assert_not_none(klass, *args):
+ for arg in args:
+ if arg == None:
+ raise TypeError(repr(klass) + " has uninitialized data")
+
+def pack_objarray(ncl, list):
+ # FIXME: Support for length assertion.
+ ncl.packer.pack_uint(len(list))
+ for item in list:
+ item.pack()
+
+def unpack_objarray(ncl, klass):
+ n = ncl.unpacker.unpack_uint()
+ list = []
+ for i in range(n):
+ obj = klass(ncl)
+ obj.unpack()
+ list.append(obj)
+ return list
+
+
+class BadDiscriminant(rpc.RPCException):
+ def __init__(self, value, klass):
+ self.value = value
+ self.klass = klass
+
+ def __str__(self):
+ return "Bad Discriminant %s in %s" % (self.value, self.klass)
+
+class fhstatus:
+ # XDR definition:
+ # union fhstatus switch (unsigned fhs_status) {
+ # case 0:
+ # fhandle2 fhs_fhandle;
+ # default:
+ # void;
+ # };
+ def __init__(self, ncl, fhs_status=None, fhs_fhandle=None):
+ init_type_class(self, ncl)
+ self.fhs_status = fhs_status
+ self.fhs_fhandle = fhs_fhandle
+ # Shortcut to current arm
+ self.arm = None
+
+ def __repr__(self):
+ s = " fhs_status=%s fhs_fhandle=%s" % (str(self.fhs_status), str(self.fhs_fhandle))
+ if len(s) > 70: s = s[:70] + "..."
+ return "<fhstatus:%s>" % s
+
+ def pack(self, dummy=None):
+ assert_not_none(self, self.fhs_status)
+ self.packer.pack_unsigned(self.fhs_status)
+ if self.fhs_status == 0:
+ assert_not_none(self, self.fhs_fhandle)
+ self.packer.pack_fhandle2(self.fhs_fhandle)
+ self.arm = self.fhs_fhandle
+ else:
+ pass
+
+
+ def unpack(self):
+ self.fhs_status = self.unpacker.unpack_unsigned()
+ if self.fhs_status == 0:
+ self.fhs_fhandle = self.unpacker.unpack_fhandle2()
+ self.arm = self.fhs_fhandle
+ else:
+ pass
+
+
+class mountres3_ok:
+ # XDR definition:
+ # struct mountres3_ok {
+ # fhandle3 fhandle;
+ # int auth_flavors<>;
+ # };
+ def __init__(self, ncl, fhandle=None, auth_flavors=None):
+ init_type_class(self, ncl)
+ self.fhandle = fhandle
+ self.auth_flavors = auth_flavors
+
+ def __repr__(self):
+ s = " fhandle=%s auth_flavors=%s" % (str(self.fhandle), str(self.auth_flavors))
+ if len(s) > 70: s = s[:70] + "..."
+ return "<mountres3_ok:%s>" % s
+
+ def pack(self, dummy=None):
+ assert_not_none(self, self.fhandle, self.auth_flavors)
+ self.packer.pack_fhandle3(self.fhandle)
+ self.packer.pack_int(self.auth_flavors)
+
+ def unpack(self):
+ self.fhandle = self.unpacker.unpack_fhandle3()
+ self.auth_flavors = self.unpacker.unpack_array(self.unpacker.unpack_int)
+
+class mountres3:
+ # XDR definition:
+ # union mountres3 switch (mountstat3 fhs_status) {
+ # case MNT3_OK:
+ # mountres3_ok mountinfo;
+ # default:
+ # void;
+ # };
+ def __init__(self, ncl, fhs_status=None, mountinfo=None):
+ init_type_class(self, ncl)
+ self.fhs_status = fhs_status
+ self.mountinfo = mountinfo
+ # Shortcut to current arm
+ self.arm = None
+
+ def __repr__(self):
+ s = " fhs_status=%s mountinfo=%s" % (str(self.fhs_status), str(self.mountinfo))
+ if len(s) > 70: s = s[:70] + "..."
+ return "<mountres3:%s>" % s
+
+ def pack(self, dummy=None):
+ assert_not_none(self, self.fhs_status)
+ self.packer.pack_mountstat3(self.fhs_status)
+ if self.fhs_status == MNT3_OK:
+ assert_not_none(self, self.mountinfo)
+ self.mountinfo.pack()
+ self.arm = self.mountinfo
+ else:
+ pass
+
+
+ def unpack(self):
+ self.fhs_status = self.unpacker.unpack_mountstat3()
+ if self.fhs_status == MNT3_OK:
+ self.mountinfo = mountres3_ok(self)
+ self.mountinfo.unpack()
+ self.arm = self.mountinfo
+ else:
+ pass
+
+
+class mountbody:
+ # XDR definition:
+ # struct mountbody {
+ # name ml_hostname;
+ # dirpath ml_directory;
+ # mountlist ml_next;
+ # };
+ def __init__(self, ncl, ml_hostname=None, ml_directory=None, ml_next=None):
+ init_type_class(self, ncl)
+ self.ml_hostname = ml_hostname
+ self.ml_directory = ml_directory
+ self.ml_next = ml_next
+
+ def __repr__(self):
+ s = " ml_hostname=%s ml_directory=%s ml_next=%s" % (str(self.ml_hostname), str(self.ml_directory), str(self.ml_next))
+ if len(s) > 70: s = s[:70] + "..."
+ return "<mountbody:%s>" % s
+
+ def pack(self, dummy=None):
+ assert_not_none(self, self.ml_hostname, self.ml_directory, self.ml_next)
+ self.packer.pack_name(self.ml_hostname)
+ self.packer.pack_dirpath(self.ml_directory)
+ self.packer.pack_mountlist(self.ml_next)
+
+ def unpack(self):
+ self.ml_hostname = self.unpacker.unpack_name()
+ self.ml_directory = self.unpacker.unpack_dirpath()
+ self.ml_next = self.unpacker.unpack_mountlist()
+
+class groupnode:
+ # XDR definition:
+ # struct groupnode {
+ # name gr_name;
+ # groups gr_next;
+ # };
+ def __init__(self, ncl, gr_name=None, gr_next=None):
+ init_type_class(self, ncl)
+ self.gr_name = gr_name
+ self.gr_next = gr_next
+
+ def __repr__(self):
+ s = " gr_name=%s gr_next=%s" % (str(self.gr_name), str(self.gr_next))
+ if len(s) > 70: s = s[:70] + "..."
+ return "<groupnode:%s>" % s
+
+ def pack(self, dummy=None):
+ assert_not_none(self, self.gr_name, self.gr_next)
+ self.packer.pack_name(self.gr_name)
+ self.packer.pack_groups(self.gr_next)
+
+ def unpack(self):
+ self.gr_name = self.unpacker.unpack_name()
+ self.gr_next = self.unpacker.unpack_groups()
+
+class exportnode:
+ # XDR definition:
+ # struct exportnode {
+ # dirpath ex_dir;
+ # groups ex_groups;
+ # exports ex_next;
+ # };
+ def __init__(self, ncl, ex_dir=None, ex_groups=None, ex_next=None):
+ init_type_class(self, ncl)
+ self.ex_dir = ex_dir
+ self.ex_groups = ex_groups
+ self.ex_next = ex_next
+
+ def __repr__(self):
+ s = " ex_dir=%s ex_groups=%s ex_next=%s" % (str(self.ex_dir), str(self.ex_groups), str(self.ex_next))
+ if len(s) > 70: s = s[:70] + "..."
+ return "<exportnode:%s>" % s
+
+ def pack(self, dummy=None):
+ assert_not_none(self, self.ex_dir, self.ex_groups, self.ex_next)
+ self.packer.pack_dirpath(self.ex_dir)
+ self.packer.pack_groups(self.ex_groups)
+ self.packer.pack_exports(self.ex_next)
+
+ def unpack(self):
+ self.ex_dir = self.unpacker.unpack_dirpath()
+ self.ex_groups = self.unpacker.unpack_groups()
+ self.ex_next = self.unpacker.unpack_exports()
+
diff --git a/external/fs/unfs3-0.9.22/contrib/nfsotpclient/nfsotpclient.py b/external/fs/unfs3-0.9.22/contrib/nfsotpclient/nfsotpclient.py
new file mode 100755
index 0000000..2470906
--- /dev/null
+++ b/external/fs/unfs3-0.9.22/contrib/nfsotpclient/nfsotpclient.py
@@ -0,0 +1,78 @@
+#!/usr/bin/env python
+# -*-mode: python; coding: iso-8859-1 -*-
+#
+# Copyright (c) 2002-2005 Cendio AB. All rights reserved.
+
+import sys
+import rpc
+import mountclient
+import socket
+import os
+import md5
+
+
+class PartialMOUNTClient:
+ def __init__(self):
+ pass
+
+ def addpackers(self):
+ self.packer = mountclient.mountpacker.MOUNTPacker(self)
+ self.unpacker = mountclient.mountpacker.MOUNTUnpacker(self, '')
+
+ def mnt(self, dirpath):
+ res = mountclient.mounttypes.mountres3(self)
+ self.make_call(mountclient.mountconstants.MOUNTPROC_MNT,
+ dirpath, self.packer.pack_string, res.unpack)
+ return res
+
+
+class TCPMOUNTClient(PartialMOUNTClient, rpc.RawTCPClient):
+ def __init__(self, host, port):
+ rpc.RawTCPClient.__init__(self, host,
+ mountclient.mountconstants.MOUNT_PROGRAM,
+ mountclient.mountconstants.MOUNT_V3,
+ port)
+ PartialMOUNTClient.__init__(self)
+
+
+class NFSOTPClient:
+ def __init__(self, host, port):
+ self.mountcl = TCPMOUNTClient(host, port)
+
+ def getotp(self, password):
+ res = self.mountcl.mnt("@getnonce")
+
+ if res.fhs_status != mountclient.mountconstants.MNT3_OK:
+ print >>sys.stderr, "Failed to get nonce:", mountclient.mountconstants.mountstat3_id[res.fhs_status]
+ sys.exit(1)
+
+ fhandle = res.mountinfo.fhandle
+ digest = md5.new(fhandle + password).hexdigest()
+ return digest
+
+
+def usage():
+ print >>sys.stderr, "Usage: nfsotpclient.py host[:port]"
+ sys.exit(1)
+
+
+if __name__ == "__main__":
+ if len(sys.argv) != 2:
+ usage()
+
+ fields = sys.argv[1].split(":")
+ host = fields[0]
+ del fields[0]
+ if fields:
+ port = int(fields[0])
+ else:
+ # No port specified, fetch from portmapper
+ # FIXME
+ print >>sys.stderr, "Portmapper support not yet implemented"
+ sys.exit(1)
+
+ cl = NFSOTPClient(host, port)
+ import getpass
+ password = getpass.getpass()
+
+ print cl.getotp(password)
diff --git a/external/fs/unfs3-0.9.22/contrib/nfsotpclient/rpc.py b/external/fs/unfs3-0.9.22/contrib/nfsotpclient/rpc.py
new file mode 100644
index 0000000..8be1926
--- /dev/null
+++ b/external/fs/unfs3-0.9.22/contrib/nfsotpclient/rpc.py
@@ -0,0 +1,1050 @@
+
+# rpc.py - RFC1057/RFC1831
+#
+# Copyright (C) 2001 Cendio Systems AB (http://www.cendio.se)
+# All rights reserved.
+#
+# Copyright (c) 2001 Python Software Foundation.
+# All rights reserved.
+#
+# Copyright (c) 2000 BeOpen.com.
+# All rights reserved.
+#
+# Copyright (c) 1995-2001 Corporation for National Research Initiatives.
+# All rights reserved.
+#
+# Copyright (c) 1991-1995 Stichting Mathematisch Centrum.
+# All rights reserved.
+#
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+# XXX The UDP version of the protocol resends requests when it does
+# XXX not receive a timely reply -- use only for idempotent calls!
+
+# XXX There is no provision for call timeout on TCP connections
+
+__pychecker__ = 'no-callinit'
+
+import xdrlib
+import socket
+import os
+import time
+
+RPCVERSION = 2
+
+CALL = 0
+REPLY = 1
+
+AUTH_NULL = 0
+AUTH_UNIX = 1
+AUTH_SHORT = 2
+AUTH_DES = 3
+
+MSG_ACCEPTED = 0
+MSG_DENIED = 1
+
+SUCCESS = 0 # RPC executed successfully
+PROG_UNAVAIL = 1 # remote hasn't exported program
+PROG_MISMATCH = 2 # remote can't support version #
+PROC_UNAVAIL = 3 # program can't support procedure
+GARBAGE_ARGS = 4 # procedure can't decode params
+
+RPC_MISMATCH = 0 # RPC version number != 2
+AUTH_ERROR = 1 # remote can't authenticate caller
+
+AUTH_BADCRED = 1 # bad credentials (seal broken)
+AUTH_REJECTEDCRED = 2 # client must begin new session
+AUTH_BADVERF = 3 # bad verifier (seal broken)
+AUTH_REJECTEDVERF = 4 # verifier expired or replayed
+AUTH_TOOWEAK = 5 # rejected for security reasons
+
+# All RPC errors are subclasses of RPCException
+class RPCException(Exception):
+ def __str__(self):
+ return "RPCException"
+
+class BadRPCMsgType(RPCException):
+ def __init__(self, msg_type):
+ self.msg_type = msg_type
+
+ def __str__(self):
+ return "BadRPCMsgType %d" % self.msg_type
+
+class BadRPCVersion(RPCException):
+ def __init__(self, version):
+ self.version = version
+
+ def __str__(self):
+ return "BadRPCVersion %d" % self.version
+
+class RPCMsgDenied(RPCException):
+ # MSG_DENIED
+ def __init__(self, stat):
+ self.stat = stat
+
+ def __str__(self):
+ return "RPCMsgDenied %d" % self.stat
+
+class RPCMisMatch(RPCException):
+ # MSG_DENIED: RPC_MISMATCH
+ def __init__(self, low, high):
+ self.low = low
+ self.high = high
+
+ def __str__(self):
+ return "RPCMisMatch %d,%d" % (self.low, self.high)
+
+class RPCAuthError(RPCException):
+ # MSG_DENIED: AUTH_ERROR
+ def __init__(self, stat):
+ self.stat = stat
+
+ def __str__(self):
+ return "RPCAuthError %d" % self.stat
+
+class BadRPCReplyType(RPCException):
+ # Neither MSG_DENIED nor MSG_ACCEPTED
+ def __init__(self, msg_type):
+ self.msg_type = msg_type
+
+ def __str__(self):
+ return "BadRPCReplyType %d" % self.msg_type
+
+class RPCProgUnavail(RPCException):
+ # PROG_UNAVAIL
+ def __str__(self):
+ return "RPCProgUnavail"
+
+class RPCProgMismatch(RPCException):
+ # PROG_MISMATCH
+ def __init__(self, low, high):
+ self.low = low
+ self.high = high
+
+ def __str__(self):
+ return "RPCProgMismatch %d,%d" % (self.low, self.high)
+
+class RPCProcUnavail(RPCException):
+ # PROC_UNAVAIL
+ def __str__(self):
+ return "RPCProcUnavail"
+
+class RPCGarbageArgs(RPCException):
+ # GARBAGE_ARGS
+ def __str__(self):
+ return "RPCGarbageArgs"
+
+class RPCUnextractedData(RPCException):
+ # xdrlib raised exception because unextracted data remained
+ def __str__(self):
+ return "RPCUnextractedData"
+
+class RPCBadAcceptStats(RPCException):
+ # Unknown accept_stat
+ def __init__(self, stat):
+ self.stat = stat
+
+ def __str__(self):
+ return "RPCBadAcceptStats %d" % self.stat
+
+class XidMismatch(RPCException):
+ # Got wrong XID in reply, got "xid" instead of "expected"
+ def __init__(self, xid, expected):
+ self.xid = xid
+ self.expected = expected
+
+ def __str__(self):
+ return "XidMismatch %d,%d" % (self.xid, self.expected)
+
+class TimeoutError(RPCException):
+ pass
+
+class PortMapError(RPCException):
+ pass
+
+
+class Packer(xdrlib.Packer):
+
+ def pack_auth(self, auth):
+ flavor, stuff = auth
+ self.pack_enum(flavor)
+ self.pack_opaque(stuff)
+
+ def pack_auth_unix(self, stamp, machinename, uid, gid, gids):
+ self.pack_uint(stamp)
+ self.pack_string(machinename)
+ self.pack_uint(uid)
+ self.pack_uint(gid)
+ self.pack_uint(len(gids))
+ for i in gids:
+ self.pack_uint(i)
+
+ def pack_callheader(self, xid, prog, vers, proc, cred, verf):
+ self.pack_uint(xid)
+ self.pack_enum(CALL)
+ self.pack_uint(RPCVERSION)
+ self.pack_uint(prog)
+ self.pack_uint(vers)
+ self.pack_uint(proc)
+ self.pack_auth(cred)
+ self.pack_auth(verf)
+ # Caller must add procedure-specific part of call
+
+ def pack_replyheader(self, xid, verf):
+ self.pack_uint(xid)
+ self.pack_enum(REPLY)
+ self.pack_uint(MSG_ACCEPTED)
+ self.pack_auth(verf)
+ self.pack_enum(SUCCESS)
+ # Caller must add procedure-specific part of reply
+
+
+class Unpacker(xdrlib.Unpacker):
+
+ def unpack_auth(self):
+ flavor = self.unpack_enum()
+ stuff = self.unpack_opaque()
+ if flavor == AUTH_UNIX:
+ p = Unpacker(stuff)
+ stuff = p.unpack_auth_unix()
+ return (flavor, stuff)
+
+ def unpack_auth_unix(self):
+ stamp=self.unpack_uint()
+ machinename=self.unpack_string()
+ print "machinename: %s" % machinename
+ uid=self.unpack_uint()
+ gid=self.unpack_uint()
+ n_gids=self.unpack_uint()
+ gids = []
+ print "n_gids: %d" % n_gids
+ for i in range(n_gids):
+ gids.append(self.unpack_uint())
+ return stamp, machinename, uid, gid, gids
+
+
+ def unpack_callheader(self):
+ xid = self.unpack_uint()
+ msg_type = self.unpack_enum()
+ if msg_type <> CALL:
+ raise BadRPCMsgType(msg_type)
+ rpcvers = self.unpack_uint()
+ if rpcvers <> RPCVERSION:
+ raise BadRPCVersion(rpcvers)
+ prog = self.unpack_uint()
+ vers = self.unpack_uint()
+ proc = self.unpack_uint()
+ cred = self.unpack_auth()
+ verf = self.unpack_auth()
+ return xid, prog, vers, proc, cred, verf
+ # Caller must add procedure-specific part of call
+
+ def unpack_replyheader(self):
+ xid = self.unpack_uint()
+ msg_type = self.unpack_enum()
+ if msg_type <> REPLY:
+ raise BadRPCMsgType(msg_type)
+ stat = self.unpack_enum()
+ if stat == MSG_DENIED:
+ stat = self.unpack_enum()
+ if stat == RPC_MISMATCH:
+ low = self.unpack_uint()
+ high = self.unpack_uint()
+ raise RPCMisMatch(low, high)
+ if stat == AUTH_ERROR:
+ stat = self.unpack_uint()
+ raise RPCAuthError(stat)
+ raise RPCMsgDenied(stat)
+ if stat <> MSG_ACCEPTED:
+ raise BadRPCReplyType(stat)
+ verf = self.unpack_auth()
+ stat = self.unpack_enum()
+ if stat == PROG_UNAVAIL:
+ raise RPCProgUnavail()
+ if stat == PROG_MISMATCH:
+ low = self.unpack_uint()
+ high = self.unpack_uint()
+ raise RPCProgMismatch(low, high)
+ if stat == PROC_UNAVAIL:
+ raise RPCProcUnavail()
+ if stat == GARBAGE_ARGS:
+ raise RPCGarbageArgs()
+ if stat <> SUCCESS:
+ raise RPCBadAcceptStats(stat)
+ return xid, verf
+ # Caller must get procedure-specific part of reply
+
+
+# Subroutines to create opaque authentication objects
+
+def make_auth_null():
+ return ''
+
+def make_auth_unix(seed, host, uid, gid, groups):
+ p = Packer()
+ p.pack_auth_unix(seed, host, uid, gid, groups)
+ return p.get_buffer()
+
+def make_auth_unix_default():
+ try:
+ uid = os.getuid()
+ gid = os.getgid()
+ except AttributeError:
+ uid = gid = 0
+ return make_auth_unix(int(time.time()-unix_epoch()), \
+ socket.gethostname(), uid, gid, [])
+
+_unix_epoch = -1
+def unix_epoch():
+ """Very painful calculation of when the Unix Epoch is.
+
+ This is defined as the return value of time.time() on Jan 1st,
+ 1970, 00:00:00 GMT.
+
+ On a Unix system, this should always return 0.0. On a Mac, the
+ calculations are needed -- and hard because of integer overflow
+ and other limitations.
+
+ """
+ global _unix_epoch
+ if _unix_epoch >= 0: return _unix_epoch
+ now = time.time()
+ localt = time.localtime(now) # (y, m, d, hh, mm, ss, ..., ..., ...)
+ gmt = time.gmtime(now)
+ offset = time.mktime(localt) - time.mktime(gmt)
+ y, m, d, hh, mm, ss = 1970, 1, 1, 0, 0, 0
+ offset, ss = divmod(ss + offset, 60)
+ offset, mm = divmod(mm + offset, 60)
+ offset, hh = divmod(hh + offset, 24)
+ d = d + offset
+ _unix_epoch = time.mktime((y, m, d, hh, mm, ss, 0, 0, 0))
+ print "Unix epoch:", time.ctime(_unix_epoch)
+ return _unix_epoch
+
+
+# Common base class for clients
+
+class Client:
+
+ def __init__(self, host, prog, vers, port):
+ self.host = host
+ self.prog = prog
+ self.vers = vers
+ self.port = port
+ self.sock = None
+ self.makesocket() # Assigns to self.sock
+ self.bindsocket()
+ self.connsocket()
+ # Servers may do XID caching, so try to come up with something
+ # unique to start with. XIDs are 32 bits. Python integers are always
+ # at least 32 bits.
+ self.lastxid = int(long(time.time() * 1E6) & 0xfffffff)
+ self.addpackers()
+ self.cred = None
+ self.verf = None
+
+ def close(self):
+ self.sock.close()
+
+ def makesocket(self):
+ # This MUST be overridden
+ raise RuntimeError("makesocket not defined")
+
+ def connsocket(self):
+ # Override this if you don't want/need a connection
+ self.sock.connect((self.host, self.port))
+
+ def bindsocket(self):
+ # Override this to bind to a different port (e.g. reserved)
+ self.sock.bind(('', 0))
+
+ def addpackers(self):
+ # Override this to use derived classes from Packer/Unpacker
+ self.packer = Packer()
+ self.unpacker = Unpacker('')
+
+ def make_call(self, proc, args, pack_func, unpack_func):
+ # Don't normally override this (but see Broadcast)
+ if pack_func is None and args is not None:
+ raise TypeError("non-null args with null pack_func")
+ self.start_call(proc)
+ if pack_func:
+ pack_func(args)
+ self.do_call()
+ if unpack_func:
+ result = unpack_func()
+ else:
+ result = None
+ try:
+ self.unpacker.done()
+ except xdrlib.Error:
+ raise RPCUnextractedData()
+
+ return result
+
+ def start_call(self, proc):
+ # Don't override this
+ self.lastxid = xid = self.lastxid + 1
+ cred = self.mkcred()
+ verf = self.mkverf()
+ p = self.packer
+ p.reset()
+ p.pack_callheader(xid, self.prog, self.vers, proc, cred, verf)
+
+ def do_call(self):
+ # This MUST be overridden
+ raise RuntimeError("do_call not defined")
+
+ def mkcred(self):
+ # Override this to use more powerful credentials
+ if self.cred == None:
+ self.cred = (AUTH_NULL, make_auth_null())
+ return self.cred
+
+ def mkverf(self):
+ # Override this to use a more powerful verifier
+ if self.verf == None:
+ self.verf = (AUTH_NULL, make_auth_null())
+ return self.verf
+
+ def call_0(self): # Procedure 0 is always like this
+ return self.make_call(0, None, None, None)
+
+
+# Record-Marking standard support
+
+def sendfrag(sock, last, frag):
+ x = len(frag)
+ if last: x = x | 0x80000000L
+ header = (chr(int(x>>24 & 0xff)) + chr(int(x>>16 & 0xff)) + \
+ chr(int(x>>8 & 0xff)) + chr(int(x & 0xff)))
+ sock.send(header + frag)
+
+def sendrecord(sock, record):
+ sendfrag(sock, 1, record)
+
+def recvfrag(sock):
+ header = sock.recv(4)
+ if len(header) < 4:
+ raise EOFError
+ x = long(ord(header[0]))<<24 | ord(header[1])<<16 | \
+ ord(header[2])<<8 | ord(header[3])
+ last = ((x & 0x80000000) != 0)
+ n = int(x & 0x7fffffff)
+ frag = ''
+ while n > 0:
+ buf = sock.recv(n)
+ if not buf: raise EOFError
+ n = n - len(buf)
+ frag = frag + buf
+ return last, frag
+
+def recvrecord(sock):
+ record = ''
+ last = 0
+ while not last:
+ last, frag = recvfrag(sock)
+ record = record + frag
+ return record
+
+
+# Try to bind to a reserved port (must be root)
+
+last_resv_port_tried = None
+def bindresvport(sock, host):
+ global last_resv_port_tried
+ FIRST, LAST = 600, 1024 # Range of ports to try
+ if last_resv_port_tried == None:
+ last_resv_port_tried = FIRST + os.getpid() % (LAST-FIRST)
+ for i in range(last_resv_port_tried, LAST) + \
+ range(FIRST, last_resv_port_tried):
+ last_resv_port_tried = i
+ try:
+ sock.bind((host, i))
+ return last_resv_port_tried
+ except socket.error, (errno, msg):
+ if errno <> 114:
+ raise socket.error(errno, msg)
+ raise RuntimeError("can't assign reserved port")
+
+
+# Client using TCP to a specific port
+
+class RawTCPClient(Client):
+
+ def makesocket(self):
+ self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+
+ def do_call(self):
+ call = self.packer.get_buffer()
+ sendrecord(self.sock, call)
+ reply = recvrecord(self.sock)
+ u = self.unpacker
+ u.reset(reply)
+ xid, verf = u.unpack_replyheader()
+ if xid <> self.lastxid:
+ # Can't really happen since this is TCP...
+ raise XidMismatch(xid, self.lastxid)
+
+# Client using UDP to a specific port
+
+class RawUDPClient(Client):
+
+ def makesocket(self):
+ self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
+
+ def do_call(self):
+ call = self.packer.get_buffer()
+ self.sock.send(call)
+ try:
+ from select import select
+ except ImportError:
+ print 'WARNING: select not found, RPC may hang'
+ select = None
+ BUFSIZE = 8192 # Max UDP buffer size
+ timeout = 1
+ count = 5
+ while 1:
+ r, w, x = [self.sock], [], []
+ if select:
+ r, w, x = select(r, w, x, timeout)
+ if self.sock not in r:
+ count = count - 1
+ if count < 0: raise TimeoutError()
+ if timeout < 25: timeout = timeout *2
+## print 'RESEND', timeout, count
+ self.sock.send(call)
+ continue
+ reply = self.sock.recv(BUFSIZE)
+ u = self.unpacker
+ u.reset(reply)
+ xid, verf = u.unpack_replyheader()
+ if xid <> self.lastxid:
+## print 'BAD xid'
+ continue
+ break
+
+
+# Client using UDP broadcast to a specific port
+
+class RawBroadcastUDPClient(RawUDPClient):
+
+ def __init__(self, bcastaddr, prog, vers, port):
+ RawUDPClient.__init__(self, bcastaddr, prog, vers, port)
+ self.reply_handler = None
+ self.timeout = 30
+
+ def connsocket(self):
+ # Don't connect -- use sendto
+ self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
+
+ def set_reply_handler(self, reply_handler):
+ self.reply_handler = reply_handler
+
+ def set_timeout(self, timeout):
+ self.timeout = timeout # Use None for infinite timeout
+
+ def make_call(self, proc, args, pack_func, unpack_func):
+ if pack_func is None and args is not None:
+ raise TypeError("non-null args with null pack_func")
+ self.start_call(proc)
+ if pack_func:
+ pack_func(args)
+ call = self.packer.get_buffer()
+ self.sock.sendto(call, (self.host, self.port))
+ try:
+ from select import select
+ except ImportError:
+ print 'WARNING: select not found, broadcast will hang'
+ select = None
+ BUFSIZE = 8192 # Max UDP buffer size (for reply)
+ replies = []
+ if unpack_func is None:
+ def dummy(): pass
+ unpack_func = dummy
+ while 1:
+ r, w, x = [self.sock], [], []
+ if select:
+ if self.timeout is None:
+ r, w, x = select(r, w, x)
+ else:
+ r, w, x = select(r, w, x, self.timeout)
+ if self.sock not in r:
+ break
+ reply, fromaddr = self.sock.recvfrom(BUFSIZE)
+ u = self.unpacker
+ u.reset(reply)
+ xid, verf = u.unpack_replyheader()
+ if xid <> self.lastxid:
+## print 'BAD xid'
+ continue
+ reply = unpack_func()
+ try:
+ self.unpacker.done()
+ except xdrlib.Error:
+ raise RPCUnextractedData()
+ replies.append((reply, fromaddr))
+ if self.reply_handler:
+ self.reply_handler(reply, fromaddr)
+ return replies
+
+
+# Port mapper interface
+
+# Program number, version and (fixed!) port number
+PMAP_PROG = 100000
+PMAP_VERS = 2
+PMAP_PORT = 111
+
+# Procedure numbers
+PMAPPROC_NULL = 0 # (void) -> void
+PMAPPROC_SET = 1 # (mapping) -> bool
+PMAPPROC_UNSET = 2 # (mapping) -> bool
+PMAPPROC_GETPORT = 3 # (mapping) -> unsigned int
+PMAPPROC_DUMP = 4 # (void) -> pmaplist
+PMAPPROC_CALLIT = 5 # (call_args) -> call_result
+
+# A mapping is (prog, vers, prot, port) and prot is one of:
+
+IPPROTO_TCP = 6
+IPPROTO_UDP = 17
+
+# A pmaplist is a variable-length list of mappings, as follows:
+# either (1, mapping, pmaplist) or (0).
+
+# A call_args is (prog, vers, proc, args) where args is opaque;
+# a call_result is (port, res) where res is opaque.
+
+
+class PortMapperPacker(Packer):
+
+ def pack_mapping(self, mapping):
+ prog, vers, prot, port = mapping
+ self.pack_uint(prog)
+ self.pack_uint(vers)
+ self.pack_uint(prot)
+ self.pack_uint(port)
+
+ def pack_pmaplist(self, list):
+ self.pack_list(list, self.pack_mapping)
+
+ def pack_call_args(self, ca):
+ prog, vers, proc, args = ca
+ self.pack_uint(prog)
+ self.pack_uint(vers)
+ self.pack_uint(proc)
+ self.pack_opaque(args)
+
+
+class PortMapperUnpacker(Unpacker):
+
+ def unpack_mapping(self):
+ prog = self.unpack_uint()
+ vers = self.unpack_uint()
+ prot = self.unpack_uint()
+ port = self.unpack_uint()
+ return prog, vers, prot, port
+
+ def unpack_pmaplist(self):
+ return self.unpack_list(self.unpack_mapping)
+
+ def unpack_call_result(self):
+ port = self.unpack_uint()
+ res = self.unpack_opaque()
+ return port, res
+
+
+class PartialPortMapperClient:
+ __pychecker__ = 'no-classattr'
+ def addpackers(self):
+ self.packer = PortMapperPacker()
+ self.unpacker = PortMapperUnpacker('')
+
+ def Set(self, mapping):
+ return self.make_call(PMAPPROC_SET, mapping, \
+ self.packer.pack_mapping, \
+ self.unpacker.unpack_uint)
+
+ def Unset(self, mapping):
+ return self.make_call(PMAPPROC_UNSET, mapping, \
+ self.packer.pack_mapping, \
+ self.unpacker.unpack_uint)
+
+ def Getport(self, mapping):
+ return self.make_call(PMAPPROC_GETPORT, mapping, \
+ self.packer.pack_mapping, \
+ self.unpacker.unpack_uint)
+
+ def Dump(self):
+ return self.make_call(PMAPPROC_DUMP, None, \
+ None, \
+ self.unpacker.unpack_pmaplist)
+
+ def Callit(self, ca):
+ return self.make_call(PMAPPROC_CALLIT, ca, \
+ self.packer.pack_call_args, \
+ self.unpacker.unpack_call_result)
+
+
+class TCPPortMapperClient(PartialPortMapperClient, RawTCPClient):
+
+ def __init__(self, host):
+ RawTCPClient.__init__(self, \
+ host, PMAP_PROG, PMAP_VERS, PMAP_PORT)
+
+
+class UDPPortMapperClient(PartialPortMapperClient, RawUDPClient):
+
+ def __init__(self, host):
+ RawUDPClient.__init__(self, \
+ host, PMAP_PROG, PMAP_VERS, PMAP_PORT)
+
+
+class BroadcastUDPPortMapperClient(PartialPortMapperClient, \
+ RawBroadcastUDPClient):
+
+ def __init__(self, bcastaddr):
+ RawBroadcastUDPClient.__init__(self, \
+ bcastaddr, PMAP_PROG, PMAP_VERS, PMAP_PORT)
+
+
+# Generic clients that find their server through the Port mapper
+
+class TCPClient(RawTCPClient):
+
+ def __init__(self, host, prog, vers):
+ pmap = TCPPortMapperClient(host)
+ port = pmap.Getport((prog, vers, IPPROTO_TCP, 0))
+ pmap.close()
+ if port == 0:
+ raise PortMapError("program not registered")
+ RawTCPClient.__init__(self, host, prog, vers, port)
+
+
+class UDPClient(RawUDPClient):
+
+ def __init__(self, host, prog, vers):
+ pmap = UDPPortMapperClient(host)
+ port = pmap.Getport((prog, vers, IPPROTO_UDP, 0))
+ pmap.close()
+ if port == 0:
+ raise PortMapError("program not registered")
+ RawUDPClient.__init__(self, host, prog, vers, port)
+
+
+class BroadcastUDPClient(Client):
+
+ def __init__(self, bcastaddr, prog, vers):
+ self.pmap = BroadcastUDPPortMapperClient(bcastaddr)
+ self.pmap.set_reply_handler(self.my_reply_handler)
+ self.prog = prog
+ self.vers = vers
+ self.user_reply_handler = None
+ self.addpackers()
+
+ def close(self):
+ self.pmap.close()
+
+ def set_reply_handler(self, reply_handler):
+ self.user_reply_handler = reply_handler
+
+ def set_timeout(self, timeout):
+ self.pmap.set_timeout(timeout)
+
+ def my_reply_handler(self, reply, fromaddr):
+ port, res = reply
+ self.unpacker.reset(res)
+ result = self.unpack_func()
+ try:
+ self.unpacker.done()
+ except xdrlib.Error:
+ raise RPCUnextractedData()
+ self.replies.append((result, fromaddr))
+ if self.user_reply_handler is not None:
+ self.user_reply_handler(result, fromaddr)
+
+ def make_call(self, proc, args, pack_func, unpack_func):
+ self.packer.reset()
+ if pack_func:
+ pack_func(args)
+ if unpack_func is None:
+ def dummy(): pass
+ self.unpack_func = dummy
+ else:
+ self.unpack_func = unpack_func
+ self.replies = []
+ packed_args = self.packer.get_buffer()
+ dummy_replies = self.pmap.Callit( \
+ (self.prog, self.vers, proc, packed_args))
+ return self.replies
+
+
+# Server classes
+
+# These are not symmetric to the Client classes
+# XXX No attempt is made to provide authorization hooks yet
+
+class Server:
+
+ def __init__(self, host, prog, vers, port):
+ self.host = host # Should normally be '' for default interface
+ self.prog = prog
+ self.vers = vers
+ self.port = port # Should normally be 0 for random port
+ self.sock = None
+ self.prot = None
+ self.makesocket() # Assigns to self.sock and self.prot
+ self.bindsocket()
+ self.host, self.port = self.sock.getsockname()
+ self.addpackers()
+
+ def register(self):
+ mapping = self.prog, self.vers, self.prot, self.port
+ p = TCPPortMapperClient(self.host)
+ if not p.Set(mapping):
+ raise PortMapError("register failed")
+
+ def unregister(self):
+ mapping = self.prog, self.vers, self.prot, self.port
+ p = TCPPortMapperClient(self.host)
+ if not p.Unset(mapping):
+ raise PortMapError("unregister failed")
+
+ def handle(self, call):
+ # Don't use unpack_header but parse the header piecewise
+ # XXX I have no idea if I am using the right error responses!
+ self.unpacker.reset(call)
+ self.packer.reset()
+ xid = self.unpacker.unpack_uint()
+ self.packer.pack_uint(xid)
+ temp = self.unpacker.unpack_enum()
+ if temp <> CALL:
+ return None # Not worthy of a reply
+ self.packer.pack_uint(REPLY)
+ temp = self.unpacker.unpack_uint()
+ if temp <> RPCVERSION:
+ self.packer.pack_uint(MSG_DENIED)
+ self.packer.pack_uint(RPC_MISMATCH)
+ self.packer.pack_uint(RPCVERSION)
+ self.packer.pack_uint(RPCVERSION)
+ return self.packer.get_buffer()
+ self.packer.pack_uint(MSG_ACCEPTED)
+ self.packer.pack_auth((AUTH_NULL, make_auth_null()))
+ prog = self.unpacker.unpack_uint()
+ if prog <> self.prog:
+ self.packer.pack_uint(PROG_UNAVAIL)
+ return self.packer.get_buffer()
+ vers = self.unpacker.unpack_uint()
+ if vers <> self.vers:
+ self.packer.pack_uint(PROG_MISMATCH)
+ self.packer.pack_uint(self.vers)
+ self.packer.pack_uint(self.vers)
+ return self.packer.get_buffer()
+ proc = self.unpacker.unpack_uint()
+ methname = 'handle_' + `proc`
+ try:
+ meth = getattr(self, methname)
+ except AttributeError:
+ self.packer.pack_uint(PROC_UNAVAIL)
+ return self.packer.get_buffer()
+ self.recv_cred = self.unpacker.unpack_auth()
+ self.recv_verf = self.unpacker.unpack_auth()
+ try:
+ meth() # Unpack args, call turn_around(), pack reply
+ except (EOFError, RPCGarbageArgs):
+ # Too few or too many arguments
+ self.packer.reset()
+ self.packer.pack_uint(xid)
+ self.packer.pack_uint(REPLY)
+ self.packer.pack_uint(MSG_ACCEPTED)
+ self.packer.pack_auth((AUTH_NULL, make_auth_null()))
+ self.packer.pack_uint(GARBAGE_ARGS)
+ return self.packer.get_buffer()
+
+ def turn_around(self):
+ try:
+ self.unpacker.done()
+ except xdrlib.Error:
+ raise RPCUnextractedData()
+
+ self.packer.pack_uint(SUCCESS)
+
+ def handle_0(self): # Handle NULL message
+ self.turn_around()
+
+ def makesocket(self):
+ # This MUST be overridden
+ raise RuntimeError("makesocket not defined")
+
+ def bindsocket(self):
+ # Override this to bind to a different port (e.g. reserved)
+ self.sock.bind((self.host, self.port))
+
+ def addpackers(self):
+ # Override this to use derived classes from Packer/Unpacker
+ self.packer = Packer()
+ self.unpacker = Unpacker('')
+
+
+class TCPServer(Server):
+
+ def makesocket(self):
+ self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ self.prot = IPPROTO_TCP
+
+ def loop(self):
+ self.sock.listen(0)
+ while 1:
+ self.session(self.sock.accept())
+
+ def session(self, connection):
+ sock, (host, port) = connection
+ while 1:
+ try:
+ call = recvrecord(sock)
+ except EOFError:
+ break
+ except socket.error, msg:
+ print 'socket error:', msg
+ break
+ reply = self.handle(call)
+ if reply is not None:
+ sendrecord(sock, reply)
+
+ def forkingloop(self):
+ # Like loop but uses forksession()
+ self.sock.listen(0)
+ while 1:
+ self.forksession(self.sock.accept())
+
+ def forksession(self, connection):
+ # Like session but forks off a subprocess
+ # Wait for deceased children
+ try:
+ while 1:
+ pid, sts = os.waitpid(0, 1)
+ except os.error:
+ pass
+ pid = None
+ try:
+ pid = os.fork()
+ if pid: # Parent
+ connection[0].close()
+ return
+ # Child
+ self.session(connection)
+ finally:
+ # Make sure we don't fall through in the parent
+ if pid == 0:
+ os._exit(0)
+
+
+class UDPServer(Server):
+
+ def makesocket(self):
+ self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
+ self.prot = IPPROTO_UDP
+
+ def loop(self):
+ while 1:
+ self.session()
+
+ def session(self):
+ call, host_port = self.sock.recvfrom(8192)
+ self.sender_port = host_port
+ reply = self.handle(call)
+ if reply <> None:
+ self.sock.sendto(reply, host_port)
+
+
+# Simple test program -- dump local portmapper status
+
+def test():
+ pmap = UDPPortMapperClient('')
+ list = pmap.Dump()
+ list.sort()
+ for prog, vers, prot, port in list:
+ print prog, vers,
+ if prot == IPPROTO_TCP: print 'tcp',
+ elif prot == IPPROTO_UDP: print 'udp',
+ else: print prot,
+ print port
+
+
+# Test program for broadcast operation -- dump everybody's portmapper status
+
+def testbcast():
+ import sys
+ if sys.argv[1:]:
+ bcastaddr = sys.argv[1]
+ else:
+ bcastaddr = '<broadcast>'
+ def rh(reply, fromaddr):
+ host, port = fromaddr
+ print host + '\t' + `reply`
+ pmap = BroadcastUDPPortMapperClient(bcastaddr)
+ pmap.set_reply_handler(rh)
+ pmap.set_timeout(5)
+ unused_replies = pmap.Getport((100002, 1, IPPROTO_UDP, 0))
+
+
+# Test program for server, with corresponding client
+# On machine A: python -c 'import rpc; rpc.testsvr()'
+# On machine B: python -c 'import rpc; rpc.testclt()' A
+# (A may be == B)
+
+def testsvr():
+ # Simple test class -- proc 1 doubles its string argument as reply
+ class S(UDPServer):
+ def handle_1(self):
+ arg = self.unpacker.unpack_string()
+ self.turn_around()
+ print 'RPC function 1 called, arg', `arg`
+ self.packer.pack_string(arg + arg)
+ #
+ s = S('', 0x20000000, 1, 0)
+ try:
+ s.unregister()
+ except PortMapError, e:
+ print 'RuntimeError:', e.args, '(ignored)'
+ s.register()
+ print 'Service started...'
+ try:
+ s.loop()
+ finally:
+ s.unregister()
+ print 'Service interrupted.'
+
+
+def testclt():
+ import sys
+ if sys.argv[1:]: host = sys.argv[1]
+ else: host = ''
+ # Client for above server
+ class C(UDPClient):
+ def call_1(self, arg):
+ return self.make_call(1, arg, \
+ self.packer.pack_string, \
+ self.unpacker.unpack_string)
+ c = C(host, 0x20000000, 1)
+ print 'making call...'
+ reply = c.call_1('hello, world, ')
+ print 'call returned', `reply`
+
+
+# Local variables:
+# py-indent-offset: 4
+# tab-width: 8
+# End:
diff --git a/external/fs/unfs3-0.9.22/contrib/rpcproxy/rpcproxy b/external/fs/unfs3-0.9.22/contrib/rpcproxy/rpcproxy
new file mode 100755
index 0000000..e800b1e
--- /dev/null
+++ b/external/fs/unfs3-0.9.22/contrib/rpcproxy/rpcproxy
@@ -0,0 +1,378 @@
+#!/usr/bin/env python
+# -*-mode: python; coding: utf-8 -*-
+
+# TODO:
+# Support for limiting data sizes, max number of connections from the same IP etc
+
+import sys
+import time
+import socket
+import select
+import struct
+
+# Connection states, both for client and server connection.
+# Client cycle: STATE_READING, WAITING, WRITING
+# Server cycle: WAITING, WRITING, STATE_READING
+STATE_READING = 0 # Reading record
+STATE_WAITING = 2 # Waiting for server response callback, or client mission.
+STATE_WRITING = 3 # Writing response to client or request to server
+STATE_EOF = 4 # EOF while reading
+
+# Constants
+FRAG_HEADER_LEN = 4
+FRAG_MAX_SIZE = 2**31 - 1
+FRAG_SIZE = FRAG_MAX_SIZE # Size of newly created fragments
+
+
+class ProxyEngine:
+ def __init__(self):
+ self.connections = [] # Client or server connections
+ self.proxies = [] # Proxy objects
+
+
+ def add_proxy(self, bind_address, port, host, hostport):
+ """Add a new proxy"""
+ proxy = Proxy(self, bind_address, port, host, hostport)
+ self.proxies.append(proxy)
+ self.connections.append(proxy.srv)
+
+ def add_connection(self, conn):
+ """Add a new connection"""
+ self.connections.append(conn)
+
+
+class Proxy:
+ def __init__(self, pe, bind_address, port, host, hostport):
+ self.pe = pe
+ self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
+ self.sock.bind((bind_address, port))
+ self.sock.listen(1)
+ self.srv = ServerConnection(host, hostport)
+
+
+ def fileno(self):
+ """Return the sockets fileno"""
+ return self.sock.fileno()
+
+
+ def handle_read(self):
+ """Accept a new connection. Return a new ClientConnection"""
+ sock, addr = self.sock.accept()
+ self.pe.add_connection(ClientConnection(sock, addr, self.srv))
+
+
+class ServerCall:
+ def __init__(self, data, callback):
+ self.data = data
+ self.callback = callback
+
+
+class RPCConnection:
+ def __init__(self):
+ self.record = "" # Current record, as stream with RMs
+ self.sndbuf = None
+ self.sock = None
+
+
+ def set_sock(self, sock):
+ """Set socket to use"""
+ self.sock = sock
+ self.sndbuf = sock.getsockopt(socket.SOL_SOCKET, socket.SO_SNDBUF)
+
+
+ def eof_event(self):
+ """recv/send discovered that the connection was closed"""
+ self.state = STATE_EOF
+ self.sock.close()
+
+
+ def assert_sock(self):
+ """Make sure a socket is available. May be overridden."""
+ assert self.sock is not None
+
+
+ def readable(self):
+ """Returns true if connection wants to read"""
+ return self.state is STATE_READING
+
+
+ def writable(self):
+ """Returns true if connection wants to write"""
+ return self.state is STATE_WRITING
+
+
+ def eof(self):
+ """Returns true if EOF has been detected"""
+ return self.state is STATE_EOF
+
+
+ def fileno(self):
+ """Return the sockets fileno"""
+ self.assert_sock()
+ return self.sock.fileno()
+
+
+ def write_record(self):
+ """Write RPC record. Returns true when everything is written"""
+ self.assert_sock()
+ # We can write up to SO_SNDBUF without risk blocking
+ wrote = self.sock.send(buffer(self.record, 0, self.sndbuf))
+ self.record = self.record[wrote:]
+ return len(self.record) == 0
+
+
+ def frag_length(self, head):
+ """Return the length of a fragment, including header"""
+ assert len(head) == FRAG_HEADER_LEN
+ x = struct.unpack('>L', head)[0]
+ return int(x & 0x7fffffff) + FRAG_HEADER_LEN
+
+
+ def frag_last(self, head):
+ """Return true if last flag is set"""
+ assert len(head) == FRAG_HEADER_LEN
+ x = struct.unpack('>L', head)[0]
+ return ((x & 0x80000000L) != 0)
+
+
+ def rm_stream(self, stream):
+ """Record-mark a data stream"""
+ fragpos = 0
+ data = []
+
+ while 1:
+ last = (fragpos+FRAG_SIZE >= len(stream))
+ frag_data = buffer(stream, fragpos, FRAG_SIZE)
+ x = len(frag_data)
+ if last:
+ x = x | 0x80000000L
+ frag_head = struct.pack('>L', x)
+ data.append(frag_head + str(frag_data))
+ if last:
+ break
+ fragpos += len(frag_data)
+
+ return "".join(data)
+
+
+ def parsed_record(self):
+ """Return tupel (data, missing_bytes) of record"""
+ fragpos = 0
+ data = []
+ while 1:
+ frag = buffer(self.record, fragpos)
+ fraghead = buffer(self.record, fragpos, FRAG_HEADER_LEN)
+ data.append(frag[4:])
+
+ if len(frag) < FRAG_HEADER_LEN:
+ return ("".join(data), FRAG_HEADER_LEN - len(frag))
+
+ len_from_head = self.frag_length(fraghead)
+ if len(frag) < len_from_head:
+ # Incomplete fragment
+ return ("".join(data), len_from_head - len(frag))
+ elif len(frag) == len_from_head:
+ # Complete fragment
+ if self.frag_last(fraghead):
+ # No need to read anything more
+ return ("".join(data), 0)
+ else:
+ # Read another fragment
+ return ("".join(data), FRAG_HEADER_LEN)
+ elif len(frag) > len_from_head:
+ # There are more fragments, check them
+ fragpos += len(frag)
+ else:
+ assert 0
+
+
+ def read_record(self):
+ """Read RPC record. Returns true if record complete"""
+ self.assert_sock()
+ assert self.state == STATE_READING
+ bytes_to_read = self.parsed_record()[1]
+ if bytes_to_read == 0:
+ return 1
+
+ data = self.sock.recv(bytes_to_read)
+
+ if data == "":
+ self.eof_event()
+ return 0
+
+ self.record += data
+ return self.parsed_record()[1] == 0
+
+
+class ServerConnection(RPCConnection):
+ def __init__(self, host, port):
+ RPCConnection.__init__(self)
+ self.host = host
+ self.port = port
+ self.calls = [] # A list of ServerCalls
+ self.state = STATE_WAITING
+ self.current_cb = None
+
+
+ def eof_event(self):
+ """Overridden eof_event, which re-connects"""
+ print >>sys.stderr, "Lost connection to server, trying to reconnect."
+ # Discard the current call
+ self.current_cb("")
+ self.current_cb = None
+ if self.calls:
+ self.state = STATE_WRITING
+ else:
+ self.state = STATE_WAITING
+
+ # Re-create socket
+ self.sock.close()
+ self.sock = None
+ self.assert_sock()
+
+
+ def assert_sock(self):
+ """Overridden assert_sock, which connects dynamically"""
+ if self.sock is None:
+ srv_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ while 1:
+ try:
+ srv_sock.connect((self.host, self.port))
+ print >>sys.stderr, "Connected to %s:%d" % (self.host, self.port)
+ break
+ except socket.error, e:
+ print >>sys.stderr, "Connection to %s:%d failed: %s" % (self.host, self.port, e[1])
+ time.sleep(5)
+ self.set_sock(srv_sock)
+
+
+ def call(self, servercall):
+ """Put another call on the call queue. The call argument is a
+ stream, without RMs. The callback will be called with result"""
+ self.calls.append(servercall)
+ if self.state == STATE_WAITING:
+ self.state = STATE_WRITING
+
+
+ def handle_read(self):
+ """Called when socket is ready for read"""
+ if self.read_record():
+ self.current_cb(self.parsed_record()[0])
+ self.current_cb = None
+ if self.calls:
+ self.state = STATE_WRITING
+ else:
+ self.state = STATE_WAITING
+
+
+ def handle_write(self):
+ """Called when socket is ready for write"""
+ assert self.state == STATE_WRITING
+ if self.current_cb is None:
+ # Start working on another request
+ servercall = self.calls.pop(0)
+ self.record = self.rm_stream(servercall.data)
+ self.current_cb = servercall.callback
+
+ assert self.current_cb
+ if self.write_record():
+ self.state = STATE_READING
+ self.record = ""
+
+
+class ClientConnection(RPCConnection):
+ def __init__(self, sock, addr, srv):
+ RPCConnection.__init__(self)
+ self.set_sock(sock)
+ self.addr = addr
+ self.srv = srv
+ self.state = STATE_READING
+
+
+ def handle_read(self):
+ """Called when socket is ready for read"""
+ if self.read_record():
+ self.state = STATE_WAITING
+ self.srv.call(ServerCall(self.parsed_record()[0], self.got_response))
+
+
+ def handle_write(self):
+ """Called when socket is ready for write"""
+ assert self.state == STATE_WRITING
+ if self.write_record():
+ self.state = STATE_READING
+ self.record = ""
+
+
+ def got_response(self, data):
+ """Callback: We got a response from the server"""
+ # send to client
+ self.state = STATE_WRITING
+ self.record = self.rm_stream(data)
+
+
+def usage():
+ sys.exit("Usage: %s [bind_address:]port:host:hostport ..." % sys.argv[0])
+
+
+def parse_arg(arg):
+ """Parse a command argument, specifying hosts and ports.
+ Returns tuple (bind_address, port, host, hostport)"""
+ fields = arg.split(":")
+ if len(fields) == 3:
+ fields.insert(0, "127.0.0.1")
+
+ if len(fields) != 4:
+ usage()
+
+ bind_address, port, host, hostport = fields
+ port = int(port)
+ hostport = int(hostport)
+ return bind_address, port, host, hostport
+
+
+def main():
+ if len(sys.argv) < 2:
+ usage()
+
+ pe = ProxyEngine()
+
+ #
+ # Determine hosts and ports
+ #
+ for arg in sys.argv[1:]:
+ pe.add_proxy(*parse_arg(arg))
+
+ #
+ # Select loop
+ #
+ while 1:
+ # Set up sets
+ read_set = []
+ read_set.extend(pe.proxies)
+ write_set = []
+ for conn in pe.connections:
+ if conn.readable():
+ read_set.append(conn)
+ if conn.writable():
+ write_set.append(conn)
+
+ rlist, wlist, xlist = select.select(read_set, write_set, [])
+
+ for obj in rlist:
+ obj.handle_read()
+
+ for obj in wlist:
+ obj.handle_write()
+
+ for conn in pe.connections:
+ if conn.eof():
+ pe.connections.remove(conn)
+
+
+if __name__ == "__main__":
+ try:
+ main()
+ except KeyboardInterrupt:
+ sys.exit(0)
diff --git a/external/fs/unfs3-0.9.22/daemon.c b/external/fs/unfs3-0.9.22/daemon.c
new file mode 100644
index 0000000..d14af45
--- /dev/null
+++ b/external/fs/unfs3-0.9.22/daemon.c
@@ -0,0 +1,974 @@
+
+/*
+ * UNFS3 server framework
+ * Originally generated using rpcgen
+ * Portions (C) 2004, Pascal Schmidt
+ * see file LICENSE for license details
+ */
+
+#include "config.h"
+
+#include <sys/file.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <rpc/rpc.h>
+#include <rpc/pmap_clnt.h>
+
+#ifndef WIN32
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <syslog.h>
+#else /* WIN32 */
+#include <winsock.h>
+#endif /* WIN32 */
+
+#include <fcntl.h>
+#include <memory.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#include <errno.h>
+
+#if HAVE_RPC_SVC_SOC_H == 1
+# include <rpc/svc_soc.h>
+#endif
+
+#include "nfs.h"
+#include "mount.h"
+#include "xdr.h"
+#include "fh.h"
+#include "fh_cache.h"
+#include "fd_cache.h"
+#include "user.h"
+#include "daemon.h"
+#include "backend.h"
+#include "Config/exports.h"
+
+#ifndef SIG_PF
+#define SIG_PF void(*)(int)
+#endif
+
+#define UNFS_NAME "UNFS3 unfsd " PACKAGE_VERSION " (C) 2006, Pascal Schmidt <unfs3-...@ewetel.net>\n"
+
+/* write verifier */
+writeverf3 wverf;
+
+/* readdir cookie */
+cookie3 rcookie = 0;
+
+/* options and default values */
+int opt_detach = TRUE;
+char *opt_exports = "/etc/exports";
+int opt_cluster = FALSE;
+char *opt_cluster_path = "/";
+int opt_tcponly = FALSE;
+unsigned int opt_nfs_port = NFS_PORT; /* 0 means RPC_ANYSOCK */
+unsigned int opt_mount_port = NFS_PORT;
+int opt_singleuser = FALSE;
+int opt_brute_force = FALSE;
+int opt_testconfig = FALSE;
+struct in_addr opt_bind_addr;
+int opt_readable_executables = FALSE;
+char *opt_pid_file = NULL;
+
+/* Register with portmapper? */
+int opt_portmapper = TRUE;
+
+/*
+ * output message to syslog or stdout
+ */
+void logmsg(int prio, const char *fmt, ...)
+{
+ va_list ap;
+
+#if HAVE_VSYSLOG == 0
+ char mesg[1024];
+#endif
+
+ va_start(ap, fmt);
+ if (opt_detach) {
+#if HAVE_VSYSLOG == 1
+ vsyslog(prio, fmt, ap);
+#else
+ vsnprintf(mesg, 1024, fmt, ap);
+ syslog(prio, mesg, 1024);
+#endif
+ } else {
+ vprintf(fmt, ap);
+ putchar('\n');
+ }
+ va_end(ap);
+}
+
+/*
+ * return remote address from svc_req structure
+ */
+struct in_addr get_remote(struct svc_req *rqstp)
+{
+ return (svc_getcaller(rqstp->rq_xprt))->sin_addr;
+}
+
+/*
+ * return remote port from svc_req structure
+ */
+short get_port(struct svc_req *rqstp)
+{
+ return (svc_getcaller(rqstp->rq_xprt))->sin_port;
+}
+
+/*
+ * return the socket type of the request (SOCK_STREAM or SOCK_DGRAM)
+ */
+int get_socket_type(struct svc_req *rqstp)
+{
+ int v, res;
+ socklen_t l;
+
+ l = sizeof(v);
+
+#if HAVE_STRUCT___RPC_SVCXPRT_XP_FD == 1
+ res = getsockopt(rqstp->rq_xprt->xp_fd, SOL_SOCKET, SO_TYPE, &v, &l);
+#else
+ res = getsockopt(rqstp->rq_xprt->xp_sock, SOL_SOCKET, SO_TYPE, &v, &l);
+#endif
+
+ if (res < 0) {
+ logmsg(LOG_CRIT, "unable to determine socket type");
+ return -1;
+ }
+
+ return v;
+}
+
+/*
+ * write current pid to a file
+ */
+static void create_pid_file(void)
+{
+ char buf[16];
+ int fd, res, len;
+
+ if (!opt_pid_file)
+ return;
+
+ fd = backend_open_create(opt_pid_file, O_RDWR | O_CREAT | O_TRUNC, 0644);
+ if (fd == -1) {
+ logmsg(LOG_WARNING, "failed to create pid file `%s'", opt_pid_file);
+ return;
+ }
+#if defined(LOCK_EX) && defined(LOCK_NB)
+ res = backend_flock(fd, LOCK_EX | LOCK_NB);
+ if (res == -1) {
+ logmsg(LOG_WARNING, "failed to lock pid file `%s'", opt_pid_file);
+ backend_close(fd);
+ return;
+ }
+#endif
+
+ sprintf(buf, "%i\n", backend_getpid());
+ len = strlen(buf);
+
+ res = backend_pwrite(fd, buf, len, 0);
+ backend_close(fd);
+ if (res != len) {
+ logmsg(LOG_WARNING, "failed to write pid file `%s'", opt_pid_file);
+ }
+}
+
+/*
+ * remove pid file
+ */
+static void remove_pid_file(void)
+{
+ int res;
+
+ if (!opt_pid_file)
+ return;
+
+ res = backend_remove(opt_pid_file);
+ if (res == -1 && errno != ENOENT) {
+ logmsg(LOG_WARNING, "failed to remove pid file `%s'", opt_pid_file);
+ }
+}
+
+/*
+ * parse command line options
+ */
+static void parse_options(int argc, char **argv)
+{
+ int opt = 0;
+ char *optstring = "bcC:de:hl:m:n:prstTuwi:";
+
+ while (opt != -1) {
+ opt = getopt(argc, argv, optstring);
+ switch (opt) {
+ case 'b':
+ opt_brute_force = TRUE;
+ break;
+#ifdef WANT_CLUSTER
+ case 'c':
+ opt_cluster = TRUE;
+ break;
+ case 'C':
+ opt_cluster_path = optarg;
+ break;
+#endif
+ case 'd':
+ printf(UNFS_NAME);
+ opt_detach = FALSE;
+ break;
+ case 'e':
+#ifndef WIN32
+ if (optarg[0] != '/') {
+ /* A relative path won't work for re-reading the exports
+ file on SIGHUP, since we are changing directory */
+ fprintf(stderr, "Error: relative path to exports file\n");
+ exit(1);
+ }
+#endif
+ opt_exports = optarg;
+ break;
+ case 'h':
+ printf(UNFS_NAME);
+ printf("Usage: %s [options]\n", argv[0]);
+ printf("\t-h display this short option summary\n");
+ printf("\t-u use unprivileged port for services\n");
+ printf("\t-d do not detach from terminal\n");
+ printf("\t-e <file> file to use instead of /etc/exports\n");
+ printf("\t-i <file> write daemon pid to given file\n");
+#ifdef WANT_CLUSTER
+ printf("\t-c enable cluster extensions\n");
+ printf("\t-C <path> set path for cluster extensions\n");
+#endif
+ printf("\t-n <port> port to use for NFS service\n");
+ printf("\t-m <port> port to use for MOUNT service\n");
+ printf
+ ("\t-t TCP only, do not listen on UDP ports\n");
+ printf("\t-p do not register with the portmapper\n");
+ printf("\t-s single user mode\n");
+ printf("\t-b enable brute force file searching\n");
+ printf
+ ("\t-l <addr> bind to interface with specified address\n");
+ printf
+ ("\t-r report unreadable executables as readable\n");
+ printf("\t-T test exports file and exit\n");
+ exit(0);
+ break;
+ case 'l':
+ opt_bind_addr.s_addr = inet_addr(optarg);
+ if (opt_bind_addr.s_addr == (unsigned) -1) {
+ fprintf(stderr, "Invalid bind address\n");
+ exit(1);
+ }
+ break;
+ case 'm':
+ opt_mount_port = strtol(optarg, NULL, 10);
+ if (opt_mount_port == 0) {
+ fprintf(stderr, "Invalid port\n");
+ exit(1);
+ }
+ break;
+ case 'n':
+ opt_nfs_port = strtol(optarg, NULL, 10);
+ if (opt_nfs_port == 0) {
+ fprintf(stderr, "Invalid port\n");
+ exit(1);
+ }
+ break;
+ case 'p':
+ opt_portmapper = FALSE;
+ break;
+ case 'r':
+ opt_readable_executables = TRUE;
+ break;
+ case 's':
+ opt_singleuser = TRUE;
+#ifndef WIN32
+ if (backend_getuid() == 0) {
+ logmsg(LOG_WARNING,
+ "Warning: running as root with -s is dangerous");
+ logmsg(LOG_WARNING,
+ "All clients will have root access to all exported files!");
+ }
+#endif
+ break;
+ case 't':
+ opt_tcponly = TRUE;
+ break;
+ case 'T':
+ opt_testconfig = TRUE;
+ break;
+ case 'u':
+ opt_nfs_port = 0;
+ opt_mount_port = 0;
+ break;
+ case 'i':
+ opt_pid_file = optarg;
+ break;
+ case '?':
+ exit(1);
+ break;
+ }
+ }
+}
+
+/*
+ * signal handler and error exit function
+ */
+void daemon_exit(int error)
+{
+#ifndef WIN32
+ if (error == SIGHUP) {
+ get_squash_ids();
+ exports_parse();
+ return;
+ }
+
+ if (error == SIGUSR1) {
+ if (fh_cache_use > 0)
+ logmsg(LOG_INFO, "fh entries %i access %i hit %i miss %i",
+ fh_cache_max, fh_cache_use, fh_cache_hit,
+ fh_cache_use - fh_cache_hit);
+ else
+ logmsg(LOG_INFO, "fh cache unused");
+ logmsg(LOG_INFO, "open file descriptors: read %i, write %i",
+ fd_cache_readers, fd_cache_writers);
+ return;
+ }
+#endif /* WIN32 */
+
+ if (opt_portmapper) {
+ svc_unregister(MOUNTPROG, MOUNTVERS1);
+ svc_unregister(MOUNTPROG, MOUNTVERS3);
+ }
+
+ if (opt_portmapper) {
+ svc_unregister(NFS3_PROGRAM, NFS_V3);
+ }
+
+ if (error == SIGSEGV)
+ logmsg(LOG_EMERG, "segmentation fault");
+
+ fd_cache_purge();
+
+ if (opt_detach)
+ closelog();
+
+ remove_pid_file();
+ backend_shutdown();
+
+ exit(1);
+}
+
+/*
+ * NFS service dispatch function
+ * generated by rpcgen
+ */
+static void nfs3_program_3(struct svc_req *rqstp, register SVCXPRT * transp)
+{
+ union {
+ GETATTR3args nfsproc3_getattr_3_arg;
+ SETATTR3args nfsproc3_setattr_3_arg;
+ LOOKUP3args nfsproc3_lookup_3_arg;
+ ACCESS3args nfsproc3_access_3_arg;
+ READLINK3args nfsproc3_readlink_3_arg;
+ READ3args nfsproc3_read_3_arg;
+ WRITE3args nfsproc3_write_3_arg;
+ CREATE3args nfsproc3_create_3_arg;
+ MKDIR3args nfsproc3_mkdir_3_arg;
+ SYMLINK3args nfsproc3_symlink_3_arg;
+ MKNOD3args nfsproc3_mknod_3_arg;
+ REMOVE3args nfsproc3_remove_3_arg;
+ RMDIR3args nfsproc3_rmdir_3_arg;
+ RENAME3args nfsproc3_rename_3_arg;
+ LINK3args nfsproc3_link_3_arg;
+ READDIR3args nfsproc3_readdir_3_arg;
+ READDIRPLUS3args nfsproc3_readdirplus_3_arg;
+ FSSTAT3args nfsproc3_fsstat_3_arg;
+ FSINFO3args nfsproc3_fsinfo_3_arg;
+ PATHCONF3args nfsproc3_pathconf_3_arg;
+ COMMIT3args nfsproc3_commit_3_arg;
+ } argument;
+ char *result;
+ xdrproc_t _xdr_argument, _xdr_result;
+ char *(*local) (char *, struct svc_req *);
+
+ switch (rqstp->rq_proc) {
+ case NFSPROC3_NULL:
+ _xdr_argument = (xdrproc_t) xdr_void;
+ _xdr_result = (xdrproc_t) xdr_void;
+ local = (char *(*)(char *, struct svc_req *)) nfsproc3_null_3_svc;
+ break;
+
+ case NFSPROC3_GETATTR:
+ _xdr_argument = (xdrproc_t) xdr_GETATTR3args;
+ _xdr_result = (xdrproc_t) xdr_GETATTR3res;
+ local =
+ (char *(*)(char *, struct svc_req *)) nfsproc3_getattr_3_svc;
+ break;
+
+ case NFSPROC3_SETATTR:
+ _xdr_argument = (xdrproc_t) xdr_SETATTR3args;
+ _xdr_result = (xdrproc_t) xdr_SETATTR3res;
+ local =
+ (char *(*)(char *, struct svc_req *)) nfsproc3_setattr_3_svc;
+ break;
+
+ case NFSPROC3_LOOKUP:
+ _xdr_argument = (xdrproc_t) xdr_LOOKUP3args;
+ _xdr_result = (xdrproc_t) xdr_LOOKUP3res;
+ local =
+ (char *(*)(char *, struct svc_req *)) nfsproc3_lookup_3_svc;
+ break;
+
+ case NFSPROC3_ACCESS:
+ _xdr_argument = (xdrproc_t) xdr_ACCESS3args;
+ _xdr_result = (xdrproc_t) xdr_ACCESS3res;
+ local =
+ (char *(*)(char *, struct svc_req *)) nfsproc3_access_3_svc;
+ break;
+
+ case NFSPROC3_READLINK:
+ _xdr_argument = (xdrproc_t) xdr_READLINK3args;
+ _xdr_result = (xdrproc_t) xdr_READLINK3res;
+ local =
+ (char *(*)(char *, struct svc_req *)) nfsproc3_readlink_3_svc;
+ break;
+
+ case NFSPROC3_READ:
+ _xdr_argument = (xdrproc_t) xdr_READ3args;
+ _xdr_result = (xdrproc_t) xdr_READ3res;
+ local = (char *(*)(char *, struct svc_req *)) nfsproc3_read_3_svc;
+ break;
+
+ case NFSPROC3_WRITE:
+ _xdr_argument = (xdrproc_t) xdr_WRITE3args;
+ _xdr_result = (xdrproc_t) xdr_WRITE3res;
+ local =
+ (char *(*)(char *, struct svc_req *)) nfsproc3_write_3_svc;
+ break;
+
+ case NFSPROC3_CREATE:
+ _xdr_argument = (xdrproc_t) xdr_CREATE3args;
+ _xdr_result = (xdrproc_t) xdr_CREATE3res;
+ local =
+ (char *(*)(char *, struct svc_req *)) nfsproc3_create_3_svc;
+ break;
+
+ case NFSPROC3_MKDIR:
+ _xdr_argument = (xdrproc_t) xdr_MKDIR3args;
+ _xdr_result = (xdrproc_t) xdr_MKDIR3res;
+ local =
+ (char *(*)(char *, struct svc_req *)) nfsproc3_mkdir_3_svc;
+ break;
+
+ case NFSPROC3_SYMLINK:
+ _xdr_argument = (xdrproc_t) xdr_SYMLINK3args;
+ _xdr_result = (xdrproc_t) xdr_SYMLINK3res;
+ local =
+ (char *(*)(char *, struct svc_req *)) nfsproc3_symlink_3_svc;
+ break;
+
+ case NFSPROC3_MKNOD:
+ _xdr_argument = (xdrproc_t) xdr_MKNOD3args;
+ _xdr_result = (xdrproc_t) xdr_MKNOD3res;
+ local =
+ (char *(*)(char *, struct svc_req *)) nfsproc3_mknod_3_svc;
+ break;
+
+ case NFSPROC3_REMOVE:
+ _xdr_argument = (xdrproc_t) xdr_REMOVE3args;
+ _xdr_result = (xdrproc_t) xdr_REMOVE3res;
+ local =
+ (char *(*)(char *, struct svc_req *)) nfsproc3_remove_3_svc;
+ break;
+
+ case NFSPROC3_RMDIR:
+ _xdr_argument = (xdrproc_t) xdr_RMDIR3args;
+ _xdr_result = (xdrproc_t) xdr_RMDIR3res;
+ local =
+ (char *(*)(char *, struct svc_req *)) nfsproc3_rmdir_3_svc;
+ break;
+
+ case NFSPROC3_RENAME:
+ _xdr_argument = (xdrproc_t) xdr_RENAME3args;
+ _xdr_result = (xdrproc_t) xdr_RENAME3res;
+ local =
+ (char *(*)(char *, struct svc_req *)) nfsproc3_rename_3_svc;
+ break;
+
+ case NFSPROC3_LINK:
+ _xdr_argument = (xdrproc_t) xdr_LINK3args;
+ _xdr_result = (xdrproc_t) xdr_LINK3res;
+ local = (char *(*)(char *, struct svc_req *)) nfsproc3_link_3_svc;
+ break;
+
+ case NFSPROC3_READDIR:
+ _xdr_argument = (xdrproc_t) xdr_READDIR3args;
+ _xdr_result = (xdrproc_t) xdr_READDIR3res;
+ local =
+ (char *(*)(char *, struct svc_req *)) nfsproc3_readdir_3_svc;
+ break;
+
+ case NFSPROC3_READDIRPLUS:
+ _xdr_argument = (xdrproc_t) xdr_READDIRPLUS3args;
+ _xdr_result = (xdrproc_t) xdr_READDIRPLUS3res;
+ local = (char *(*)(char *, struct svc_req *))
+ nfsproc3_readdirplus_3_svc;
+ break;
+
+ case NFSPROC3_FSSTAT:
+ _xdr_argument = (xdrproc_t) xdr_FSSTAT3args;
+ _xdr_result = (xdrproc_t) xdr_FSSTAT3res;
+ local =
+ (char *(*)(char *, struct svc_req *)) nfsproc3_fsstat_3_svc;
+ break;
+
+ case NFSPROC3_FSINFO:
+ _xdr_argument = (xdrproc_t) xdr_FSINFO3args;
+ _xdr_result = (xdrproc_t) xdr_FSINFO3res;
+ local =
+ (char *(*)(char *, struct svc_req *)) nfsproc3_fsinfo_3_svc;
+ break;
+
+ case NFSPROC3_PATHCONF:
+ _xdr_argument = (xdrproc_t) xdr_PATHCONF3args;
+ _xdr_result = (xdrproc_t) xdr_PATHCONF3res;
+ local =
+ (char *(*)(char *, struct svc_req *)) nfsproc3_pathconf_3_svc;
+ break;
+
+ case NFSPROC3_COMMIT:
+ _xdr_argument = (xdrproc_t) xdr_COMMIT3args;
+ _xdr_result = (xdrproc_t) xdr_COMMIT3res;
+ local =
+ (char *(*)(char *, struct svc_req *)) nfsproc3_commit_3_svc;
+ break;
+
+ default:
+ svcerr_noproc(transp);
+ return;
+ }
+ memset((char *) &argument, 0, sizeof(argument));
+ if (!svc_getargs(transp, (xdrproc_t) _xdr_argument, (caddr_t) & argument)) {
+ svcerr_decode(transp);
+ return;
+ }
+ result = (*local) ((char *) &argument, rqstp);
+ if (result != NULL &&
+ !svc_sendreply(transp, (xdrproc_t) _xdr_result, result)) {
+ svcerr_systemerr(transp);
+ logmsg(LOG_CRIT, "unable to send RPC reply");
+ }
+ if (!svc_freeargs
+ (transp, (xdrproc_t) _xdr_argument, (caddr_t) & argument)) {
+ logmsg(LOG_CRIT, "unable to free XDR arguments");
+ }
+ return;
+}
+
+/*
+ * mount protocol dispatcher
+ * generated by rpcgen
+ */
+static void mountprog_3(struct svc_req *rqstp, register SVCXPRT * transp)
+{
+ union {
+ dirpath mountproc_mnt_3_arg;
+ dirpath mountproc_umnt_3_arg;
+ } argument;
+ char *result;
+ xdrproc_t _xdr_argument, _xdr_result;
+ char *(*local) (char *, struct svc_req *);
+
+ switch (rqstp->rq_proc) {
+ case MOUNTPROC_NULL:
+ _xdr_argument = (xdrproc_t) xdr_void;
+ _xdr_result = (xdrproc_t) xdr_void;
+ local =
+ (char *(*)(char *, struct svc_req *)) mountproc_null_3_svc;
+ break;
+
+ case MOUNTPROC_MNT:
+ _xdr_argument = (xdrproc_t) xdr_dirpath;
+ _xdr_result = (xdrproc_t) xdr_mountres3;
+ local = (char *(*)(char *, struct svc_req *)) mountproc_mnt_3_svc;
+ break;
+
+ case MOUNTPROC_DUMP:
+ _xdr_argument = (xdrproc_t) xdr_void;
+ _xdr_result = (xdrproc_t) xdr_mountlist;
+ local =
+ (char *(*)(char *, struct svc_req *)) mountproc_dump_3_svc;
+ break;
+
+ case MOUNTPROC_UMNT:
+ _xdr_argument = (xdrproc_t) xdr_dirpath;
+ _xdr_result = (xdrproc_t) xdr_void;
+ local =
+ (char *(*)(char *, struct svc_req *)) mountproc_umnt_3_svc;
+ break;
+
+ case MOUNTPROC_UMNTALL:
+ _xdr_argument = (xdrproc_t) xdr_void;
+ _xdr_result = (xdrproc_t) xdr_void;
+ local =
+ (char *(*)(char *, struct svc_req *)) mountproc_umntall_3_svc;
+ break;
+
+ case MOUNTPROC_EXPORT:
+ _xdr_argument = (xdrproc_t) xdr_void;
+ _xdr_result = (xdrproc_t) xdr_exports;
+ local =
+ (char *(*)(char *, struct svc_req *)) mountproc_export_3_svc;
+ break;
+
+ default:
+ svcerr_noproc(transp);
+ return;
+ }
+ memset((char *) &argument, 0, sizeof(argument));
+ if (!svc_getargs(transp, (xdrproc_t) _xdr_argument, (caddr_t) & argument)) {
+ svcerr_decode(transp);
+ return;
+ }
+ result = (*local) ((char *) &argument, rqstp);
+ if (result != NULL &&
+ !svc_sendreply(transp, (xdrproc_t) _xdr_result, result)) {
+ svcerr_systemerr(transp);
+ logmsg(LOG_CRIT, "unable to send RPC reply");
+ }
+ if (!svc_freeargs
+ (transp, (xdrproc_t) _xdr_argument, (caddr_t) & argument)) {
+ logmsg(LOG_CRIT, "unable to free XDR arguments");
+ }
+ return;
+}
+
+static void register_nfs_service(SVCXPRT * udptransp, SVCXPRT * tcptransp)
+{
+ if (opt_portmapper) {
+ pmap_unset(NFS3_PROGRAM, NFS_V3);
+ }
+
+ if (udptransp != NULL) {
+ /* Register NFS service for UDP */
+ if (!svc_register
+ (udptransp, NFS3_PROGRAM, NFS_V3, nfs3_program_3,
+ opt_portmapper ? IPPROTO_UDP : 0)) {
+ fprintf(stderr, "%s\n",
+ "unable to register (NFS3_PROGRAM, NFS_V3, udp).");
+ daemon_exit(0);
+ }
+ }
+
+ if (tcptransp != NULL) {
+ /* Register NFS service for TCP */
+ if (!svc_register
+ (tcptransp, NFS3_PROGRAM, NFS_V3, nfs3_program_3,
+ opt_portmapper ? IPPROTO_TCP : 0)) {
+ fprintf(stderr, "%s\n",
+ "unable to register (NFS3_PROGRAM, NFS_V3, tcp).");
+ daemon_exit(0);
+ }
+ }
+}
+
+static void register_mount_service(SVCXPRT * udptransp, SVCXPRT * tcptransp)
+{
+ if (opt_portmapper) {
+ pmap_unset(MOUNTPROG, MOUNTVERS1);
+ pmap_unset(MOUNTPROG, MOUNTVERS3);
+ }
+
+ if (udptransp != NULL) {
+ /* Register MOUNT service (v1) for UDP */
+ if (!svc_register
+ (udptransp, MOUNTPROG, MOUNTVERS1, mountprog_3,
+ opt_portmapper ? IPPROTO_UDP : 0)) {
+ fprintf(stderr, "%s\n",
+ "unable to register (MOUNTPROG, MOUNTVERS1, udp).");
+ daemon_exit(0);
+ }
+
+ /* Register MOUNT service (v3) for UDP */
+ if (!svc_register
+ (udptransp, MOUNTPROG, MOUNTVERS3, mountprog_3,
+ opt_portmapper ? IPPROTO_UDP : 0)) {
+ fprintf(stderr, "%s\n",
+ "unable to register (MOUNTPROG, MOUNTVERS3, udp).");
+ daemon_exit(0);
+ }
+ }
+
+ if (tcptransp != NULL) {
+ /* Register MOUNT service (v1) for TCP */
+ if (!svc_register
+ (tcptransp, MOUNTPROG, MOUNTVERS1, mountprog_3,
+ opt_portmapper ? IPPROTO_TCP : 0)) {
+ fprintf(stderr, "%s\n",
+ "unable to register (MOUNTPROG, MOUNTVERS1, tcp).");
+ daemon_exit(0);
+ }
+
+ /* Register MOUNT service (v3) for TCP */
+ if (!svc_register
+ (tcptransp, MOUNTPROG, MOUNTVERS3, mountprog_3,
+ opt_portmapper ? IPPROTO_TCP : 0)) {
+ fprintf(stderr, "%s\n",
+ "unable to register (MOUNTPROG, MOUNTVERS3, tcp).");
+ daemon_exit(0);
+ }
+ }
+}
+
+static SVCXPRT *create_udp_transport(unsigned int port)
+{
+ SVCXPRT *transp = NULL;
+ struct sockaddr_in sin;
+ int sock;
+ const int on = 1;
+
+ if (port == 0)
+ sock = RPC_ANYSOCK;
+ else {
+ sin.sin_family = AF_INET;
+ sin.sin_port = htons(port);
+ sin.sin_addr.s_addr = opt_bind_addr.s_addr;
+ sock = socket(PF_INET, SOCK_DGRAM, 0);
+ setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *) &on, sizeof(on));
+ if (bind(sock, (struct sockaddr *) &sin, sizeof(struct sockaddr))) {
+ perror("bind");
+ fprintf(stderr, "Couldn't bind to udp port %d\n", port);
+ exit(1);
+ }
+ }
+
+ transp = svcudp_bufcreate(sock, NFS_MAX_UDP_PACKET, NFS_MAX_UDP_PACKET);
+
+ if (transp == NULL) {
+ fprintf(stderr, "%s\n", "cannot create udp service.");
+ daemon_exit(0);
+ }
+
+ return transp;
+}
+
+static SVCXPRT *create_tcp_transport(unsigned int port)
+{
+ SVCXPRT *transp = NULL;
+ struct sockaddr_in sin;
+ int sock;
+ const int on = 1;
+
+ if (port == 0)
+ sock = RPC_ANYSOCK;
+ else {
+ sin.sin_family = AF_INET;
+ sin.sin_port = htons(port);
+ sin.sin_addr.s_addr = opt_bind_addr.s_addr;
+ sock = socket(PF_INET, SOCK_STREAM, 0);
+ setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *) &on, sizeof(on));
+ if (bind(sock, (struct sockaddr *) &sin, sizeof(struct sockaddr))) {
+ perror("bind");
+ fprintf(stderr, "Couldn't bind to tcp port %d\n", port);
+ exit(1);
+ }
+ }
+
+ transp = svctcp_create(sock, 0, 0);
+
+ if (transp == NULL) {
+ fprintf(stderr, "%s\n", "cannot create tcp service.");
+ daemon_exit(0);
+ }
+
+ return transp;
+}
+
+/* Run RPC service. This is our own implementation of svc_run(), which
+ allows us to handle other events as well. */
+static void unfs3_svc_run()
+{
+ fd_set readfds;
+ struct timeval tv;
+
+ for (;;) {
+ fd_cache_close_inactive();
+ readfds = svc_fdset;
+ tv.tv_sec = 1;
+ tv.tv_usec = 0;
+ /* Note: On Windows, it's not possible to call select with all sets
+ empty; to use it as a sleep function. In our case, however,
+ readfds should never be empty, since we always have our listen
+ socket. Well, at least hope that our Windows RPC library works
+ like that. oncrpc-ms does. */
+ switch (select(FD_SETSIZE, &readfds, NULL, NULL, &tv)) {
+ case -1:
+ if (errno == EINTR) {
+ continue;
+ }
+ perror("unfs3_svc_run: select failed");
+ return;
+ case 0:
+ /* timeout */
+ continue;
+ default:
+ svc_getreqset(&readfds);
+ }
+ }
+}
+
+/*
+ * Generate write verifier based on PID and current time
+ */
+void regenerate_write_verifier(void)
+{
+ *(wverf + 0) = (uint32) getpid();
+ *(wverf + 0) ^= rand();
+ *(wverf + 4) = (uint32) time(NULL);
+}
+
+/*
+ * Change readdir cookie value
+ */
+void change_readdir_cookie(void)
+{
+ rcookie = rcookie >> 32;
+ ++rcookie;
+ rcookie = rcookie << 32;
+}
+
+/*
+ * NFSD main function
+ * originally generated by rpcgen
+ * forking, logging, options, and signal handler stuff added
+ */
+int main(int argc, char **argv)
+{
+ register SVCXPRT *tcptransp = NULL, *udptransp = NULL;
+ pid_t pid = 0;
+
+#ifndef WIN32
+ struct sigaction act;
+ sigset_t actset;
+#endif /* WIN32 */
+ int res;
+
+ opt_bind_addr.s_addr = INADDR_ANY;
+
+ parse_options(argc, argv);
+ if (optind < argc) {
+ fprintf(stderr, "Error: extra arguments on command line\n");
+ exit(1);
+ }
+
+ /* init write verifier */
+ regenerate_write_verifier();
+
+ res = backend_init();
+ if (res == -1) {
+ fprintf(stderr, "backend initialization failed\n");
+ daemon_exit(0);
+ }
+
+ /* config test mode */
+ if (opt_testconfig) {
+ res = exports_parse();
+ if (res) {
+ exit(0);
+ } else {
+ fprintf(stderr, "Parse error in `%s'\n", opt_exports);
+ exit(1);
+ }
+ }
+
+ if (opt_detach) {
+ /* prepare syslog access */
+ openlog("unfsd", LOG_CONS | LOG_PID, LOG_DAEMON);
+ } else {
+ /* flush stdout after each newline */
+ setvbuf(stdout, NULL, _IOLBF, 0);
+ }
+
+ /* NFS transports */
+ if (!opt_tcponly)
+ udptransp = create_udp_transport(opt_nfs_port);
+ tcptransp = create_tcp_transport(opt_nfs_port);
+
+ register_nfs_service(udptransp, tcptransp);
+
+ /* MOUNT transports. If ports are equal, then the MOUNT service can reuse
+ the NFS transports. */
+ if (opt_mount_port != opt_nfs_port) {
+ if (!opt_tcponly)
+ udptransp = create_udp_transport(opt_mount_port);
+ tcptransp = create_tcp_transport(opt_mount_port);
+ }
+
+ register_mount_service(udptransp, tcptransp);
+
+#ifndef WIN32
+ if (opt_detach) {
+ pid = fork();
+ if (pid == -1) {
+ fprintf(stderr, "could not fork into background\n");
+ daemon_exit(0);
+ }
+ }
+#endif /* WIN32 */
+
+ if (!opt_detach || pid == 0) {
+#ifndef WIN32
+ sigemptyset(&actset);
+ act.sa_handler = daemon_exit;
+ act.sa_mask = actset;
+ act.sa_flags = 0;
+ sigaction(SIGHUP, &act, NULL);
+ sigaction(SIGTERM, &act, NULL);
+ sigaction(SIGINT, &act, NULL);
+ sigaction(SIGQUIT, &act, NULL);
+ sigaction(SIGSEGV, &act, NULL);
+ sigaction(SIGUSR1, &act, NULL);
+
+ act.sa_handler = SIG_IGN;
+ sigaction(SIGPIPE, &act, NULL);
+ sigaction(SIGUSR2, &act, NULL);
+ sigaction(SIGALRM, &act, NULL);
+
+ /* don't make directory we started in busy */
+ chdir("/");
+
+ /* detach from terminal */
+ if (opt_detach) {
+ setsid();
+ fclose(stdin);
+ fclose(stdout);
+ fclose(stderr);
+ }
+#endif /* WIN32 */
+
+ /* no umask to not screw up create modes */
+ umask(0);
+
+ /* create pid file if wanted */
+ create_pid_file();
+
+ /* initialize internal stuff */
+ fh_cache_init();
+ fd_cache_init();
+ get_squash_ids();
+ exports_parse();
+
+ unfs3_svc_run();
+ exit(1);
+ /* NOTREACHED */
+ }
+
+ return 0;
+}
diff --git a/external/fs/unfs3-0.9.22/daemon.h b/external/fs/unfs3-0.9.22/daemon.h
new file mode 100644
index 0000000..13b20af
--- /dev/null
+++ b/external/fs/unfs3-0.9.22/daemon.h
@@ -0,0 +1,49 @@
+/*
+ * UNFS3 server framework
+ * (C) 2004, Pascal Schmidt
+ * see file LICENSE for license details
+ */
+
+#ifndef UNFS3_DAEMON_H
+#define UNFS3_DAEMON_H
+
+#include "nfs.h"
+
+/* exit status for internal errors */
+#define CRISIS 99
+
+/* HP-UX does not have seteuid() and setegid() */
+#if HAVE_SETEUID == 0 && HAVE_SETRESUID == 1
+#define seteuid(u) setresuid(-1, u, -1)
+#endif
+#if HAVE_SETEGID == 0 && HAVE_SETRESGID == 1
+#define setegid(g) setresgid(-1, g, -1)
+#endif
+
+/* error handling */
+void daemon_exit(int);
+void logmsg(int, const char *, ...);
+
+/* remote address */
+struct in_addr get_remote(struct svc_req *);
+short get_port(struct svc_req *);
+int get_socket_type(struct svc_req *rqstp);
+
+/* write verifier */
+extern writeverf3 wverf;
+void regenerate_write_verifier(void);
+
+/* readdir cookie */
+extern cookie3 rcookie;
+void change_readdir_cookie(void);
+
+/* options */
+extern int opt_detach;
+extern char *opt_exports;
+extern int opt_cluster;
+extern char *opt_cluster_path;
+extern int opt_singleuser;
+extern int opt_brute_force;
+extern int opt_readable_executables;
+
+#endif
diff --git a/external/fs/unfs3-0.9.22/doc/README.win b/external/fs/unfs3-0.9.22/doc/README.win
new file mode 100644
index 0000000..55fa4d7
--- /dev/null
+++ b/external/fs/unfs3-0.9.22/doc/README.win
@@ -0,0 +1,51 @@
+
+Building unfs3 for Windows
+==========================
+
+Building unfs3 using MinGW
+--------------------------
+1. Build and install the oncrpc-ms library (http://oncrpc-ms.sourceforge.net/)
+
+2. Configure unfs3 with:
+
+LIBS="/myprefix/oncrpc-ms/lib/liboncrpc.a -lwsock32" CFLAGS="-I/myprefix/oncrpc-ms/include -DONCRPCDLL" ./configure --host=`gcc -dumpmachine`
+
+
+Using unfs3 on Windows
+======================
+
+Limitations
+-----------
+* Single-user mode is required. Internally, unfs3 assumes that it is
+ running with uid 0.
+
+* Foreground mode is required.
+
+* Inode numbers are emulated by hashing file paths. This means that
+ there's a small risk that two files ends up with the same inode
+ number.
+
+
+Path syntax
+-----------
+unfs3 implements a virtual file system. The root "/" directory
+contains the drive letters of the drives present on the system. Below
+each drive letter, the actual drive contents is found. unfs3 uses
+forward slashes instead of backslashes. This applies both to mount
+requests and the exports-file.
+
+
+Example exports file
+--------------------
+/a (ro)
+/c/windows/temp (rw)
+
+
+Example invocation
+------------------
+unfsd.exe -s -d -p -n 4711 -m 4711 -e exports
+
+
+Example mount command from a Linux host
+---------------------------------------
+mount -o port=4711,mountport=4711,mountvers=3,nfsvers=3,nolock,tcp mywindowshost:/c/windows/temp /mnt
diff --git a/external/fs/unfs3-0.9.22/doc/TODO b/external/fs/unfs3-0.9.22/doc/TODO
new file mode 100644
index 0000000..291bd76
--- /dev/null
+++ b/external/fs/unfs3-0.9.22/doc/TODO
@@ -0,0 +1,12 @@
+
+* In some cases, unfs3 issues system calls like stat() with a path
+ beginning with double slashes. This happens to work on most UNIX
+ systems, but this is not guaranteed by POSIX. See
+ http://www.opengroup.org/onlinepubs/009695399/xrat/xbd_chap04.html
+ or section 2.2.2.102 in POSIX-1003.2-Draft-12.
+
+Windows platform:
+
+* Cluster extensions have not been tried on this platform.
+
+* Investigate possibilities for changing times on directory
diff --git a/external/fs/unfs3-0.9.22/doc/kirch1.txt b/external/fs/unfs3-0.9.22/doc/kirch1.txt
new file mode 100644
index 0000000..eb0ea25
--- /dev/null
+++ b/external/fs/unfs3-0.9.22/doc/kirch1.txt
@@ -0,0 +1,271 @@
+
+ Re: A multi-threaded NFS server for Linux
+
+ Olaf Kirch (ok...@monad.swb.de)
+ Tue, 26 Nov 1996 23:09:08 +0100
+
+ * Messages sorted by: [1][ date ][2][ thread ][3][ subject ][4][
+ author ]
+ * Next message: [5]Olaf Kirch: "Re: rpc.lockd/rpc.statd"
+ * Previous message: [6]Paul Christenson: "smail SPAM filter?"
+ * Next in thread: [7]Linus Torvalds: "Re: A multi-threaded NFS
+ server for Linux"
+ * Reply: [8]Linus Torvalds: "Re: A multi-threaded NFS server for
+ Linux"
+ _________________________________________________________________
+
+ Hi all,
+
+ here are some ramblings about implementing nfsd, the differences
+ between kernel- and user-space, and life in general. It's become quite
+ long, so if you're not interested in either of these topics,
+ just skip it...
+
+ On Sun, 24 Nov 1996 12:01:01 PST, "H.J. Lu" wrote:
+ > With the upcoming the Linux C library 6.0, it is possible to
+ > implement a multi-threaded NFS server in the user space using
+ > the kernel-based pthread and MT-safe API included in libc 6.0.
+
+ In my opinion, servicing NFS from user space is an idea that should
+ die.
+ The current unfsd (and I'm pretty sure this will hold for any other
+ implementation) has a host of problems:
+
+ 1. Speed.
+
+ This is only partly related to nfsd being single-threaded. I have
+ run some benchmarks a while ago comparing my kernel-based nfsd to
+ the user-space nfsd.
+
+ In the unfsd case, I was running 4 daemons in parallel (which is
+ possible
+ even now as long as you restrict yourself to read-only access), and
+ found the upper limit for peak throughput was around 800 KBps; the
+ rate
+ for sustained reads was even lower. In comparison, the kernel-based
+ nfsd achieved around than 1.1 MBps peak throughput which is almost
+ the theoretical cheapernet limit; its sustained rate was around 1
+ MBps.
+ Testers of my recent knfsd implementation reported a sustained rate
+ of 3.8 MBps over 100 Mbps Ethernet.
+
+ Even though some tweaking of the unfsd source (especially by getting
+ rid
+ of the Sun RPC code) may improve performance some more, I don't
+ believe
+ the user-space can be pushed much further. [Speaking of the RPC
+ library,
+ a rewrite would be required anyway to safely support NFS over TCP. You
+ can easily hang a vanilla RPC server by sending an incomplete request
+ over TCP and keeping the connection open]
+
+ Now add to that the synchronization overhead required to keep the file
+ handle cache in sync between the various threads...
+
+ This leads me straight to the next topic:
+
+ 2. File Handle Layout
+
+ Traditional nfsds usually stuff a file's device and inode number into
+ the
+ file handle, along with some information on the exported inode. Since
+ a user space program has no way of opening a file just given its inode
+ number, unfsd takes a different approach. It basically creates a
+ hashed
+ version of the file's path. Each path component is stat'ed, and an
+ 8bit
+ hash of the component's device and inode number is used.
+
+ The first problem is that this kind of file handle is not invariant
+ against renames from one directory to another. Agreed, this doesn't
+ happen too often, but it does break Unix semantics. Try this on an
+ nfs-mounted file system (with appropriate foo and bar):
+
+ (mv bar foo/bar; cat) < bar
+
+ The second problem is a lot worse. When unfsd is presented with a file
+ handle it does not have in its cache, it must map it to a valid path
+ name. This is basically done in the following way:
+
+ path = "/";
+ depth = 0;
+ while (depth < length(fhandle)) {
+ deeper:
+ dirp = opendir(path);
+ while ((entry = readdir(dirp)) != NULL) {
+ if (hash(dev,ino) matches fhandle component) {
+ remember dirp
+ append entry to path
+ depth++;
+ goto deeper;
+ }
+ }
+ closedir(dirp);
+ backtrack;
+ }
+
+ Needless to say, this is not very fast. The file handle cache helps
+ a lot here, but this kind of mapping operation occurs far more often
+ than one might expect (consider a development tree where files get
+ created and deleted continuously). In addition, the current
+ implementation
+ discards conflicting handles when there's a hash collision.
+
+ This file handle layout also leaves little room for any additional
+ baggage. Unfsd currently uses 4 bytes for an inode hash of the file
+ itself and 28 bytes for the hashed path, but as soon as you add other
+ information like the inode generation number, you will sooner or
+ later run out of room.
+
+ Last not least, the file handle cache must be strictly synchronized
+ between different nfsd processes/threads. Suppose you rename foo to
+ bar, which is performed by thread1, then try to read the file, which
+ is
+ performed by thread2. If the latter doesn't know the cached path is
+ stale,
+ it will fail. You could of course retry every operation that fails
+ with
+ ENOENT, but this will add even more clutter and overhead to the code.
+
+ 3. Adherence to the NFSv2 specification
+
+ The Linux nfsd currently does not fulfill the NFSv2 spec in its
+ entirety.
+ Especially when it comes to safe writes, it is really a fake. It
+ neither
+ makes an attempt to sync file data before replying to the client
+ (which
+ could be implemented, along with the `async' export option for turning
+ off this kind of behavior), nor does it sync meta-data after inode
+ operations (which is impossible from user space). To most people this
+ is no big loss, but this behavior is definitely not acceptable if you
+ want industry-strengh NFS.
+
+ But even if you did implement at least synchronous file writes in
+ unfsd,
+ be it as an option or as the default, there seems to be no way to
+ implement some of the more advanced techniques like gathered writes.
+ When implementing gathered writes, the server tries to detect whether
+ other nfsd threads are writing to the file at the same time (which
+ frequently happens when the client's biods flush out the data on file
+ close), and if they do, it delays syncing file data for a few
+ milliseconds
+ so the others can finish first, and then flushes all data in one go.
+ You
+ can do this in kernel-land by watching inode->i_writecount, but you're
+ totally at a loss in user-space.
+
+ 4. Supporting NFSv3
+
+ A user-space NFS server is not particularly well suited for
+ implementing
+ NFSv3. For instance, NFSv3 tries to help cache consistency on the
+ client
+ by providing pre-operation attributes for some operations, for
+ instance
+ the WRITE call. When a client finds that the pre-operation attributes
+ returned by the server agree with those it has cached, it can safely
+ assume that any data it has cached was still valid when the server
+ replied to its call, so there's no need to discard the cached file
+ data
+ and meta-data.
+
+ However, pre-op attributes can only be provided safely when the server
+ retains exclusive access to the inode throughout the operation. This
+ is
+ impossible from user space.
+
+ A similar example is the exclusive create operation where a verifier
+ is stored in the inode's atime/mtime fields by the server to guarantee
+ exactly-once behavior even in the face of request retransmissions.
+ These
+ values cannot be checked atomically by a user-space server.
+
+ What this boils down to is that a user-space server cannot, without
+ violating the protocol spec, implement many of the advanced features
+ of NFSv3.
+
+ 5. File locking over NFS
+
+ Supporting lockd in user-space is close to impossible. I've tried it,
+ and have run into a large number of problems. Some of the highlights:
+
+ * lockd can provide only a limited number of locks at the same
+ time because it has only a limited number of file descriptors.
+
+ * When lockd blocks a client's lock request because of a lock held
+ by a local process on the server, it must continuously poll
+ /proc/locks to see whether the request could be granted. What's
+ more, if there's heavy contention for the file, it may take
+ a long time before it succeeds because it cannot add itself
+ to the inode's lock wait list in the kernel. That is, unless
+ you want it to create a new thread just for blocking on this
+ lock.
+
+ * Lockd must synchronize its file handle cache with that of
+ the NFS servers. Unfortunately, lockd is also needed when
+ running as an NFS client only, so you run into problems with
+ who owns the file handle cache, and how to share it between
+ these to services.
+
+ 6. Conclusion
+
+ Alright, this has become rather long. Some of the problems I've
+ described
+ above may be solvable with more or less effort, but I believe that,
+ taken
+ as a whole, they make a pretty strong argument against sticking with
+ a user-space nfsd.
+
+ In kernel-space, most of these issues are addressed most easily, and
+ more
+ efficiently. My current kernel nfsd is fairly small. Together with the
+ RPC core, which is used by both client and server, it takes up
+ something
+ like 20 pages--don't quote me on the exact number. As mentioned above,
+ it is also pretty fast, and I hope I'll be able to also provide fully
+ functional file locking soon.
+
+ If you want to take a look at the current snapshot, it's available at
+ ftp.mathematik.th-darmstadt.de/pub/linux/okir/dontuse/linux-nfs-X.Y.ta
+ r.gz.
+ This version still has a bug in the nfsd readdir implementation, but
+ I'll release an updated (and fixed) version as soon as I have the
+ necessary
+ lockd rewrite sorted out.
+
+ I would particularly welcome comments from Keepers of the Source
+ whether
+ my NFS rewrite has any chance of being incorporated into the kernel at
+ some time... that would definitely motivate me to sick more time into
+ it than I currently do.
+
+ Happy hacking
+ Olaf
+--
+Olaf Kirch | --- o --- Nous sommes du soleil we love when we play
+ok...@monad.swb.de | / | \ sol.dhoop.naytheet.ah kin.ir.samse.qurax
+ For my PGP public key, finger ok...@brewhq.swb.de.
+ _________________________________________________________________
+
+ * Next message: [9]Olaf Kirch: "Re: rpc.lockd/rpc.statd"
+ * Previous message: [10]Paul Christenson: "smail SPAM filter?"
+ * Next in thread: [11]Linus Torvalds: "Re: A multi-threaded NFS
+ server for Linux"
+ * Reply: [12]Linus Torvalds: "Re: A multi-threaded NFS server for
+ Linux"
+
+Referenser
+
+ 1. http://www.ussg.iu.edu/hypermail/linux/net/9611.3/date.html#18
+ 2. http://www.ussg.iu.edu/hypermail/linux/net/9611.3/index.html#18
+ 3. http://www.ussg.iu.edu/hypermail/linux/net/9611.3/subject.html#18
+ 4. http://www.ussg.iu.edu/hypermail/linux/net/9611.3/author.html#18
+ 5. http://www.ussg.iu.edu/hypermail/linux/net/9611.3/0019.html
+ 6. http://www.ussg.iu.edu/hypermail/linux/net/9611.3/0017.html
+ 7. http://www.ussg.iu.edu/hypermail/linux/net/9611.3/0020.html
+ 8. http://www.ussg.iu.edu/hypermail/linux/net/9611.3/0020.html
+ 9. http://www.ussg.iu.edu/hypermail/linux/net/9611.3/0019.html
+ 10. http://www.ussg.iu.edu/hypermail/linux/net/9611.3/0017.html
+ 11. http://www.ussg.iu.edu/hypermail/linux/net/9611.3/0020.html
+ 12. http://www.ussg.iu.edu/hypermail/linux/net/9611.3/0020.html
diff --git a/external/fs/unfs3-0.9.22/doc/passwords.txt b/external/fs/unfs3-0.9.22/doc/passwords.txt
new file mode 100644
index 0000000..f7c73d1
--- /dev/null
+++ b/external/fs/unfs3-0.9.22/doc/passwords.txt
@@ -0,0 +1,46 @@
+
+unfs3 mount-time password support
+=================================
+
+Example exports file:
+
+/tmp (rw,password=gazonk)
+
+Syntax note: The password may contain any character, except
+whitespace, comma and right parenthesis.
+
+
+Mounting with clear-text passwords
+----------------------------------
+
+mount yourhost:@password:gazonk/tmp /mnt
+
+Note: When using @password, the password cannot contain slashes.
+
+
+Mounting with one-time passwords
+--------------------------------
+
+1. Communicate with the mount server and issue a mount for
+ "@getnonce". The returned filehandle is your nonce.
+
+2. Concatenate the nonce with the password, and run it through
+ MD5. Convert the result to a hexascii representation.
+
+3. Example mount command:
+
+mount yourhost:@otp:851d689b11ed4779dd5fbb084b136c52/tmp /mnt
+
+Step 1 and 2 can be done by using the "nfsotpclient" found in the
+contrib directory.
+
+Note: With otp:s, a race condition exists. Consider the following:
+
+1) client A requests nonce, gets NA
+2) client B requests nonce, gets NB
+3) client A sends otp mount using NA
+4) client B sends otp mount using NB
+
+Step 3 will not succeed because the server only stores the last
+nonce. Step 4 will succeed, though. Client A needs to fetch a new
+nonce and retry the mount.
diff --git a/external/fs/unfs3-0.9.22/error.c b/external/fs/unfs3-0.9.22/error.c
new file mode 100644
index 0000000..920d974
--- /dev/null
+++ b/external/fs/unfs3-0.9.22/error.c
@@ -0,0 +1,280 @@
+
+/*
+ * UNFS3 error translation
+ * (C) 2004, Pascal Schmidt
+ * see file LICENSE for license details
+ */
+
+/*
+ * translations from Unix errno to NFS error numbers
+ */
+
+#include "config.h"
+
+#include <rpc/rpc.h>
+#include <errno.h>
+
+#include "nfs.h"
+#include "error.h"
+#include "backend.h"
+
+static int is_stale(void)
+{
+ if (errno == ENOTDIR || errno == ELOOP || errno == ENOENT ||
+ errno == ENAMETOOLONG)
+ return -1;
+ else
+ return 0;
+}
+
+nfsstat3 symlink_err(void)
+{
+ if (errno == EACCES || errno == EPERM)
+ return NFS3ERR_ACCES;
+ else if (is_stale())
+ return NFS3ERR_STALE;
+ else if (errno == EROFS)
+ return NFS3ERR_ROFS;
+ else if (errno == EEXIST)
+ return NFS3ERR_EXIST;
+ else if (errno == ENOSPC)
+ return NFS3ERR_NOSPC;
+#ifdef EDQUOT
+ else if (errno == EDQUOT)
+ return NFS3ERR_DQUOT;
+#endif
+ else if (errno == ENOSYS)
+ return NFS3ERR_NOTSUPP;
+ else if (errno == EINVAL)
+ return NFS3ERR_INVAL;
+ else
+ return NFS3ERR_IO;
+}
+
+nfsstat3 mkdir_err(void)
+{
+ return symlink_err();
+}
+
+nfsstat3 mknod_err(void)
+{
+ return symlink_err();
+}
+
+nfsstat3 link_err(void)
+{
+ if (errno == EXDEV)
+ return NFS3ERR_XDEV;
+ else if (errno == EMLINK)
+ return NFS3ERR_MLINK;
+#ifdef EDQUOT
+ else if (errno == EDQUOT)
+ return NFS3ERR_DQUOT;
+#endif
+ else
+ return symlink_err();
+}
+
+nfsstat3 lookup_err(void)
+{
+ if (errno == ENOENT)
+ return NFS3ERR_NOENT;
+#ifdef ENOMEDIUM
+ else if (errno == ENOMEDIUM)
+ return NFS3ERR_NOENT;
+#endif
+ else if (errno == EACCES)
+ return NFS3ERR_ACCES;
+ else if (errno == ENOTDIR || errno == ELOOP || errno == ENAMETOOLONG)
+ return NFS3ERR_STALE;
+ else if (errno == EINVAL)
+ return NFS3ERR_INVAL;
+ else
+ return NFS3ERR_IO;
+}
+
+nfsstat3 readlink_err(void)
+{
+ if (errno == EINVAL)
+ return NFS3ERR_INVAL;
+ else if (errno == EACCES)
+ return NFS3ERR_ACCES;
+ else if (errno == ENOSYS)
+ return NFS3ERR_NOTSUPP;
+ else if (is_stale())
+ return NFS3ERR_STALE;
+ else
+ return NFS3ERR_IO;
+}
+
+nfsstat3 read_err(void)
+{
+ if (errno == EINVAL)
+ return NFS3ERR_INVAL;
+ else if (is_stale())
+ return NFS3ERR_STALE;
+ else if (errno == EACCES)
+ return NFS3ERR_ACCES;
+ else if (errno == ENXIO || errno == ENODEV)
+ return NFS3ERR_NXIO;
+ else
+ return NFS3ERR_IO;
+}
+
+nfsstat3 write_open_err(void)
+{
+ if (errno == EACCES)
+ return NFS3ERR_ACCES;
+ else if (is_stale())
+ return NFS3ERR_STALE;
+ else if (errno == EINVAL)
+ return NFS3ERR_INVAL;
+ else if (errno == EROFS)
+ return NFS3ERR_ROFS;
+ else
+ return NFS3ERR_IO;
+}
+
+nfsstat3 write_write_err(void)
+{
+ if (errno == EINVAL)
+ return NFS3ERR_INVAL;
+ else if (errno == EFBIG)
+ return NFS3ERR_FBIG;
+ else if (errno == ENOSPC)
+ return NFS3ERR_NOSPC;
+#ifdef EDQUOT
+ else if (errno == EDQUOT)
+ return NFS3ERR_DQUOT;
+#endif
+ else
+ return NFS3ERR_IO;
+}
+
+nfsstat3 create_err(void)
+{
+ if (errno == EACCES)
+ return NFS3ERR_ACCES;
+ else if (is_stale())
+ return NFS3ERR_STALE;
+ else if (errno == EROFS)
+ return NFS3ERR_ROFS;
+ else if (errno == ENOSPC)
+ return NFS3ERR_NOSPC;
+ else if (errno == EEXIST)
+ return NFS3ERR_EXIST;
+#ifdef EDQUOT
+ else if (errno == EDQUOT)
+ return NFS3ERR_DQUOT;
+#endif
+ else
+ return NFS3ERR_IO;
+}
+
+nfsstat3 rename_err(void)
+{
+ if (errno == EISDIR)
+ return NFS3ERR_ISDIR;
+ else if (errno == EXDEV)
+ return NFS3ERR_XDEV;
+ else if (errno == EEXIST)
+ return NFS3ERR_EXIST;
+ else if (errno == ENOTEMPTY)
+ return NFS3ERR_NOTEMPTY;
+ else if (errno == EINVAL)
+ return NFS3ERR_INVAL;
+ else if (errno == ENOTDIR)
+ return NFS3ERR_NOTDIR;
+ else if (errno == EACCES || errno == EPERM)
+ return NFS3ERR_ACCES;
+ else if (errno == ENOENT)
+ return NFS3ERR_NOENT;
+ else if (errno == ELOOP || errno == ENAMETOOLONG)
+ return NFS3ERR_STALE;
+ else if (errno == EROFS)
+ return NFS3ERR_ROFS;
+ else if (errno == ENOSPC)
+ return NFS3ERR_NOSPC;
+#ifdef EDQUOT
+ else if (errno == EDQUOT)
+ return NFS3ERR_DQUOT;
+#endif
+ else
+ return NFS3ERR_IO;
+}
+
+nfsstat3 remove_err(void)
+{
+ if (errno == EACCES || errno == EPERM)
+ return NFS3ERR_ACCES;
+ else if (errno == ENOENT)
+ return ENOENT;
+ else if (errno == ENOTDIR || errno == ELOOP || errno == ENAMETOOLONG)
+ return NFS3ERR_STALE;
+ else if (errno == EINVAL)
+ return NFS3ERR_INVAL;
+ else if (errno == EROFS)
+ return NFS3ERR_ROFS;
+ else
+ return NFS3ERR_IO;
+}
+
+nfsstat3 rmdir_err(void)
+{
+ if (errno == ENOTEMPTY)
+ return NFS3ERR_NOTEMPTY;
+ else
+ return remove_err();
+}
+
+nfsstat3 setattr_err(void)
+{
+ if (errno == EPERM)
+ return NFS3ERR_PERM;
+ else if (errno == EROFS)
+ return NFS3ERR_ROFS;
+ else if (is_stale())
+ return NFS3ERR_STALE;
+ else if (errno == EACCES)
+ return NFS3ERR_ACCES;
+#ifdef EDQUOT
+ else if (errno == EDQUOT)
+ return NFS3ERR_DQUOT;
+#endif
+ else if (errno == EINVAL)
+ return NFS3ERR_INVAL;
+ else
+ return NFS3ERR_IO;
+}
+
+nfsstat3 readdir_err(void)
+{
+ if (errno == EPERM)
+ return NFS3ERR_PERM;
+ else if (errno == EACCES)
+ return NFS3ERR_ACCES;
+ else if (errno == ENOTDIR)
+ return NFS3ERR_NOTDIR;
+ else if (is_stale())
+ return NFS3ERR_STALE;
+ else if (errno == EINVAL)
+ return NFS3ERR_INVAL;
+ else
+ return NFS3ERR_IO;
+}
+
+/*
+ * combine two error values
+ */
+nfsstat3 join(nfsstat3 x, nfsstat3 y)
+{
+ return (x != NFS3_OK) ? x : y;
+}
+
+/*
+ * combine three error values
+ */
+nfsstat3 join3(nfsstat3 x, nfsstat3 y, nfsstat3 z)
+{
+ return (x != NFS3_OK) ? x : join(y, z);
+}
diff --git a/external/fs/unfs3-0.9.22/error.h b/external/fs/unfs3-0.9.22/error.h
new file mode 100644
index 0000000..1787a09
--- /dev/null
+++ b/external/fs/unfs3-0.9.22/error.h
@@ -0,0 +1,29 @@
+/*
+ * UNFS3 error translation
+ * (C) 2004, Pascal Schmidt
+ * see file LICENSE for license details
+ */
+
+#ifndef UNFS3_ERROR_H
+#define UNFS3_ERROR_H
+
+nfsstat3 symlink_err(void);
+nfsstat3 remove_err(void);
+nfsstat3 rmdir_err(void);
+nfsstat3 setattr_err(void);
+nfsstat3 readdir_err(void);
+nfsstat3 mkdir_err(void);
+nfsstat3 mknod_err(void);
+nfsstat3 link_err(void);
+nfsstat3 lookup_err(void);
+nfsstat3 readlink_err(void);
+nfsstat3 read_err(void);
+nfsstat3 write_open_err(void);
+nfsstat3 write_write_err(void);
+nfsstat3 create_err(void);
+nfsstat3 rename_err(void);
+
+nfsstat3 join(nfsstat3, nfsstat3);
+nfsstat3 join3(nfsstat3, nfsstat3, nfsstat3);
+
+#endif
diff --git a/external/fs/unfs3-0.9.22/fd_cache.c b/external/fs/unfs3-0.9.22/fd_cache.c
new file mode 100644
index 0000000..e22b636
--- /dev/null
+++ b/external/fs/unfs3-0.9.22/fd_cache.c
@@ -0,0 +1,398 @@
+
+/*
+ * UNFS3 file descriptor cache
+ * (C) 2004, Pascal Schmidt
+ * see file LICENSE for license details
+ */
+
+#include "config.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <rpc/rpc.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <time.h>
+#ifndef WIN32
+#include <syslog.h>
+#include <unistd.h>
+#endif /* WIN32 */
+
+#include "nfs.h"
+#include "mount.h"
+#include "fh.h"
+#include "daemon.h"
+#include "Config/exports.h"
+#include "fd_cache.h"
+#include "backend.h"
+
+/*
+ * intention of the file descriptor cache
+ *
+ * for READ operations, the intent is to open() the file on the first
+ * access and to close() it when we hit EOF or after two seconds of
+ * inactivity.
+ *
+ * for WRITE operations, the intent is to open() the file on the first
+ * UNSTABLE access and to close() it when COMMIT is called or after
+ * two seconds of inactivity.
+ *
+ * There are three states of an entry:
+ * 1) Unused. use == 0.
+ * 2) Open fd. use != 0, fd != -1.
+ * 3) Pending fsync/close error, to be reported in next COMMIT or WRITE. use != 0, fd == -1.
+ *
+ * Handling fsync/close errors 100% correctly is very difficult for a
+ * user space server. Although rare, fsync/close might fail, for
+ * example when out of quota or closing a file on a NFS file
+ * system. The most correct way of handling these errors would be to
+ * keep track of "dirty" and failed ranges. However, this would
+ * require runtime memory allocation, with no known upper bound, which
+ * in turn can lead to DOS attacks etc. Our solution returns a
+ * fsync/close error in the first WRITE or COMMIT
+ * response. Additionally, the write verifier is changed. Subsequent
+ * COMMITs may succeed even though data has been lost, but since the
+ * verifier is changed, clients will notice this and re-send their
+ * data. Eventually, with some luck, all clients will get an IO error.
+ */
+
+/* number of entries in fd cache */
+#define FD_ENTRIES 256
+
+/* The number of seconds to wait before closing inactive fd */
+#define INACTIVE_TIMEOUT 2
+
+/* The number of seconds to keep pending errors */
+#define PENDING_ERROR_TIMEOUT 7200 /* 2 hours */
+
+typedef struct {
+ int fd; /* open file descriptor */
+ int kind; /* read or write */
+ time_t use; /* last use */
+ uint32 dev; /* device */
+ uint64 ino; /* inode */
+ uint32 gen; /* inode generation */
+} fd_cache_t;
+
+static fd_cache_t fd_cache[FD_ENTRIES];
+
+/* statistics */
+int fd_cache_readers = 0;
+int fd_cache_writers = 0;
+
+/*
+ * initialize the fd cache
+ */
+void fd_cache_init(void)
+{
+ int i;
+
+ for (i = 0; i < FD_ENTRIES; i++) {
+ fd_cache[i].fd = -1;
+ fd_cache[i].kind = UNFS3_FD_READ;
+ fd_cache[i].use = 0;
+ fd_cache[i].dev = 0;
+ fd_cache[i].ino = 0;
+ fd_cache[i].gen = 0;
+ }
+}
+
+/*
+ * find cache index to use for new entry
+ * returns an empty slot if found, else return error
+ */
+static int fd_cache_unused(void)
+{
+ int i;
+ static time_t last_warning = 0;
+
+ for (i = 0; i < FD_ENTRIES; i++) {
+ if (fd_cache[i].use == 0)
+ return i;
+ }
+
+ /* Do not print warning more than once per 10 second */
+ if (time(NULL) > last_warning + 10) {
+ last_warning = time(NULL);
+ logmsg(LOG_INFO,
+ "fd cache full due to more than %d active files or pending IO errors",
+ FD_ENTRIES);
+ }
+
+ return -1;
+}
+
+/*
+
+ * remove an entry from the cache. The keep_on_error variable
+ * indicates if the entry should be kept in the cache upon
+ * fsync/close failures. It should be set to TRUE when fd_cache_del is
+ * called from a code path which cannot report an IO error back to the
+ * client through WRITE or COMMIT.
+ */
+static int fd_cache_del(int idx, int keep_on_error)
+{
+ int res1, res2;
+
+ res1 = -1;
+
+ if (fd_cache[idx].fd != -1) {
+ if (fd_cache[idx].kind == UNFS3_FD_WRITE) {
+ /* sync file data if writing descriptor */
+ fd_cache_writers--;
+ res1 = backend_fsync(fd_cache[idx].fd);
+ } else {
+ fd_cache_readers--;
+ res1 = 0;
+ }
+ res2 = backend_close(fd_cache[idx].fd);
+ fd_cache[idx].fd = -1;
+
+ /* return -1 if something went wrong during sync or close */
+ if (res1 == -1 || res2 == -1) {
+ res1 = -1;
+ }
+ } else
+ /* pending error */
+ errno = EIO;
+
+ if (res1 == -1 && !keep_on_error) {
+ /* The verifier should not be changed until we actually report &
+ remove the error */
+ regenerate_write_verifier();
+ }
+
+ if (res1 != -1 || !keep_on_error) {
+ fd_cache[idx].fd = -1;
+ fd_cache[idx].use = 0;
+ fd_cache[idx].dev = 0;
+ fd_cache[idx].ino = 0;
+ fd_cache[idx].gen = 0;
+ }
+
+ return res1;
+}
+
+/*
+ * add an entry to the cache
+ */
+static void fd_cache_add(int fd, unfs3_fh_t * ufh, int kind)
+{
+ int idx;
+
+ idx = fd_cache_unused();
+ if (idx != -1) {
+ /* update statistics */
+ if (kind == UNFS3_FD_READ)
+ fd_cache_readers++;
+ else
+ fd_cache_writers++;
+
+ fd_cache[idx].fd = fd;
+ fd_cache[idx].kind = kind;
+ fd_cache[idx].use = time(NULL);
+ fd_cache[idx].dev = ufh->dev;
+ fd_cache[idx].ino = ufh->ino;
+ fd_cache[idx].gen = ufh->gen;
+ }
+}
+
+/*
+ * find entry by operating system fd number
+ */
+static int idx_by_fd(int fd, int kind)
+{
+ int i;
+ int idx = -1;
+
+ for (i = 0; i < FD_ENTRIES; i++)
+ if (fd_cache[i].fd == fd && fd_cache[i].kind == kind) {
+ idx = i;
+ break;
+ }
+ return idx;
+}
+
+/*
+ * find entry by fh (device, inode, and generation number)
+ */
+static int idx_by_fh(unfs3_fh_t * ufh, int kind)
+{
+ int i;
+ int idx = -1;
+
+ for (i = 0; i < FD_ENTRIES; i++)
+ if (fd_cache[i].kind == kind) {
+ if (fd_cache[i].dev == ufh->dev && fd_cache[i].ino == ufh->ino &&
+ fd_cache[i].gen == ufh->gen) {
+ idx = i;
+ break;
+ }
+ }
+ return idx;
+}
+
+/*
+ * open a file descriptor
+ * uses fd from cache if possible
+ */
+int fd_open(const char *path, nfs_fh3 nfh, int kind, int allow_caching)
+{
+ int idx, res, fd;
+ backend_statstruct buf;
+ unfs3_fh_t *fh = (void *) nfh.data.data_val;
+
+ idx = idx_by_fh(fh, kind);
+
+ if (idx != -1) {
+ if (fd_cache[idx].fd == -1) {
+ /* pending error, report to client and remove from cache */
+ fd_cache_del(idx, FALSE);
+ return -1;
+ }
+ return fd_cache[idx].fd;
+ } else {
+ /* call open to obtain new fd */
+ if (kind == UNFS3_FD_READ)
+ fd = backend_open(path, O_RDONLY);
+ else
+ fd = backend_open(path, O_WRONLY);
+ if (fd == -1)
+ return -1;
+
+ /* check for local fs race */
+ res = backend_fstat(fd, &buf);
+ if ((res == -1) ||
+ (fh->dev != buf.st_dev || fh->ino != buf.st_ino ||
+ fh->gen != backend_get_gen(buf, fd, path))) {
+ /*
+ * local fs changed meaning of path between
+ * calling NFS operation doing fh_decomp and
+ * arriving here
+ *
+ * set errno to ELOOP to make calling NFS
+ * operation return NFS3ERR_STALE
+ */
+ backend_close(fd);
+ errno = ELOOP;
+ return -1;
+ }
+
+ /*
+ * success, add to cache for later use
+ */
+ if (allow_caching)
+ fd_cache_add(fd, fh, kind);
+ return fd;
+ }
+}
+
+/*
+ * close a file descriptor
+ * returns error number from real close() if applicable
+ */
+int fd_close(int fd, int kind, int really_close)
+{
+ int idx, res1 = 0, res2 = 0;
+
+ idx = idx_by_fd(fd, kind);
+ if (idx != -1) {
+ /* update usage time of cache entry */
+ fd_cache[idx].use = time(NULL);
+
+ if (really_close == FD_CLOSE_REAL)
+ /* delete entry on real close, will close() fd */
+ return fd_cache_del(idx, FALSE);
+ else
+ return 0;
+ } else {
+ /* not in cache, sync and close directly */
+ if (kind == UNFS3_FD_WRITE)
+ res1 = backend_fsync(fd);
+
+ res2 = backend_close(fd);
+
+ if (res1 != 0)
+ return res1;
+ else
+ return res2;
+ }
+}
+
+/*
+ * sync file descriptor data to disk
+ */
+int fd_sync(nfs_fh3 nfh)
+{
+ int idx;
+ unfs3_fh_t *fh = (void *) nfh.data.data_val;
+
+ idx = idx_by_fh(fh, UNFS3_FD_WRITE);
+ if (idx != -1)
+ /* delete entry, will fsync() and close() the fd */
+ return fd_cache_del(idx, FALSE);
+ else
+ return 0;
+}
+
+/*
+ * purge/shutdown the cache
+ */
+void fd_cache_purge(void)
+{
+ int i;
+
+ /* close any open file descriptors we still have */
+ for (i = 0; i < FD_ENTRIES; i++) {
+ if (fd_cache[i].use != 0) {
+ if (fd_cache_del(i, TRUE) == -1)
+ logmsg(LOG_CRIT,
+ "Error during shutdown fsync/close for dev %lu, inode %lu",
+ fd_cache[i].dev, fd_cache[i].ino);
+
+ }
+ }
+}
+
+/*
+ * close inactive fds
+ */
+void fd_cache_close_inactive(void)
+{
+ time_t now;
+ int i;
+ int found_error = 0;
+ int active_error = 0;
+
+ now = time(NULL);
+ for (i = 0; i < FD_ENTRIES; i++) {
+ /* Check for inactive open fds */
+ if (fd_cache[i].use && fd_cache[i].fd != -1 &&
+ fd_cache[i].use + INACTIVE_TIMEOUT < now) {
+ fd_cache_del(i, TRUE);
+ }
+
+ /* Check for inactive pending errors */
+ if (fd_cache[i].use && fd_cache[i].fd == -1) {
+ found_error = 1;
+ if (fd_cache[i].use + PENDING_ERROR_TIMEOUT > now)
+ active_error = 1;
+ }
+ }
+
+ if (found_error && !active_error) {
+ /* All pending errors are old. Delete them all from the table and
+ generate new verifier. This is done to prevent the table from
+ filling up with old pending errors, perhaps for files that never
+ will be written again. In this case, we throw away the errors, and
+ change the server verifier. If clients has pending COMMITs, they
+ will notify the changed verifier and re-send. */
+ for (i = 0; i < FD_ENTRIES; i++) {
+ if (fd_cache[i].use && fd_cache[i].fd == -1) {
+ fd_cache_del(i, FALSE);
+ }
+ }
+ regenerate_write_verifier();
+ }
+}
diff --git a/external/fs/unfs3-0.9.22/fd_cache.h b/external/fs/unfs3-0.9.22/fd_cache.h
new file mode 100644
index 0000000..3812c5d
--- /dev/null
+++ b/external/fs/unfs3-0.9.22/fd_cache.h
@@ -0,0 +1,29 @@
+/*
+ * UNFS3 file descriptor cache
+ * (C) 2004, Pascal Schmidt
+ * see file LICENSE for license details
+ */
+
+#ifndef UNFS3_FD_CACHE_H
+#define UNFS3_FD_CACHE_H
+
+/* FD_READ and FD_WRITE are already defined on Win32 */
+#define UNFS3_FD_READ 0 /* fd for READ */
+#define UNFS3_FD_WRITE 1 /* fd for WRITE */
+
+#define FD_CLOSE_VIRT 0 /* virtually close the fd */
+#define FD_CLOSE_REAL 1 /* really close the fd */
+
+/* statistics */
+extern int fd_cache_readers;
+extern int fd_cache_writers;
+
+void fd_cache_init(void);
+
+int fd_open(const char *path, nfs_fh3 fh, int kind, int allow_caching);
+int fd_close(int fd, int kind, int really_close);
+int fd_sync(nfs_fh3 nfh);
+void fd_cache_purge(void);
+void fd_cache_close_inactive(void);
+
+#endif
diff --git a/external/fs/unfs3-0.9.22/fh.c b/external/fs/unfs3-0.9.22/fh.c
new file mode 100644
index 0000000..46c66cd
--- /dev/null
+++ b/external/fs/unfs3-0.9.22/fh.c
@@ -0,0 +1,473 @@
+
+/*
+ * UNFS3 low-level filehandle routines
+ * (C) 2004, Pascal Schmidt
+ * see file LICENSE for license details
+ */
+
+#include "config.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#ifndef WIN32
+#include <sys/ioctl.h>
+#include <syslog.h>
+#endif /* WIN32 */
+#include <rpc/rpc.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#if HAVE_LINUX_EXT2_FS_H == 1
+
+/*
+ * presence of linux/ext2_fs.h is a hint that we are on Linux, really
+ * including that file doesn't work on Debian, so define the ioctl
+ * number here
+ */
+#define EXT2_IOC_GETVERSION 0x80047601
+#endif
+
+#include "nfs.h"
+#include "mount.h"
+#include "daemon.h"
+#include "fh.h"
+#include "backend.h"
+#include "Config/exports.h"
+
+/*
+ * hash function for inode numbers
+ */
+#define FH_HASH(n) ((n ^ (n >> 8) ^ (n >> 16) ^ (n >> 24) ^ (n >> 32) ^ (n >> 40) ^ (n >> 48) ^ (n >> 56)) & 0xFF)
+
+/*
+ * stat cache
+ */
+int st_cache_valid = FALSE;
+backend_statstruct st_cache;
+
+/*
+ * --------------------------------
+ * INODE GENERATION NUMBER HANDLING
+ * --------------------------------
+ */
+
+/*
+ * obtain inode generation number if possible
+ *
+ * obuf: filled out stat buffer (must be given!)
+ * fd: open fd to file or FD_NONE (-1) if no fd open
+ * path: path to object in case we need to open it here
+ *
+ * returns 0 on failure
+ */
+uint32 get_gen(backend_statstruct obuf, U(int fd), U(const char *path))
+{
+#if HAVE_STRUCT_STAT_ST_GEN == 1
+ return obuf.st_gen;
+#endif
+
+#if HAVE_STRUCT_STAT_ST_GEN == 0 && HAVE_LINUX_EXT2_FS_H == 1
+ int newfd, res;
+ uint32 gen;
+ uid_t euid;
+ gid_t egid;
+
+ if (!S_ISREG(obuf.st_mode) && !S_ISDIR(obuf.st_mode))
+ return 0;
+
+ euid = backend_geteuid();
+ egid = backend_getegid();
+ backend_setegid(0);
+ backend_seteuid(0);
+
+ if (fd != FD_NONE) {
+ res = ioctl(fd, EXT2_IOC_GETVERSION, &gen);
+ if (res == -1)
+ gen = 0;
+ } else {
+ newfd = backend_open(path, O_RDONLY);
+ if (newfd == -1)
+ gen = 0;
+ else {
+ res = ioctl(newfd, EXT2_IOC_GETVERSION, &gen);
+ close(newfd);
+
+ if (res == -1)
+ gen = 0;
+ }
+ }
+
+ backend_setegid(egid);
+ backend_seteuid(euid);
+
+ if (backend_geteuid() != euid || backend_getegid() != egid) {
+ logmsg(LOG_EMERG, "euid/egid switching failed, aborting");
+ daemon_exit(CRISIS);
+ }
+
+ return gen;
+#endif
+
+#if HAVE_STRUCT_STAT_ST_GEN == 0 && HAVE_LINUX_EXT2_FS_H == 0
+ return obuf.st_ino;
+#endif
+}
+
+/*
+ * --------------------------------
+ * FILEHANDLE COMPOSITION FUNCTIONS
+ * --------------------------------
+ */
+
+/*
+ * check whether an NFS filehandle is valid
+ */
+int nfh_valid(nfs_fh3 fh)
+{
+ unfs3_fh_t *obj = (void *) fh.data.data_val;
+
+ /* too small? */
+ if (fh.data.data_len < FH_MINLEN)
+ return FALSE;
+
+ /* encoded length different from real length? */
+ if (fh.data.data_len != fh_length(obj))
+ return FALSE;
+
+ return TRUE;
+}
+
+/*
+ * check whether a filehandle is valid
+ */
+int fh_valid(unfs3_fh_t fh)
+{
+ /* invalid filehandles have zero device and inode */
+ return (int) (fh.dev != 0 || fh.ino != 0);
+}
+
+/*
+ * invalid fh for error returns
+ */
+#ifdef __GNUC__
+static const unfs3_fh_t invalid_fh = {.dev = 0,.ino = 0,.gen = 0,.len =
+ 0,.inos = {0}
+};
+#else
+static const unfs3_fh_t invalid_fh = { 0, 0, 0, 0, {0} };
+#endif
+
+/*
+ * compose a filehandle for a given path
+ * path: path to compose fh for
+ * rqstp: If not NULL, generate special FHs for removables
+ * need_dir: if not 0, path must point to a directory
+ */
+unfs3_fh_t fh_comp_raw(const char *path, struct svc_req *rqstp, int need_dir)
+{
+ char work[NFS_MAXPATHLEN];
+ unfs3_fh_t fh;
+ backend_statstruct buf;
+ int res;
+ char *last;
+ int pos = 0;
+
+ fh.len = 0;
+
+ /* special case for removable device export point: return preset fsid and
+ inod 1. */
+ if (rqstp && export_point(path)) {
+ uint32 fsid;
+
+ if (exports_options(path, rqstp, NULL, &fsid) == -1) {
+ /* Shouldn't happen, unless the exports file changed after the
+ call to export_point() */
+ return invalid_fh;
+ }
+ if (exports_opts & OPT_REMOVABLE) {
+ fh.dev = fsid;
+ /* There's a small risk that the file system contains other file
+ objects with st_ino = 1. This should be fairly uncommon,
+ though. The FreeBSD fs(5) man page says:
+
+ "The root inode is the root of the file system. Inode 0
+ cannot be used for normal purposes and historically bad blocks
+ were linked to inode 1, thus the root inode is 2 (inode 1 is
+ no longer used for this purpose, however numerous dump tapes
+ make this assumption, so we are stuck with it)."
+
+ In Windows, there's also a small risk that the hash ends up
+ being exactly 1. */
+ fh.ino = 0x1;
+ fh.gen = 0;
+ return fh;
+ }
+ }
+
+ res = backend_lstat(path, &buf);
+ if (res == -1)
+ return invalid_fh;
+
+ /* check for dir if need_dir is set */
+ if (need_dir != 0 && !S_ISDIR(buf.st_mode))
+ return invalid_fh;
+
+ fh.dev = buf.st_dev;
+ fh.ino = buf.st_ino;
+ fh.gen = backend_get_gen(buf, FD_NONE, path);
+
+ /* special case for root directory */
+ if (strcmp(path, "/") == 0)
+ return fh;
+
+ strcpy(work, path);
+ last = work;
+
+ do {
+ *last = '/';
+ last = strchr(last + 1, '/');
+ if (last != NULL)
+ *last = 0;
+
+ res = backend_lstat(work, &buf);
+ if (res == -1) {
+ return invalid_fh;
+ }
+
+ /* store 8 bit hash of the component's inode */
+ fh.inos[pos] = FH_HASH(buf.st_ino);
+ pos++;
+
+ } while (last && pos < FH_MAXLEN);
+
+ if (last) /* path too deep for filehandle */
+ return invalid_fh;
+
+ fh.len = pos;
+
+ return fh;
+}
+
+/*
+ * get real length of a filehandle
+ */
+u_int fh_length(const unfs3_fh_t * fh)
+{
+ return fh->len + sizeof(fh->len) + sizeof(fh->dev) + sizeof(fh->ino) +
+ sizeof(fh->gen) + sizeof(fh->pwhash);
+}
+
+/*
+ * extend a filehandle with a given device, inode, and generation number
+ */
+unfs3_fh_t *fh_extend(nfs_fh3 nfh, uint32 dev, uint64 ino, uint32 gen)
+{
+ static unfs3_fh_t new;
+ unfs3_fh_t *fh = (void *) nfh.data.data_val;
+
+ memcpy(&new, fh, fh_length(fh));
+
+ if (new.len == 0) {
+ char *path;
+
+ path = export_point_from_fsid(new.dev, NULL, NULL);
+ if (path != NULL) {
+ /* Our FH to extend refers to a removable device export point,
+ which lacks .inos. We need to construct a real FH to extend,
+ which can be done by passing rqstp=NULL to fh_comp_raw. */
+ new = fh_comp_raw(path, NULL, FH_ANY);
+ if (!fh_valid(new))
+ return NULL;
+ }
+ }
+
+ if (new.len == FH_MAXLEN)
+ return NULL;
+
+ new.dev = dev;
+ new.ino = ino;
+ new.gen = gen;
+ new.pwhash = export_password_hash;
+ new.inos[new.len] = FH_HASH(ino);
+ new.len++;
+
+ return &new;
+}
+
+/*
+ * get post_op_fh3 extended by device, inode, and generation number
+ */
+post_op_fh3 fh_extend_post(nfs_fh3 fh, uint32 dev, uint64 ino, uint32 gen)
+{
+ post_op_fh3 post;
+ unfs3_fh_t *new;
+
+ new = fh_extend(fh, dev, ino, gen);
+
+ if (new) {
+ post.handle_follows = TRUE;
+ post.post_op_fh3_u.handle.data.data_len = fh_length(new);
+ post.post_op_fh3_u.handle.data.data_val = (char *) new;
+ } else
+ post.handle_follows = FALSE;
+
+ return post;
+}
+
+/*
+ * extend a filehandle given a path and needed type
+ */
+post_op_fh3 fh_extend_type(nfs_fh3 fh, const char *path, unsigned int type)
+{
+ post_op_fh3 result;
+ backend_statstruct buf;
+ int res;
+
+ res = backend_lstat(path, &buf);
+ if (res == -1 || (buf.st_mode & type) != type) {
+ st_cache_valid = FALSE;
+ result.handle_follows = FALSE;
+ return result;
+ }
+
+ st_cache_valid = TRUE;
+ st_cache = buf;
+
+ return fh_extend_post(fh, buf.st_dev, buf.st_ino,
+ backend_get_gen(buf, FD_NONE, path));
+}
+
+/*
+ * -------------------------------
+ * FILEHANDLE RESOLUTION FUNCTIONS
+ * -------------------------------
+ */
+
+/*
+ * filehandles have the following fields:
+ * dev: device of the file system object fh points to
+ * ino: inode of the file system object fh points to
+ * gen: inode generation number, if available
+ * len: number of entries in following inos array
+ * inos: array of max FH_MAXLEN directories needed to traverse to reach
+ * object, for each name, an 8 bit hash of the inode number is stored
+ *
+ * - search functions traverse directory structure from the root looking
+ * for directories matching the inode information stored
+ * - if such a directory is found, we descend into it trying to locate the
+ * object
+ */
+
+/*
+ * recursive directory search
+ * fh: filehandle being resolved
+ * pos: position in filehandles path inode array
+ * lead: current directory for search
+ * result: where to store path if seach is complete
+ */
+static int fh_rec(const unfs3_fh_t * fh, int pos, const char *lead,
+ char *result)
+{
+ backend_dirstream *search;
+ struct dirent *entry;
+ backend_statstruct buf;
+ int res, rec;
+ char obj[NFS_MAXPATHLEN];
+
+ /* There's a slight risk of multiple files with the same st_ino on
+ Windows. Take extra care and make sure that there are no collisions */
+ unsigned short matches = 0;
+
+ /* went in too deep? */
+ if (pos == fh->len)
+ return FALSE;
+
+ search = backend_opendir(lead);
+ if (!search)
+ return FALSE;
+
+ entry = backend_readdir(search);
+
+ while (entry) {
+ if (strlen(lead) + strlen(entry->d_name) + 1 < NFS_MAXPATHLEN) {
+
+ sprintf(obj, "%s/%s", lead, entry->d_name);
+
+ res = backend_lstat(obj, &buf);
+ if (res == -1) {
+ buf.st_dev = 0;
+ buf.st_ino = 0;
+ }
+
+ if (buf.st_dev == fh->dev && buf.st_ino == fh->ino) {
+ /* found the object */
+ sprintf(result, "%s/%s", lead + 1, entry->d_name);
+ /* update stat cache */
+ st_cache_valid = TRUE;
+ st_cache = buf;
+ matches++;
+#ifndef WIN32
+ break;
+#endif
+ }
+
+ if (strcmp(entry->d_name, "..") != 0 &&
+ strcmp(entry->d_name, ".") != 0 &&
+ FH_HASH(buf.st_ino) == fh->inos[pos]) {
+ /*
+ * might be directory we're looking for,
+ * try descending into it
+ */
+ rec = fh_rec(fh, pos + 1, obj, result);
+ if (rec) {
+ /* object was found in dir */
+ backend_closedir(search);
+ return TRUE;
+ }
+ }
+ }
+ entry = backend_readdir(search);
+ }
+
+ backend_closedir(search);
+ switch (matches) {
+ case 0:
+ return FALSE;
+ case 1:
+ return TRUE;
+ default:
+#ifdef WIN32
+ logmsg(LOG_CRIT, "Hash collision detected for file %s!", result);
+#endif
+ return FALSE;
+ }
+}
+
+/*
+ * resolve a filehandle into a path
+ */
+char *fh_decomp_raw(const unfs3_fh_t * fh)
+{
+ int rec = 0;
+ static char result[NFS_MAXPATHLEN];
+
+ /* valid fh? */
+ if (!fh)
+ return NULL;
+
+ /* special case for root directory */
+ if (fh->len == 0)
+ return "/";
+
+ rec = fh_rec(fh, 0, "/", result);
+
+ if (rec)
+ return result;
+
+ /* could not find object */
+ return NULL;
+}
diff --git a/external/fs/unfs3-0.9.22/fh.h b/external/fs/unfs3-0.9.22/fh.h
new file mode 100644
index 0000000..341982f
--- /dev/null
+++ b/external/fs/unfs3-0.9.22/fh.h
@@ -0,0 +1,62 @@
+/*
+ * UNFS3 low-level filehandle routines
+ * (C) 2004, Pascal Schmidt
+ * see file LICENSE for license details
+ */
+
+#ifndef UNFS3_FH_H
+#define UNFS3_FH_H
+
+#include "backend.h"
+
+/* minimum length of complete filehandle */
+#define FH_MINLEN 21
+
+/* maximum depth of pathname described by filehandle */
+#define FH_MAXLEN (64 - FH_MINLEN)
+
+#ifdef __GNUC__
+typedef struct {
+ uint32 dev;
+ uint64 ino;
+ uint32 gen;
+ uint32 pwhash;
+ unsigned char len;
+ unsigned char inos[FH_MAXLEN];
+} __attribute__((packed)) unfs3_fh_t;
+#else
+#pragma pack(1)
+typedef struct {
+ uint32 dev;
+ uint64 ino;
+ uint32 gen;
+ uint32 pwhash;
+ unsigned char len;
+ unsigned char inos[FH_MAXLEN];
+} unfs3_fh_t;
+#pragma pack(4)
+#endif
+
+#define FH_ANY 0
+#define FH_DIR 1
+
+#define FD_NONE (-1) /* used for get_gen */
+
+extern int st_cache_valid; /* stat value is valid */
+extern backend_statstruct st_cache; /* cached stat value */
+
+uint32 get_gen(backend_statstruct obuf, int fd, const char *path);
+
+int nfh_valid(nfs_fh3 fh);
+int fh_valid(unfs3_fh_t fh);
+
+unfs3_fh_t fh_comp_raw(const char *path, struct svc_req *rqstp, int need_dir);
+u_int fh_length(const unfs3_fh_t *fh);
+
+unfs3_fh_t *fh_extend(nfs_fh3 fh, uint32 dev, uint64 ino, uint32 gen);
+post_op_fh3 fh_extend_post(nfs_fh3 fh, uint32 dev, uint64 ino, uint32 gen);
+post_op_fh3 fh_extend_type(nfs_fh3 fh, const char *path, unsigned int type);
+
+char *fh_decomp_raw(const unfs3_fh_t *fh);
+
+#endif
diff --git a/external/fs/unfs3-0.9.22/fh_cache.c b/external/fs/unfs3-0.9.22/fh_cache.c
new file mode 100644
index 0000000..b411469
--- /dev/null
+++ b/external/fs/unfs3-0.9.22/fh_cache.c
@@ -0,0 +1,347 @@
+
+/*
+ * UNFS3 filehandle cache
+ * (C) 2004
+ * see file LICENSE for license details
+ */
+
+#include "config.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <rpc/rpc.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <time.h>
+
+#include "nfs.h"
+#include "fh.h"
+#include "locate.h"
+#include "fh_cache.h"
+#include "mount.h"
+#include "daemon.h"
+#include "Config/exports.h"
+#include "readdir.h"
+#include "backend.h"
+
+/* number of entries in fh cache */
+#define CACHE_ENTRIES 4096
+
+typedef struct {
+ uint32 dev; /* device */
+ uint64 ino; /* inode */
+ char path[NFS_MAXPATHLEN]; /* pathname */
+ unsigned int use; /* last use */
+} unfs3_cache_t;
+
+static unfs3_cache_t fh_cache[CACHE_ENTRIES];
+
+/* statistics */
+int fh_cache_max = 0;
+int fh_cache_use = 0;
+int fh_cache_hit = 0;
+
+/* counter for LRU */
+static unsigned int fh_cache_time = 0;
+
+/*
+ * last returned entry
+ *
+ * this entry must not be overwritten before the next lookup, because
+ * operations such as CREATE may still be needing the path inside the
+ * entry for getting directory attributes
+ *
+ * this is needed since fh_cache_time can roll around to 0, thus
+ * making the entry evictable
+ */
+static int fh_last_entry = -1;
+
+/*
+ * return next pseudo-time value for LRU counter
+ */
+static unsigned int fh_cache_next(void)
+{
+ return ++fh_cache_time;
+}
+
+/*
+ * initialize cache
+ */
+void fh_cache_init(void)
+{
+ memset(fh_cache, 0, sizeof(unfs3_cache_t) * CACHE_ENTRIES);
+}
+
+/*
+ * find cache index to use for new entry
+ * returns either an empty slot or the least recently used slot if no
+ * empty slot is present
+ */
+static int fh_cache_lru(void)
+{
+ unsigned int best = UINT_MAX;
+ int best_idx = 0;
+ int i;
+
+ /* if cache is not full, we simply hand out the next slot */
+ if (fh_cache_max < CACHE_ENTRIES - 1)
+ return fh_cache_max++;
+
+ for (i = 0; i < CACHE_ENTRIES; i++) {
+ if (i == fh_last_entry)
+ continue;
+ if (fh_cache[i].use == 0)
+ return i;
+ if (fh_cache[i].use < best) {
+ best = fh_cache[i].use;
+ best_idx = i;
+ }
+ }
+
+ /* avoid stomping over last returned entry */
+ if (best_idx == 0 && fh_last_entry == 0)
+ best_idx = 1;
+
+ return best_idx;
+}
+
+/*
+ * invalidate (clear) a cache entry
+ */
+static void fh_cache_inval(int idx)
+{
+ fh_cache[idx].dev = 0;
+ fh_cache[idx].ino = 0;
+ fh_cache[idx].use = 0;
+ fh_cache[idx].path[0] = 0;
+}
+
+/*
+ * find index given device and inode number
+ */
+static int fh_cache_index(uint32 dev, uint64 ino)
+{
+ int i, res = -1;
+
+ for (i = 0; i < fh_cache_max + 1; i++)
+ if (fh_cache[i].dev == dev && fh_cache[i].ino == ino) {
+ res = i;
+ break;
+ }
+
+ return res;
+}
+
+/*
+ * add an entry to the filehandle cache
+ */
+char *fh_cache_add(uint32 dev, uint64 ino, const char *path)
+{
+ int idx;
+
+ /* if we already have a matching entry, overwrite that */
+ idx = fh_cache_index(dev, ino);
+
+ /* otherwise overwrite least recently used entry */
+ if (idx == -1)
+ idx = fh_cache_lru();
+
+ fh_cache[idx].dev = dev;
+ fh_cache[idx].ino = ino;
+ fh_cache[idx].use = fh_cache_next();
+
+ strcpy(fh_cache[idx].path, path);
+
+ return fh_cache[idx].path;
+}
+
+/*
+ * lookup an entry in the cache given a device, inode, and generation number
+ */
+static char *fh_cache_lookup(uint32 dev, uint64 ino)
+{
+ int i, res;
+ backend_statstruct buf;
+
+ i = fh_cache_index(dev, ino);
+
+ if (i != -1) {
+ /* check whether path to <dev,ino> relation still holds */
+ res = backend_lstat(fh_cache[i].path, &buf);
+ if (res == -1) {
+ /* object does not exist any more */
+ fh_cache_inval(i);
+ return NULL;
+ }
+ if (buf.st_dev == dev && buf.st_ino == ino) {
+ /* cache hit, update time on cache entry */
+ fh_cache[i].use = fh_cache_next();
+
+ /* update stat cache */
+ st_cache_valid = TRUE;
+ st_cache = buf;
+
+ /* prevent next fh_cache_add from overwriting entry */
+ fh_last_entry = i;
+
+ return fh_cache[i].path;
+ } else {
+ /* path to <dev,ino> relation has changed */
+ fh_cache_inval(i);
+ return NULL;
+ }
+ }
+
+ return NULL;
+}
+
+/*
+ * resolve a filename into a path
+ * cache-using wrapper for fh_decomp_raw
+ */
+char *fh_decomp(nfs_fh3 fh)
+{
+ char *result;
+ unfs3_fh_t *obj = (void *) fh.data.data_val;
+ time_t *last_mtime;
+ uint32 *dir_hash, new_dir_hash;
+
+ if (!nfh_valid(fh)) {
+ st_cache_valid = FALSE;
+ return NULL;
+ }
+
+ /* Does the fsid match some static fsid? */
+ if ((result =
+ export_point_from_fsid(obj->dev, &last_mtime, &dir_hash)) != NULL) {
+ if (obj->ino == 0x1) {
+ /* This FH refers to the export point itself */
+ /* Need to fill stat cache */
+ st_cache_valid = TRUE;
+
+ if (backend_lstat(result, &st_cache) == -1) {
+ /* export point does not exist. This probably means that we
+ are using autofs and no media is inserted. Fill stat cache
+ with dummy information */
+ st_cache.st_mode = S_IFDIR | S_IRWXU | S_IRWXG | S_IRWXO;
+ st_cache.st_nlink = 2;
+ st_cache.st_uid = 0;
+ st_cache.st_gid = 0;
+ st_cache.st_rdev = 0;
+ st_cache.st_size = 4096;
+ st_cache.st_blksize = 512;
+ st_cache.st_blocks = 8;
+ } else {
+ /* Stat was OK, but make sure the values are sane. Supermount
+ returns insane values when no media is inserted, for
+ example. */
+ if (st_cache.st_nlink == 0)
+ st_cache.st_nlink = 1;
+ if (st_cache.st_size == 0)
+ st_cache.st_size = 4096;
+ if (st_cache.st_blksize == 0)
+ st_cache.st_blksize = 512;
+ if (st_cache.st_blocks == 0)
+ st_cache.st_blocks = 8;
+ }
+
+ st_cache.st_dev = obj->dev;
+ st_cache.st_ino = 0x1;
+
+ /* It's very important that we get mtime correct, since it's used
+ as verifier in READDIR. The generation of mtime is tricky,
+ because with some filesystems, such as the Linux 2.4 FAT fs,
+ the mtime value for the mount point is set to *zero* on each
+ mount. I consider this a bug, but we need to work around it
+ anyway.
+
+ We store the last mtime returned. When stat returns a smaller
+ value than this, we double-check by doing a hash of the names
+ in the directory. If this hash is different from what we had
+ earlier, return current time.
+
+ Note: Since dir_hash is stored in memory, we have introduced a
+ little statefulness here. This means that if unfsd is
+ restarted during two READDIR calls, NFS3ERR_BAD_COOKIE will be
+ returned, and the client has to retry the READDIR operation
+ with a zero cookie */
+
+ if (st_cache.st_mtime > *last_mtime) {
+ /* stat says our directory has changed */
+ *last_mtime = st_cache.st_mtime;
+ } else if (*dir_hash != (new_dir_hash = directory_hash(result))) {
+ /* The names in the directory has changed. Return current
+ time. */
+ st_cache.st_mtime = time(NULL);
+ *last_mtime = st_cache.st_mtime;
+ *dir_hash = new_dir_hash;
+ } else {
+ /* Hash unchanged. Returned stored mtime. */
+ st_cache.st_mtime = *last_mtime;
+ }
+
+ return result;
+ }
+ }
+
+ /* try lookup in cache, increase cache usage counter */
+ result = fh_cache_lookup(obj->dev, obj->ino);
+ fh_cache_use++;
+
+ if (!result) {
+ /* not found, resolve the hard way */
+ result = fh_decomp_raw(obj);
+
+ /* if still not found, do full recursive search) */
+ if (!result)
+ result = backend_locate_file(obj->dev, obj->ino);
+
+ if (result)
+ /* add to cache for later use if resolution ok */
+ result = fh_cache_add(obj->dev, obj->ino, result);
+ else
+ /* could not resolve in any way */
+ st_cache_valid = FALSE;
+ } else
+ /* found, update cache hit statistic */
+ fh_cache_hit++;
+
+ return result;
+}
+
+/*
+ * compose a filehandle for a path
+ * cache-using wrapper for fh_comp_raw
+ * exports_options must be called before
+ */
+unfs3_fh_t fh_comp(const char *path, struct svc_req * rqstp, int need_dir)
+{
+ unfs3_fh_t res;
+
+ res = fh_comp_raw(path, rqstp, need_dir);
+ if (fh_valid(res))
+ /* add to cache for later use */
+ fh_cache_add(res.dev, res.ino, path);
+
+ res.pwhash = export_password_hash;
+ return res;
+}
+
+/*
+ * return pointer to composed filehandle
+ * wrapper for fh_comp
+ */
+unfs3_fh_t *fh_comp_ptr(const char *path, struct svc_req * rqstp,
+ int need_dir)
+{
+ static unfs3_fh_t res;
+
+ res = fh_comp(path, rqstp, need_dir);
+ if (fh_valid(res))
+ return &res;
+ else
+ return NULL;
+}
diff --git a/external/fs/unfs3-0.9.22/fh_cache.h b/external/fs/unfs3-0.9.22/fh_cache.h
new file mode 100644
index 0000000..5801709
--- /dev/null
+++ b/external/fs/unfs3-0.9.22/fh_cache.h
@@ -0,0 +1,23 @@
+/*
+ * UNFS3 filehandle cache
+ * (C) 2003, Pascal Schmidt
+ * see file LICENSE for license details
+ */
+
+#ifndef UNFS3_FH_CACHE_H
+#define UNFS3_FH_CACHE_H
+
+/* statistics */
+extern int fh_cache_max;
+extern int fh_cache_use;
+extern int fh_cache_hit;
+
+void fh_cache_init(void);
+
+char *fh_decomp(nfs_fh3 fh);
+unfs3_fh_t fh_comp(const char *path, struct svc_req *rqstp, int need_dir);
+unfs3_fh_t *fh_comp_ptr(const char *path, struct svc_req *rqstp, int need_dir);
+
+char *fh_cache_add(uint32 dev, uint64 ino, const char *path);
+
+#endif
diff --git a/external/fs/unfs3-0.9.22/indent-all b/external/fs/unfs3-0.9.22/indent-all
new file mode 100755
index 0000000..5ba6bb7
--- /dev/null
+++ b/external/fs/unfs3-0.9.22/indent-all
@@ -0,0 +1,5 @@
+#!/bin/sh
+indent -bad -bap -bbb -bli4 -br -brs -c40 -cbi4 -c40 -cdw -ce -ci4 -cli4 \
+ -cp40 -cs -d0 -di0 -fca -i4 -l78 -lc78 -lp -nbbo -nbc -nbfda -nhnl \
+ -npcs -nprs -npsl -pi0 -saf -sai -saw -sob -ss -ts8 -ut \
+ *.c Extras/*.c
diff --git a/external/fs/unfs3-0.9.22/install-sh b/external/fs/unfs3-0.9.22/install-sh
new file mode 100755
index 0000000..e9de238
--- /dev/null
+++ b/external/fs/unfs3-0.9.22/install-sh
@@ -0,0 +1,251 @@
+#!/bin/sh
+#
+# install - install a program, script, or datafile
+# This comes from X11R5 (mit/util/scripts/install.sh).
+#
+# Copyright 1991 by the Massachusetts Institute of Technology
+#
+# Permission to use, copy, modify, distribute, and sell this software and its
+# documentation for any purpose is hereby granted without fee, provided that
+# the above copyright notice appear in all copies and that both that
+# copyright notice and this permission notice appear in supporting
+# documentation, and that the name of M.I.T. not be used in advertising or
+# publicity pertaining to distribution of the software without specific,
+# written prior permission. M.I.T. makes no representations about the
+# suitability of this software for any purpose. It is provided "as is"
+# without express or implied warranty.
+#
+# Calling this script install-sh is preferred over install.sh, to prevent
+# `make' implicit rules from creating a file called install from it
+# when there is no Makefile.
+#
+# This script is compatible with the BSD install script, but was written
+# from scratch. It can only install one file at a time, a restriction
+# shared with many OS's install programs.
+
+
+# set DOITPROG to echo to test this script
+
+# Don't use :- since 4.3BSD and earlier shells don't like it.
+doit="${DOITPROG-}"
+
+
+# put in absolute paths if you don't have them in your path; or use env. vars.
+
+mvprog="${MVPROG-mv}"
+cpprog="${CPPROG-cp}"
+chmodprog="${CHMODPROG-chmod}"
+chownprog="${CHOWNPROG-chown}"
+chgrpprog="${CHGRPPROG-chgrp}"
+stripprog="${STRIPPROG-strip}"
+rmprog="${RMPROG-rm}"
+mkdirprog="${MKDIRPROG-mkdir}"
+
+transformbasename=""
+transform_arg=""
+instcmd="$mvprog"
+chmodcmd="$chmodprog 0755"
+chowncmd=""
+chgrpcmd=""
+stripcmd=""
+rmcmd="$rmprog -f"
+mvcmd="$mvprog"
+src=""
+dst=""
+dir_arg=""
+
+while [ x"$1" != x ]; do
+ case $1 in
+ -c) instcmd="$cpprog"
+ shift
+ continue;;
+
+ -d) dir_arg=true
+ shift
+ continue;;
+
+ -m) chmodcmd="$chmodprog $2"
+ shift
+ shift
+ continue;;
+
+ -o) chowncmd="$chownprog $2"
+ shift
+ shift
+ continue;;
+
+ -g) chgrpcmd="$chgrpprog $2"
+ shift
+ shift
+ continue;;
+
+ -s) stripcmd="$stripprog"
+ shift
+ continue;;
+
+ -t=*) transformarg=`echo $1 | sed 's/-t=//'`
+ shift
+ continue;;
+
+ -b=*) transformbasename=`echo $1 | sed 's/-b=//'`
+ shift
+ continue;;
+
+ *) if [ x"$src" = x ]
+ then
+ src=$1
+ else
+ # this colon is to work around a 386BSD /bin/sh bug
+ :
+ dst=$1
+ fi
+ shift
+ continue;;
+ esac
+done
+
+if [ x"$src" = x ]
+then
+ echo "install: no input file specified"
+ exit 1
+else
+ true
+fi
+
+if [ x"$dir_arg" != x ]; then
+ dst=$src
+ src=""
+
+ if [ -d $dst ]; then
+ instcmd=:
+ chmodcmd=""
+ else
+ instcmd=mkdir
+ fi
+else
+
+# Waiting for this to be detected by the "$instcmd $src $dsttmp" command
+# might cause directories to be created, which would be especially bad
+# if $src (and thus $dsttmp) contains '*'.
+
+ if [ -f $src -o -d $src ]
+ then
+ true
+ else
+ echo "install: $src does not exist"
+ exit 1
+ fi
+
+ if [ x"$dst" = x ]
+ then
+ echo "install: no destination specified"
+ exit 1
+ else
+ true
+ fi
+
+# If destination is a directory, append the input filename; if your system
+# does not like double slashes in filenames, you may need to add some logic
+
+ if [ -d $dst ]
+ then
+ dst="$dst"/`basename $src`
+ else
+ true
+ fi
+fi
+
+## this sed command emulates the dirname command
+dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
+
+# Make sure that the destination directory exists.
+# this part is taken from Noah Friedman's mkinstalldirs script
+
+# Skip lots of stat calls in the usual case.
+if [ ! -d "$dstdir" ]; then
+defaultIFS='
+'
+IFS="${IFS-${defaultIFS}}"
+
+oIFS="${IFS}"
+# Some sh's can't handle IFS=/ for some reason.
+IFS='%'
+set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'`
+IFS="${oIFS}"
+
+pathcomp=''
+
+while [ $# -ne 0 ] ; do
+ pathcomp="${pathcomp}${1}"
+ shift
+
+ if [ ! -d "${pathcomp}" ] ;
+ then
+ $mkdirprog "${pathcomp}"
+ else
+ true
+ fi
+
+ pathcomp="${pathcomp}/"
+done
+fi
+
+if [ x"$dir_arg" != x ]
+then
+ $doit $instcmd $dst &&
+
+ if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi &&
+ if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi &&
+ if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi &&
+ if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi
+else
+
+# If we're going to rename the final executable, determine the name now.
+
+ if [ x"$transformarg" = x ]
+ then
+ dstfile=`basename $dst`
+ else
+ dstfile=`basename $dst $transformbasename |
+ sed $transformarg`$transformbasename
+ fi
+
+# don't allow the sed command to completely eliminate the filename
+
+ if [ x"$dstfile" = x ]
+ then
+ dstfile=`basename $dst`
+ else
+ true
+ fi
+
+# Make a temp file name in the proper directory.
+
+ dsttmp=$dstdir/#inst.$$#
+
+# Move or copy the file name to the temp name
+
+ $doit $instcmd $src $dsttmp &&
+
+ trap "rm -f ${dsttmp}" 0 &&
+
+# and set any options; do chmod last to preserve setuid bits
+
+# If any of these fail, we abort the whole thing. If we want to
+# ignore errors from any of these, just make sure not to ignore
+# errors from the above "$doit $instcmd $src $dsttmp" command.
+
+ if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi &&
+ if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi &&
+ if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi &&
+ if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi &&
+
+# Now rename the file to the real destination.
+
+ $doit $rmcmd -f $dstdir/$dstfile &&
+ $doit $mvcmd $dsttmp $dstdir/$dstfile
+
+fi &&
+
+
+exit 0
diff --git a/external/fs/unfs3-0.9.22/locate.c b/external/fs/unfs3-0.9.22/locate.c
new file mode 100644
index 0000000..c5ed219
--- /dev/null
+++ b/external/fs/unfs3-0.9.22/locate.c
@@ -0,0 +1,171 @@
+
+/*
+ * UNFS3 brute force file search
+ * (C) 2004, Pascal Schmidt
+ * see file LICENSE for license details
+ */
+
+#include "config.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <rpc/rpc.h>
+#include <dirent.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#if HAVE_MNTENT_H == 1
+#include <mntent.h>
+#endif
+
+#if HAVE_SYS_MNTTAB_H == 1
+#include <sys/mnttab.h>
+#endif
+
+#include "nfs.h"
+#include "fh.h"
+#include "daemon.h"
+
+/*
+ * these are the brute-force file searching routines that are used
+ * when both the filehandle cache and the hashed path inside the
+ * filehandle are unable to locate the file
+ *
+ * this can only happen if a file was rename(3)'d across directories
+ *
+ * these routines are slow, but better than returning ESTALE to
+ * clients
+ */
+
+#if HAVE_MNTENT_H == 1 || HAVE_SYS_MNTTAB_H == 1
+
+/*
+ * locate file given prefix, device, and inode number
+ */
+static int locate_pfx(const char *pfx, uint32 dev, uint64 ino, char *result)
+{
+ char path[NFS_MAXPATHLEN];
+ backend_dirstream *search;
+ struct dirent *ent;
+ struct stat buf;
+ int res;
+
+ search = opendir(pfx);
+ if (!search)
+ return FALSE;
+
+ while ((ent = readdir(search))) {
+ if (strlen(pfx) + strlen(ent->d_name) + 2 >= NFS_MAXPATHLEN)
+ continue;
+
+ sprintf(path, "%s/%s", pfx, ent->d_name);
+
+ res = lstat(path, &buf);
+ if (res != 0)
+ continue;
+
+ /* check for matching object */
+ if (buf.st_dev == dev && buf.st_ino == ino) {
+ strcpy(result, path);
+ st_cache = buf;
+ st_cache_valid = TRUE;
+ closedir(search);
+ return TRUE;
+ }
+
+ /* descend into directories with same dev */
+ if (buf.st_dev == dev && S_ISDIR(buf.st_mode) &&
+ strcmp(ent->d_name, ".") != 0 && strcmp(ent->d_name, "..") != 0) {
+ res = locate_pfx(path, dev, ino, result);
+ if (res == TRUE) {
+ closedir(search);
+ return TRUE;
+ }
+ }
+ }
+
+ closedir(search);
+ return FALSE;
+}
+#endif
+
+/*
+ * locate file given device and inode number
+ *
+ * slow fallback in case other filehandle resolution functions fail
+ */
+char *locate_file(U(uint32 dev), U(uint64 ino))
+{
+#if HAVE_MNTENT_H == 1 || HAVE_SYS_MNTTAB_H == 1
+ static char path[NFS_MAXPATHLEN];
+ FILE *mtab;
+ struct stat buf;
+ int res;
+#endif
+
+#if HAVE_MNTENT_H == 1
+ struct mntent *ent;
+#endif
+
+#if HAVE_SYS_MNTTAB_H == 1
+ struct mnttab ent;
+ int found = FALSE;
+#endif
+
+ if (!opt_brute_force)
+ return NULL;
+
+#if HAVE_MNTENT_H == 1
+ mtab = setmntent("/etc/mtab", "r");
+ if (!mtab)
+ return NULL;
+
+ /*
+ * look for mtab entry with matching device
+ */
+ while ((ent = getmntent(mtab))) {
+ res = lstat(ent->mnt_dir, &buf);
+
+ if (res == 0 && buf.st_dev == dev)
+ break;
+ }
+ endmntent(mtab);
+
+ /* found matching entry? */
+ if (ent) {
+ res = locate_pfx(ent->mnt_dir, dev, ino, path);
+ if (res == TRUE)
+ return path;
+ }
+#endif
+
+#if HAVE_SYS_MNTTAB_H == 1
+ mtab = fopen("/etc/mnttab", "r");
+ if (!mtab)
+ return NULL;
+
+ /*
+ * look for mnttab entry with matching device
+ */
+ while (getmntent(mtab, &ent) == 0) {
+ res = lstat(ent.mnt_mountp, &buf);
+
+ if (res == 0 && buf.st_dev == dev) {
+ found = TRUE;
+ break;
+ }
+ }
+ fclose(mtab);
+
+ /* found matching entry? */
+ if (found) {
+ res = locate_pfx(ent.mnt_mountp, dev, ino, path);
+ if (res == TRUE)
+ return path;
+ }
+#endif
+
+ return NULL;
+}
diff --git a/external/fs/unfs3-0.9.22/locate.h b/external/fs/unfs3-0.9.22/locate.h
new file mode 100644
index 0000000..45ac305
--- /dev/null
+++ b/external/fs/unfs3-0.9.22/locate.h
@@ -0,0 +1,13 @@
+
+/*
+ * UNFS3 brute force file search
+ * (C) 2004, Pascal Schmidt
+ * see file LICENSE for license details
+ */
+
+#ifndef UNFS3_LOCATE_H
+#define UNFS3_LOCATE_H
+
+char *locate_file(uint32 dev, uint64 ino);
+
+#endif
diff --git a/external/fs/unfs3-0.9.22/md5.c b/external/fs/unfs3-0.9.22/md5.c
new file mode 100644
index 0000000..7a7c7a5
--- /dev/null
+++ b/external/fs/unfs3-0.9.22/md5.c
@@ -0,0 +1,379 @@
+
+/*
+ Copyright (C) 1999, 2000, 2002 Aladdin Enterprises. All rights reserved.
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ L. Peter Deutsch
+ gh...@aladdin.com
+
+ */
+
+/*
+ Independent implementation of MD5 (RFC 1321).
+
+ This code implements the MD5 Algorithm defined in RFC 1321, whose
+ text is available at
+ http://www.ietf.org/rfc/rfc1321.txt
+ The code is derived from the text of the RFC, including the test suite
+ (section A.5) but excluding the rest of Appendix A. It does not include
+ any code or documentation that is identified in the RFC as being
+ copyrighted.
+
+ The original and principal author of md5.c is L. Peter Deutsch
+ <gh...@aladdin.com>. Other authors are noted in the change history
+ that follows (in reverse chronological order):
+
+ 2002-04-13 lpd Clarified derivation from RFC 1321; now handles byte order
+ either statically or dynamically; added missing #include <string.h>
+ in library.
+ 2002-03-11 lpd Corrected argument list for main(), and added int return
+ type, in test program and T value program.
+ 2002-02-21 lpd Added missing #include <stdio.h> in test program.
+ 2000-07-03 lpd Patched to eliminate warnings about "constant is
+ unsigned in ANSI C, signed in traditional"; made test program
+ self-checking.
+ 1999-11-04 lpd Edited comments slightly for automatic TOC extraction.
+ 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5).
+ 1999-05-03 lpd Original version.
+ */
+
+#include "md5.h"
+#include <string.h>
+
+#undef BYTE_ORDER /* 1 = big-endian, -1 = little-endian,
+ 0 = unknown */
+#ifdef ARCH_IS_BIG_ENDIAN
+# define BYTE_ORDER (ARCH_IS_BIG_ENDIAN ? 1 : -1)
+#else
+# define BYTE_ORDER 0
+#endif
+
+#define T_MASK ((md5_word_t)~0)
+#define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87)
+#define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9)
+#define T3 0x242070db
+#define T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111)
+#define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050)
+#define T6 0x4787c62a
+#define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec)
+#define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe)
+#define T9 0x698098d8
+#define T10 /* 0x8b44f7af */ (T_MASK ^ 0x74bb0850)
+#define T11 /* 0xffff5bb1 */ (T_MASK ^ 0x0000a44e)
+#define T12 /* 0x895cd7be */ (T_MASK ^ 0x76a32841)
+#define T13 0x6b901122
+#define T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c)
+#define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71)
+#define T16 0x49b40821
+#define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d)
+#define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf)
+#define T19 0x265e5a51
+#define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855)
+#define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2)
+#define T22 0x02441453
+#define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e)
+#define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437)
+#define T25 0x21e1cde6
+#define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829)
+#define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278)
+#define T28 0x455a14ed
+#define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa)
+#define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07)
+#define T31 0x676f02d9
+#define T32 /* 0x8d2a4c8a */ (T_MASK ^ 0x72d5b375)
+#define T33 /* 0xfffa3942 */ (T_MASK ^ 0x0005c6bd)
+#define T34 /* 0x8771f681 */ (T_MASK ^ 0x788e097e)
+#define T35 0x6d9d6122
+#define T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3)
+#define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb)
+#define T38 0x4bdecfa9
+#define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f)
+#define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f)
+#define T41 0x289b7ec6
+#define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805)
+#define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a)
+#define T44 0x04881d05
+#define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6)
+#define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a)
+#define T47 0x1fa27cf8
+#define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a)
+#define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb)
+#define T50 0x432aff97
+#define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58)
+#define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6)
+#define T53 0x655b59c3
+#define T54 /* 0x8f0ccc92 */ (T_MASK ^ 0x70f3336d)
+#define T55 /* 0xffeff47d */ (T_MASK ^ 0x00100b82)
+#define T56 /* 0x85845dd1 */ (T_MASK ^ 0x7a7ba22e)
+#define T57 0x6fa87e4f
+#define T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f)
+#define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb)
+#define T60 0x4e0811a1
+#define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d)
+#define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca)
+#define T63 0x2ad7d2bb
+#define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e)
+
+static void md5_process(md5_state_t * pms, const md5_byte_t * data /* [64]
+ */ )
+{
+ md5_word_t a = pms->abcd[0], b = pms->abcd[1], c = pms->abcd[2], d =
+ pms->abcd[3];
+ md5_word_t t;
+
+#if BYTE_ORDER > 0
+ /* Define storage only for big-endian CPUs. */
+ md5_word_t X[16];
+#else
+ /* Define storage for little-endian or both types of CPUs. */
+ md5_word_t xbuf[16];
+ const md5_word_t *X;
+#endif
+
+ {
+#if BYTE_ORDER == 0
+ /*
+ * Determine dynamically whether this is a big-endian or
+ * little-endian machine, since we can use a more efficient
+ * algorithm on the latter.
+ */
+ static const int w = 1;
+
+ if (*((const md5_byte_t *) &w)) /* dynamic little-endian */
+#endif
+#if BYTE_ORDER <= 0 /* little-endian */
+ {
+ /*
+ * On little-endian machines, we can process properly aligned
+ * data without copying it.
+ */
+ if (!((data - (const md5_byte_t *) 0) & 3)) {
+ /* data are properly aligned */
+ X = (const md5_word_t *) data;
+ } else {
+ /* not aligned */
+ memcpy(xbuf, data, 64);
+ X = xbuf;
+ }
+ }
+#endif
+#if BYTE_ORDER == 0
+ else /* dynamic big-endian */
+#endif
+#if BYTE_ORDER >= 0 /* big-endian */
+ {
+ /*
+ * On big-endian machines, we must arrange the bytes in the
+ * right order.
+ */
+ const md5_byte_t *xp = data;
+ int i;
+
+# if BYTE_ORDER == 0
+ X = xbuf; /* (dynamic only) */
+# else
+# define xbuf X /* (static only) */
+# endif
+ for (i = 0; i < 16; ++i, xp += 4)
+ xbuf[i] =
+ xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24);
+ }
+#endif
+ }
+
+#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
+
+ /* Round 1. */
+ /* Let [abcd k s i] denote the operation a = b + ((a + F(b,c,d) + X[k] +
+ T[i]) <<< s). */
+#define F(x, y, z) (((x) & (y)) | (~(x) & (z)))
+#define SET(a, b, c, d, k, s, Ti)\
+ t = a + F(b,c,d) + X[k] + Ti;\
+ a = ROTATE_LEFT(t, s) + b
+ /* Do the following 16 operations. */
+ SET(a, b, c, d, 0, 7, T1);
+ SET(d, a, b, c, 1, 12, T2);
+ SET(c, d, a, b, 2, 17, T3);
+ SET(b, c, d, a, 3, 22, T4);
+ SET(a, b, c, d, 4, 7, T5);
+ SET(d, a, b, c, 5, 12, T6);
+ SET(c, d, a, b, 6, 17, T7);
+ SET(b, c, d, a, 7, 22, T8);
+ SET(a, b, c, d, 8, 7, T9);
+ SET(d, a, b, c, 9, 12, T10);
+ SET(c, d, a, b, 10, 17, T11);
+ SET(b, c, d, a, 11, 22, T12);
+ SET(a, b, c, d, 12, 7, T13);
+ SET(d, a, b, c, 13, 12, T14);
+ SET(c, d, a, b, 14, 17, T15);
+ SET(b, c, d, a, 15, 22, T16);
+#undef SET
+
+ /* Round 2. */
+ /* Let [abcd k s i] denote the operation a = b + ((a + G(b,c,d) + X[k] +
+ T[i]) <<< s). */
+#define G(x, y, z) (((x) & (z)) | ((y) & ~(z)))
+#define SET(a, b, c, d, k, s, Ti)\
+ t = a + G(b,c,d) + X[k] + Ti;\
+ a = ROTATE_LEFT(t, s) + b
+ /* Do the following 16 operations. */
+ SET(a, b, c, d, 1, 5, T17);
+ SET(d, a, b, c, 6, 9, T18);
+ SET(c, d, a, b, 11, 14, T19);
+ SET(b, c, d, a, 0, 20, T20);
+ SET(a, b, c, d, 5, 5, T21);
+ SET(d, a, b, c, 10, 9, T22);
+ SET(c, d, a, b, 15, 14, T23);
+ SET(b, c, d, a, 4, 20, T24);
+ SET(a, b, c, d, 9, 5, T25);
+ SET(d, a, b, c, 14, 9, T26);
+ SET(c, d, a, b, 3, 14, T27);
+ SET(b, c, d, a, 8, 20, T28);
+ SET(a, b, c, d, 13, 5, T29);
+ SET(d, a, b, c, 2, 9, T30);
+ SET(c, d, a, b, 7, 14, T31);
+ SET(b, c, d, a, 12, 20, T32);
+#undef SET
+
+ /* Round 3. */
+ /* Let [abcd k s t] denote the operation a = b + ((a + H(b,c,d) + X[k] +
+ T[i]) <<< s). */
+#define H(x, y, z) ((x) ^ (y) ^ (z))
+#define SET(a, b, c, d, k, s, Ti)\
+ t = a + H(b,c,d) + X[k] + Ti;\
+ a = ROTATE_LEFT(t, s) + b
+ /* Do the following 16 operations. */
+ SET(a, b, c, d, 5, 4, T33);
+ SET(d, a, b, c, 8, 11, T34);
+ SET(c, d, a, b, 11, 16, T35);
+ SET(b, c, d, a, 14, 23, T36);
+ SET(a, b, c, d, 1, 4, T37);
+ SET(d, a, b, c, 4, 11, T38);
+ SET(c, d, a, b, 7, 16, T39);
+ SET(b, c, d, a, 10, 23, T40);
+ SET(a, b, c, d, 13, 4, T41);
+ SET(d, a, b, c, 0, 11, T42);
+ SET(c, d, a, b, 3, 16, T43);
+ SET(b, c, d, a, 6, 23, T44);
+ SET(a, b, c, d, 9, 4, T45);
+ SET(d, a, b, c, 12, 11, T46);
+ SET(c, d, a, b, 15, 16, T47);
+ SET(b, c, d, a, 2, 23, T48);
+#undef SET
+
+ /* Round 4. */
+ /* Let [abcd k s t] denote the operation a = b + ((a + I(b,c,d) + X[k] +
+ T[i]) <<< s). */
+#define I(x, y, z) ((y) ^ ((x) | ~(z)))
+#define SET(a, b, c, d, k, s, Ti)\
+ t = a + I(b,c,d) + X[k] + Ti;\
+ a = ROTATE_LEFT(t, s) + b
+ /* Do the following 16 operations. */
+ SET(a, b, c, d, 0, 6, T49);
+ SET(d, a, b, c, 7, 10, T50);
+ SET(c, d, a, b, 14, 15, T51);
+ SET(b, c, d, a, 5, 21, T52);
+ SET(a, b, c, d, 12, 6, T53);
+ SET(d, a, b, c, 3, 10, T54);
+ SET(c, d, a, b, 10, 15, T55);
+ SET(b, c, d, a, 1, 21, T56);
+ SET(a, b, c, d, 8, 6, T57);
+ SET(d, a, b, c, 15, 10, T58);
+ SET(c, d, a, b, 6, 15, T59);
+ SET(b, c, d, a, 13, 21, T60);
+ SET(a, b, c, d, 4, 6, T61);
+ SET(d, a, b, c, 11, 10, T62);
+ SET(c, d, a, b, 2, 15, T63);
+ SET(b, c, d, a, 9, 21, T64);
+#undef SET
+
+ /* Then perform the following additions. (That is increment each of the
+ four registers by the value it had before this block was started.) */
+ pms->abcd[0] += a;
+ pms->abcd[1] += b;
+ pms->abcd[2] += c;
+ pms->abcd[3] += d;
+}
+
+void md5_init(md5_state_t * pms)
+{
+ pms->count[0] = pms->count[1] = 0;
+ pms->abcd[0] = 0x67452301;
+ pms->abcd[1] = /* 0xefcdab89 */ T_MASK ^ 0x10325476;
+ pms->abcd[2] = /* 0x98badcfe */ T_MASK ^ 0x67452301;
+ pms->abcd[3] = 0x10325476;
+}
+
+void md5_append(md5_state_t * pms, const md5_byte_t * data, int nbytes)
+{
+ const md5_byte_t *p = data;
+ int left = nbytes;
+ int offset = (pms->count[0] >> 3) & 63;
+ md5_word_t nbits = (md5_word_t) (nbytes << 3);
+
+ if (nbytes <= 0)
+ return;
+
+ /* Update the message length. */
+ pms->count[1] += nbytes >> 29;
+ pms->count[0] += nbits;
+ if (pms->count[0] < nbits)
+ pms->count[1]++;
+
+ /* Process an initial partial block. */
+ if (offset) {
+ int copy = (offset + nbytes > 64 ? 64 - offset : nbytes);
+
+ memcpy(pms->buf + offset, p, copy);
+ if (offset + copy < 64)
+ return;
+ p += copy;
+ left -= copy;
+ md5_process(pms, pms->buf);
+ }
+
+ /* Process full blocks. */
+ for (; left >= 64; p += 64, left -= 64)
+ md5_process(pms, p);
+
+ /* Process a final partial block. */
+ if (left)
+ memcpy(pms->buf, p, left);
+}
+
+void md5_finish(md5_state_t * pms, md5_byte_t digest[16])
+{
+ static const md5_byte_t pad[64] = {
+ 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ };
+ md5_byte_t data[8];
+ int i;
+
+ /* Save the length before padding. */
+ for (i = 0; i < 8; ++i)
+ data[i] = (md5_byte_t) (pms->count[i >> 2] >> ((i & 3) << 3));
+ /* Pad to 56 bytes mod 64. */
+ md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1);
+ /* Append the length. */
+ md5_append(pms, data, 8);
+ for (i = 0; i < 16; ++i)
+ digest[i] = (md5_byte_t) (pms->abcd[i >> 2] >> ((i & 3) << 3));
+}
diff --git a/external/fs/unfs3-0.9.22/md5.h b/external/fs/unfs3-0.9.22/md5.h
new file mode 100644
index 0000000..bc49597
--- /dev/null
+++ b/external/fs/unfs3-0.9.22/md5.h
@@ -0,0 +1,91 @@
+/*
+ Copyright (C) 1999, 2002 Aladdin Enterprises. All rights reserved.
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ L. Peter Deutsch
+ gh...@aladdin.com
+
+ */
+
+/*
+ Independent implementation of MD5 (RFC 1321).
+
+ This code implements the MD5 Algorithm defined in RFC 1321, whose
+ text is available at
+ http://www.ietf.org/rfc/rfc1321.txt
+ The code is derived from the text of the RFC, including the test suite
+ (section A.5) but excluding the rest of Appendix A. It does not include
+ any code or documentation that is identified in the RFC as being
+ copyrighted.
+
+ The original and principal author of md5.h is L. Peter Deutsch
+ <gh...@aladdin.com>. Other authors are noted in the change history
+ that follows (in reverse chronological order):
+
+ 2002-04-13 lpd Removed support for non-ANSI compilers; removed
+ references to Ghostscript; clarified derivation from RFC 1321;
+ now handles byte order either statically or dynamically.
+ 1999-11-04 lpd Edited comments slightly for automatic TOC extraction.
+ 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5);
+ added conditionalization for C++ compilation from Martin
+ Purschke <purs...@bnl.gov>.
+ 1999-05-03 lpd Original version.
+ */
+
+#ifndef md5_INCLUDED
+# define md5_INCLUDED
+
+/*
+ * This package supports both compile-time and run-time determination of CPU
+ * byte order. If ARCH_IS_BIG_ENDIAN is defined as 0, the code will be
+ * compiled to run only on little-endian CPUs; if ARCH_IS_BIG_ENDIAN is
+ * defined as non-zero, the code will be compiled to run only on big-endian
+ * CPUs; if ARCH_IS_BIG_ENDIAN is not defined, the code will be compiled to
+ * run on either big- or little-endian CPUs, but will run slightly less
+ * efficiently on either one than if ARCH_IS_BIG_ENDIAN is defined.
+ */
+
+typedef unsigned char md5_byte_t; /* 8-bit byte */
+typedef unsigned int md5_word_t; /* 32-bit word */
+
+/* Define the state of the MD5 Algorithm. */
+typedef struct md5_state_s {
+ md5_word_t count[2]; /* message length in bits, lsw first */
+ md5_word_t abcd[4]; /* digest buffer */
+ md5_byte_t buf[64]; /* accumulate block */
+} md5_state_t;
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/* Initialize the algorithm. */
+void md5_init(md5_state_t *pms);
+
+/* Append a string to the message. */
+void md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes);
+
+/* Finish the message and return the digest. */
+void md5_finish(md5_state_t *pms, md5_byte_t digest[16]);
+
+#ifdef __cplusplus
+} /* end extern "C" */
+#endif
+
+#endif /* md5_INCLUDED */
diff --git a/external/fs/unfs3-0.9.22/mount.c b/external/fs/unfs3-0.9.22/mount.c
new file mode 100644
index 0000000..d14956e
--- /dev/null
+++ b/external/fs/unfs3-0.9.22/mount.c
@@ -0,0 +1,289 @@
+
+/*
+ * UNFS3 mount protocol procedures
+ * (C) 2004, Pascal Schmidt
+ * see file LICENSE for license details
+ */
+
+#include "config.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <rpc/rpc.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <string.h>
+#ifndef WIN32
+#include <syslog.h>
+#include <unistd.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#endif /* WIN32 */
+#include <fcntl.h>
+
+#include "nfs.h"
+#include "mount.h"
+#include "daemon.h"
+#include "fh.h"
+#include "fh_cache.h"
+#include "fd_cache.h"
+#include "Config/exports.h"
+#include "password.h"
+#include "backend.h"
+
+#ifndef PATH_MAX
+# define PATH_MAX 4096
+#endif
+
+#define IS_SECURE(port) ((port) < 1024)
+
+/*
+ * number of active mounts
+ *
+ * only a guess since clients can crash and/or not sent UMNT calls
+ */
+static int mount_cnt = 0;
+
+/* list of currently mounted directories */
+static mountlist mount_list = NULL;
+
+static char nonce[32] = "";
+
+/*
+ * add entry to mount list
+ */
+static void add_mount(const char *path, struct svc_req *rqstp)
+{
+ mountlist new;
+ mountlist iter;
+ char *host;
+
+ new = malloc(sizeof(struct mountbody));
+ if (!new) {
+ logmsg(LOG_CRIT, "add_mount: Unable to allocate memory");
+ return;
+ }
+
+ host = inet_ntoa(get_remote(rqstp));
+ new->ml_hostname = malloc(strlen(host) + 1);
+ if (!new->ml_hostname) {
+ logmsg(LOG_CRIT, "add_mount: Unable to allocate memory");
+ free(new);
+ return;
+ }
+
+ new->ml_directory = malloc(strlen(path) + 1);
+ if (!new->ml_directory) {
+ logmsg(LOG_CRIT, "add_mount: Unable to allocate memory");
+ free(new->ml_hostname);
+ free(new);
+ return;
+ }
+
+ /* initialize the new entry */
+ new->ml_next = NULL;
+ strcpy(new->ml_hostname, host);
+ strcpy(new->ml_directory, path);
+
+ iter = mount_list;
+ if (iter) {
+ while (iter->ml_next)
+ iter = iter->ml_next;
+ iter->ml_next = new;
+ } else
+ mount_list = new;
+
+ mount_cnt++;
+}
+
+/*
+ * remove entries from mount list
+ */
+static void remove_mount(const char *path, struct svc_req *rqstp)
+{
+ mountlist iter, next, prev = NULL;
+ char *host;
+
+ host = inet_ntoa(get_remote(rqstp));
+
+ iter = mount_list;
+ while (iter) {
+ if (strcmp(iter->ml_hostname, host) == 0 &&
+ (!path || strcmp(iter->ml_directory, path) == 0)) {
+ if (prev)
+ prev->ml_next = iter->ml_next;
+ else
+ mount_list = iter->ml_next;
+
+ next = iter->ml_next;
+
+ free(iter->ml_hostname);
+ free(iter->ml_directory);
+ free(iter);
+
+ iter = next;
+
+ /* adjust mount count */
+ if (mount_cnt > 0)
+ mount_cnt--;
+ } else {
+ prev = iter;
+ iter = iter->ml_next;
+ }
+ }
+}
+
+void *mountproc_null_3_svc(U(void *argp), U(struct svc_req *rqstp))
+{
+ static void *result = NULL;
+
+ return &result;
+}
+
+mountres3 *mountproc_mnt_3_svc(dirpath * argp, struct svc_req * rqstp)
+{
+ char buf[PATH_MAX];
+ static unfs3_fh_t fh;
+ static mountres3 result;
+ static int auth = AUTH_UNIX;
+ int authenticated = 0;
+ char *password;
+
+ /* We need to modify the *argp pointer. Make a copy. */
+ char *dpath = *argp;
+
+ /* error out if not version 3 */
+ if (rqstp->rq_vers != 3) {
+ logmsg(LOG_INFO,
+ "%s attempted mount with unsupported protocol version",
+ inet_ntoa(get_remote(rqstp)));
+ result.fhs_status = MNT3ERR_INVAL;
+ return &result;
+ }
+
+ /* Check for "mount commands" */
+ if (strncmp(dpath, "@getnonce", sizeof("@getnonce") - 1) == 0) {
+ if (backend_gen_nonce(nonce) < 0) {
+ result.fhs_status = MNT3ERR_IO;
+ } else {
+ result.fhs_status = MNT3_OK;
+ result.mountres3_u.mountinfo.fhandle.fhandle3_len = 32;
+ result.mountres3_u.mountinfo.fhandle.fhandle3_val = nonce;
+ result.mountres3_u.mountinfo.auth_flavors.auth_flavors_len = 1;
+ result.mountres3_u.mountinfo.auth_flavors.auth_flavors_val =
+ &auth;
+ }
+ return &result;
+ } else if (strncmp(dpath, "@password:", sizeof("@password:") - 1) == 0) {
+ char pw[PASSWORD_MAXLEN + 1];
+
+ mnt_cmd_argument(&dpath, "@password:", pw, PASSWORD_MAXLEN);
+ if (exports_options(dpath, rqstp, &password, NULL) != -1) {
+ authenticated = !strcmp(password, pw);
+ }
+ /* else leave authenticated unchanged */
+ } else if (strncmp(dpath, "@otp:", sizeof("@otp:") - 1) == 0) {
+ /* The otp from the client */
+ char otp[PASSWORD_MAXLEN + 1];
+
+ /* Our calculated otp */
+ char hexdigest[32];
+
+ mnt_cmd_argument(&dpath, "@otp:", otp, PASSWORD_MAXLEN);
+ if (exports_options(dpath, rqstp, &password, NULL) != -1) {
+ otp_digest(nonce, password, hexdigest);
+
+ /* Compare our calculated digest with what the client submitted */
+ authenticated = !strncmp(hexdigest, otp, 32);
+
+ /* Change nonce */
+ backend_gen_nonce(nonce);
+ }
+ /* else leave authenticated unchanged */
+ }
+
+ if ((exports_opts & OPT_REMOVABLE) && export_point(dpath)) {
+ /* Removable media export point. Do not call realpath; simply copy
+ path */
+ strncpy(buf, dpath, PATH_MAX);
+ } else if (!backend_realpath(dpath, buf)) {
+ /* the given path does not exist */
+ result.fhs_status = MNT3ERR_NOENT;
+ return &result;
+ }
+
+ if (strlen(buf) + 1 > NFS_MAXPATHLEN) {
+ logmsg(LOG_INFO, "%s attempted to mount jumbo path",
+ inet_ntoa(get_remote(rqstp)));
+ result.fhs_status = MNT3ERR_NAMETOOLONG;
+ return &result;
+ }
+
+ if ((exports_options(buf, rqstp, &password, NULL) == -1)
+ || (!authenticated && password[0])
+ || (!(exports_opts & OPT_INSECURE) &&
+ !IS_SECURE(ntohs(get_port(rqstp))))
+ ) {
+ /* not exported to this host or at all, or a password defined and not
+ authenticated */
+ result.fhs_status = MNT3ERR_ACCES;
+ return &result;
+ }
+
+ fh = fh_comp(buf, rqstp, FH_DIR);
+
+ if (!fh_valid(fh)) {
+ logmsg(LOG_INFO, "%s attempted to mount non-directory",
+ inet_ntoa(get_remote(rqstp)));
+ result.fhs_status = MNT3ERR_NOTDIR;
+ return &result;
+ }
+
+ add_mount(dpath, rqstp);
+
+ result.fhs_status = MNT3_OK;
+ result.mountres3_u.mountinfo.fhandle.fhandle3_len = fh_length(&fh);
+ result.mountres3_u.mountinfo.fhandle.fhandle3_val = (char *) &fh;
+ result.mountres3_u.mountinfo.auth_flavors.auth_flavors_len = 1;
+ result.mountres3_u.mountinfo.auth_flavors.auth_flavors_val = &auth;
+
+ return &result;
+}
+
+mountlist *mountproc_dump_3_svc(U(void *argp), U(struct svc_req *rqstp))
+{
+ return &mount_list;
+}
+
+void *mountproc_umnt_3_svc(dirpath * argp, struct svc_req *rqstp)
+{
+ /* RPC times out if we use a NULL pointer */
+ static void *result = NULL;
+
+ remove_mount(*argp, rqstp);
+
+ /* if no more mounts are active, flush all open file descriptors */
+ if (mount_cnt == 0)
+ fd_cache_purge();
+
+ return &result;
+}
+
+void *mountproc_umntall_3_svc(U(void *argp), struct svc_req *rqstp)
+{
+ /* RPC times out if we use a NULL pointer */
+ static void *result = NULL;
+
+ remove_mount(NULL, rqstp);
+
+ /* if no more mounts are active, flush all open file descriptors */
+ if (mount_cnt == 0)
+ fd_cache_purge();
+
+ return &result;
+}
+
+exports *mountproc_export_3_svc(U(void *argp), U(struct svc_req *rqstp))
+{
+ return &exports_nfslist;
+}
diff --git a/external/fs/unfs3-0.9.22/mount.h b/external/fs/unfs3-0.9.22/mount.h
new file mode 100644
index 0000000..94327f3
--- /dev/null
+++ b/external/fs/unfs3-0.9.22/mount.h
@@ -0,0 +1,97 @@
+/*
+ * UNFS3 mount protocol definitions
+ * Generated by rpcgen
+ */
+
+#ifndef _MOUNT_H_RPCGEN
+#define _MOUNT_H_RPCGEN
+
+#define MNTPATHLEN 1024
+#define MNTNAMLEN 255
+#define FHSIZE3 64
+
+typedef struct {
+ u_int fhandle3_len;
+ char *fhandle3_val;
+} fhandle3;
+
+enum mountstat3 {
+ MNT3_OK = 0,
+ MNT3ERR_PERM = 1,
+ MNT3ERR_NOENT = 2,
+ MNT3ERR_IO = 5,
+ MNT3ERR_ACCES = 13,
+ MNT3ERR_NOTDIR = 20,
+ MNT3ERR_INVAL = 22,
+ MNT3ERR_NAMETOOLONG = 63,
+ MNT3ERR_NOTSUPP = 10004,
+ MNT3ERR_SERVERFAULT = 10006,
+};
+typedef enum mountstat3 mountstat3;
+
+struct mountres3_ok {
+ fhandle3 fhandle;
+ struct {
+ u_int auth_flavors_len;
+ int *auth_flavors_val;
+ } auth_flavors;
+};
+typedef struct mountres3_ok mountres3_ok;
+
+struct mountres3 {
+ mountstat3 fhs_status;
+ union {
+ mountres3_ok mountinfo;
+ } mountres3_u;
+};
+typedef struct mountres3 mountres3;
+
+typedef char *dirpath;
+
+typedef char *name;
+
+typedef struct mountbody *mountlist;
+
+struct mountbody {
+ name ml_hostname;
+ dirpath ml_directory;
+ mountlist ml_next;
+};
+typedef struct mountbody mountbody;
+
+typedef struct groupnode *groups;
+
+struct groupnode {
+ name gr_name;
+ groups gr_next;
+};
+typedef struct groupnode groupnode;
+
+typedef struct exportnode *exports;
+
+struct exportnode {
+ dirpath ex_dir;
+ groups ex_groups;
+ exports ex_next;
+};
+typedef struct exportnode exportnode;
+
+#define MOUNTPROG 100005
+#define MOUNTVERS1 1
+#define MOUNTVERS3 3
+
+#define MOUNTPROC_NULL 0
+extern void * mountproc_null_3_svc(void *, struct svc_req *);
+#define MOUNTPROC_MNT 1
+extern mountres3 * mountproc_mnt_3_svc(dirpath *, struct svc_req *);
+#define MOUNTPROC_DUMP 2
+extern mountlist * mountproc_dump_3_svc(void *, struct svc_req *);
+#define MOUNTPROC_UMNT 3
+extern void * mountproc_umnt_3_svc(dirpath *, struct svc_req *);
+#define MOUNTPROC_UMNTALL 4
+extern void * mountproc_umntall_3_svc(void *, struct svc_req *);
+#define MOUNTPROC_EXPORT 5
+extern exports * mountproc_export_3_svc(void *, struct svc_req *);
+extern int mountprog_3_freeresult (SVCXPRT *, xdrproc_t, caddr_t);
+
+#endif /* !_MOUNT_H_RPCGEN */
diff --git a/external/fs/unfs3-0.9.22/nfs.c b/external/fs/unfs3-0.9.22/nfs.c
new file mode 100644
index 0000000..5d99bf8
--- /dev/null
+++ b/external/fs/unfs3-0.9.22/nfs.c
@@ -0,0 +1,1083 @@
+
+/*
+ * UNFS3 NFS protocol procedures
+ * (C) 2004, Pascal Schmidt
+ * see file LICENSE for license details
+ */
+
+#include "config.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/param.h> /* needed for statfs() on NetBSD */
+#if HAVE_SYS_MOUNT_H == 1
+#include <sys/mount.h> /* dito */
+#endif
+#if HAVE_SYS_VMOUNT_H == 1
+#include <sys/vmount.h> /* AIX */
+#endif
+#include <rpc/rpc.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <utime.h>
+#ifndef WIN32
+#include <sys/socket.h>
+#include <sys/un.h>
+#endif /* WIN32 */
+
+#if HAVE_STATVFS == 1
+# include <sys/statvfs.h>
+#else
+# define statvfs statfs
+#endif
+
+#include "nfs.h"
+#include "mount.h"
+#include "fh.h"
+#include "fh_cache.h"
+#include "attr.h"
+#include "readdir.h"
+#include "user.h"
+#include "error.h"
+#include "fd_cache.h"
+#include "daemon.h"
+#include "backend.h"
+#include "Config/exports.h"
+#include "Extras/cluster.h"
+
+/*
+ * decompose filehandle and switch user if permitted access
+ * otherwise zero result structure and return with error status
+ */
+#define PREP(p,f) do { \
+ unfs3_fh_t *fh = (void *)f.data.data_val; \
+ switch_to_root(); \
+ p = fh_decomp(f); \
+ if (exports_options(p, rqstp, NULL, NULL) == -1) { \
+ memset(&result, 0, sizeof(result)); \
+ if (p) \
+ result.status = NFS3ERR_ACCES; \
+ else \
+ result.status = NFS3ERR_STALE; \
+ return &result; \
+ } \
+ if (fh->pwhash != export_password_hash) { \
+ memset(&result, 0, sizeof(result)); \
+ result.status = NFS3ERR_STALE; \
+ return &result; \
+ } \
+ switch_user(rqstp); \
+ } while (0)
+
+/*
+ * cat an object name onto a path, checking for illegal input
+ */
+nfsstat3 cat_name(const char *path, const char *name, char *result)
+{
+ char *last;
+
+ if (!path)
+ return NFS3ERR_STALE;
+
+ if (!name)
+ return NFS3ERR_ACCES;
+
+ if (name[0] == 0 || strchr(name, '/') != NULL)
+ return NFS3ERR_ACCES;
+
+ if (strlen(path) + strlen(name) + 2 > NFS_MAXPATHLEN)
+ return NFS3ERR_NAMETOOLONG;
+
+ if (strcmp(name, ".") == 0) {
+ strcpy(result, path);
+ return NFS3_OK;
+ }
+
+ /*
+ * Irix clients do lookups for .. and then use the
+ * resulting filehandle for more lookups, causing them
+ * to get filehandles that fh_decomp_raw will refuse to
+ * resolve. Export list handling will also get very
+ * confused if we allow such filehandles.
+ */
+ if (strcmp(name, "..") == 0) {
+ last = strrchr(path, '/');
+ if (!last || last == path)
+ strcpy(result, "/");
+ else {
+ *last = 0;
+ strcpy(result, path);
+ *last = '/';
+ }
+ return NFS3_OK;
+ }
+
+ sprintf(result, "%s/%s", path, name);
+ return NFS3_OK;
+}
+
+void *nfsproc3_null_3_svc(U(void *argp), U(struct svc_req *rqstp))
+{
+ static void *result = NULL;
+
+ return &result;
+}
+
+GETATTR3res *nfsproc3_getattr_3_svc(GETATTR3args * argp,
+ struct svc_req * rqstp)
+{
+ static GETATTR3res result;
+ char *path;
+ post_op_attr post;
+
+ PREP(path, argp->object);
+ post = get_post_cached(rqstp);
+
+ result.status = NFS3_OK;
+ result.GETATTR3res_u.resok.obj_attributes =
+ post.post_op_attr_u.attributes;
+
+ return &result;
+}
+
+/*
+ * check ctime guard for SETATTR procedure
+ */
+static nfsstat3 in_sync(sattrguard3 guard, pre_op_attr pre)
+{
+ if (!pre.attributes_follow)
+ return NFS3ERR_STALE;
+
+ if (!guard.check)
+ return NFS3_OK;
+
+ if (guard.sattrguard3_u.obj_ctime.seconds !=
+ pre.pre_op_attr_u.attributes.ctime.seconds)
+ return NFS3ERR_NOT_SYNC;
+
+ return NFS3_OK;
+}
+
+SETATTR3res *nfsproc3_setattr_3_svc(SETATTR3args * argp,
+ struct svc_req * rqstp)
+{
+ static SETATTR3res result;
+ pre_op_attr pre;
+ char *path;
+
+ PREP(path, argp->object);
+ pre = get_pre_cached();
+ result.status = join(in_sync(argp->guard, pre), exports_rw());
+
+ if (result.status == NFS3_OK)
+ result.status = set_attr(path, argp->object, argp->new_attributes);
+
+ /* overlaps with resfail */
+ result.SETATTR3res_u.resok.obj_wcc.before = pre;
+ result.SETATTR3res_u.resok.obj_wcc.after = get_post_stat(path, rqstp);
+
+ return &result;
+}
+
+LOOKUP3res *nfsproc3_lookup_3_svc(LOOKUP3args * argp, struct svc_req * rqstp)
+{
+ static LOOKUP3res result;
+ unfs3_fh_t *fh;
+ char *path;
+ char obj[NFS_MAXPATHLEN];
+ backend_statstruct buf;
+ int res;
+ uint32 gen;
+
+ PREP(path, argp->what.dir);
+ result.status = cat_name(path, argp->what.name, obj);
+
+ cluster_lookup(obj, rqstp, &result.status);
+
+ if (result.status == NFS3_OK) {
+ res = backend_lstat(obj, &buf);
+ if (res == -1)
+ result.status = lookup_err();
+ else {
+ if (strcmp(argp->what.name, ".") == 0 ||
+ strcmp(argp->what.name, "..") == 0) {
+ fh = fh_comp_ptr(obj, rqstp, 0);
+ } else {
+ gen = backend_get_gen(buf, FD_NONE, obj);
+ fh = fh_extend(argp->what.dir, buf.st_dev, buf.st_ino, gen);
+ fh_cache_add(buf.st_dev, buf.st_ino, obj);
+ }
+
+ if (fh) {
+ result.LOOKUP3res_u.resok.object.data.data_len =
+ fh_length(fh);
+ result.LOOKUP3res_u.resok.object.data.data_val = (char *) fh;
+ result.LOOKUP3res_u.resok.obj_attributes =
+ get_post_buf(buf, rqstp);
+ } else {
+ /* path was too long */
+ result.status = NFS3ERR_NAMETOOLONG;
+ }
+ }
+ }
+
+ /* overlaps with resfail */
+ result.LOOKUP3res_u.resok.dir_attributes = get_post_stat(path, rqstp);
+
+ return &result;
+}
+
+ACCESS3res *nfsproc3_access_3_svc(ACCESS3args * argp, struct svc_req * rqstp)
+{
+ static ACCESS3res result;
+ char *path;
+ post_op_attr post;
+ mode_t mode;
+ int access = 0;
+
+ PREP(path, argp->object);
+ post = get_post_cached(rqstp);
+ mode = post.post_op_attr_u.attributes.mode;
+
+ /* owner permissions */
+ if (is_owner(st_cache.st_uid, rqstp)) {
+ if (mode & S_IRUSR)
+ access |= ACCESS3_READ;
+ if (mode & S_IWUSR)
+ access |= ACCESS3_MODIFY | ACCESS3_EXTEND;
+ if (mode & S_IXUSR) {
+ access |= ACCESS3_EXECUTE;
+ if (opt_readable_executables)
+ access |= ACCESS3_READ;
+ }
+ } else if (has_group(st_cache.st_gid, rqstp)) {
+ /* group permissions */
+ if (mode & S_IRGRP)
+ access |= ACCESS3_READ;
+ if (mode & S_IWGRP)
+ access |= ACCESS3_MODIFY | ACCESS3_EXTEND;
+ if (mode & S_IXGRP) {
+ access |= ACCESS3_EXECUTE;
+ if (opt_readable_executables)
+ access |= ACCESS3_READ;
+ }
+ } else {
+ /* other permissions */
+ if (mode & S_IROTH)
+ access |= ACCESS3_READ;
+ if (mode & S_IWOTH)
+ access |= ACCESS3_MODIFY | ACCESS3_EXTEND;
+ if (mode & S_IXOTH) {
+ access |= ACCESS3_EXECUTE;
+ if (opt_readable_executables)
+ access |= ACCESS3_READ;
+ }
+ }
+
+ /* root is allowed everything */
+ if (get_uid(rqstp) == 0)
+ access |= ACCESS3_READ | ACCESS3_MODIFY | ACCESS3_EXTEND;
+
+ /* adjust if directory */
+ if (post.post_op_attr_u.attributes.type == NF3DIR) {
+ if (access & (ACCESS3_READ | ACCESS3_EXECUTE))
+ access |= ACCESS3_LOOKUP;
+ if (access & ACCESS3_MODIFY)
+ access |= ACCESS3_DELETE;
+ access &= ~ACCESS3_EXECUTE;
+ }
+
+ result.status = NFS3_OK;
+ result.ACCESS3res_u.resok.access = access & argp->access;
+ result.ACCESS3res_u.resok.obj_attributes = post;
+
+ return &result;
+}
+
+READLINK3res *nfsproc3_readlink_3_svc(READLINK3args * argp,
+ struct svc_req * rqstp)
+{
+ static READLINK3res result;
+ char *path;
+ static char buf[NFS_MAXPATHLEN];
+ int res;
+
+ PREP(path, argp->symlink);
+
+ res = backend_readlink(path, buf, NFS_MAXPATHLEN - 1);
+ if (res == -1)
+ result.status = readlink_err();
+ else {
+ /* readlink does not NULL-terminate */
+ buf[res] = 0;
+
+ result.status = NFS3_OK;
+ result.READLINK3res_u.resok.data = buf;
+ }
+
+ /* overlaps with resfail */
+ result.READLINK3res_u.resok.symlink_attributes =
+ get_post_stat(path, rqstp);
+
+ return &result;
+}
+
+READ3res *nfsproc3_read_3_svc(READ3args * argp, struct svc_req * rqstp)
+{
+ static READ3res result;
+ char *path;
+ int fd, res;
+ static char buf[NFS_MAXDATA_TCP + 1];
+ unsigned int maxdata;
+
+ if (get_socket_type(rqstp) == SOCK_STREAM)
+ maxdata = NFS_MAXDATA_TCP;
+ else
+ maxdata = NFS_MAXDATA_UDP;
+
+ PREP(path, argp->file);
+ result.status = is_reg();
+
+ /* handle reading of executables */
+ read_executable(rqstp, st_cache);
+
+ /* handle read of owned files */
+ read_by_owner(rqstp, st_cache);
+
+ /* if bigger than rtmax, truncate length */
+ if (argp->count > maxdata)
+ argp->count = maxdata;
+
+ if (result.status == NFS3_OK) {
+ fd = fd_open(path, argp->file, UNFS3_FD_READ, TRUE);
+ if (fd != -1) {
+ /* read one more to check for eof */
+ res = backend_pread(fd, buf, argp->count + 1, argp->offset);
+
+ /* eof if we could not read one more */
+ result.READ3res_u.resok.eof = (res <= (int64) argp->count);
+
+ /* close for real when hitting eof */
+ if (result.READ3res_u.resok.eof)
+ fd_close(fd, UNFS3_FD_READ, FD_CLOSE_REAL);
+ else {
+ fd_close(fd, UNFS3_FD_READ, FD_CLOSE_VIRT);
+ res--;
+ }
+
+ if (res >= 0) {
+ result.READ3res_u.resok.count = res;
+ result.READ3res_u.resok.data.data_len = res;
+ result.READ3res_u.resok.data.data_val = buf;
+ } else {
+ /* error during read() */
+
+ /* EINVAL means unreadable object */
+ if (errno == EINVAL)
+ result.status = NFS3ERR_INVAL;
+ else
+ result.status = NFS3ERR_IO;
+ }
+ } else
+ /* opening for read failed */
+ result.status = read_err();
+ }
+
+ /* overlaps with resfail */
+ result.READ3res_u.resok.file_attributes = get_post_stat(path, rqstp);
+
+ return &result;
+}
+
+WRITE3res *nfsproc3_write_3_svc(WRITE3args * argp, struct svc_req * rqstp)
+{
+ static WRITE3res result;
+ char *path;
+ int fd, res, res_close;
+
+ PREP(path, argp->file);
+ result.status = join(is_reg(), exports_rw());
+
+ /* handle write of owned files */
+ write_by_owner(rqstp, st_cache);
+
+ if (result.status == NFS3_OK) {
+ /* We allow caching of the fd only for unstable writes. This is to
+ prevent generating a new write verifier for failed stable writes,
+ when the fd was not in the cache. Besides, for stable writes, the
+ fd will be removed from the cache by fd_close() below, so adding
+ it to and removing it from the cache is just a waste of CPU cycles
+ */
+ fd = fd_open(path, argp->file, UNFS3_FD_WRITE,
+ (argp->stable == UNSTABLE));
+ if (fd != -1) {
+ res =
+ backend_pwrite(fd, argp->data.data_val, argp->data.data_len,
+ argp->offset);
+
+ /* close for real if not UNSTABLE write */
+ if (argp->stable == UNSTABLE)
+ res_close = fd_close(fd, UNFS3_FD_WRITE, FD_CLOSE_VIRT);
+ else
+ res_close = fd_close(fd, UNFS3_FD_WRITE, FD_CLOSE_REAL);
+
+ /* we always do fsync(), never fdatasync() */
+ if (argp->stable == DATA_SYNC)
+ argp->stable = FILE_SYNC;
+
+ if (res != -1 && res_close != -1) {
+ result.WRITE3res_u.resok.count = res;
+ result.WRITE3res_u.resok.committed = argp->stable;
+ memcpy(result.WRITE3res_u.resok.verf, wverf,
+ NFS3_WRITEVERFSIZE);
+ } else {
+ /* error during write or close */
+ result.status = write_write_err();
+ }
+ } else
+ /* could not open for writing */
+ result.status = write_open_err();
+ }
+
+ /* overlaps with resfail */
+ result.WRITE3res_u.resok.file_wcc.before = get_pre_cached();
+ result.WRITE3res_u.resok.file_wcc.after = get_post_stat(path, rqstp);
+
+ return &result;
+}
+
+#ifndef WIN32
+
+/*
+ * store verifier in atime and mtime
+ */
+static int store_create_verifier(char *obj, createverf3 verf)
+{
+ struct utimbuf ubuf;
+
+ ubuf.actime = verf[0] | verf[1] << 8 | verf[2] << 16 | verf[3] << 24;
+ ubuf.modtime = verf[4] | verf[5] << 8 | verf[6] << 16 | verf[7] << 24;
+
+ return backend_utime(obj, &ubuf);
+}
+
+/*
+ * check if a create verifier matches
+ */
+static int check_create_verifier(backend_statstruct * buf, createverf3 verf)
+{
+ return ((buf->st_atime ==
+ (verf[0] | verf[1] << 8 | verf[2] << 16 | verf[3] << 24))
+ && (buf->st_mtime ==
+ (verf[4] | verf[5] << 8 | verf[6] << 16 | verf[7] << 24)));
+}
+#endif /* WIN32 */
+
+CREATE3res *nfsproc3_create_3_svc(CREATE3args * argp, struct svc_req * rqstp)
+{
+ static CREATE3res result;
+ char *path;
+ char obj[NFS_MAXPATHLEN];
+ sattr3 new_attr;
+ int fd = -1, res = -1;
+ backend_statstruct buf;
+ uint32 gen;
+ int flags = O_RDWR | O_CREAT | O_TRUNC | O_NONBLOCK;
+
+ PREP(path, argp->where.dir);
+ result.status = join(cat_name(path, argp->where.name, obj), exports_rw());
+
+ cluster_create(obj, rqstp, &result.status);
+
+ /* GUARDED and EXCLUSIVE maps to Unix exclusive create */
+ if (argp->how.mode != UNCHECKED)
+ flags = flags | O_EXCL;
+
+ if (argp->how.mode != EXCLUSIVE) {
+ new_attr = argp->how.createhow3_u.obj_attributes;
+ result.status = join(result.status, atomic_attr(new_attr));
+ }
+
+ /* Try to open the file */
+ if (result.status == NFS3_OK) {
+ if (argp->how.mode != EXCLUSIVE) {
+ fd = backend_open_create(obj, flags, create_mode(new_attr));
+ } else {
+ fd = backend_open_create(obj, flags, create_mode(new_attr));
+ }
+ }
+
+ if (fd != -1) {
+ /* Successful open */
+ res = backend_fstat(fd, &buf);
+ if (res != -1) {
+ /* Successful stat */
+ if (argp->how.mode == EXCLUSIVE) {
+ /* Save verifier in atime and mtime */
+ res =
+ backend_store_create_verifier(obj,
+ argp->how.createhow3_u.
+ verf);
+ }
+ }
+
+ if (res != -1) {
+ /* So far, so good */
+ gen = backend_get_gen(buf, fd, obj);
+ fh_cache_add(buf.st_dev, buf.st_ino, obj);
+ backend_close(fd);
+
+ result.CREATE3res_u.resok.obj =
+ fh_extend_post(argp->where.dir, buf.st_dev, buf.st_ino, gen);
+ result.CREATE3res_u.resok.obj_attributes =
+ get_post_buf(buf, rqstp);
+ }
+
+ if (res == -1) {
+ /* backend_fstat() or backend_store_create_verifier() failed */
+ backend_close(fd);
+ result.status = NFS3ERR_IO;
+ }
+
+ } else if (result.status == NFS3_OK) {
+ /* open() failed */
+ if (argp->how.mode == EXCLUSIVE && errno == EEXIST) {
+ /* Check if verifier matches */
+ fd = backend_open(obj, O_NONBLOCK);
+ if (fd != -1) {
+ res = backend_fstat(fd, &buf);
+ }
+
+ if (res != -1) {
+ if (backend_check_create_verifier
+ (&buf, argp->how.createhow3_u.verf)) {
+ /* The verifier matched. Return success */
+ gen = backend_get_gen(buf, fd, obj);
+ fh_cache_add(buf.st_dev, buf.st_ino, obj);
+ backend_close(fd);
+
+ result.CREATE3res_u.resok.obj =
+ fh_extend_post(argp->where.dir, buf.st_dev,
+ buf.st_ino, gen);
+ result.CREATE3res_u.resok.obj_attributes =
+ get_post_buf(buf, rqstp);
+ } else {
+ /* The verifier doesn't match */
+ result.status = NFS3ERR_EXIST;
+ }
+ }
+ }
+ if (res == -1) {
+ result.status = create_err();
+ }
+ }
+
+ /* overlaps with resfail */
+ result.CREATE3res_u.resok.dir_wcc.before = get_pre_cached();
+ result.CREATE3res_u.resok.dir_wcc.after = get_post_stat(path, rqstp);
+
+ return &result;
+}
+
+MKDIR3res *nfsproc3_mkdir_3_svc(MKDIR3args * argp, struct svc_req * rqstp)
+{
+ static MKDIR3res result;
+ char *path;
+ pre_op_attr pre;
+ post_op_attr post;
+ char obj[NFS_MAXPATHLEN];
+ int res;
+
+ PREP(path, argp->where.dir);
+ pre = get_pre_cached();
+ result.status =
+ join3(cat_name(path, argp->where.name, obj),
+ atomic_attr(argp->attributes), exports_rw());
+
+ cluster_create(obj, rqstp, &result.status);
+
+ if (result.status == NFS3_OK) {
+ res = backend_mkdir(obj, create_mode(argp->attributes));
+ if (res == -1)
+ result.status = mkdir_err();
+ else {
+ result.MKDIR3res_u.resok.obj =
+ fh_extend_type(argp->where.dir, obj, S_IFDIR);
+ result.MKDIR3res_u.resok.obj_attributes = get_post_cached(rqstp);
+ }
+ }
+
+ post = get_post_attr(path, argp->where.dir, rqstp);
+
+ /* overlaps with resfail */
+ result.MKDIR3res_u.resok.dir_wcc.before = pre;
+ result.MKDIR3res_u.resok.dir_wcc.after = post;
+
+ return &result;
+}
+
+SYMLINK3res *nfsproc3_symlink_3_svc(SYMLINK3args * argp,
+ struct svc_req * rqstp)
+{
+ static SYMLINK3res result;
+ char *path;
+ pre_op_attr pre;
+ post_op_attr post;
+ char obj[NFS_MAXPATHLEN];
+ int res;
+ mode_t new_mode;
+
+ PREP(path, argp->where.dir);
+ pre = get_pre_cached();
+ result.status =
+ join3(cat_name(path, argp->where.name, obj),
+ atomic_attr(argp->symlink.symlink_attributes), exports_rw());
+
+ cluster_create(obj, rqstp, &result.status);
+
+ if (argp->symlink.symlink_attributes.mode.set_it == TRUE)
+ new_mode = create_mode(argp->symlink.symlink_attributes);
+ else {
+ /* default rwxrwxrwx */
+ new_mode =
+ S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IWGRP | S_IXGRP |
+ S_IROTH | S_IWOTH | S_IXOTH;
+ }
+
+ if (result.status == NFS3_OK) {
+ umask(~new_mode);
+ res = backend_symlink(argp->symlink.symlink_data, obj);
+ umask(0);
+ if (res == -1)
+ result.status = symlink_err();
+ else {
+ result.SYMLINK3res_u.resok.obj =
+ fh_extend_type(argp->where.dir, obj, S_IFLNK);
+ result.SYMLINK3res_u.resok.obj_attributes =
+ get_post_cached(rqstp);
+ }
+ }
+
+ post = get_post_attr(path, argp->where.dir, rqstp);
+
+ /* overlaps with resfail */
+ result.SYMLINK3res_u.resok.dir_wcc.before = pre;
+ result.SYMLINK3res_u.resok.dir_wcc.after = post;
+
+ return &result;
+}
+
+#ifndef WIN32
+
+/*
+ * create Unix socket
+ */
+static int mksocket(const char *path, mode_t mode)
+{
+ int res, sock;
+ struct sockaddr_un addr;
+
+ sock = socket(PF_UNIX, SOCK_STREAM, 0);
+ addr.sun_family = AF_UNIX;
+ strcpy(addr.sun_path, path);
+ res = sock;
+ if (res != -1) {
+ umask(~mode);
+ res =
+ bind(sock, (struct sockaddr *) &addr,
+ sizeof(addr.sun_family) + strlen(addr.sun_path));
+ umask(0);
+ close(sock);
+ }
+ return res;
+}
+
+#endif /* WIN32 */
+
+/*
+ * check and process arguments to MKNOD procedure
+ */
+static nfsstat3 mknod_args(mknoddata3 what, const char *obj, mode_t * mode,
+ dev_t * dev)
+{
+ sattr3 attr;
+
+ /* determine attributes */
+ switch (what.type) {
+ case NF3REG:
+ case NF3DIR:
+ case NF3LNK:
+ return NFS3ERR_INVAL;
+ case NF3SOCK:
+ if (strlen(obj) + 1 > UNIX_PATH_MAX)
+ return NFS3ERR_NAMETOOLONG;
+ /* fall thru */
+ case NF3FIFO:
+ attr = what.mknoddata3_u.pipe_attributes;
+ break;
+ case NF3BLK:
+ case NF3CHR:
+ attr = what.mknoddata3_u.device.dev_attributes;
+ *dev = (what.mknoddata3_u.device.spec.specdata1 << 8)
+ + what.mknoddata3_u.device.spec.specdata2;
+ break;
+ }
+
+ *mode = create_mode(attr);
+
+ /* adjust mode for creation of device special files */
+ switch (what.type) {
+ case NF3CHR:
+ *mode |= S_IFCHR;
+ break;
+ case NF3BLK:
+ *mode |= S_IFBLK;
+ break;
+ default:
+ break;
+ }
+
+ return atomic_attr(attr);
+}
+
+MKNOD3res *nfsproc3_mknod_3_svc(MKNOD3args * argp, struct svc_req * rqstp)
+{
+ static MKNOD3res result;
+ char *path;
+ pre_op_attr pre;
+ post_op_attr post;
+ char obj[NFS_MAXPATHLEN];
+ int res;
+ mode_t new_mode = 0;
+ dev_t dev = 0;
+
+ PREP(path, argp->where.dir);
+ pre = get_pre_cached();
+ result.status =
+ join3(cat_name(path, argp->where.name, obj),
+ mknod_args(argp->what, obj, &new_mode, &dev), exports_rw());
+
+ cluster_create(obj, rqstp, &result.status);
+
+ if (result.status == NFS3_OK) {
+ if (argp->what.type == NF3CHR || argp->what.type == NF3BLK)
+ res = backend_mknod(obj, new_mode, dev); /* device */
+ else if (argp->what.type == NF3FIFO)
+ res = backend_mkfifo(obj, new_mode); /* FIFO */
+ else
+ res = backend_mksocket(obj, new_mode); /* socket */
+
+ if (res == -1) {
+ result.status = mknod_err();
+ } else {
+ result.MKNOD3res_u.resok.obj =
+ fh_extend_type(argp->where.dir, obj,
+ type_to_mode(argp->what.type));
+ result.MKNOD3res_u.resok.obj_attributes = get_post_cached(rqstp);
+ }
+ }
+
+ post = get_post_attr(path, argp->where.dir, rqstp);
+
+ /* overlaps with resfail */
+ result.MKNOD3res_u.resok.dir_wcc.before = pre;
+ result.MKNOD3res_u.resok.dir_wcc.after = post;
+
+ return &result;
+}
+
+REMOVE3res *nfsproc3_remove_3_svc(REMOVE3args * argp, struct svc_req * rqstp)
+{
+ static REMOVE3res result;
+ char *path;
+ char obj[NFS_MAXPATHLEN];
+ int res;
+
+ PREP(path, argp->object.dir);
+ result.status =
+ join(cat_name(path, argp->object.name, obj), exports_rw());
+
+ cluster_lookup(obj, rqstp, &result.status);
+
+ if (result.status == NFS3_OK) {
+ change_readdir_cookie();
+ res = backend_remove(obj);
+ if (res == -1)
+ result.status = remove_err();
+ }
+
+ /* overlaps with resfail */
+ result.REMOVE3res_u.resok.dir_wcc.before = get_pre_cached();
+ result.REMOVE3res_u.resok.dir_wcc.after = get_post_stat(path, rqstp);
+
+ return &result;
+}
+
+RMDIR3res *nfsproc3_rmdir_3_svc(RMDIR3args * argp, struct svc_req * rqstp)
+{
+ static RMDIR3res result;
+ char *path;
+ char obj[NFS_MAXPATHLEN];
+ int res;
+
+ PREP(path, argp->object.dir);
+ result.status =
+ join(cat_name(path, argp->object.name, obj), exports_rw());
+
+ cluster_lookup(obj, rqstp, &result.status);
+
+ if (result.status == NFS3_OK) {
+ change_readdir_cookie();
+ res = backend_rmdir(obj);
+ if (res == -1)
+ result.status = rmdir_err();
+ }
+
+ /* overlaps with resfail */
+ result.RMDIR3res_u.resok.dir_wcc.before = get_pre_cached();
+ result.RMDIR3res_u.resok.dir_wcc.after = get_post_stat(path, rqstp);
+
+ return &result;
+}
+
+RENAME3res *nfsproc3_rename_3_svc(RENAME3args * argp, struct svc_req * rqstp)
+{
+ static RENAME3res result;
+ char *from;
+ char *to;
+ char from_obj[NFS_MAXPATHLEN];
+ char to_obj[NFS_MAXPATHLEN];
+ pre_op_attr pre;
+ post_op_attr post;
+ int res;
+
+ PREP(from, argp->from.dir);
+ pre = get_pre_cached();
+ result.status =
+ join(cat_name(from, argp->from.name, from_obj), exports_rw());
+
+ cluster_lookup(from_obj, rqstp, &result.status);
+
+ to = fh_decomp(argp->to.dir);
+
+ if (result.status == NFS3_OK) {
+ result.status =
+ join(cat_name(to, argp->to.name, to_obj),
+ exports_compat(to, rqstp));
+
+ cluster_create(to_obj, rqstp, &result.status);
+
+ if (result.status == NFS3_OK) {
+ change_readdir_cookie();
+ res = backend_rename(from_obj, to_obj);
+ if (res == -1)
+ result.status = rename_err();
+ }
+ }
+
+ post = get_post_attr(from, argp->from.dir, rqstp);
+
+ /* overlaps with resfail */
+ result.RENAME3res_u.resok.fromdir_wcc.before = pre;
+ result.RENAME3res_u.resok.fromdir_wcc.after = post;
+ result.RENAME3res_u.resok.todir_wcc.before = get_pre_cached();
+ result.RENAME3res_u.resok.todir_wcc.after = get_post_stat(to, rqstp);
+
+ return &result;
+}
+
+LINK3res *nfsproc3_link_3_svc(LINK3args * argp, struct svc_req * rqstp)
+{
+ static LINK3res result;
+ char *path, *old;
+ pre_op_attr pre;
+ post_op_attr post;
+ char obj[NFS_MAXPATHLEN];
+ int res;
+
+ PREP(path, argp->link.dir);
+ pre = get_pre_cached();
+ result.status = join(cat_name(path, argp->link.name, obj), exports_rw());
+
+ cluster_create(obj, rqstp, &result.status);
+
+ old = fh_decomp(argp->file);
+
+ if (old && result.status == NFS3_OK) {
+ result.status = exports_compat(old, rqstp);
+
+ if (result.status == NFS3_OK) {
+ res = backend_link(old, obj);
+ if (res == -1)
+ result.status = link_err();
+ }
+ } else if (!old)
+ result.status = NFS3ERR_STALE;
+
+ post = get_post_attr(path, argp->link.dir, rqstp);
+
+ /* overlaps with resfail */
+ result.LINK3res_u.resok.file_attributes = get_post_stat(old, rqstp);
+ result.LINK3res_u.resok.linkdir_wcc.before = pre;
+ result.LINK3res_u.resok.linkdir_wcc.after = post;
+
+ return &result;
+}
+
+READDIR3res *nfsproc3_readdir_3_svc(READDIR3args * argp,
+ struct svc_req * rqstp)
+{
+ static READDIR3res result;
+ char *path;
+
+ PREP(path, argp->dir);
+
+ result = read_dir(path, argp->cookie, argp->cookieverf, argp->count);
+ result.READDIR3res_u.resok.dir_attributes = get_post_stat(path, rqstp);
+
+ return &result;
+}
+
+READDIRPLUS3res *nfsproc3_readdirplus_3_svc(U(READDIRPLUS3args * argp),
+ U(struct svc_req * rqstp))
+{
+ static READDIRPLUS3res result;
+
+ /*
+ * we don't do READDIRPLUS since it involves filehandle and
+ * attribute getting which is impossible to do atomically
+ * from user-space
+ */
+ result.status = NFS3ERR_NOTSUPP;
+ result.READDIRPLUS3res_u.resfail.dir_attributes.attributes_follow = FALSE;
+
+ return &result;
+}
+
+FSSTAT3res *nfsproc3_fsstat_3_svc(FSSTAT3args * argp, struct svc_req * rqstp)
+{
+ static FSSTAT3res result;
+ char *path;
+ backend_statvfsstruct buf;
+ int res;
+
+ PREP(path, argp->fsroot);
+
+ /* overlaps with resfail */
+ result.FSSTAT3res_u.resok.obj_attributes = get_post_cached(rqstp);
+
+ res = backend_statvfs(path, &buf);
+ if (res == -1) {
+ /* statvfs fell on its nose */
+ if ((exports_opts & OPT_REMOVABLE) && export_point(path)) {
+ /* Removable media export point; probably no media inserted.
+ Return dummy values. */
+ result.status = NFS3_OK;
+ result.FSSTAT3res_u.resok.tbytes = 0;
+ result.FSSTAT3res_u.resok.fbytes = 0;
+ result.FSSTAT3res_u.resok.abytes = 0;
+ result.FSSTAT3res_u.resok.tfiles = 0;
+ result.FSSTAT3res_u.resok.ffiles = 0;
+ result.FSSTAT3res_u.resok.afiles = 0;
+ result.FSSTAT3res_u.resok.invarsec = 0;
+ } else {
+ result.status = NFS3ERR_IO;
+ }
+ } else {
+ result.status = NFS3_OK;
+ result.FSSTAT3res_u.resok.tbytes =
+ (uint64) buf.f_blocks * buf.f_frsize;
+ result.FSSTAT3res_u.resok.fbytes =
+ (uint64) buf.f_bfree * buf.f_frsize;
+ result.FSSTAT3res_u.resok.abytes =
+ (uint64) buf.f_bavail * buf.f_frsize;
+ result.FSSTAT3res_u.resok.tfiles = buf.f_files;
+ result.FSSTAT3res_u.resok.ffiles = buf.f_ffree;
+ result.FSSTAT3res_u.resok.afiles = buf.f_ffree;
+ result.FSSTAT3res_u.resok.invarsec = 0;
+ }
+
+ return &result;
+}
+
+FSINFO3res *nfsproc3_fsinfo_3_svc(FSINFO3args * argp, struct svc_req * rqstp)
+{
+ static FSINFO3res result;
+ char *path;
+ unsigned int maxdata;
+
+ if (get_socket_type(rqstp) == SOCK_STREAM)
+ maxdata = NFS_MAXDATA_TCP;
+ else
+ maxdata = NFS_MAXDATA_UDP;
+
+ PREP(path, argp->fsroot);
+
+ result.FSINFO3res_u.resok.obj_attributes = get_post_cached(rqstp);
+
+ result.status = NFS3_OK;
+ result.FSINFO3res_u.resok.rtmax = maxdata;
+ result.FSINFO3res_u.resok.rtpref = maxdata;
+ result.FSINFO3res_u.resok.rtmult = 4096;
+ result.FSINFO3res_u.resok.wtmax = maxdata;
+ result.FSINFO3res_u.resok.wtpref = maxdata;
+ result.FSINFO3res_u.resok.wtmult = 4096;
+ result.FSINFO3res_u.resok.dtpref = 4096;
+ result.FSINFO3res_u.resok.maxfilesize = ~0ULL;
+ result.FSINFO3res_u.resok.time_delta.seconds = backend_time_delta_seconds;
+ result.FSINFO3res_u.resok.time_delta.nseconds = 0;
+ result.FSINFO3res_u.resok.properties = backend_fsinfo_properties;
+
+ return &result;
+}
+
+PATHCONF3res *nfsproc3_pathconf_3_svc(PATHCONF3args * argp,
+ struct svc_req * rqstp)
+{
+ static PATHCONF3res result;
+ char *path;
+
+ PREP(path, argp->object);
+
+ result.PATHCONF3res_u.resok.obj_attributes = get_post_cached(rqstp);
+
+ result.status = NFS3_OK;
+ result.PATHCONF3res_u.resok.linkmax = 0xFFFFFFFF;
+ result.PATHCONF3res_u.resok.name_max = NFS_MAXPATHLEN;
+ result.PATHCONF3res_u.resok.no_trunc = TRUE;
+ result.PATHCONF3res_u.resok.chown_restricted = FALSE;
+ result.PATHCONF3res_u.resok.case_insensitive =
+ backend_pathconf_case_insensitive;
+ result.PATHCONF3res_u.resok.case_preserving = TRUE;
+
+ return &result;
+}
+
+COMMIT3res *nfsproc3_commit_3_svc(COMMIT3args * argp, struct svc_req * rqstp)
+{
+ static COMMIT3res result;
+ char *path;
+ int res;
+
+ PREP(path, argp->file);
+ result.status = join(is_reg(), exports_rw());
+
+ if (result.status == NFS3_OK) {
+ res = fd_sync(argp->file);
+ if (res != -1)
+ memcpy(result.COMMIT3res_u.resok.verf, wverf, NFS3_WRITEVERFSIZE);
+ else
+ /* error during fsync() or close() */
+ result.status = NFS3ERR_IO;
+ }
+
+ /* overlaps with resfail */
+ result.COMMIT3res_u.resfail.file_wcc.before = get_pre_cached();
+ result.COMMIT3res_u.resfail.file_wcc.after = get_post_stat(path, rqstp);
+
+ return &result;
+}
diff --git a/external/fs/unfs3-0.9.22/nfs.h b/external/fs/unfs3-0.9.22/nfs.h
new file mode 100644
index 0000000..63041fa
--- /dev/null
+++ b/external/fs/unfs3-0.9.22/nfs.h
@@ -0,0 +1,1007 @@
+/*
+ * UNFS3 NFS protocol definitions
+ * Generated by rpcgen
+ */
+
+#ifndef _NFS_PROT_H_RPCGEN
+#define _NFS_PROT_H_RPCGEN
+
+/* for lack of a better place */
+#ifdef __GNUC__
+#define U(x) x __attribute__ ((unused))
+#else
+#define U(x) x
+#endif
+
+#if HAVE_STDINT_H == 1
+#include <stdint.h>
+#endif
+
+#include <rpc/rpc.h>
+
+#define UNIX_PATH_MAX 108
+
+#define NFS_PORT 2049
+#define NFS_MAXDATA_TCP 524288
+#define NFS_MAXDATA_UDP 32768
+#define NFS_MAX_UDP_PACKET (NFS_MAXDATA_UDP + 4096) /* The extra 4096 bytes are for the RPC header */
+#define NFS_MAXPATHLEN 1024
+#define NFS_MAXNAMLEN 255
+#define NFS_FIFO_DEV -1
+#define NFSMODE_FMT 0170000
+#define NFSMODE_DIR 0040000
+#define NFSMODE_CHR 0020000
+#define NFSMODE_BLK 0060000
+#define NFSMODE_REG 0100000
+#define NFSMODE_LNK 0120000
+#define NFSMODE_SOCK 0140000
+#define NFSMODE_FIFO 0010000
+
+typedef char *filename;
+
+typedef char *nfspath;
+#define NFS3_FHSIZE 64
+#define NFS3_COOKIEVERFSIZE 8
+#define NFS3_CREATEVERFSIZE 8
+#define NFS3_WRITEVERFSIZE 8
+
+#if HAVE_UINT64 == 0
+typedef uint64_t uint64;
+#endif
+
+#if HAVE_INT64 == 0
+typedef int64_t int64;
+#endif
+
+#if HAVE_UINT32 == 0
+#if HAVE_XDR_U_LONG == 1
+typedef u_long uint32;
+#else
+typedef uint32_t uint32;
+#endif
+#endif
+
+#if HAVE_INT32 == 0
+#if HAVE_XDR_LONG == 1
+typedef long int32;
+#else
+typedef int32_t int32;
+#endif
+#endif
+
+typedef char *filename3;
+
+typedef char *nfspath3;
+
+typedef uint64 fileid3;
+
+typedef uint64 cookie3;
+
+typedef char cookieverf3[NFS3_COOKIEVERFSIZE];
+
+typedef char createverf3[NFS3_CREATEVERFSIZE];
+
+typedef char writeverf3[NFS3_WRITEVERFSIZE];
+
+typedef uint32 uid3;
+
+typedef uint32 gid3;
+
+typedef uint64 size3;
+
+typedef uint64 offset3;
+
+typedef uint32 mode3;
+
+typedef uint32 count3;
+
+enum nfsstat3 {
+ NFS3_OK = 0,
+ NFS3ERR_PERM = 1,
+ NFS3ERR_NOENT = 2,
+ NFS3ERR_IO = 5,
+ NFS3ERR_NXIO = 6,
+ NFS3ERR_ACCES = 13,
+ NFS3ERR_EXIST = 17,
+ NFS3ERR_XDEV = 18,
+ NFS3ERR_NODEV = 19,
+ NFS3ERR_NOTDIR = 20,
+ NFS3ERR_ISDIR = 21,
+ NFS3ERR_INVAL = 22,
+ NFS3ERR_FBIG = 27,
+ NFS3ERR_NOSPC = 28,
+ NFS3ERR_ROFS = 30,
+ NFS3ERR_MLINK = 31,
+ NFS3ERR_NAMETOOLONG = 63,
+ NFS3ERR_NOTEMPTY = 66,
+ NFS3ERR_DQUOT = 69,
+ NFS3ERR_STALE = 70,
+ NFS3ERR_REMOTE = 71,
+ NFS3ERR_BADHANDLE = 10001,
+ NFS3ERR_NOT_SYNC = 10002,
+ NFS3ERR_BAD_COOKIE = 10003,
+ NFS3ERR_NOTSUPP = 10004,
+ NFS3ERR_TOOSMALL = 10005,
+ NFS3ERR_SERVERFAULT = 10006,
+ NFS3ERR_BADTYPE = 10007,
+ NFS3ERR_JUKEBOX = 10008,
+};
+typedef enum nfsstat3 nfsstat3;
+
+enum ftype3 {
+ NF3REG = 1,
+ NF3DIR = 2,
+ NF3BLK = 3,
+ NF3CHR = 4,
+ NF3LNK = 5,
+ NF3SOCK = 6,
+ NF3FIFO = 7,
+};
+typedef enum ftype3 ftype3;
+
+struct specdata3 {
+ uint32 specdata1;
+ uint32 specdata2;
+};
+typedef struct specdata3 specdata3;
+
+struct nfs_fh3 {
+ struct {
+ u_int data_len;
+ char *data_val;
+ } data;
+};
+typedef struct nfs_fh3 nfs_fh3;
+
+struct nfstime3 {
+ uint32 seconds;
+ uint32 nseconds;
+};
+typedef struct nfstime3 nfstime3;
+
+struct fattr3 {
+ ftype3 type;
+ mode3 mode;
+ uint32 nlink;
+ uid3 uid;
+ gid3 gid;
+ size3 size;
+ size3 used;
+ specdata3 rdev;
+ uint64 fsid;
+ fileid3 fileid;
+ nfstime3 atime;
+ nfstime3 mtime;
+ nfstime3 ctime;
+};
+typedef struct fattr3 fattr3;
+
+struct post_op_attr {
+ bool_t attributes_follow;
+ union {
+ fattr3 attributes;
+ } post_op_attr_u;
+};
+typedef struct post_op_attr post_op_attr;
+
+struct wcc_attr {
+ size3 size;
+ nfstime3 mtime;
+ nfstime3 ctime;
+};
+typedef struct wcc_attr wcc_attr;
+
+struct pre_op_attr {
+ bool_t attributes_follow;
+ union {
+ wcc_attr attributes;
+ } pre_op_attr_u;
+};
+typedef struct pre_op_attr pre_op_attr;
+
+struct wcc_data {
+ pre_op_attr before;
+ post_op_attr after;
+};
+typedef struct wcc_data wcc_data;
+
+struct post_op_fh3 {
+ bool_t handle_follows;
+ union {
+ nfs_fh3 handle;
+ } post_op_fh3_u;
+};
+typedef struct post_op_fh3 post_op_fh3;
+
+enum time_how {
+ DONT_CHANGE = 0,
+ SET_TO_SERVER_TIME = 1,
+ SET_TO_CLIENT_TIME = 2,
+};
+typedef enum time_how time_how;
+
+struct set_mode3 {
+ bool_t set_it;
+ union {
+ mode3 mode;
+ } set_mode3_u;
+};
+typedef struct set_mode3 set_mode3;
+
+struct set_uid3 {
+ bool_t set_it;
+ union {
+ uid3 uid;
+ } set_uid3_u;
+};
+typedef struct set_uid3 set_uid3;
+
+struct set_gid3 {
+ bool_t set_it;
+ union {
+ gid3 gid;
+ } set_gid3_u;
+};
+typedef struct set_gid3 set_gid3;
+
+struct set_size3 {
+ bool_t set_it;
+ union {
+ size3 size;
+ } set_size3_u;
+};
+typedef struct set_size3 set_size3;
+
+struct set_atime {
+ time_how set_it;
+ union {
+ nfstime3 atime;
+ } set_atime_u;
+};
+typedef struct set_atime set_atime;
+
+struct set_mtime {
+ time_how set_it;
+ union {
+ nfstime3 mtime;
+ } set_mtime_u;
+};
+typedef struct set_mtime set_mtime;
+
+struct sattr3 {
+ set_mode3 mode;
+ set_uid3 uid;
+ set_gid3 gid;
+ set_size3 size;
+ set_atime atime;
+ set_mtime mtime;
+};
+typedef struct sattr3 sattr3;
+
+struct diropargs3 {
+ nfs_fh3 dir;
+ filename3 name;
+};
+typedef struct diropargs3 diropargs3;
+
+struct GETATTR3args {
+ nfs_fh3 object;
+};
+typedef struct GETATTR3args GETATTR3args;
+
+struct GETATTR3resok {
+ fattr3 obj_attributes;
+};
+typedef struct GETATTR3resok GETATTR3resok;
+
+struct GETATTR3res {
+ nfsstat3 status;
+ union {
+ GETATTR3resok resok;
+ } GETATTR3res_u;
+};
+typedef struct GETATTR3res GETATTR3res;
+
+struct sattrguard3 {
+ bool_t check;
+ union {
+ nfstime3 obj_ctime;
+ } sattrguard3_u;
+};
+typedef struct sattrguard3 sattrguard3;
+
+struct SETATTR3args {
+ nfs_fh3 object;
+ sattr3 new_attributes;
+ sattrguard3 guard;
+};
+typedef struct SETATTR3args SETATTR3args;
+
+struct SETATTR3resok {
+ wcc_data obj_wcc;
+};
+typedef struct SETATTR3resok SETATTR3resok;
+
+struct SETATTR3resfail {
+ wcc_data obj_wcc;
+};
+typedef struct SETATTR3resfail SETATTR3resfail;
+
+struct SETATTR3res {
+ nfsstat3 status;
+ union {
+ SETATTR3resok resok;
+ SETATTR3resfail resfail;
+ } SETATTR3res_u;
+};
+typedef struct SETATTR3res SETATTR3res;
+
+struct LOOKUP3args {
+ diropargs3 what;
+};
+typedef struct LOOKUP3args LOOKUP3args;
+
+struct LOOKUP3resok {
+ post_op_attr dir_attributes;
+ nfs_fh3 object;
+ post_op_attr obj_attributes;
+};
+typedef struct LOOKUP3resok LOOKUP3resok;
+
+struct LOOKUP3resfail {
+ post_op_attr dir_attributes;
+};
+typedef struct LOOKUP3resfail LOOKUP3resfail;
+
+struct LOOKUP3res {
+ nfsstat3 status;
+ union {
+ LOOKUP3resok resok;
+ LOOKUP3resfail resfail;
+ } LOOKUP3res_u;
+};
+typedef struct LOOKUP3res LOOKUP3res;
+
+#define ACCESS3_READ 0x0001
+#define ACCESS3_LOOKUP 0x0002
+#define ACCESS3_MODIFY 0x0004
+#define ACCESS3_EXTEND 0x0008
+#define ACCESS3_DELETE 0x0010
+#define ACCESS3_EXECUTE 0x0020
+
+struct ACCESS3args {
+ nfs_fh3 object;
+ uint32 access;
+};
+typedef struct ACCESS3args ACCESS3args;
+
+struct ACCESS3resok {
+ post_op_attr obj_attributes;
+ uint32 access;
+};
+typedef struct ACCESS3resok ACCESS3resok;
+
+struct ACCESS3resfail {
+ post_op_attr obj_attributes;
+};
+typedef struct ACCESS3resfail ACCESS3resfail;
+
+struct ACCESS3res {
+ nfsstat3 status;
+ union {
+ ACCESS3resok resok;
+ ACCESS3resfail resfail;
+ } ACCESS3res_u;
+};
+typedef struct ACCESS3res ACCESS3res;
+
+struct READLINK3args {
+ nfs_fh3 symlink;
+};
+typedef struct READLINK3args READLINK3args;
+
+struct READLINK3resok {
+ post_op_attr symlink_attributes;
+ nfspath3 data;
+};
+typedef struct READLINK3resok READLINK3resok;
+
+struct READLINK3resfail {
+ post_op_attr symlink_attributes;
+};
+typedef struct READLINK3resfail READLINK3resfail;
+
+struct READLINK3res {
+ nfsstat3 status;
+ union {
+ READLINK3resok resok;
+ READLINK3resfail resfail;
+ } READLINK3res_u;
+};
+typedef struct READLINK3res READLINK3res;
+
+struct READ3args {
+ nfs_fh3 file;
+ offset3 offset;
+ count3 count;
+};
+typedef struct READ3args READ3args;
+
+struct READ3resok {
+ post_op_attr file_attributes;
+ count3 count;
+ bool_t eof;
+ struct {
+ u_int data_len;
+ char *data_val;
+ } data;
+};
+typedef struct READ3resok READ3resok;
+
+struct READ3resfail {
+ post_op_attr file_attributes;
+};
+typedef struct READ3resfail READ3resfail;
+
+struct READ3res {
+ nfsstat3 status;
+ union {
+ READ3resok resok;
+ READ3resfail resfail;
+ } READ3res_u;
+};
+typedef struct READ3res READ3res;
+
+enum stable_how {
+ UNSTABLE = 0,
+ DATA_SYNC = 1,
+ FILE_SYNC = 2,
+};
+typedef enum stable_how stable_how;
+
+struct WRITE3args {
+ nfs_fh3 file;
+ offset3 offset;
+ count3 count;
+ stable_how stable;
+ struct {
+ u_int data_len;
+ char *data_val;
+ } data;
+};
+typedef struct WRITE3args WRITE3args;
+
+struct WRITE3resok {
+ wcc_data file_wcc;
+ count3 count;
+ stable_how committed;
+ writeverf3 verf;
+};
+typedef struct WRITE3resok WRITE3resok;
+
+struct WRITE3resfail {
+ wcc_data file_wcc;
+};
+typedef struct WRITE3resfail WRITE3resfail;
+
+struct WRITE3res {
+ nfsstat3 status;
+ union {
+ WRITE3resok resok;
+ WRITE3resfail resfail;
+ } WRITE3res_u;
+};
+typedef struct WRITE3res WRITE3res;
+
+enum createmode3 {
+ UNCHECKED = 0,
+ GUARDED = 1,
+ EXCLUSIVE = 2,
+};
+typedef enum createmode3 createmode3;
+
+struct createhow3 {
+ createmode3 mode;
+ union {
+ sattr3 obj_attributes;
+ createverf3 verf;
+ } createhow3_u;
+};
+typedef struct createhow3 createhow3;
+
+struct CREATE3args {
+ diropargs3 where;
+ createhow3 how;
+};
+typedef struct CREATE3args CREATE3args;
+
+struct CREATE3resok {
+ wcc_data dir_wcc;
+ post_op_fh3 obj;
+ post_op_attr obj_attributes;
+};
+typedef struct CREATE3resok CREATE3resok;
+
+struct CREATE3resfail {
+ wcc_data dir_wcc;
+};
+typedef struct CREATE3resfail CREATE3resfail;
+
+struct CREATE3res {
+ nfsstat3 status;
+ union {
+ CREATE3resok resok;
+ CREATE3resfail resfail;
+ } CREATE3res_u;
+};
+typedef struct CREATE3res CREATE3res;
+
+struct MKDIR3args {
+ diropargs3 where;
+ sattr3 attributes;
+};
+typedef struct MKDIR3args MKDIR3args;
+
+struct MKDIR3resok {
+ wcc_data dir_wcc;
+ post_op_fh3 obj;
+ post_op_attr obj_attributes;
+};
+typedef struct MKDIR3resok MKDIR3resok;
+
+struct MKDIR3resfail {
+ wcc_data dir_wcc;
+};
+typedef struct MKDIR3resfail MKDIR3resfail;
+
+struct MKDIR3res {
+ nfsstat3 status;
+ union {
+ MKDIR3resok resok;
+ MKDIR3resfail resfail;
+ } MKDIR3res_u;
+};
+typedef struct MKDIR3res MKDIR3res;
+
+struct symlinkdata3 {
+ sattr3 symlink_attributes;
+ nfspath3 symlink_data;
+};
+typedef struct symlinkdata3 symlinkdata3;
+
+struct SYMLINK3args {
+ diropargs3 where;
+ symlinkdata3 symlink;
+};
+typedef struct SYMLINK3args SYMLINK3args;
+
+struct SYMLINK3resok {
+ wcc_data dir_wcc;
+ post_op_fh3 obj;
+ post_op_attr obj_attributes;
+};
+typedef struct SYMLINK3resok SYMLINK3resok;
+
+struct SYMLINK3resfail {
+ wcc_data dir_wcc;
+};
+typedef struct SYMLINK3resfail SYMLINK3resfail;
+
+struct SYMLINK3res {
+ nfsstat3 status;
+ union {
+ SYMLINK3resok resok;
+ SYMLINK3resfail resfail;
+ } SYMLINK3res_u;
+};
+typedef struct SYMLINK3res SYMLINK3res;
+
+struct devicedata3 {
+ sattr3 dev_attributes;
+ specdata3 spec;
+};
+typedef struct devicedata3 devicedata3;
+
+struct mknoddata3 {
+ ftype3 type;
+ union {
+ devicedata3 device;
+ sattr3 pipe_attributes;
+ } mknoddata3_u;
+};
+typedef struct mknoddata3 mknoddata3;
+
+struct MKNOD3args {
+ diropargs3 where;
+ mknoddata3 what;
+};
+typedef struct MKNOD3args MKNOD3args;
+
+struct MKNOD3resok {
+ wcc_data dir_wcc;
+ post_op_fh3 obj;
+ post_op_attr obj_attributes;
+};
+typedef struct MKNOD3resok MKNOD3resok;
+
+struct MKNOD3resfail {
+ wcc_data dir_wcc;
+};
+typedef struct MKNOD3resfail MKNOD3resfail;
+
+struct MKNOD3res {
+ nfsstat3 status;
+ union {
+ MKNOD3resok resok;
+ MKNOD3resfail resfail;
+ } MKNOD3res_u;
+};
+typedef struct MKNOD3res MKNOD3res;
+
+struct REMOVE3args {
+ diropargs3 object;
+};
+typedef struct REMOVE3args REMOVE3args;
+
+struct REMOVE3resok {
+ wcc_data dir_wcc;
+};
+typedef struct REMOVE3resok REMOVE3resok;
+
+struct REMOVE3resfail {
+ wcc_data dir_wcc;
+};
+typedef struct REMOVE3resfail REMOVE3resfail;
+
+struct REMOVE3res {
+ nfsstat3 status;
+ union {
+ REMOVE3resok resok;
+ REMOVE3resfail resfail;
+ } REMOVE3res_u;
+};
+typedef struct REMOVE3res REMOVE3res;
+
+struct RMDIR3args {
+ diropargs3 object;
+};
+typedef struct RMDIR3args RMDIR3args;
+
+struct RMDIR3resok {
+ wcc_data dir_wcc;
+};
+typedef struct RMDIR3resok RMDIR3resok;
+
+struct RMDIR3resfail {
+ wcc_data dir_wcc;
+};
+typedef struct RMDIR3resfail RMDIR3resfail;
+
+struct RMDIR3res {
+ nfsstat3 status;
+ union {
+ RMDIR3resok resok;
+ RMDIR3resfail resfail;
+ } RMDIR3res_u;
+};
+typedef struct RMDIR3res RMDIR3res;
+
+struct RENAME3args {
+ diropargs3 from;
+ diropargs3 to;
+};
+typedef struct RENAME3args RENAME3args;
+
+struct RENAME3resok {
+ wcc_data fromdir_wcc;
+ wcc_data todir_wcc;
+};
+typedef struct RENAME3resok RENAME3resok;
+
+struct RENAME3resfail {
+ wcc_data fromdir_wcc;
+ wcc_data todir_wcc;
+};
+typedef struct RENAME3resfail RENAME3resfail;
+
+struct RENAME3res {
+ nfsstat3 status;
+ union {
+ RENAME3resok resok;
+ RENAME3resfail resfail;
+ } RENAME3res_u;
+};
+typedef struct RENAME3res RENAME3res;
+
+struct LINK3args {
+ nfs_fh3 file;
+ diropargs3 link;
+};
+typedef struct LINK3args LINK3args;
+
+struct LINK3resok {
+ post_op_attr file_attributes;
+ wcc_data linkdir_wcc;
+};
+typedef struct LINK3resok LINK3resok;
+
+struct LINK3resfail {
+ post_op_attr file_attributes;
+ wcc_data linkdir_wcc;
+};
+typedef struct LINK3resfail LINK3resfail;
+
+struct LINK3res {
+ nfsstat3 status;
+ union {
+ LINK3resok resok;
+ LINK3resfail resfail;
+ } LINK3res_u;
+};
+typedef struct LINK3res LINK3res;
+
+struct READDIR3args {
+ nfs_fh3 dir;
+ cookie3 cookie;
+ cookieverf3 cookieverf;
+ count3 count;
+};
+typedef struct READDIR3args READDIR3args;
+
+struct entry3 {
+ fileid3 fileid;
+ filename3 name;
+ cookie3 cookie;
+ struct entry3 *nextentry;
+};
+typedef struct entry3 entry3;
+
+struct dirlist3 {
+ entry3 *entries;
+ bool_t eof;
+};
+typedef struct dirlist3 dirlist3;
+
+struct READDIR3resok {
+ post_op_attr dir_attributes;
+ cookieverf3 cookieverf;
+ dirlist3 reply;
+};
+typedef struct READDIR3resok READDIR3resok;
+
+struct READDIR3resfail {
+ post_op_attr dir_attributes;
+};
+typedef struct READDIR3resfail READDIR3resfail;
+
+struct READDIR3res {
+ nfsstat3 status;
+ union {
+ READDIR3resok resok;
+ READDIR3resfail resfail;
+ } READDIR3res_u;
+};
+typedef struct READDIR3res READDIR3res;
+
+struct READDIRPLUS3args {
+ nfs_fh3 dir;
+ cookie3 cookie;
+ cookieverf3 cookieverf;
+ count3 dircount;
+ count3 maxcount;
+};
+typedef struct READDIRPLUS3args READDIRPLUS3args;
+
+struct entryplus3 {
+ fileid3 fileid;
+ filename3 name;
+ cookie3 cookie;
+ post_op_attr name_attributes;
+ post_op_fh3 name_handle;
+ struct entryplus3 *nextentry;
+};
+typedef struct entryplus3 entryplus3;
+
+struct dirlistplus3 {
+ entryplus3 *entries;
+ bool_t eof;
+};
+typedef struct dirlistplus3 dirlistplus3;
+
+struct READDIRPLUS3resok {
+ post_op_attr dir_attributes;
+ cookieverf3 cookieverf;
+ dirlistplus3 reply;
+};
+typedef struct READDIRPLUS3resok READDIRPLUS3resok;
+
+struct READDIRPLUS3resfail {
+ post_op_attr dir_attributes;
+};
+typedef struct READDIRPLUS3resfail READDIRPLUS3resfail;
+
+struct READDIRPLUS3res {
+ nfsstat3 status;
+ union {
+ READDIRPLUS3resok resok;
+ READDIRPLUS3resfail resfail;
+ } READDIRPLUS3res_u;
+};
+typedef struct READDIRPLUS3res READDIRPLUS3res;
+
+struct FSSTAT3args {
+ nfs_fh3 fsroot;
+};
+typedef struct FSSTAT3args FSSTAT3args;
+
+struct FSSTAT3resok {
+ post_op_attr obj_attributes;
+ size3 tbytes;
+ size3 fbytes;
+ size3 abytes;
+ size3 tfiles;
+ size3 ffiles;
+ size3 afiles;
+ uint32 invarsec;
+};
+typedef struct FSSTAT3resok FSSTAT3resok;
+
+struct FSSTAT3resfail {
+ post_op_attr obj_attributes;
+};
+typedef struct FSSTAT3resfail FSSTAT3resfail;
+
+struct FSSTAT3res {
+ nfsstat3 status;
+ union {
+ FSSTAT3resok resok;
+ FSSTAT3resfail resfail;
+ } FSSTAT3res_u;
+};
+typedef struct FSSTAT3res FSSTAT3res;
+#define FSF3_LINK 0x0001
+#define FSF3_SYMLINK 0x0002
+#define FSF3_HOMOGENEOUS 0x0008
+#define FSF3_CANSETTIME 0x0010
+
+struct FSINFO3args {
+ nfs_fh3 fsroot;
+};
+typedef struct FSINFO3args FSINFO3args;
+
+struct FSINFO3resok {
+ post_op_attr obj_attributes;
+ uint32 rtmax;
+ uint32 rtpref;
+ uint32 rtmult;
+ uint32 wtmax;
+ uint32 wtpref;
+ uint32 wtmult;
+ uint32 dtpref;
+ size3 maxfilesize;
+ nfstime3 time_delta;
+ uint32 properties;
+};
+typedef struct FSINFO3resok FSINFO3resok;
+
+struct FSINFO3resfail {
+ post_op_attr obj_attributes;
+};
+typedef struct FSINFO3resfail FSINFO3resfail;
+
+struct FSINFO3res {
+ nfsstat3 status;
+ union {
+ FSINFO3resok resok;
+ FSINFO3resfail resfail;
+ } FSINFO3res_u;
+};
+typedef struct FSINFO3res FSINFO3res;
+
+struct PATHCONF3args {
+ nfs_fh3 object;
+};
+typedef struct PATHCONF3args PATHCONF3args;
+
+struct PATHCONF3resok {
+ post_op_attr obj_attributes;
+ uint32 linkmax;
+ uint32 name_max;
+ bool_t no_trunc;
+ bool_t chown_restricted;
+ bool_t case_insensitive;
+ bool_t case_preserving;
+};
+typedef struct PATHCONF3resok PATHCONF3resok;
+
+struct PATHCONF3resfail {
+ post_op_attr obj_attributes;
+};
+typedef struct PATHCONF3resfail PATHCONF3resfail;
+
+struct PATHCONF3res {
+ nfsstat3 status;
+ union {
+ PATHCONF3resok resok;
+ PATHCONF3resfail resfail;
+ } PATHCONF3res_u;
+};
+typedef struct PATHCONF3res PATHCONF3res;
+
+struct COMMIT3args {
+ nfs_fh3 file;
+ offset3 offset;
+ count3 count;
+};
+typedef struct COMMIT3args COMMIT3args;
+
+struct COMMIT3resok {
+ wcc_data file_wcc;
+ writeverf3 verf;
+};
+typedef struct COMMIT3resok COMMIT3resok;
+
+struct COMMIT3resfail {
+ wcc_data file_wcc;
+};
+typedef struct COMMIT3resfail COMMIT3resfail;
+
+struct COMMIT3res {
+ nfsstat3 status;
+ union {
+ COMMIT3resok resok;
+ COMMIT3resfail resfail;
+ } COMMIT3res_u;
+};
+typedef struct COMMIT3res COMMIT3res;
+
+#define NFS3_PROGRAM 100003
+#define NFS_V3 3
+
+#define NFSPROC3_NULL 0
+extern void * nfsproc3_null_3_svc(void *, struct svc_req *);
+#define NFSPROC3_GETATTR 1
+extern GETATTR3res * nfsproc3_getattr_3_svc(GETATTR3args *, struct svc_req *);
+#define NFSPROC3_SETATTR 2
+extern SETATTR3res * nfsproc3_setattr_3_svc(SETATTR3args *, struct svc_req *);
+#define NFSPROC3_LOOKUP 3
+extern LOOKUP3res * nfsproc3_lookup_3_svc(LOOKUP3args *, struct svc_req *);
+#define NFSPROC3_ACCESS 4
+extern ACCESS3res * nfsproc3_access_3_svc(ACCESS3args *, struct svc_req *);
+#define NFSPROC3_READLINK 5
+extern READLINK3res * nfsproc3_readlink_3_svc(READLINK3args *, struct svc_req *);
+#define NFSPROC3_READ 6
+extern READ3res * nfsproc3_read_3_svc(READ3args *, struct svc_req *);
+#define NFSPROC3_WRITE 7
+extern WRITE3res * nfsproc3_write_3_svc(WRITE3args *, struct svc_req *);
+#define NFSPROC3_CREATE 8
+extern CREATE3res * nfsproc3_create_3_svc(CREATE3args *, struct svc_req *);
+#define NFSPROC3_MKDIR 9
+extern MKDIR3res * nfsproc3_mkdir_3_svc(MKDIR3args *, struct svc_req *);
+#define NFSPROC3_SYMLINK 10
+extern SYMLINK3res * nfsproc3_symlink_3_svc(SYMLINK3args *, struct svc_req *);
+#define NFSPROC3_MKNOD 11
+extern MKNOD3res * nfsproc3_mknod_3_svc(MKNOD3args *, struct svc_req *);
+#define NFSPROC3_REMOVE 12
+extern REMOVE3res * nfsproc3_remove_3_svc(REMOVE3args *, struct svc_req *);
+#define NFSPROC3_RMDIR 13
+extern RMDIR3res * nfsproc3_rmdir_3_svc(RMDIR3args *, struct svc_req *);
+#define NFSPROC3_RENAME 14
+extern RENAME3res * nfsproc3_rename_3_svc(RENAME3args *, struct svc_req *);
+#define NFSPROC3_LINK 15
+extern LINK3res * nfsproc3_link_3_svc(LINK3args *, struct svc_req *);
+#define NFSPROC3_READDIR 16
+extern READDIR3res * nfsproc3_readdir_3_svc(READDIR3args *, struct svc_req *);
+#define NFSPROC3_READDIRPLUS 17
+extern READDIRPLUS3res * nfsproc3_readdirplus_3_svc(READDIRPLUS3args *, struct svc_req *);
+#define NFSPROC3_FSSTAT 18
+extern FSSTAT3res * nfsproc3_fsstat_3_svc(FSSTAT3args *, struct svc_req *);
+#define NFSPROC3_FSINFO 19
+extern FSINFO3res * nfsproc3_fsinfo_3_svc(FSINFO3args *, struct svc_req *);
+#define NFSPROC3_PATHCONF 20
+extern PATHCONF3res * nfsproc3_pathconf_3_svc(PATHCONF3args *, struct svc_req *);
+#define NFSPROC3_COMMIT 21
+extern COMMIT3res * nfsproc3_commit_3_svc(COMMIT3args *, struct svc_req *);
+extern int nfs3_program_3_freeresult (SVCXPRT *, xdrproc_t, caddr_t);
+
+#endif /* !_NFS_PROT_H_RPCGEN */
diff --git a/external/fs/unfs3-0.9.22/password.c b/external/fs/unfs3-0.9.22/password.c
new file mode 100644
index 0000000..868bb4d
--- /dev/null
+++ b/external/fs/unfs3-0.9.22/password.c
@@ -0,0 +1,116 @@
+
+/*
+ * UNFS3 mount password support routines
+ * (C) 2004, Peter Astrand <ast...@cendio.se>
+ * see file LICENSE for license details
+ */
+
+#include "config.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <rpc/rpc.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <string.h>
+#ifndef WIN32
+#include <syslog.h>
+#include <unistd.h>
+#include <sys/times.h> /* times */
+#endif /* WIN32 */
+#include <fcntl.h>
+#include <sys/time.h> /* gettimeofday */
+#include "md5.h"
+#include "backend.h"
+#include "daemon.h" /* logmsg */
+
+#ifndef WIN32
+int gen_nonce(char *nonce)
+{
+ struct stat st;
+ struct tms tmsbuf;
+ md5_state_t state;
+ unsigned int *arr;
+ int bytes_read, fd;
+
+ if (((fd = open("/dev/urandom", O_RDONLY)) != -1)
+ || ((fd = open("/dev/random", O_RDONLY)) != -1)) {
+ bytes_read = read(fd, nonce, 32);
+ close(fd);
+ if (bytes_read == 32)
+ return 0;
+ }
+
+ /* No /dev/random; do it by hand */
+ arr = (unsigned int *) nonce;
+ stat("/tmp", &st);
+ arr[0] = st.st_mtime;
+ arr[1] = st.st_atime;
+ arr[2] = st.st_ctime;
+ arr[3] = times(&tmsbuf);
+ arr[4] = tmsbuf.tms_cutime;
+ arr[5] = tmsbuf.tms_cstime;
+ gettimeofday((struct timeval *) &arr[6], NULL);
+
+ md5_init(&state);
+ md5_append(&state, (md5_byte_t *) nonce, 32);
+ md5_finish(&state, (md5_byte_t *) nonce);
+ return 0;
+}
+#endif /* WIN32 */
+
+static char nibble_as_hexchar(unsigned char c)
+{
+ if (c <= 9)
+ return c + '0';
+
+ return c - 10 + 'a';
+}
+
+static void hexify(md5_byte_t digest[16], char hexdigest[32])
+{
+ int i, j;
+
+ for (i = j = 0; i < 16; i++) {
+ char c;
+
+ /* The first four bits */
+ c = (digest[i] >> 4) & 0xf;
+ hexdigest[j++] = nibble_as_hexchar(c);
+ /* The next four bits */
+ c = (digest[i] & 0xf);
+ hexdigest[j++] = nibble_as_hexchar(c);
+ }
+}
+
+/* Handle mount commands:
+ * Advance dpath to first slash
+ * Copy command arguments to arg.
+*/
+void mnt_cmd_argument(char **dpath, const char *cmd, char *arg, size_t maxlen)
+{
+ char *slash;
+
+ *dpath += strlen(cmd);
+ strncpy(arg, *dpath, maxlen);
+ arg[maxlen] = '\0';
+
+ slash = strchr(arg, '/');
+ if (slash != NULL)
+ *slash = '\0';
+
+ *dpath += strlen(arg);
+}
+
+void otp_digest(char nonce[32], char *password, char hexdigest[32])
+{
+ md5_state_t state;
+ md5_byte_t digest[16];
+
+ /* Calculate the digest, in the same way as the client did */
+ md5_init(&state);
+ md5_append(&state, (md5_byte_t *) nonce, 32);
+ md5_append(&state, (md5_byte_t *) password, strlen(password));
+ md5_finish(&state, digest);
+ hexify(digest, hexdigest);
+}
diff --git a/external/fs/unfs3-0.9.22/password.h b/external/fs/unfs3-0.9.22/password.h
new file mode 100644
index 0000000..946a6d8
--- /dev/null
+++ b/external/fs/unfs3-0.9.22/password.h
@@ -0,0 +1,13 @@
+/*
+ * UNFS3 mount password support routines
+ * (C) 2004, Peter Astrand <ast...@cendio.se>
+ * see file LICENSE for license details
+ */
+
+int gen_nonce(char *nonce);
+
+void mnt_cmd_argument(char **dpath, const char *cmd, char *arg, size_t maxlen);
+
+void otp_digest(char nonce[32],
+ char *password,
+ char hexdigest[32]);
diff --git a/external/fs/unfs3-0.9.22/readdir.c b/external/fs/unfs3-0.9.22/readdir.c
new file mode 100644
index 0000000..0e7290c
--- /dev/null
+++ b/external/fs/unfs3-0.9.22/readdir.c
@@ -0,0 +1,215 @@
+
+/*
+ * UNFS3 readdir routine
+ * (C) 2004, Pascal Schmidt
+ * see file LICENSE for license details
+ */
+
+#include "config.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <rpc/rpc.h>
+#include <dirent.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "nfs.h"
+#include "mount.h"
+#include "fh.h"
+#include "readdir.h"
+#include "backend.h"
+#include "Config/exports.h"
+#include "daemon.h"
+#include "error.h"
+
+/*
+ * maximum number of entries in readdir results
+ *
+ * this is 4096 / 28 (the minimum size of an entry3)
+ */
+#define MAX_ENTRIES 143
+
+/*
+ * static READDIR3resok size with XDR overhead
+ *
+ * 88 bytes attributes, 8 bytes verifier, 4 bytes value_follows for
+ * first entry, 4 bytes eof flag
+ */
+#define RESOK_SIZE 104
+
+/*
+ * static entry3 size with XDR overhead
+ *
+ * 8 bytes fileid, 4 bytes name length, 8 bytes cookie, 4 byte value_follows
+ */
+#define ENTRY_SIZE 24
+
+/*
+ * size of a name with XDR overhead
+ *
+ * XDR pads to multiple of 4 bytes
+ */
+#define NAME_SIZE(x) (((strlen((x))+3)/4)*4)
+
+uint32 directory_hash(const char *path)
+{
+ backend_dirstream *search;
+ struct dirent *this;
+ uint32 hval = 0;
+
+ search = backend_opendir(path);
+ if (!search) {
+ return 0;
+ }
+
+ while ((this = backend_readdir(search)) != NULL) {
+ hval = fnv1a_32(this->d_name, hval);
+ }
+
+ backend_closedir(search);
+ return hval;
+}
+
+/*
+ * perform a READDIR operation
+ *
+ * fh_decomp must be called directly before to fill the stat cache
+ */
+READDIR3res read_dir(const char *path, cookie3 cookie, cookieverf3 verf,
+ count3 count)
+{
+ READDIR3res result;
+ READDIR3resok resok;
+ cookie3 upper;
+ static entry3 entry[MAX_ENTRIES];
+ backend_statstruct buf;
+ int res;
+ backend_dirstream *search;
+ struct dirent *this;
+ count3 i, real_count;
+ static char obj[NFS_MAXPATHLEN * MAX_ENTRIES];
+ char scratch[NFS_MAXPATHLEN];
+
+ /* check upper part of cookie */
+ upper = cookie & 0xFFFFFFFF00000000ULL;
+ if (cookie != 0 && upper != rcookie) {
+ /* ignore cookie if unexpected so we restart from the beginning */
+ cookie = 0;
+ }
+ cookie &= 0xFFFFFFFFULL;
+
+ /* we refuse to return more than 4k from READDIR */
+ if (count > 4096)
+ count = 4096;
+
+ /* account for size of information heading resok structure */
+ real_count = RESOK_SIZE;
+
+ /* We are always returning zero as a cookie verifier. One reason for this
+ is that stat() on Windows seems to return cached st_mtime values,
+ which gives spurious NFS3ERR_BAD_COOKIEs. Btw, here's what Peter
+ Staubach has to say about cookie verifiers:
+
+ "From my viewpoint, the cookieverifier was a failed experiment in NFS
+ Version 3. The semantics were never well understood nor supported by
+ many local file systems. The Solaris NFS server always returns zeros
+ in the cookieverifier field." */
+ memset(verf, 0, NFS3_COOKIEVERFSIZE);
+
+ search = backend_opendir(path);
+ if (!search) {
+ if ((exports_opts & OPT_REMOVABLE) && (export_point(path))) {
+ /* Removable media export point; probably no media inserted.
+ Return empty directory. */
+ memset(resok.cookieverf, 0, NFS3_COOKIEVERFSIZE);
+ resok.reply.entries = NULL;
+ resok.reply.eof = TRUE;
+ result.status = NFS3_OK;
+ result.READDIR3res_u.resok = resok;
+ return result;
+ } else {
+ result.status = readdir_err();
+ return result;
+ }
+ }
+
+ this = backend_readdir(search);
+ /* We cannot use telldir()/seekdir(), since the value from telldir() is
+ not valid after closedir(). */
+ for (i = 0; i < cookie; i++)
+ if (this)
+ this = backend_readdir(search);
+
+ i = 0;
+ entry[0].name = NULL;
+ while (this && real_count < count && i < MAX_ENTRIES) {
+ if (i > 0)
+ entry[i - 1].nextentry = &entry[i];
+
+ if (strlen(path) + strlen(this->d_name) + 1 < NFS_MAXPATHLEN) {
+
+ if (strcmp(path, "/") == 0)
+ sprintf(scratch, "/%s", this->d_name);
+ else
+ sprintf(scratch, "%s/%s", path, this->d_name);
+
+ res = backend_lstat(scratch, &buf);
+ if (res == -1) {
+ result.status = readdir_err();
+ backend_closedir(search);
+ return result;
+ }
+
+ strcpy(&obj[i * NFS_MAXPATHLEN], this->d_name);
+
+#ifdef WIN32
+ /* See comment in attr.c:get_post_buf */
+ entry[i].fileid = (buf.st_ino >> 32) ^ (buf.st_ino & 0xffffffff);
+#else
+ entry[i].fileid = buf.st_ino;
+#endif
+ entry[i].name = &obj[i * NFS_MAXPATHLEN];
+ entry[i].cookie = (cookie + 1 + i) | rcookie;
+ entry[i].nextentry = NULL;
+
+ /* account for entry size */
+ real_count += ENTRY_SIZE + NAME_SIZE(this->d_name);
+
+ /* whoops, overflowed the maximum size */
+ if (real_count > count && i > 0)
+ entry[i - 1].nextentry = NULL;
+ else {
+ /* advance to next entry */
+ this = backend_readdir(search);
+ }
+
+ i++;
+ } else {
+ result.status = NFS3ERR_IO;
+ backend_closedir(search);
+ return result;
+ }
+ }
+ backend_closedir(search);
+
+ if (entry[0].name)
+ resok.reply.entries = &entry[0];
+ else
+ resok.reply.entries = NULL;
+
+ if (this)
+ resok.reply.eof = FALSE;
+ else
+ resok.reply.eof = TRUE;
+
+ memcpy(resok.cookieverf, verf, NFS3_COOKIEVERFSIZE);
+
+ result.status = NFS3_OK;
+ result.READDIR3res_u.resok = resok;
+
+ return result;
+}
diff --git a/external/fs/unfs3-0.9.22/readdir.h b/external/fs/unfs3-0.9.22/readdir.h
new file mode 100644
index 0000000..3ec78bb
--- /dev/null
+++ b/external/fs/unfs3-0.9.22/readdir.h
@@ -0,0 +1,14 @@
+/*
+ * UNFS3 readdir routine
+ * (C) 2003, Pascal Schmidt
+ * see file LICENSE for license details
+ */
+
+#ifndef UNFS3_READDIR_H
+#define UNFS3_READDIR_H
+
+READDIR3res
+read_dir(const char *path, cookie3 cookie, cookieverf3 verf, count3 count);
+uint32 directory_hash(const char *path);
+
+#endif
diff --git a/external/fs/unfs3-0.9.22/unfs3.spec b/external/fs/unfs3-0.9.22/unfs3.spec
new file mode 100644
index 0000000..88859f0
--- /dev/null
+++ b/external/fs/unfs3-0.9.22/unfs3.spec
@@ -0,0 +1,38 @@
+%define version 0.9.22
+Summary: UNFS3 user-space NFSv3 server
+Group: Applications/System
+Name: unfs3
+Version: %{version}
+Release: 1
+License: BSD
+Packager: Pascal Schmidt <unfs3-...@ewetel.net>
+Vendor: none
+Source: unfs3-%{version}.tar.gz
+Buildroot: /tmp/unfs3
+
+%prep
+%setup
+
+%build
+./configure --enable-cluster --prefix=/usr --mandir=/usr/share/man
+make
+
+%install
+[ -n "$RPM_BUILD_ROOT" ] && rm -rf "$RPM_BUILD_ROOT"
+make DESTDIR="$RPM_BUILD_ROOT" install install-init
+
+%clean
+[ -n "$RPM_BUILD_ROOT" ] && rm -rf "$RPM_BUILD_ROOT"
+
+%description
+UNFS3 is a user-space implementation of the NFS (Network File System)
+version 3 server specification. It provides a daemon that supports both
+the MOUNT and NFS protocol.
+
+%files
+%attr ( -, root, root) %doc CREDITS README README.nfsroot LICENSE NEWS contrib doc
+%attr (755, root, root) /usr/sbin/unfsd
+%attr (755, root, root) /etc/init.d/unfsd
+%attr (644, root, root) %doc /usr/share/man/man7/tags.7.gz
+%attr (644, root, root) %doc /usr/share/man/man8/unfsd.8.gz
+
diff --git a/external/fs/unfs3-0.9.22/unfsd.8 b/external/fs/unfs3-0.9.22/unfsd.8
new file mode 100644
index 0000000..eb7dd20
--- /dev/null
+++ b/external/fs/unfs3-0.9.22/unfsd.8
@@ -0,0 +1,394 @@
+.\"
+.\" (C) 2008, Pascal Schmidt
+.\"
+.TH unfsd 8 "05 Jan 2008"
+.SH NAME
+unfsd \- NFS server process
+.SH SYNOPSIS
+.BI "/usr/sbin/unfsd [" options "]"
+.SH DESCRIPTION
+The
+.B unfsd
+program implements the MOUNT and NFS version 3 protocols. It listens for
+client requests, performs them on the local filesystem of the server, and
+then returns the results of the operations to the clients.
+.P
+At startup,
+.B unfsd
+reads the exports file,
+.I /etc/exports
+by default, to find out which directories are available to clients
+and what options are in effect (see
+.B EXPORTS FILE
+section below for syntax and possible options).
+.P
+Normally,
+.B unfsd
+should be run as the
+.B root
+user. It will then switch its effective
+user and group id to the numbers listed in incoming NFS requests. This
+means filesystem operations will be performed as if done by a local
+user with the same ids. If the incoming request is for user or group
+id 0 (meaning
+.BR root "), " unfsd
+will switch to the user and group id of the
+.B nobody
+user before performing filesystem operations (this is known as
+.BR "root squashing" ")."
+If the user
+.B nobody
+does not exist on the system, a user and group id of 65534 will be used.
+This behavior can be modified by use of the
+.B no_root_squash
+and
+.B all_squash
+options in the exports file as well as the
+.B anonuid
+and
+.B anongid
+options on a per-share basis.
+.P
+If
+.B unfsd
+is running as a normal unprivileged user, no switching of the effective
+user and group id will take place. Instead, all filesystem operations
+will be performed with the id of the user running
+.BR unfsd .
+.SH RESTRICTIONS
+Some NFS clients may attempt to perform operations that
+.B unfsd
+cannot fully support.
+.TP
+.B "Object Creation"
+When creating filesystem objects, it is only possible to specify the
+initial mode for the object. The initial user and group ownership,
+object size, and timestamps cannot be specified and will be set to
+default values.
+.TP
+.B "File Locking"
+The network lock manager (NLM) protocol is not supported. This means that
+clients may have to mount with special mount options, disabling locking
+on the mounted NFS volume (nolock for Linux clients).
+.SH OPTIONS
+.TP
+.B \-h
+Display a short option summary.
+.TP
+.BI "\-e " "\<file\>"
+Use the given file as the exports file, instead of using
+.IR /etc/exports .
+Note that the file needs to be specified using an absolute path.
+.TP
+.BI "\-i " "\<file\>"
+Use the given file as pid file. When the daemon starts up, it will
+write its pid (process id) to the given file. Upon exit, the daemon
+will remove the file. Failure to create or remove the pid file is
+not considered fatal and only reported to syslog.
+.TP
+.B \-u
+Use an unprivileged port for NFS and MOUNT service. Normally,
+.B unfsd
+will use port number 2049, which is the standard port for NFS.
+When this option is in effect, arbitrary ports chosen by the RPC library
+will be used. You may need to use this option when running
+.B unfsd
+from a normal user account.
+.TP
+.BI "\-n " "\<port\>"
+Use the specified port for the NFS service.
+.TP
+.BI "\-m " "\<port\>"
+Use the specified port for the MOUNT service. The default is to
+use port number 2049, the same as for the NFS service. You can use
+the same port for both services if you want.
+.TP
+.B \-t
+TCP only operation. By default,
+.B unfsd
+provides its services to clients using either UDP or TCP as communications
+protocol. When this option is present, only TCP connections are
+serviced.
+.TP
+.B \-p
+Do not register with the portmapper. This will prevent other hosts from
+finding out the port numbers used for the MOUNT and NFS services by
+querying the portmap daemon. Clients
+will need to manually specify the port numbers to use (on Linux clients,
+use the
+.BR mountport " and " port
+mount options).
+.TP
+.B \-c
+Enable cluster extensions. This feature is only available when
+.B unfsd
+was compiled with cluster support. When this option is enabled, so-called
+tagged files are handled differently from normal files, making it possible
+to serve different file contents to different clients for the same filename.
+See
+.BR tags (7)
+for a description of tagged files. This option causes a performance hit.
+.TP
+.BI "\-C" "\ <path>"
+Limit the use of cluster extensions to a list of colon-seperated
+directories. When this option is present, the performance hit caused by
+clustering extensions only applies to the listed directories and their
+subdirectories.
+.TP
+.B \-s
+Single user mode; activate basic uid translation. This option is
+useful when the server and client are using different user and group
+ids. All requests from the client will be served from the user id that started
+.B unfsd,
+no user id switching will take place (even if unfsd was started by
+root).
+Ownership is reported as follows: files belonging to the user id
+running
+.B unfsd
+will look as if they are owned by the client's user. Other files will
+look as if they are owned by root. The same principle applies to
+group ownership.
+.TP
+.B \-b
+Enable brute force file searching. Normally, when you rename a file
+across several directories on an NFS volume, the filehandle for that
+file becomes stale. When this option is enabled,
+.B unfsd
+will attempt a recursive search on the relevant server filesystem to
+find the file referenced by the filehandle. This can have a huge
+performance impact as this will also happen for files that were
+really deleted (by another NFS client) instead of moved, and cannot be found.
+.TP
+.B \-l <addr>
+Bind to interface with specified address. The default is to bind to
+all local interfaces.
+.TP
+.B \-d
+Debug mode. When this option is present,
+.B unfsd
+will not fork into the background at startup, and all messages that
+would normally go to the system log go to stdout instead.
+.TP
+.B \-r
+Report unreadable executables as readable. This applies both to
+returned attributes and ACCESS requests. Please note that READ
+requests for unreadable executables are always allowed, if
+.B unfsd
+is running as root, regardless of this option.
+.TP
+.B \-T
+Test exports file and exit. When this option is given,
+.B unfsd
+will try to parse the exports file and exit with status 0 if this
+is successful. If there is a syntax error in the exports file,
+a message is printed on standard error and
+.B unfsd
+exits with status 1.
+.SH SIGNALS
+.TP
+.BR "SIGTERM " "and " SIGINT
+will cause
+.B unfsd
+to unregister itself from the portmapper and exit.
+.TP
+.B SIGHUP
+will cause
+.B unfsd
+to re-read its configuration data. Currently, this means the program
+will query the
+.I passwd
+database to find out the user and group id of user
+.BR nobody .
+.B unfsd
+will also attempt to reload the exports file. If the exports file
+contains errors,
+.B unfsd
+sends a warning message to the system log and nothing is exported until
+the situation is corrected and another
+.B SIGHUP
+is sent.
+.TP
+.B SIGUSR1
+will cause
+.B unfsd
+to output statistics about its filehandle and file descriptor cache
+to the system log. For the filehandle cache, it will output the number
+of filehandles in the cache, the total number of cache accesses, and the
+number of hits and misses. For the file descriptor cache, it will output
+the number of currently held open READ and WRITE file descriptors.
+.SH "EXPORTS FILE"
+The exports file,
+.I /etc/exports
+by default, determines which directories on the server can be accessed
+from NFS clients. An example:
+
+.nf
+# sample NFS exports file
+/home trusted(rw,no_root_squash) (ro)
+"/with spaces" weirdo
+/usr 1.2.3.4(rw) 192.168.2.0/24(ro,all_squash)
+/home/foo bar(rw) 10.0.0.0/255.0.0.0(root_squash)
+/home/joe joes_pc(anonuid=1100,anongid=1100,rw,all_squash)
+.fi
+
+Comments start with a # character and cause the rest of the line to be
+ignored. Extremely long exports can be split across multiple lines by
+escaping the intermediate newlines with a backslash character.
+.P
+Each line starts with a directory that is to be exported. If
+the directory name contains whitespace, it must be enclosed in double
+quotes. To the right of the directory name, a list of client
+specifications can be given. If this list is missing, the directory
+is exported to everyone, using default options
+.RB ( ro " and " root_squash ")."
+.P
+If the directory name contains symbolic links, they are expanded. This
+means that you have to force
+.B unfsd
+to reload the exports file if the symlinks happen to change.
+.P
+Clients can be specified using either a hostname, an IP address, or
+an IP network. Networks can be given by specifying the number of leading 1
+bits in the netmask or by giving the full netmask. If the hostname is
+empty, the directory is exported to everyone.
+.P
+Options can follow a client specification and have to be enclosed
+in parenthesis, with the opening paren directly following the client
+name or address. If no options are given,
+.B ro
+and
+.B root_squash
+are enabled by default. The following options are supported by
+.BR unfsd :
+.TP
+.B root_squash
+Enable root squashing, mapping all NFS request done with a user id of
+0 to the user id of the
+.B nobody
+user. This option is enabled by default.
+.TP
+.B no_root_squash
+Disable root squashing. When this option is present, NFS requests done
+with a user id of 0 will be done as the
+.B root
+user of the server, effectively disabling all permissions checks.
+.TP
+.B all_squash
+Squash all users. When this option is present, all NFS requests will
+be done as the
+.B nobody
+user of the server.
+.TP
+.B no_all_squash
+Don't squash all users. This option is enabled by default.
+.TP
+.B rw
+Allow read and write access on the exported directory. When this option
+is present, clients are allowed to modify files and directories on
+the server.
+.TP
+.B ro
+Allow only read access on the exported directory. When this option
+is present, clients are not allowed to modify files and directories
+on the server. This option is enabled by default.
+.TP
+.B anonuid/anongid
+Sets the uid and gid for anonymous mounts for this share - by default the
+uid for nobody will be used, but using these options you can change this
+on a per-share basis.
+.TP
+.B secure
+Allow only mount requests coming from a source port below 1024. Using
+these ports requires super-user privileges on many operating systems.
+This option is enabled by default.
+.TP
+.B insecure
+Allow mount requests coming from any source port.
+.TP
+.B removable
+Consider this directory to be on a removable medium. When this option
+is present,
+.B unfsd
+will not keep files open across multiple read or write requests. This
+allows unmounting of the underlying filesystem on the server at any time.
+Also,
+.B unfsd
+will not require that the exported path exists at startup or mount
+time. If the path does not exist, an empty directory will be presented
+to the client. This is useful for exporting mount points handled by
+autofs.
+.TP
+.B fixed
+Consider this directory to be on a fixed medium. This options is enabled
+by default and allows
+.B unfsd
+to keep files open between multiple read or write requests.
+.TP
+.B password=<password>
+To be able to mount this export, the specified password is
+required. The password needs be given in the mount request,
+as in "mount yourhost:@password:gazonk/tmp /mnt". One time passwords
+are also supported. When using passwords, the file handles
+will include a hash of the password. This means that
+.B if you change the password, all clients will need to remount this export.
+See the file "doc/passwords.txt" in the source for more information.
+.PP
+If options not present on this list are encountered by
+.BR unfsd ,
+they are silently ignored.
+.SH BUGS
+There are a few possible race conditions with other processes on the
+server. They can happen if
+.B unfsd
+is performing an operation on a filesystem object while another
+process is simultaneously first (a) removing the object and then (b)
+creating a new object of the same name. If this happens,
+.B unfsd
+will attempt to perform the operation on the wrong, new object.
+The time window in which this can happen is small.
+.PP
+When a client does a CREATE EXCLUSIVE procedure call,
+.B unfsd
+stores the verifier data in the mtime and atime attributes of the
+created file. Malicious processes on the server could manipulate
+those attributes, breaking the semantics of the exclusive create
+operation. A process attempting to do so would need to be able
+to see the NFS network traffic.
+.PP
+unfsd always uses the "nohide" semantics, which means that clients
+will see all file systems mounted below the exported path. However,
+some NFS clients do not cope well with this situation as, for
+instance, it is then possible for two files in the one apparent
+filesystem to have the same inode number. To avoid this, make sure
+that the client mounts each exported file system.
+.PP
+Due to the way
+.B unfsd
+operates, it needs execute (lookup) and read permission on all directories
+from the root directory all the way up to exported directories.
+For example, if
+.I /usr/share
+is exported,
+.B unfsd
+is going to need permission for
+.IR / ", " /usr ", and " /usr/share .
+Since root squashing can be in effect,
+.B unfsd
+may run as the nobody user, which normally means having to grant
+execute (lookup) and read permission for everybody on the server.
+In the above example,
+.B unfsd
+also needs permission to access
+.IR /usr/share/.. ,
+which can be different from
+.I /usr
+for some special setups (for example when using bind mounts under
+Linux).
+.SH FILES
+.TP 20
+.I /etc/exports
+Default exports file.
+.SH AUTHOR
+Pascal Schmidt
+.SH "SEE ALSO"
+.BR tags (7)
diff --git a/external/fs/unfs3-0.9.22/unfsd.init b/external/fs/unfs3-0.9.22/unfsd.init
new file mode 100755
index 0000000..0f66d2a
--- /dev/null
+++ b/external/fs/unfs3-0.9.22/unfsd.init
@@ -0,0 +1,71 @@
+#!/bin/bash
+# -*- mode: shell-script; coding: UTF-8 -*-
+#
+# chkconfig: 235 99 10
+# description: Start or stop the unfs3 server
+#
+### BEGIN INIT INFO
+# Provides: unfsd
+# Required-Start: $network
+# Required-Stop: $network
+# Default-Start: 2 3 4 5
+# Default-Stop: 0 1 6
+# Description: Start or stop the unfs3 server
+### END INIT INFO
+
+description="unfs3 NFS server"
+lockfile="/var/lock/subsys/unfsd"
+pidfile="/var/run/unfsd.pid"
+
+
+case "$1" in
+ 'start')
+ echo "Starting" ${description}
+ /usr/sbin/unfsd -i ${pidfile}
+ RETVAL=$?
+ if [ "${RETVAL}" = "0" ]; then
+ touch ${lockfile} >/dev/null 2>&1
+ fi
+ ;;
+ 'stop')
+ echo "Shutting down" ${description}
+ if [ -s ${pidfile} ]; then
+ pid=`cat ${pidfile}`
+ kill -TERM ${pid} 2>/dev/null
+ sleep 2
+ if kill -0 ${pid} 2>/dev/null; then
+ kill -KILL ${pid}
+ fi
+ fi
+ rm -f ${lockfile} ${pidfile}
+ ;;
+ 'status')
+ if [ -s ${pidfile} ]; then
+ pid=`cat ${pidfile}`
+ if kill -0 ${pid} 2>/dev/null; then
+ echo "${description} (pid ${pid}) is running"
+ RETVAL=0
+ else
+ echo "${description} is stopped"
+ RETVAL=1
+ fi
+ else
+ echo "${description} is stopped"
+ RETVAL=1
+ fi
+ ;;
+ 'restart')
+ /etc/init.d/unfsd stop && /etc/init.d/unfsd start
+ RETVAL=$?
+ ;;
+ 'condrestart')
+ [ -f /var/lock/subsys/unfsd ] && /etc/init.d/unfsd stop && /etc/init.d/unfsd start
+ RETVAL=$?
+ ;;
+ *)
+ echo "Usage: $0 {start|stop|restart|condrestart|status}"
+ RETVAL=1
+ ;;
+esac
+exit $RETVAL
+
diff --git a/external/fs/unfs3-0.9.22/user.c b/external/fs/unfs3-0.9.22/user.c
new file mode 100644
index 0000000..241da1e
--- /dev/null
+++ b/external/fs/unfs3-0.9.22/user.c
@@ -0,0 +1,293 @@
+
+/*
+ * UNFS3 user and group id handling
+ * (C) 2003, Pascal Schmidt
+ * see file LICENSE for license details
+ */
+
+#include "config.h"
+
+#ifndef WIN32
+#include <pwd.h>
+#include <grp.h>
+#include <syslog.h>
+#include <unistd.h>
+#endif /* WIN32 */
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <rpc/rpc.h>
+#include <stdlib.h>
+
+#include "nfs.h"
+#include "mount.h"
+#include "daemon.h"
+#include "user.h"
+#include "backend.h"
+#include "Config/exports.h"
+
+/* user and group id we squash to */
+static uid_t squash_uid = 65534;
+static gid_t squash_gid = 65534;
+
+/* whether we can use seteuid/setegid */
+static int can_switch = TRUE;
+
+/*
+ * initialize group and user id used for squashing
+ */
+void get_squash_ids(void)
+{
+ backend_passwdstruct *passwd;
+
+ if (can_switch) {
+ passwd = backend_getpwnam("nobody");
+ if (passwd) {
+ squash_uid = passwd->pw_uid;
+ squash_gid = passwd->pw_gid;
+ } else {
+ squash_uid = 65534;
+ squash_gid = 65534;
+ }
+ }
+}
+
+/*
+ * mangle an id
+ */
+static int mangle(int id, int squash)
+{
+ if (!can_switch || (exports_opts & OPT_ALL_SQUASH))
+ return squash;
+ else if (exports_opts & OPT_NO_ROOT_SQUASH)
+ return id;
+ else if (id == 0)
+ return squash;
+ else
+ return id;
+}
+
+/*
+ * Mangle a given user id according to current settings
+ */
+int mangle_uid(int id)
+{
+ int squash = squash_uid;
+
+ if (exports_anonuid() != ANON_NOTSPECIAL)
+ squash = exports_anonuid();
+
+ return mangle(id, squash);
+}
+
+/*
+ * Mangle a given group id according to current settings
+ */
+int mangle_gid(int id)
+{
+ int squash = squash_gid;
+
+ if (exports_anongid() != ANON_NOTSPECIAL)
+ squash = exports_anongid();
+
+ return mangle(id, squash);
+}
+
+/*
+ * return user id of a request
+ */
+int get_uid(struct svc_req *req)
+{
+ struct authunix_parms *auth = (void *) req->rq_clntcred;
+ int squash = squash_uid;
+
+ if (exports_anonuid() != ANON_NOTSPECIAL)
+ squash = exports_anonuid();
+
+ if (req->rq_cred.oa_flavor == AUTH_UNIX)
+ return mangle(auth->aup_uid, squash);
+ else
+ return squash; /* fallback if no uid given */
+}
+
+/*
+ * return group id of a request
+ */
+static int get_gid(struct svc_req *req)
+{
+ struct authunix_parms *auth = (void *) req->rq_clntcred;
+ int squash = squash_gid;
+
+ if (exports_anongid() != ANON_NOTSPECIAL)
+ squash = exports_anongid();
+
+ if (req->rq_cred.oa_flavor == AUTH_UNIX)
+ return mangle(auth->aup_gid, squash);
+ else
+ return squash; /* fallback if no gid given */
+}
+
+/*
+ * check whether a request comes from a given user id
+ */
+int is_owner(int owner, struct svc_req *req)
+{
+ return (int) (owner == get_uid(req));
+}
+
+/*
+ * check if a request comes from somebody who has a given group id
+ */
+int has_group(int group, struct svc_req *req)
+{
+ struct authunix_parms *auth = (void *) req->rq_clntcred;
+ unsigned int i;
+
+ if (req->rq_cred.oa_flavor == AUTH_UNIX) {
+ if (mangle(auth->aup_gid, squash_gid) == group)
+ return TRUE;
+
+ /* search groups */
+ for (i = 0; i < auth->aup_len; i++)
+ if (mangle(auth->aup_gids[i], squash_gid) == group)
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/*
+ * switch to root
+ */
+void switch_to_root()
+{
+ if (!can_switch)
+ return;
+
+ backend_setegid(0);
+ backend_seteuid(0);
+}
+
+/*
+ * switch auxiliary group ids
+ */
+static int switch_groups(struct svc_req *req)
+{
+ struct authunix_parms *auth = (void *) req->rq_clntcred;
+ unsigned int i, max;
+
+ max = (auth->aup_len <= 32) ? auth->aup_len : 32;
+
+ for (i = 0; i < max; ++i) {
+ auth->aup_gids[i] = mangle(auth->aup_gids[i], squash_gid);
+ }
+
+ return backend_setgroups(max, auth->aup_gids);
+}
+
+/*
+ * switch user and group id to values listed in request
+ */
+void switch_user(struct svc_req *req)
+{
+ int uid, gid, aid;
+
+ if (!can_switch)
+ return;
+
+ if (opt_singleuser || (backend_getuid() != 0)) {
+ /*
+ * have uid/gid functions behave correctly by squashing
+ * all user and group ids to the current values
+ *
+ * otherwise ACCESS would malfunction
+ */
+ squash_uid = backend_getuid();
+ squash_gid = backend_getgid();
+
+ can_switch = FALSE;
+ return;
+ }
+
+ backend_setegid(0);
+ backend_seteuid(0);
+ gid = backend_setegid(get_gid(req));
+ aid = switch_groups(req);
+ uid = backend_seteuid(get_uid(req));
+
+ if (uid == -1 || gid == -1 || aid == -1) {
+ logmsg(LOG_EMERG, "euid/egid switching failed, aborting");
+ daemon_exit(CRISIS);
+ }
+}
+
+/*
+ * re-switch to root for reading executable files
+ */
+void read_executable(struct svc_req *req, backend_statstruct buf)
+{
+ int have_exec = 0;
+
+ if (is_owner(buf.st_uid, req)) {
+ if (!(buf.st_mode & S_IRUSR) && (buf.st_mode & S_IXUSR))
+ have_exec = 1;
+ } else if (has_group(buf.st_gid, req)) {
+ if (!(buf.st_mode & S_IRGRP) && (buf.st_mode & S_IXGRP))
+ have_exec = 1;
+ } else {
+ if (!(buf.st_mode & S_IROTH) && (buf.st_mode & S_IXOTH))
+ have_exec = 1;
+ }
+
+ if (have_exec) {
+ backend_setegid(0);
+ backend_seteuid(0);
+ }
+}
+
+/*
+ * re-switch to root for reading owned file
+ */
+void read_by_owner(struct svc_req *req, backend_statstruct buf)
+{
+ int have_owner = 0;
+ int have_read = 0;
+
+ have_owner = is_owner(buf.st_uid, req);
+
+ if (have_owner && (buf.st_mode & S_IRUSR)) {
+ have_read = 1;
+ } else if (has_group(buf.st_gid, req) && (buf.st_mode & S_IRGRP)) {
+ have_read = 1;
+ } else if (buf.st_mode & S_IROTH) {
+ have_read = 1;
+ }
+
+ if (have_owner && !have_read) {
+ backend_setegid(0);
+ backend_seteuid(0);
+ }
+}
+
+/*
+ * re-switch to root for writing owned file
+ */
+void write_by_owner(struct svc_req *req, backend_statstruct buf)
+{
+ int have_owner = 0;
+ int have_write = 0;
+
+ have_owner = is_owner(buf.st_uid, req);
+
+ if (have_owner && (buf.st_mode & S_IWUSR)) {
+ have_write = 1;
+ } else if (has_group(buf.st_gid, req) && (buf.st_mode & S_IWGRP)) {
+ have_write = 1;
+ } else if (buf.st_mode & S_IWOTH) {
+ have_write = 1;
+ }
+
+ if (have_owner && !have_write) {
+ backend_setegid(0);
+ backend_seteuid(0);
+ }
+}
diff --git a/external/fs/unfs3-0.9.22/user.h b/external/fs/unfs3-0.9.22/user.h
new file mode 100644
index 0000000..0109d25
--- /dev/null
+++ b/external/fs/unfs3-0.9.22/user.h
@@ -0,0 +1,29 @@
+/*
+ * UNFS3 user and group id handling
+ * (C) 2003, Pascal Schmidt
+ * see file LICENSE for license details
+ */
+
+#ifndef UNFS3_USER_H
+#define UNFS3_USER_H
+
+#include "backend.h"
+
+int get_uid(struct svc_req *req);
+
+int mangle_uid(int id);
+int mangle_gid(int id);
+
+int is_owner(int owner, struct svc_req *req);
+int has_group(int group, struct svc_req *req);
+
+void get_squash_ids(void);
+
+void switch_to_root();
+void switch_user(struct svc_req *req);
+
+void read_executable(struct svc_req *req, backend_statstruct buf);
+void read_by_owner(struct svc_req *req, backend_statstruct buf);
+void write_by_owner(struct svc_req *req, backend_statstruct buf);
+
+#endif
diff --git a/external/fs/unfs3-0.9.22/winsupport.c b/external/fs/unfs3-0.9.22/winsupport.c
new file mode 100644
index 0000000..15c37b0
--- /dev/null
+++ b/external/fs/unfs3-0.9.22/winsupport.c
@@ -0,0 +1,1062 @@
+
+/*
+ * unfs3 Windows compatibility layer
+ * Copyright 2006 Peter Åstrand <ast...@cendio.se> for Cendio AB
+ * see file LICENSE for license details
+ */
+
+#ifdef WIN32
+#define _WIN32_WINDOWS 0x0410 /* We require Windows 98 or later For
+ GetLongPathName */
+#include <errno.h>
+#include <stdio.h>
+#include "winsupport.h"
+#include "Config/exports.h"
+#include "daemon.h"
+#include <assert.h>
+#include <windows.h>
+#include <wincrypt.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <direct.h>
+#include <dirent.h>
+#include <locale.h>
+
+#define MAX_NUM_DRIVES 26
+#define FT70SEC 11644473600LL /* seconds between 1601-01-01 and
+ 1970-01-01 */
+#define FT80SEC 315529200 /* seconds between 1970-01-01 and
+ 1980-01-01 */
+
+#define wsizeof(x) (sizeof(x)/sizeof(wchar_t))
+
+typedef struct _fdname {
+ int fd;
+ char *name;
+ struct _fdname *next;
+} fdname;
+
+static fdname *fdnames = NULL;
+
+static char *get_fdname(int fd)
+{
+ fdname *fn;
+
+ for (fn = fdnames; fn; fn = fn->next) {
+ if (fn->fd == fd) {
+ return fn->name;
+ break;
+ }
+ }
+
+ assert(0);
+ return NULL;
+}
+
+static int add_fdname(int fd, const char *name)
+{
+ fdname *fn;
+
+ fn = malloc(sizeof(fdname));
+ if (!fn) {
+ logmsg(LOG_CRIT, "add_mount: Unable to allocate memory");
+ return -1;
+ }
+
+ fn->fd = fd;
+ fn->name = strdup(name);
+ fn->next = fdnames;
+ fdnames = fn;
+
+ return fd;
+}
+
+static void remove_fdname(int fd)
+{
+ fdname *fn, **prevnext = &fdnames;
+
+ for (fn = fdnames; fn; fn = fn->next) {
+ if (fn->fd == fd) {
+ *prevnext = fn->next;
+ free(fn->name);
+ free(fn);
+ break;
+ }
+ prevnext = &fn->next;
+ }
+}
+
+/*
+ * The following UTF-8 validation is borrowed from
+ * ftp://ftp.unicode.org/Public/PROGRAMS/CVTUTF/ConvertUTF.c.
+ */
+
+/*
+ * Copyright 2001-2004 Unicode, Inc.
+ *
+ * Disclaimer
+ *
+ * This source code is provided as is by Unicode, Inc. No claims are
+ * made as to fitness for any particular purpose. No warranties of any
+ * kind are expressed or implied. The recipient agrees to determine
+ * applicability of information provided. If this file has been
+ * purchased on magnetic or optical media from Unicode, Inc., the
+ * sole remedy for any claim will be exchange of defective media
+ * within 90 days of receipt.
+ *
+ * Limitations on Rights to Redistribute This Code
+ *
+ * Unicode, Inc. hereby grants the right to freely use the information
+ * supplied in this file in the creation of products supporting the
+ * Unicode Standard, and to make copies of this file in any form
+ * for internal or external distribution as long as this notice
+ * remains attached.
+ */
+
+/*
+ * Index into the table below with the first byte of a UTF-8 sequence to
+ * get the number of trailing bytes that are supposed to follow it.
+ * Note that *legal* UTF-8 values can't have 4 or 5-bytes. The table is
+ * left as-is for anyone who may want to do such conversion, which was
+ * allowed in earlier algorithms.
+ */
+static const char trailingBytesForUTF8[256] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5
+};
+
+/*
+ * Utility routine to tell whether a sequence of bytes is legal UTF-8.
+ * This must be called with the length pre-determined by the first byte.
+ * If not calling this from ConvertUTF8to*, then the length can be set by:
+ * length = trailingBytesForUTF8[*source]+1;
+ * and the sequence is illegal right away if there aren't that many bytes
+ * available.
+ * If presented with a length > 4, this returns 0. The Unicode
+ * definition of UTF-8 goes up to 4-byte sequences.
+ */
+
+static int isLegalUTF8(const unsigned char *source, int length)
+{
+ unsigned char a;
+ const unsigned char *srcptr = source + length;
+
+ switch (length) {
+ default:
+ return 0;
+ /* Everything else falls through when "1"... */
+ case 4:
+ if ((a = (*--srcptr)) < 0x80 || a > 0xBF)
+ return 0;
+ case 3:
+ if ((a = (*--srcptr)) < 0x80 || a > 0xBF)
+ return 0;
+ case 2:
+ if ((a = (*--srcptr)) > 0xBF)
+ return 0;
+
+ switch (*source) {
+ /* no fall-through in this inner switch */
+ case 0xE0:
+ if (a < 0xA0)
+ return 0;
+ break;
+ case 0xED:
+ if (a > 0x9F)
+ return 0;
+ break;
+ case 0xF0:
+ if (a < 0x90)
+ return 0;
+ break;
+ case 0xF4:
+ if (a > 0x8F)
+ return 0;
+ break;
+ default:
+ if (a < 0x80)
+ return 0;
+ }
+
+ case 1:
+ if (*source >= 0x80 && *source < 0xC2)
+ return 0;
+ }
+ if (*source > 0xF4)
+ return 0;
+ return 1;
+}
+
+/* End of code borrowed from ConvertUTF.c */
+
+int isLegalUTF8String(const unsigned char *source)
+{
+ const unsigned char *seq, *sourceend;
+ int seqlen;
+
+ sourceend = source + strlen(source);
+ seq = source;
+
+ while (seq < sourceend) {
+ seqlen = trailingBytesForUTF8[*seq] + 1;
+ if (!isLegalUTF8(seq, seqlen))
+ return 0;
+ seq += seqlen;
+ }
+
+ return 1;
+}
+
+/* Translate an internal representation of a path (like /c/home) to
+ a Windows path (like c:\home) */
+static wchar_t *intpath2winpath(const char *intpath)
+{
+ wchar_t *winpath;
+ int winpath_len;
+ wchar_t *slash;
+ const char *lastrootslash;
+ wchar_t *lastslash;
+ size_t intlen;
+
+ /* Verify that input is valid UTF-8. We cannot use MB_ERR_INVALID_CHARS
+ to MultiByteToWideChar, since it's only available in late versions of
+ Windows. */
+ if (!isLegalUTF8String(intpath)) {
+ logmsg(LOG_CRIT, "intpath2winpath: Illegal UTF-8 string:%s", intpath);
+ return NULL;
+ }
+
+ /* Skip over multiple root slashes for paths like ///home/john */
+ lastrootslash = intpath;
+ while (*lastrootslash == '/')
+ lastrootslash++;
+ if (lastrootslash != intpath)
+ lastrootslash--;
+
+ intlen = strlen(lastrootslash);
+ /* One extra for /c -> c:\ */
+ winpath_len = sizeof(wchar_t) * (intlen + 2);
+ winpath = malloc(winpath_len);
+ if (!winpath) {
+ logmsg(LOG_CRIT, "intpath2winpath: Unable to allocate memory");
+ return NULL;
+ }
+
+ if (!MultiByteToWideChar
+ (CP_UTF8, 0, lastrootslash, -1, winpath, winpath_len)) {
+ logmsg(LOG_CRIT, "intpath2winpath: MultiByteToWideChar failed");
+ return NULL;
+ }
+
+ /* If path ends with /.., chop of the last component. Eventually, we
+ might want to eliminate all occurances of .. */
+ lastslash = wcsrchr(winpath, '/');
+ if (!wcscmp(lastslash, L"/..")) {
+ *lastslash = '\0';
+ lastslash = wcsrchr(winpath, '/');
+ *lastslash = '\0';
+ }
+
+ /* Translate /x -> x:/ and /x/something -> x:/something */
+ if ((winpath[0] == '/') && winpath[1]) {
+ switch (winpath[2]) {
+ case '\0':
+ winpath[2] = '/';
+ winpath[3] = '\0';
+ /* fall through */
+
+ case '/':
+ winpath[0] = winpath[1];
+ winpath[1] = ':';
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ while ((slash = wcschr(winpath, '/')) != NULL) {
+ *slash = '\\';
+ }
+
+ return winpath;
+}
+
+int win_seteuid(U(uid_t euid))
+{
+ return 0;
+}
+
+int win_setegid(U(gid_t egid))
+{
+ return 0;
+}
+
+int win_truncate(const char *path, off_t length)
+{
+ int fd, ret, saved_errno;
+
+ fd = win_open(path, O_WRONLY);
+ if (fd < 0)
+ return -1;
+ ret = chsize(fd, length);
+ saved_errno = errno;
+ win_close(fd);
+ errno = saved_errno;
+
+ return ret;
+}
+
+int win_chown(U(const char *path), U(uid_t owner), U(gid_t group))
+{
+ errno = EINVAL;
+ return -1;
+}
+
+int win_fchown(U(int fd), U(uid_t owner), U(gid_t group))
+{
+ errno = EINVAL;
+ return -1;
+}
+
+int win_fchmod(int fildes, mode_t mode)
+{
+ wchar_t *winpath;
+ int ret;
+
+ winpath = intpath2winpath(get_fdname(fildes));
+ if (!winpath) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ ret = _wchmod(winpath, mode);
+ free(winpath);
+ return ret;
+}
+
+int inet_aton(const char *cp, struct in_addr *addr)
+{
+ addr->s_addr = inet_addr(cp);
+ return (addr->s_addr == INADDR_NONE) ? 0 : 1;
+}
+
+/*
+ If you need a good laugh, take a look at the "Suggested Interix
+ replacement" at:
+ http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnucmg/html/UCMGch10.asp
+*/
+ssize_t pread(int fd, void *buf, size_t count, off_t offset)
+{
+ ssize_t size;
+ off_t ret;
+
+ if ((ret = lseek(fd, offset, SEEK_SET)) < 0)
+ return -1;
+ size = read(fd, buf, count);
+ return size;
+}
+
+ssize_t pwrite(int fd, const void *buf, size_t count, off_t offset)
+{
+ ssize_t size;
+ off_t ret;
+ HANDLE h;
+ FILETIME ft;
+ SYSTEMTIME st;
+ ULARGE_INTEGER fti;
+
+ if ((ret = lseek(fd, offset, SEEK_SET)) < 0)
+ return -1;
+ size = write(fd, buf, count);
+
+ /* Since we are using the CreationTime attribute as "ctime", we need to
+ update it. From RFC1813: "Writing to the file changes the ctime in
+ addition to the mtime." */
+ h = (HANDLE) _get_osfhandle(fd);
+ GetSystemTime(&st);
+ SystemTimeToFileTime(&st, &ft);
+ /* Ceil up to nearest even second */
+ fti.LowPart = ft.dwLowDateTime;
+ fti.HighPart = ft.dwHighDateTime;
+ fti.QuadPart = ((fti.QuadPart + 20000000 - 1) / 20000000) * 20000000;
+ ft.dwLowDateTime = fti.LowPart;
+ ft.dwHighDateTime = fti.HighPart;
+ if (!SetFileTime(h, &ft, NULL, NULL)) {
+ fprintf(stderr,
+ "warning: pwrite: SetFileTime failed with error %ld\n",
+ GetLastError());
+ }
+
+ return size;
+}
+
+void syslog(U(int priority), U(const char *format), ...)
+{
+ assert(0);
+}
+
+int win_init()
+{
+ WORD winsock_ver;
+ WSADATA wsadata;
+
+ /* Set up locale, so that string compares works correctly */
+ setlocale(LC_ALL, "");
+
+ /* Verify that -s is used */
+ if (!opt_singleuser) {
+ fprintf(stderr, "Single-user mode is required on this platform.\n");
+ exit(1);
+ }
+
+ /* Verify that -d is used */
+ if (opt_detach) {
+ fprintf(stderr,
+ "Foreground (debug) mode is required on this platform.\n");
+ exit(1);
+ }
+
+ /* init winsock */
+ winsock_ver = MAKEWORD(1, 1);
+ if (WSAStartup(winsock_ver, &wsadata)) {
+ fprintf(stderr, "Unable to initialise WinSock\n");
+ exit(1);
+ }
+ if (LOBYTE(wsadata.wVersion) != 1 || HIBYTE(wsadata.wVersion) != 1) {
+ fprintf(stderr, "WinSock version is incompatible with 1.1\n");
+ WSACleanup();
+ exit(1);
+ }
+
+ /* disable error popups, for example from drives not ready */
+ SetErrorMode(SEM_FAILCRITICALERRORS);
+
+ return 0;
+}
+
+void win_shutdown()
+{
+ WSACleanup();
+}
+
+/* Wrapper for Windows stat function, which provides
+ st_dev and st_ino. These are calculated as follows:
+
+ st_dev is set to the drive number (0=A 1=B ...). Our virtual root
+ "/" gets a st_dev of 0xff.
+
+ st_ino is hashed from the full file path. Each half produces a 32
+ bit hash. These are concatenated to a 64 bit value. The risk that
+ st_ino is the same for two files on the system is, if I'm not
+ mistaken, b=pigeon(2**32, f)**2. For f=1000, b=1e-08. By using a 64
+ bit hash function this risk can be lowered. Possible future
+ enhancement.
+
+ pigeon() can be calculated in Python with:
+
+ def pigeon(m, n):
+ res = 1.0
+ for i in range(m - n + 1, m):
+ res = res * i / m
+ return 1 - res
+*/
+int win_stat(const char *file_name, backend_statstruct * buf)
+{
+ wchar_t *winpath;
+ int ret;
+ wchar_t pathbuf[4096];
+ int retval;
+ size_t namelen;
+ wchar_t *splitpoint;
+ char savedchar;
+ struct _stat win_statbuf;
+
+ /* Special case: Our top-level virtual root, containing each drive
+ represented as a directory. Compare with "My Computer" etc. This
+ virtual root has a hardcoded hash value of 1, to simplify debugging
+ etc. */
+ if (!strcmp(file_name, "/")) {
+ buf->st_mode = S_IFDIR | S_IRUSR | S_IWUSR;
+ buf->st_nlink = MAX_NUM_DRIVES + 3; /* 3 extra for: . .. / */
+ buf->st_uid = 1;
+ buf->st_gid = 1;
+ buf->st_rdev = 0;
+ buf->st_size = 4096;
+ buf->st_atime = 0;
+ buf->st_mtime = 0;
+ buf->st_ctime = 0;
+ buf->st_dev = 0xff;
+ buf->st_ino = 1;
+ return 0;
+ }
+
+ winpath = intpath2winpath(file_name);
+ if (!winpath) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ ret = _wstat(winpath, &win_statbuf);
+ if (ret < 0) {
+ free(winpath);
+ return ret;
+ }
+
+ /* Copy values to our struct */
+ buf->st_mode = win_statbuf.st_mode;
+ buf->st_nlink = win_statbuf.st_nlink;
+ buf->st_uid = win_statbuf.st_uid;
+ buf->st_gid = win_statbuf.st_gid;
+ buf->st_rdev = win_statbuf.st_rdev;
+ buf->st_size = win_statbuf.st_size;
+ buf->st_atime = win_statbuf.st_atime;
+ buf->st_mtime = win_statbuf.st_mtime;
+ buf->st_ctime = win_statbuf.st_ctime;
+ buf->st_blocks = win_statbuf.st_size / 512;
+
+ retval = GetFullPathNameW(winpath, wsizeof(pathbuf), pathbuf, NULL);
+ if (!retval) {
+ errno = ENOENT;
+ return -1;
+ }
+
+ /* Set st_dev to the drive number */
+ buf->st_dev = tolower(pathbuf[0]) - 'a';
+
+ /* GetLongPathName fails if called with only x:\, and drive x is not
+ ready. So, only call it for other paths. */
+ if (pathbuf[0] && wcscmp(pathbuf + 1, L":\\")) {
+ retval = GetLongPathNameW(pathbuf, pathbuf, wsizeof(pathbuf));
+ if (!retval || (unsigned) retval > wsizeof(pathbuf)) {
+ /* Strangely enough, GetLongPathName returns
+ ERROR_SHARING_VIOLATION for locked files, such as hiberfil.sys
+ */
+ if (GetLastError() != ERROR_SHARING_VIOLATION) {
+ errno = ENAMETOOLONG;
+ return -1;
+ }
+ }
+ }
+
+ /* Hash st_ino, by splitting in two halves */
+ namelen = wcslen(pathbuf);
+ splitpoint = &pathbuf[namelen / 2];
+ savedchar = *splitpoint;
+ *splitpoint = '\0';
+ buf->st_ino = wfnv1a_32(pathbuf, 0);
+ assert(sizeof(buf->st_ino) == 8);
+ buf->st_ino = buf->st_ino << 32;
+ *splitpoint = savedchar;
+ buf->st_ino |= wfnv1a_32(splitpoint, 0);
+
+#if 0
+ fprintf(stderr,
+ "win_stat: file=%s, ret=%d, st_dev=0x%x, st_ino=0x%I64x\n",
+ file_name, ret, buf->st_dev, buf->st_ino);
+#endif
+ free(winpath);
+ return ret;
+}
+
+int win_open(const char *pathname, int flags, ...)
+{
+ va_list args;
+ mode_t mode;
+ int fd;
+ wchar_t *winpath;
+
+ va_start(args, flags);
+ mode = va_arg(args, int);
+
+ va_end(args);
+
+ winpath = intpath2winpath(pathname);
+ if (!winpath) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ fd = _wopen(winpath, flags | O_BINARY, mode);
+ free(winpath);
+ if (fd < 0) {
+ return fd;
+ }
+
+ return add_fdname(fd, pathname);
+
+}
+
+int win_close(int fd)
+{
+ remove_fdname(fd);
+ return close(fd);
+}
+
+int win_fstat(int fd, backend_statstruct * buf)
+{
+ return win_stat(get_fdname(fd), buf);
+}
+
+/*
+ opendir implementation which emulates a virtual root with the drive
+ letters presented as directories.
+*/
+UNFS3_WIN_DIR *win_opendir(const char *name)
+{
+ wchar_t *winpath;
+ UNFS3_WIN_DIR *ret;
+
+ ret = malloc(sizeof(UNFS3_WIN_DIR));
+ if (!ret) {
+ logmsg(LOG_CRIT, "win_opendir: Unable to allocate memory");
+ return NULL;
+ }
+
+ if (!strcmp("/", name)) {
+ /* Emulate root */
+ ret->stream = NULL;
+ ret->currentdrive = 0;
+ ret->logdrives = GetLogicalDrives();
+ } else {
+ winpath = intpath2winpath(name);
+ if (!winpath) {
+ free(ret);
+ errno = EINVAL;
+ return NULL;
+ }
+
+ ret->stream = _wopendir(winpath);
+ free(winpath);
+ if (ret->stream == NULL) {
+ free(ret);
+ ret = NULL;
+ }
+ }
+
+ return ret;
+}
+
+struct dirent *win_readdir(UNFS3_WIN_DIR * dir)
+{
+ if (dir->stream == NULL) {
+ /* Emulate root */
+ for (; dir->currentdrive < MAX_NUM_DRIVES; dir->currentdrive++) {
+ if (dir->logdrives & 1 << dir->currentdrive)
+ break;
+ }
+
+ if (dir->currentdrive < MAX_NUM_DRIVES) {
+ dir->de.d_name[0] = 'a' + dir->currentdrive;
+ dir->de.d_name[1] = '\0';
+ dir->currentdrive++;
+ return &dir->de;
+ } else {
+ return NULL;
+ }
+ } else {
+ struct _wdirent *de;
+
+ de = _wreaddir(dir->stream);
+ if (!de) {
+ return NULL;
+ }
+
+ if (!WideCharToMultiByte
+ (CP_UTF8, 0, de->d_name, -1, dir->de.d_name,
+ sizeof(dir->de.d_name), NULL, NULL)) {
+ logmsg(LOG_CRIT, "win_readdir: WideCharToMultiByte failed");
+ return NULL;
+ }
+ return &dir->de;
+ }
+}
+
+int win_closedir(UNFS3_WIN_DIR * dir)
+{
+ if (dir->stream == NULL) {
+ free(dir);
+ return 0;
+ } else {
+ return _wclosedir(dir->stream);
+ }
+}
+
+void openlog(U(const char *ident), U(int option), U(int facility))
+{
+
+}
+
+char *win_realpath(const char *path, char *resolved_path)
+{
+ return normpath(path, resolved_path);
+}
+
+int win_readlink(U(const char *path), U(char *buf), U(size_t bufsiz))
+{
+ errno = ENOSYS;
+ return -1;
+}
+
+int win_mkdir(const char *pathname, U(mode_t mode))
+{
+ wchar_t *winpath;
+ int ret;
+
+ if (!strcmp("/", pathname)) {
+ /* Emulate root */
+ errno = EROFS;
+ return -1;
+ }
+
+ winpath = intpath2winpath(pathname);
+ if (!winpath) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* FIXME: Use mode */
+ ret = _wmkdir(winpath);
+ free(winpath);
+ return ret;
+}
+
+int win_symlink(U(const char *oldpath), U(const char *newpath))
+{
+ errno = ENOSYS;
+ return -1;
+}
+
+int win_mknod(U(const char *pathname), U(mode_t mode), U(dev_t dev))
+{
+ errno = ENOSYS;
+ return -1;
+}
+
+int win_mkfifo(U(const char *pathname), U(mode_t mode))
+{
+ errno = ENOSYS;
+ return -1;
+}
+
+int win_link(U(const char *oldpath), U(const char *newpath))
+{
+ errno = ENOSYS;
+ return -1;
+}
+
+int win_statvfs(const char *path, backend_statvfsstruct * buf)
+{
+ wchar_t *winpath;
+ DWORD SectorsPerCluster;
+ DWORD BytesPerSector;
+ DWORD NumberOfFreeClusters;
+ DWORD TotalNumberOfClusters;
+ ULARGE_INTEGER FreeBytesAvailable;
+ ULARGE_INTEGER TotalNumberOfBytes;
+ ULARGE_INTEGER TotalNumberOfFreeBytes;
+
+ if (!strcmp("/", path)) {
+ /* Emulate root */
+ buf->f_bsize = 1024;
+ buf->f_blocks = 1024;
+ buf->f_bfree = 0;
+ buf->f_bavail = 0;
+ buf->f_files = 1024;
+ buf->f_ffree = 0;
+ return 0;
+ }
+
+ winpath = intpath2winpath(path);
+ if (!winpath) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ winpath[3] = '\0'; /* Cut off after x:\ */
+
+ if (!GetDiskFreeSpaceW
+ (winpath, &SectorsPerCluster, &BytesPerSector, &NumberOfFreeClusters,
+ &TotalNumberOfClusters)) {
+ errno = EIO;
+ return -1;
+ }
+
+ if (!GetDiskFreeSpaceExW
+ (winpath, &FreeBytesAvailable, &TotalNumberOfBytes,
+ &TotalNumberOfFreeBytes)) {
+ errno = EIO;
+ return -1;
+ }
+
+ buf->f_bsize = BytesPerSector;
+ buf->f_blocks = TotalNumberOfBytes.QuadPart / BytesPerSector;
+ buf->f_bfree = TotalNumberOfFreeBytes.QuadPart / BytesPerSector;
+ buf->f_bavail = FreeBytesAvailable.QuadPart / BytesPerSector;
+ buf->f_files = buf->f_blocks / SectorsPerCluster;
+ buf->f_ffree = buf->f_bfree / SectorsPerCluster;
+ free(winpath);
+ return 0;
+}
+
+int win_remove(const char *pathname)
+{
+ wchar_t *winpath;
+ int ret;
+
+ if (!strcmp("/", pathname)) {
+ /* Emulate root */
+ errno = EROFS;
+ return -1;
+ }
+
+ winpath = intpath2winpath(pathname);
+ if (!winpath) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ ret = _wremove(winpath);
+ free(winpath);
+ return ret;
+}
+
+int win_chmod(const char *path, mode_t mode)
+{
+ wchar_t *winpath;
+ int ret;
+
+ if (!strcmp("/", path)) {
+ /* Emulate root */
+ errno = EROFS;
+ return -1;
+ }
+
+ winpath = intpath2winpath(path);
+ if (!winpath) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ ret = _wchmod(winpath, mode);
+ free(winpath);
+ return ret;
+}
+
+/*
+ If creation is false, the LastAccessTime will be set according to
+ times->actime. Otherwise, CreationTime will be set. LastWriteTime
+ is always set according to times->modtime.
+*/
+static int win_utime_creation(const char *path, const struct utimbuf *times,
+ int creation)
+{
+ wchar_t *winpath;
+ int ret = 0;
+ HANDLE h;
+ ULARGE_INTEGER fti;
+ FILETIME xtime, mtime;
+
+ if (!strcmp("/", path)) {
+ /* Emulate root */
+ errno = EROFS;
+ return -1;
+ }
+
+ winpath = intpath2winpath(path);
+ if (!winpath) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* Unfortunately, we cannot use utime(), since it doesn't support
+ directories. */
+ fti.QuadPart = UInt32x32To64(times->actime + FT70SEC, 10000000);
+ xtime.dwHighDateTime = fti.HighPart;
+ xtime.dwLowDateTime = fti.LowPart;
+ fti.QuadPart = UInt32x32To64(times->modtime + FT70SEC, 10000000);
+ mtime.dwHighDateTime = fti.HighPart;
+ mtime.dwLowDateTime = fti.LowPart;
+
+ h = CreateFileW(winpath, FILE_WRITE_ATTRIBUTES,
+ FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL | FILE_FLAG_BACKUP_SEMANTICS, NULL);
+
+ if (!SetFileTime
+ (h, creation ? &xtime : NULL, creation ? NULL : &xtime, &mtime)) {
+ errno = EACCES;
+ ret = -1;
+ }
+
+ CloseHandle(h);
+ free(winpath);
+ return ret;
+}
+
+int win_utime(const char *path, const struct utimbuf *times)
+{
+ return win_utime_creation(path, times, FALSE);
+}
+
+int win_rmdir(const char *path)
+{
+ wchar_t *winpath;
+ int ret;
+
+ if (!strcmp("/", path)) {
+ /* Emulate root */
+ errno = EROFS;
+ return -1;
+ }
+
+ winpath = intpath2winpath(path);
+ if (!winpath) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ ret = _wrmdir(winpath);
+ free(winpath);
+ return ret;
+}
+
+int win_rename(const char *oldpath, const char *newpath)
+{
+ wchar_t *oldwinpath, *newwinpath;
+ int ret;
+
+ if (!strcmp("/", oldpath) && !strcmp("/", newpath)) {
+ /* Emulate root */
+ errno = EROFS;
+ return -1;
+ }
+
+ oldwinpath = intpath2winpath(oldpath);
+ if (!oldwinpath) {
+ errno = EINVAL;
+ return -1;
+ }
+ newwinpath = intpath2winpath(newpath);
+ if (!newwinpath) {
+ free(oldwinpath);
+ errno = EINVAL;
+ return -1;
+ }
+
+ ret = _wrename(oldwinpath, newwinpath);
+ free(oldwinpath);
+ free(newwinpath);
+ return ret;
+}
+
+int win_gen_nonce(char *nonce)
+{
+ HCRYPTPROV hCryptProv;
+
+ if (!CryptAcquireContext
+ (&hCryptProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) {
+ logmsg(LOG_ERR, "CryptAcquireContext failed with error 0x%lx",
+ GetLastError());
+ return -1;
+ }
+
+ if (!CryptGenRandom(hCryptProv, 32, nonce)) {
+ logmsg(LOG_ERR, "CryptGenRandom failed with error 0x%lx",
+ GetLastError());
+ return -1;
+ }
+
+ if (!CryptReleaseContext(hCryptProv, 0)) {
+ logmsg(LOG_ERR, "CryptReleaseContext failed with error 0x%lx",
+ GetLastError());
+ return -1;
+ }
+
+ return 0;
+}
+
+/* Just like strncasecmp, but compare two UTF8 strings. Limited to 4096 chars. */
+int win_utf8ncasecmp(const char *s1, const char *s2, size_t n)
+{
+ wchar_t ws1[4096], ws2[4096];
+ int converted;
+
+ /* Make sure input is valid UTF-8 */
+ if (!isLegalUTF8String(s1)) {
+ logmsg(LOG_CRIT, "win_utf8ncasecmp: Illegal UTF-8 string:%s", s1);
+ return -1;
+ }
+ if (!isLegalUTF8String(s2)) {
+ logmsg(LOG_CRIT, "win_utf8ncasecmp: Illegal UTF-8 string:%s", s2);
+ return -1;
+ }
+
+ /* Convert both strings to wide chars */
+ converted = MultiByteToWideChar(CP_UTF8, 0, s1, n, ws1, wsizeof(ws1));
+ if (!converted) {
+ logmsg(LOG_CRIT, "win_utf8ncasecmp: MultiByteToWideChar failed");
+ return -1;
+ }
+ ws1[converted] = '\0';
+ converted = MultiByteToWideChar(CP_UTF8, 0, s2, n, ws2, wsizeof(ws2));
+ if (!converted) {
+ logmsg(LOG_CRIT, "win_utf8ncasecmp: MultiByteToWideChar failed");
+ return 1;
+ }
+ ws2[converted] = '\0';
+
+ /* compare */
+ return _wcsicmp(ws1, ws2);
+}
+
+static void win_verf_to_ubuf(struct utimbuf *ubuf, createverf3 verf)
+{
+ ubuf->actime = verf[0] | verf[1] << 8 | verf[2] << 16 | verf[3] << 24;
+ ubuf->modtime = verf[4] | verf[5] << 8 | verf[6] << 16 | verf[7] << 24;
+
+ /* FAT can only store dates in the interval 1980-01-01 to 2107-12-31.
+ However, since the utime interface uses Epoch time, we are further
+ limited to 1980-01-01 to 2038-01-19, assuming 32 bit signed time_t.
+ math.log(2**31-1 - FT80SEC, 2) = 30.7, which means that we can only
+ use 30 bits. */
+ ubuf->actime &= 0x3fffffff;
+ ubuf->actime += FT80SEC;
+ ubuf->modtime &= 0x3fffffff;
+ ubuf->modtime += FT80SEC;
+ /* While FAT CreationTime has a resolution of 10 ms, WriteTime only has a
+ resolution of 2 seconds. */
+ ubuf->modtime &= ~1;
+}
+
+int win_store_create_verifier(char *obj, createverf3 verf)
+{
+ struct utimbuf ubuf;
+
+ win_verf_to_ubuf(&ubuf, verf);
+ return win_utime_creation(obj, &ubuf, TRUE);
+}
+
+int win_check_create_verifier(backend_statstruct * buf, createverf3 verf)
+{
+ struct utimbuf ubuf;
+
+ win_verf_to_ubuf(&ubuf, verf);
+ return (buf->st_ctime == ubuf.actime && buf->st_mtime == ubuf.modtime);
+}
+
+#endif /* WIN32 */
diff --git a/external/fs/unfs3-0.9.22/winsupport.h b/external/fs/unfs3-0.9.22/winsupport.h
new file mode 100644
index 0000000..6aa295b
--- /dev/null
+++ b/external/fs/unfs3-0.9.22/winsupport.h
@@ -0,0 +1,131 @@
+
+/*
+ * unfs3 Windows compatibility
+ * Copyright 2006 Peter Åstrand <ast...@cendio.se> for Cendio AB
+ * see file LICENSE for license details
+ */
+
+#ifdef WIN32
+#ifndef UNFS3_WINSUPPORT_H
+#define UNFS3_WINSUPPORT_H
+
+#include <sys/stat.h>
+#include <dirent.h>
+#include <utime.h>
+#include "nfs.h"
+
+#define LOG_EMERG 0 /* system is unusable */
+#define LOG_ALERT 1 /* action must be taken immediately */
+#define LOG_CRIT 2 /* critical conditions */
+#define LOG_ERR 3 /* error conditions */
+#define LOG_WARNING 4 /* warning conditions */
+#define LOG_NOTICE 5 /* normal but significant condition */
+#define LOG_INFO 6 /* informational */
+#define LOG_DEBUG 7 /* debug-level messages */
+#define LOG_CONS 0
+#define LOG_PID 0
+#define LOG_DAEMON 0
+#define closelog() do { } while (0)
+
+#define O_NONBLOCK 0
+#define ELOOP ENAMETOOLONG
+
+#define S_IRWXG 0
+#define S_IXGRP S_IRGRP
+#define S_IRGRP 0
+#define S_IWGRP 0
+
+#define S_IRWXO 0
+#define S_IXOTH S_IROTH
+#define S_IROTH 0
+#define S_IWOTH 0
+
+#define S_IFLNK 0
+#define S_IFSOCK 0
+
+typedef int socklen_t;
+typedef uint32 uid_t;
+typedef uint32 gid_t;
+
+typedef struct _backend_statstruct
+{
+ uint32 st_dev;
+ uint64 st_ino;
+ _mode_t st_mode;
+ short st_nlink;
+ uint32 st_uid;
+ uint32 st_gid;
+ _dev_t st_rdev;
+ _off_t st_size;
+ short st_blksize;
+ _off_t st_blocks;
+ time_t st_atime;
+ time_t st_mtime;
+ time_t st_ctime;
+} backend_statstruct;
+
+typedef struct _backend_passwdstruct
+{
+ uid_t pw_uid;
+ gid_t pw_gid;
+} backend_passwdstruct;
+
+/* Only includes fields actually used by unfs3 */
+typedef struct _backend_statvfsstruct
+{
+ unsigned long f_bsize; /* file system block size */
+ uint64 f_blocks; /* size of fs in f_frsize units */
+ uint64 f_bfree; /* # free blocks */
+ uint64 f_bavail; /* # free blocks for non-root */
+ uint64 f_files; /* # inodes */
+ uint64 f_ffree; /* # free inodes */
+} backend_statvfsstruct;
+
+typedef struct _UNFS3_WIN_DIR
+{
+ _WDIR *stream; /* Windows DIR stream. NULL means root emulation */
+ uint32 currentdrive; /* Next drive to check/return */
+ struct dirent de;
+ DWORD logdrives;
+} UNFS3_WIN_DIR;
+
+int inet_aton(const char *cp, struct in_addr *addr);
+ssize_t pread(int fd, void *buf, size_t count, off_t offset);
+ssize_t pwrite(int fd, const void *buf, size_t count, off_t offset);
+void syslog(int priority, const char *format, ...);
+
+int win_seteuid(uid_t euid);
+int win_setegid(gid_t egid);
+int win_truncate(const char *path, off_t length);
+int win_chown(const char *path, uid_t owner, gid_t group);
+int win_fchown(int fd, uid_t owner, gid_t group);
+int win_fchmod(int fildes, mode_t mode);
+int win_stat(const char *file_name, backend_statstruct *buf);
+int win_fstat(int fd, backend_statstruct *buf);
+int win_open(const char *pathname, int flags, ...);
+int win_close(int fd);
+UNFS3_WIN_DIR *win_opendir(const char *name);
+struct dirent *win_readdir(UNFS3_WIN_DIR *dir);
+int win_closedir(UNFS3_WIN_DIR *dir);
+int win_init();
+void openlog(const char *ident, int option, int facility);
+char *win_realpath(const char *path, char *resolved_path);
+int win_readlink(const char *path, char *buf, size_t bufsiz);
+int win_mkdir(const char *pathname, mode_t mode);
+int win_symlink(const char *oldpath, const char *newpath);
+int win_mknod(const char *pathname, mode_t mode, dev_t dev);
+int win_mkfifo(const char *pathname, mode_t mode);
+int win_link(const char *oldpath, const char *newpath);
+int win_statvfs(const char *path, backend_statvfsstruct *buf);
+int win_remove(const char *pathname);
+int win_chmod(const char *path, mode_t mode);
+int win_utime(const char *path, const struct utimbuf *times);
+int win_rmdir(const char *path);
+int win_rename(const char *oldpath, const char *newpath);
+int win_gen_nonce(char *nonce);
+int win_utf8ncasecmp(const char *s1, const char *s2, size_t n);
+int win_store_create_verifier(char *obj, createverf3 verf);
+int win_check_create_verifier(backend_statstruct * buf, createverf3 verf);
+
+#endif /* UNFS3_WINSUPPORT_H */
+#endif /* WIN32 */
diff --git a/external/fs/unfs3-0.9.22/xdr.c b/external/fs/unfs3-0.9.22/xdr.c
new file mode 100644
index 0000000..21e5ea7
--- /dev/null
+++ b/external/fs/unfs3-0.9.22/xdr.c
@@ -0,0 +1,1656 @@
+
+/*
+ * UNFS3 XDR routines
+ * Generated by rpcgen
+ */
+#include "config.h"
+
+#include <sys/types.h>
+#include <rpc/rpc.h>
+#ifndef WIN32
+#include <netinet/in.h>
+#endif /* WIN32 */
+
+#if HAVE_XDR_U_INT64_T == 1
+#define xdr_uint64_t xdr_u_int64_t
+#undef HAVE_XDR_UINT64_T
+#define HAVE_XDR_UINT64_T 1
+#endif
+
+#include "mount.h"
+#include "nfs.h"
+#include "xdr.h"
+
+bool_t xdr_fhandle3(XDR * xdrs, fhandle3 * objp)
+{
+ if (!xdr_bytes
+ (xdrs, (char **) &objp->fhandle3_val, (u_int *) & objp->fhandle3_len,
+ FHSIZE3))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t xdr_mountstat3(XDR * xdrs, mountstat3 * objp)
+{
+ if (!xdr_enum(xdrs, (enum_t *) objp))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t xdr_mountres3_ok(XDR * xdrs, mountres3_ok * objp)
+{
+ if (!xdr_fhandle3(xdrs, &objp->fhandle))
+ return FALSE;
+ if (!xdr_array
+ (xdrs, (char **) (void *) &objp->auth_flavors.auth_flavors_val,
+ (u_int *) & objp->auth_flavors.auth_flavors_len, ~0, sizeof(int),
+ (xdrproc_t) xdr_int))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t xdr_mountres3(XDR * xdrs, mountres3 * objp)
+{
+ if (!xdr_mountstat3(xdrs, &objp->fhs_status))
+ return FALSE;
+ switch (objp->fhs_status) {
+ case 0:
+ if (!xdr_mountres3_ok(xdrs, &objp->mountres3_u.mountinfo))
+ return FALSE;
+ break;
+ default:
+ break;
+ }
+ return TRUE;
+}
+
+bool_t xdr_dirpath(XDR * xdrs, dirpath * objp)
+{
+ if (!xdr_string(xdrs, objp, MNTPATHLEN))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t xdr_name(XDR * xdrs, name * objp)
+{
+ if (!xdr_string(xdrs, objp, MNTNAMLEN))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t xdr_mountlist(XDR * xdrs, mountlist * objp)
+{
+ if (!xdr_pointer
+ (xdrs, (char **) objp, sizeof(struct mountbody),
+ (xdrproc_t) xdr_mountbody))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t xdr_mountbody(XDR * xdrs, mountbody * objp)
+{
+ if (!xdr_name(xdrs, &objp->ml_hostname))
+ return FALSE;
+ if (!xdr_dirpath(xdrs, &objp->ml_directory))
+ return FALSE;
+ if (!xdr_mountlist(xdrs, &objp->ml_next))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t xdr_groups(XDR * xdrs, groups * objp)
+{
+ if (!xdr_pointer
+ (xdrs, (char **) objp, sizeof(struct groupnode),
+ (xdrproc_t) xdr_groupnode))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t xdr_groupnode(XDR * xdrs, groupnode * objp)
+{
+ if (!xdr_name(xdrs, &objp->gr_name))
+ return FALSE;
+ if (!xdr_groups(xdrs, &objp->gr_next))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t xdr_exports(XDR * xdrs, exports * objp)
+{
+ if (!xdr_pointer
+ (xdrs, (char **) objp, sizeof(struct exportnode),
+ (xdrproc_t) xdr_exportnode))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t xdr_exportnode(XDR * xdrs, exportnode * objp)
+{
+ if (!xdr_dirpath(xdrs, &objp->ex_dir))
+ return FALSE;
+ if (!xdr_groups(xdrs, &objp->ex_groups))
+ return FALSE;
+ if (!xdr_exports(xdrs, &objp->ex_next))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t xdr_filename(XDR * xdrs, filename * objp)
+{
+ if (!xdr_string(xdrs, objp, NFS_MAXNAMLEN))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t xdr_nfspath(XDR * xdrs, nfspath * objp)
+{
+ if (!xdr_string(xdrs, objp, NFS_MAXPATHLEN))
+ return FALSE;
+ return TRUE;
+}
+
+#if HAVE_XDR_UINT64 == 0
+#if HAVE_XDR_UINT64_T == 1
+bool_t xdr_uint64(XDR * xdrs, uint64 * objp)
+{
+ if (!xdr_uint64_t(xdrs, objp))
+ return FALSE;
+ return TRUE;
+}
+#else
+bool_t xdr_uint64(XDR * xdrs, uint64 * objp)
+{
+ char buf[8];
+
+ if (xdrs->x_op == XDR_ENCODE) {
+ buf[0] = (*objp >> 56) & 0xFF;
+ buf[1] = (*objp >> 48) & 0xFF;
+ buf[2] = (*objp >> 40) & 0xFF;
+ buf[3] = (*objp >> 32) & 0xFF;
+ buf[4] = (*objp >> 24) & 0xFF;
+ buf[5] = (*objp >> 16) & 0xFF;
+ buf[6] = (*objp >> 8) & 0xFF;
+ buf[7] = *objp & 0xFF;
+ if (!xdr_opaque(xdrs, buf, 8))
+ return FALSE;
+ return TRUE;
+ } else if (xdrs->x_op == XDR_DECODE) {
+ uint32 *top = (void *) &buf[0];
+ uint32 *bottom = (void *) &buf[4];
+
+ if (!xdr_opaque(xdrs, buf, 8))
+ return FALSE;
+ *objp = (uint64) (ntohl(*top)) << 32 | ntohl(*bottom);
+ return TRUE;
+ }
+
+ if (!xdr_opaque(xdrs, buf, 8))
+ return FALSE;
+ return TRUE;
+}
+#endif
+#endif
+
+#if HAVE_XDR_UINT32 == 0 && HAVE_XDR_U_LONG == 1
+bool_t xdr_uint32(XDR * xdrs, uint32 * objp)
+{
+ if (!xdr_u_long(xdrs, objp))
+ return FALSE;
+ return TRUE;
+}
+#endif
+
+#if HAVE_XDR_INT32 == 0 && HAVE_XDR_LONG == 1
+bool_t xdr_int32(XDR * xdrs, int32 * objp)
+{
+ if (!xdr_long(xdrs, objp))
+ return FALSE;
+ return TRUE;
+}
+#endif
+
+bool_t xdr_filename3(XDR * xdrs, filename3 * objp)
+{
+ if (!xdr_string(xdrs, objp, ~0))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t xdr_nfspath3(XDR * xdrs, nfspath3 * objp)
+{
+ if (!xdr_string(xdrs, objp, ~0))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t xdr_fileid3(XDR * xdrs, fileid3 * objp)
+{
+ if (!xdr_uint64(xdrs, objp))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t xdr_cookie3(XDR * xdrs, cookie3 * objp)
+{
+ if (!xdr_uint64(xdrs, objp))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t xdr_cookieverf3(XDR * xdrs, cookieverf3 objp)
+{
+ if (!xdr_opaque(xdrs, objp, NFS3_COOKIEVERFSIZE))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t xdr_createverf3(XDR * xdrs, createverf3 objp)
+{
+ if (!xdr_opaque(xdrs, objp, NFS3_CREATEVERFSIZE))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t xdr_writeverf3(XDR * xdrs, writeverf3 objp)
+{
+ if (!xdr_opaque(xdrs, objp, NFS3_WRITEVERFSIZE))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t xdr_uid3(XDR * xdrs, uid3 * objp)
+{
+ if (!xdr_uint32(xdrs, objp))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t xdr_gid3(XDR * xdrs, gid3 * objp)
+{
+ if (!xdr_uint32(xdrs, objp))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t xdr_size3(XDR * xdrs, size3 * objp)
+{
+ if (!xdr_uint64(xdrs, objp))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t xdr_offset3(XDR * xdrs, offset3 * objp)
+{
+ if (!xdr_uint64(xdrs, objp))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t xdr_mode3(XDR * xdrs, mode3 * objp)
+{
+ if (!xdr_uint32(xdrs, objp))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t xdr_count3(XDR * xdrs, count3 * objp)
+{
+ if (!xdr_uint32(xdrs, objp))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t xdr_nfsstat3(XDR * xdrs, nfsstat3 * objp)
+{
+ if (!xdr_enum(xdrs, (enum_t *) objp))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t xdr_ftype3(XDR * xdrs, ftype3 * objp)
+{
+ if (!xdr_enum(xdrs, (enum_t *) objp))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t xdr_specdata3(XDR * xdrs, specdata3 * objp)
+{
+ if (!xdr_uint32(xdrs, &objp->specdata1))
+ return FALSE;
+ if (!xdr_uint32(xdrs, &objp->specdata2))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t xdr_nfs_fh3(XDR * xdrs, nfs_fh3 * objp)
+{
+ if (!xdr_bytes
+ (xdrs, (char **) &objp->data.data_val,
+ (u_int *) & objp->data.data_len, NFS3_FHSIZE))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t xdr_nfstime3(XDR * xdrs, nfstime3 * objp)
+{
+ if (!xdr_uint32(xdrs, &objp->seconds))
+ return FALSE;
+ if (!xdr_uint32(xdrs, &objp->nseconds))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t xdr_fattr3(XDR * xdrs, fattr3 * objp)
+{
+ if (!xdr_ftype3(xdrs, &objp->type))
+ return FALSE;
+ if (!xdr_mode3(xdrs, &objp->mode))
+ return FALSE;
+ if (!xdr_uint32(xdrs, &objp->nlink))
+ return FALSE;
+ if (!xdr_uid3(xdrs, &objp->uid))
+ return FALSE;
+ if (!xdr_gid3(xdrs, &objp->gid))
+ return FALSE;
+ if (!xdr_size3(xdrs, &objp->size))
+ return FALSE;
+ if (!xdr_size3(xdrs, &objp->used))
+ return FALSE;
+ if (!xdr_specdata3(xdrs, &objp->rdev))
+ return FALSE;
+ if (!xdr_uint64(xdrs, &objp->fsid))
+ return FALSE;
+ if (!xdr_fileid3(xdrs, &objp->fileid))
+ return FALSE;
+ if (!xdr_nfstime3(xdrs, &objp->atime))
+ return FALSE;
+ if (!xdr_nfstime3(xdrs, &objp->mtime))
+ return FALSE;
+ if (!xdr_nfstime3(xdrs, &objp->ctime))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t xdr_post_op_attr(XDR * xdrs, post_op_attr * objp)
+{
+ if (!xdr_bool(xdrs, &objp->attributes_follow))
+ return FALSE;
+ switch (objp->attributes_follow) {
+ case TRUE:
+ if (!xdr_fattr3(xdrs, &objp->post_op_attr_u.attributes))
+ return FALSE;
+ break;
+ case FALSE:
+ break;
+ default:
+ return FALSE;
+ }
+ return TRUE;
+}
+
+bool_t xdr_wcc_attr(XDR * xdrs, wcc_attr * objp)
+{
+ if (!xdr_size3(xdrs, &objp->size))
+ return FALSE;
+ if (!xdr_nfstime3(xdrs, &objp->mtime))
+ return FALSE;
+ if (!xdr_nfstime3(xdrs, &objp->ctime))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t xdr_pre_op_attr(XDR * xdrs, pre_op_attr * objp)
+{
+ if (!xdr_bool(xdrs, &objp->attributes_follow))
+ return FALSE;
+ switch (objp->attributes_follow) {
+ case TRUE:
+ if (!xdr_wcc_attr(xdrs, &objp->pre_op_attr_u.attributes))
+ return FALSE;
+ break;
+ case FALSE:
+ break;
+ default:
+ return FALSE;
+ }
+ return TRUE;
+}
+
+bool_t xdr_wcc_data(XDR * xdrs, wcc_data * objp)
+{
+ if (!xdr_pre_op_attr(xdrs, &objp->before))
+ return FALSE;
+ if (!xdr_post_op_attr(xdrs, &objp->after))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t xdr_post_op_fh3(XDR * xdrs, post_op_fh3 * objp)
+{
+ if (!xdr_bool(xdrs, &objp->handle_follows))
+ return FALSE;
+ switch (objp->handle_follows) {
+ case TRUE:
+ if (!xdr_nfs_fh3(xdrs, &objp->post_op_fh3_u.handle))
+ return FALSE;
+ break;
+ case FALSE:
+ break;
+ default:
+ return FALSE;
+ }
+ return TRUE;
+}
+
+bool_t xdr_time_how(XDR * xdrs, time_how * objp)
+{
+ if (!xdr_enum(xdrs, (enum_t *) objp))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t xdr_set_mode3(XDR * xdrs, set_mode3 * objp)
+{
+ if (!xdr_bool(xdrs, &objp->set_it))
+ return FALSE;
+ switch (objp->set_it) {
+ case TRUE:
+ if (!xdr_mode3(xdrs, &objp->set_mode3_u.mode))
+ return FALSE;
+ break;
+ default:
+ break;
+ }
+ return TRUE;
+}
+
+bool_t xdr_set_uid3(XDR * xdrs, set_uid3 * objp)
+{
+ if (!xdr_bool(xdrs, &objp->set_it))
+ return FALSE;
+ switch (objp->set_it) {
+ case TRUE:
+ if (!xdr_uid3(xdrs, &objp->set_uid3_u.uid))
+ return FALSE;
+ break;
+ default:
+ break;
+ }
+ return TRUE;
+}
+
+bool_t xdr_set_gid3(XDR * xdrs, set_gid3 * objp)
+{
+ if (!xdr_bool(xdrs, &objp->set_it))
+ return FALSE;
+ switch (objp->set_it) {
+ case TRUE:
+ if (!xdr_gid3(xdrs, &objp->set_gid3_u.gid))
+ return FALSE;
+ break;
+ default:
+ break;
+ }
+ return TRUE;
+}
+
+bool_t xdr_set_size3(XDR * xdrs, set_size3 * objp)
+{
+ if (!xdr_bool(xdrs, &objp->set_it))
+ return FALSE;
+ switch (objp->set_it) {
+ case TRUE:
+ if (!xdr_size3(xdrs, &objp->set_size3_u.size))
+ return FALSE;
+ break;
+ default:
+ break;
+ }
+ return TRUE;
+}
+
+bool_t xdr_set_atime(XDR * xdrs, set_atime * objp)
+{
+ if (!xdr_time_how(xdrs, &objp->set_it))
+ return FALSE;
+ switch (objp->set_it) {
+ case SET_TO_CLIENT_TIME:
+ if (!xdr_nfstime3(xdrs, &objp->set_atime_u.atime))
+ return FALSE;
+ break;
+ default:
+ break;
+ }
+ return TRUE;
+}
+
+bool_t xdr_set_mtime(XDR * xdrs, set_mtime * objp)
+{
+ if (!xdr_time_how(xdrs, &objp->set_it))
+ return FALSE;
+ switch (objp->set_it) {
+ case SET_TO_CLIENT_TIME:
+ if (!xdr_nfstime3(xdrs, &objp->set_mtime_u.mtime))
+ return FALSE;
+ break;
+ default:
+ break;
+ }
+ return TRUE;
+}
+
+bool_t xdr_sattr3(XDR * xdrs, sattr3 * objp)
+{
+ if (!xdr_set_mode3(xdrs, &objp->mode))
+ return FALSE;
+ if (!xdr_set_uid3(xdrs, &objp->uid))
+ return FALSE;
+ if (!xdr_set_gid3(xdrs, &objp->gid))
+ return FALSE;
+ if (!xdr_set_size3(xdrs, &objp->size))
+ return FALSE;
+ if (!xdr_set_atime(xdrs, &objp->atime))
+ return FALSE;
+ if (!xdr_set_mtime(xdrs, &objp->mtime))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t xdr_diropargs3(XDR * xdrs, diropargs3 * objp)
+{
+ if (!xdr_nfs_fh3(xdrs, &objp->dir))
+ return FALSE;
+ if (!xdr_filename3(xdrs, &objp->name))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t xdr_GETATTR3args(XDR * xdrs, GETATTR3args * objp)
+{
+ if (!xdr_nfs_fh3(xdrs, &objp->object))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t xdr_GETATTR3resok(XDR * xdrs, GETATTR3resok * objp)
+{
+ if (!xdr_fattr3(xdrs, &objp->obj_attributes))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t xdr_GETATTR3res(XDR * xdrs, GETATTR3res * objp)
+{
+ if (!xdr_nfsstat3(xdrs, &objp->status))
+ return FALSE;
+ switch (objp->status) {
+ case NFS3_OK:
+ if (!xdr_GETATTR3resok(xdrs, &objp->GETATTR3res_u.resok))
+ return FALSE;
+ break;
+ default:
+ break;
+ }
+ return TRUE;
+}
+
+bool_t xdr_sattrguard3(XDR * xdrs, sattrguard3 * objp)
+{
+ if (!xdr_bool(xdrs, &objp->check))
+ return FALSE;
+ switch (objp->check) {
+ case TRUE:
+ if (!xdr_nfstime3(xdrs, &objp->sattrguard3_u.obj_ctime))
+ return FALSE;
+ break;
+ case FALSE:
+ break;
+ default:
+ return FALSE;
+ }
+ return TRUE;
+}
+
+bool_t xdr_SETATTR3args(XDR * xdrs, SETATTR3args * objp)
+{
+ if (!xdr_nfs_fh3(xdrs, &objp->object))
+ return FALSE;
+ if (!xdr_sattr3(xdrs, &objp->new_attributes))
+ return FALSE;
+ if (!xdr_sattrguard3(xdrs, &objp->guard))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t xdr_SETATTR3resok(XDR * xdrs, SETATTR3resok * objp)
+{
+ if (!xdr_wcc_data(xdrs, &objp->obj_wcc))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t xdr_SETATTR3resfail(XDR * xdrs, SETATTR3resfail * objp)
+{
+ if (!xdr_wcc_data(xdrs, &objp->obj_wcc))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t xdr_SETATTR3res(XDR * xdrs, SETATTR3res * objp)
+{
+ if (!xdr_nfsstat3(xdrs, &objp->status))
+ return FALSE;
+ switch (objp->status) {
+ case NFS3_OK:
+ if (!xdr_SETATTR3resok(xdrs, &objp->SETATTR3res_u.resok))
+ return FALSE;
+ break;
+ default:
+ if (!xdr_SETATTR3resfail(xdrs, &objp->SETATTR3res_u.resfail))
+ return FALSE;
+ break;
+ }
+ return TRUE;
+}
+
+bool_t xdr_LOOKUP3args(XDR * xdrs, LOOKUP3args * objp)
+{
+ if (!xdr_diropargs3(xdrs, &objp->what))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t xdr_LOOKUP3resok(XDR * xdrs, LOOKUP3resok * objp)
+{
+ if (!xdr_nfs_fh3(xdrs, &objp->object))
+ return FALSE;
+ if (!xdr_post_op_attr(xdrs, &objp->obj_attributes))
+ return FALSE;
+ if (!xdr_post_op_attr(xdrs, &objp->dir_attributes))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t xdr_LOOKUP3resfail(XDR * xdrs, LOOKUP3resfail * objp)
+{
+ if (!xdr_post_op_attr(xdrs, &objp->dir_attributes))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t xdr_LOOKUP3res(XDR * xdrs, LOOKUP3res * objp)
+{
+ if (!xdr_nfsstat3(xdrs, &objp->status))
+ return FALSE;
+ switch (objp->status) {
+ case NFS3_OK:
+ if (!xdr_LOOKUP3resok(xdrs, &objp->LOOKUP3res_u.resok))
+ return FALSE;
+ break;
+ default:
+ if (!xdr_LOOKUP3resfail(xdrs, &objp->LOOKUP3res_u.resfail))
+ return FALSE;
+ break;
+ }
+ return TRUE;
+}
+
+bool_t xdr_ACCESS3args(XDR * xdrs, ACCESS3args * objp)
+{
+ if (!xdr_nfs_fh3(xdrs, &objp->object))
+ return FALSE;
+ if (!xdr_uint32(xdrs, &objp->access))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t xdr_ACCESS3resok(XDR * xdrs, ACCESS3resok * objp)
+{
+ if (!xdr_post_op_attr(xdrs, &objp->obj_attributes))
+ return FALSE;
+ if (!xdr_uint32(xdrs, &objp->access))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t xdr_ACCESS3resfail(XDR * xdrs, ACCESS3resfail * objp)
+{
+ if (!xdr_post_op_attr(xdrs, &objp->obj_attributes))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t xdr_ACCESS3res(XDR * xdrs, ACCESS3res * objp)
+{
+ if (!xdr_nfsstat3(xdrs, &objp->status))
+ return FALSE;
+ switch (objp->status) {
+ case NFS3_OK:
+ if (!xdr_ACCESS3resok(xdrs, &objp->ACCESS3res_u.resok))
+ return FALSE;
+ break;
+ default:
+ if (!xdr_ACCESS3resfail(xdrs, &objp->ACCESS3res_u.resfail))
+ return FALSE;
+ break;
+ }
+ return TRUE;
+}
+
+bool_t xdr_READLINK3args(XDR * xdrs, READLINK3args * objp)
+{
+ if (!xdr_nfs_fh3(xdrs, &objp->symlink))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t xdr_READLINK3resok(XDR * xdrs, READLINK3resok * objp)
+{
+ if (!xdr_post_op_attr(xdrs, &objp->symlink_attributes))
+ return FALSE;
+ if (!xdr_nfspath3(xdrs, &objp->data))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t xdr_READLINK3resfail(XDR * xdrs, READLINK3resfail * objp)
+{
+ if (!xdr_post_op_attr(xdrs, &objp->symlink_attributes))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t xdr_READLINK3res(XDR * xdrs, READLINK3res * objp)
+{
+ if (!xdr_nfsstat3(xdrs, &objp->status))
+ return FALSE;
+ switch (objp->status) {
+ case NFS3_OK:
+ if (!xdr_READLINK3resok(xdrs, &objp->READLINK3res_u.resok))
+ return FALSE;
+ break;
+ default:
+ if (!xdr_READLINK3resfail(xdrs, &objp->READLINK3res_u.resfail))
+ return FALSE;
+ break;
+ }
+ return TRUE;
+}
+
+bool_t xdr_READ3args(XDR * xdrs, READ3args * objp)
+{
+ if (!xdr_nfs_fh3(xdrs, &objp->file))
+ return FALSE;
+ if (!xdr_offset3(xdrs, &objp->offset))
+ return FALSE;
+ if (!xdr_count3(xdrs, &objp->count))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t xdr_READ3resok(XDR * xdrs, READ3resok * objp)
+{
+ if (!xdr_post_op_attr(xdrs, &objp->file_attributes))
+ return FALSE;
+ if (!xdr_count3(xdrs, &objp->count))
+ return FALSE;
+ if (!xdr_bool(xdrs, &objp->eof))
+ return FALSE;
+ if (!xdr_bytes
+ (xdrs, (char **) &objp->data.data_val,
+ (u_int *) & objp->data.data_len, ~0))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t xdr_READ3resfail(XDR * xdrs, READ3resfail * objp)
+{
+ if (!xdr_post_op_attr(xdrs, &objp->file_attributes))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t xdr_READ3res(XDR * xdrs, READ3res * objp)
+{
+ if (!xdr_nfsstat3(xdrs, &objp->status))
+ return FALSE;
+ switch (objp->status) {
+ case NFS3_OK:
+ if (!xdr_READ3resok(xdrs, &objp->READ3res_u.resok))
+ return FALSE;
+ break;
+ default:
+ if (!xdr_READ3resfail(xdrs, &objp->READ3res_u.resfail))
+ return FALSE;
+ break;
+ }
+ return TRUE;
+}
+
+bool_t xdr_stable_how(XDR * xdrs, stable_how * objp)
+{
+ if (!xdr_enum(xdrs, (enum_t *) objp))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t xdr_WRITE3args(XDR * xdrs, WRITE3args * objp)
+{
+ if (!xdr_nfs_fh3(xdrs, &objp->file))
+ return FALSE;
+ if (!xdr_offset3(xdrs, &objp->offset))
+ return FALSE;
+ if (!xdr_count3(xdrs, &objp->count))
+ return FALSE;
+ if (!xdr_stable_how(xdrs, &objp->stable))
+ return FALSE;
+ if (!xdr_bytes
+ (xdrs, (char **) &objp->data.data_val,
+ (u_int *) & objp->data.data_len, ~0))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t xdr_WRITE3resok(XDR * xdrs, WRITE3resok * objp)
+{
+ if (!xdr_wcc_data(xdrs, &objp->file_wcc))
+ return FALSE;
+ if (!xdr_count3(xdrs, &objp->count))
+ return FALSE;
+ if (!xdr_stable_how(xdrs, &objp->committed))
+ return FALSE;
+ if (!xdr_writeverf3(xdrs, objp->verf))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t xdr_WRITE3resfail(XDR * xdrs, WRITE3resfail * objp)
+{
+ if (!xdr_wcc_data(xdrs, &objp->file_wcc))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t xdr_WRITE3res(XDR * xdrs, WRITE3res * objp)
+{
+ if (!xdr_nfsstat3(xdrs, &objp->status))
+ return FALSE;
+ switch (objp->status) {
+ case NFS3_OK:
+ if (!xdr_WRITE3resok(xdrs, &objp->WRITE3res_u.resok))
+ return FALSE;
+ break;
+ default:
+ if (!xdr_WRITE3resfail(xdrs, &objp->WRITE3res_u.resfail))
+ return FALSE;
+ break;
+ }
+ return TRUE;
+}
+
+bool_t xdr_createmode3(XDR * xdrs, createmode3 * objp)
+{
+ if (!xdr_enum(xdrs, (enum_t *) objp))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t xdr_createhow3(XDR * xdrs, createhow3 * objp)
+{
+ if (!xdr_createmode3(xdrs, &objp->mode))
+ return FALSE;
+ switch (objp->mode) {
+ case UNCHECKED:
+ case GUARDED:
+ if (!xdr_sattr3(xdrs, &objp->createhow3_u.obj_attributes))
+ return FALSE;
+ break;
+ case EXCLUSIVE:
+ if (!xdr_createverf3(xdrs, objp->createhow3_u.verf))
+ return FALSE;
+ break;
+ default:
+ return FALSE;
+ }
+ return TRUE;
+}
+
+bool_t xdr_CREATE3args(XDR * xdrs, CREATE3args * objp)
+{
+ if (!xdr_diropargs3(xdrs, &objp->where))
+ return FALSE;
+ if (!xdr_createhow3(xdrs, &objp->how))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t xdr_CREATE3resok(XDR * xdrs, CREATE3resok * objp)
+{
+ if (!xdr_post_op_fh3(xdrs, &objp->obj))
+ return FALSE;
+ if (!xdr_post_op_attr(xdrs, &objp->obj_attributes))
+ return FALSE;
+ if (!xdr_wcc_data(xdrs, &objp->dir_wcc))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t xdr_CREATE3resfail(XDR * xdrs, CREATE3resfail * objp)
+{
+ if (!xdr_wcc_data(xdrs, &objp->dir_wcc))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t xdr_CREATE3res(XDR * xdrs, CREATE3res * objp)
+{
+ if (!xdr_nfsstat3(xdrs, &objp->status))
+ return FALSE;
+ switch (objp->status) {
+ case NFS3_OK:
+ if (!xdr_CREATE3resok(xdrs, &objp->CREATE3res_u.resok))
+ return FALSE;
+ break;
+ default:
+ if (!xdr_CREATE3resfail(xdrs, &objp->CREATE3res_u.resfail))
+ return FALSE;
+ break;
+ }
+ return TRUE;
+}
+
+bool_t xdr_MKDIR3args(XDR * xdrs, MKDIR3args * objp)
+{
+ if (!xdr_diropargs3(xdrs, &objp->where))
+ return FALSE;
+ if (!xdr_sattr3(xdrs, &objp->attributes))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t xdr_MKDIR3resok(XDR * xdrs, MKDIR3resok * objp)
+{
+ if (!xdr_post_op_fh3(xdrs, &objp->obj))
+ return FALSE;
+ if (!xdr_post_op_attr(xdrs, &objp->obj_attributes))
+ return FALSE;
+ if (!xdr_wcc_data(xdrs, &objp->dir_wcc))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t xdr_MKDIR3resfail(XDR * xdrs, MKDIR3resfail * objp)
+{
+ if (!xdr_wcc_data(xdrs, &objp->dir_wcc))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t xdr_MKDIR3res(XDR * xdrs, MKDIR3res * objp)
+{
+ if (!xdr_nfsstat3(xdrs, &objp->status))
+ return FALSE;
+ switch (objp->status) {
+ case NFS3_OK:
+ if (!xdr_MKDIR3resok(xdrs, &objp->MKDIR3res_u.resok))
+ return FALSE;
+ break;
+ default:
+ if (!xdr_MKDIR3resfail(xdrs, &objp->MKDIR3res_u.resfail))
+ return FALSE;
+ break;
+ }
+ return TRUE;
+}
+
+bool_t xdr_symlinkdata3(XDR * xdrs, symlinkdata3 * objp)
+{
+ if (!xdr_sattr3(xdrs, &objp->symlink_attributes))
+ return FALSE;
+ if (!xdr_nfspath3(xdrs, &objp->symlink_data))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t xdr_SYMLINK3args(XDR * xdrs, SYMLINK3args * objp)
+{
+ if (!xdr_diropargs3(xdrs, &objp->where))
+ return FALSE;
+ if (!xdr_symlinkdata3(xdrs, &objp->symlink))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t xdr_SYMLINK3resok(XDR * xdrs, SYMLINK3resok * objp)
+{
+ if (!xdr_post_op_fh3(xdrs, &objp->obj))
+ return FALSE;
+ if (!xdr_post_op_attr(xdrs, &objp->obj_attributes))
+ return FALSE;
+ if (!xdr_wcc_data(xdrs, &objp->dir_wcc))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t xdr_SYMLINK3resfail(XDR * xdrs, SYMLINK3resfail * objp)
+{
+ if (!xdr_wcc_data(xdrs, &objp->dir_wcc))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t xdr_SYMLINK3res(XDR * xdrs, SYMLINK3res * objp)
+{
+ if (!xdr_nfsstat3(xdrs, &objp->status))
+ return FALSE;
+ switch (objp->status) {
+ case NFS3_OK:
+ if (!xdr_SYMLINK3resok(xdrs, &objp->SYMLINK3res_u.resok))
+ return FALSE;
+ break;
+ default:
+ if (!xdr_SYMLINK3resfail(xdrs, &objp->SYMLINK3res_u.resfail))
+ return FALSE;
+ break;
+ }
+ return TRUE;
+}
+
+bool_t xdr_devicedata3(XDR * xdrs, devicedata3 * objp)
+{
+ if (!xdr_sattr3(xdrs, &objp->dev_attributes))
+ return FALSE;
+ if (!xdr_specdata3(xdrs, &objp->spec))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t xdr_mknoddata3(XDR * xdrs, mknoddata3 * objp)
+{
+ if (!xdr_ftype3(xdrs, &objp->type))
+ return FALSE;
+ switch (objp->type) {
+ case NF3CHR:
+ case NF3BLK:
+ if (!xdr_devicedata3(xdrs, &objp->mknoddata3_u.device))
+ return FALSE;
+ break;
+ case NF3SOCK:
+ case NF3FIFO:
+ if (!xdr_sattr3(xdrs, &objp->mknoddata3_u.pipe_attributes))
+ return FALSE;
+ break;
+ default:
+ break;
+ }
+ return TRUE;
+}
+
+bool_t xdr_MKNOD3args(XDR * xdrs, MKNOD3args * objp)
+{
+ if (!xdr_diropargs3(xdrs, &objp->where))
+ return FALSE;
+ if (!xdr_mknoddata3(xdrs, &objp->what))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t xdr_MKNOD3resok(XDR * xdrs, MKNOD3resok * objp)
+{
+ if (!xdr_post_op_fh3(xdrs, &objp->obj))
+ return FALSE;
+ if (!xdr_post_op_attr(xdrs, &objp->obj_attributes))
+ return FALSE;
+ if (!xdr_wcc_data(xdrs, &objp->dir_wcc))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t xdr_MKNOD3resfail(XDR * xdrs, MKNOD3resfail * objp)
+{
+ if (!xdr_wcc_data(xdrs, &objp->dir_wcc))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t xdr_MKNOD3res(XDR * xdrs, MKNOD3res * objp)
+{
+ if (!xdr_nfsstat3(xdrs, &objp->status))
+ return FALSE;
+ switch (objp->status) {
+ case NFS3_OK:
+ if (!xdr_MKNOD3resok(xdrs, &objp->MKNOD3res_u.resok))
+ return FALSE;
+ break;
+ default:
+ if (!xdr_MKNOD3resfail(xdrs, &objp->MKNOD3res_u.resfail))
+ return FALSE;
+ break;
+ }
+ return TRUE;
+}
+
+bool_t xdr_REMOVE3args(XDR * xdrs, REMOVE3args * objp)
+{
+ if (!xdr_diropargs3(xdrs, &objp->object))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t xdr_REMOVE3resok(XDR * xdrs, REMOVE3resok * objp)
+{
+ if (!xdr_wcc_data(xdrs, &objp->dir_wcc))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t xdr_REMOVE3resfail(XDR * xdrs, REMOVE3resfail * objp)
+{
+ if (!xdr_wcc_data(xdrs, &objp->dir_wcc))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t xdr_REMOVE3res(XDR * xdrs, REMOVE3res * objp)
+{
+ if (!xdr_nfsstat3(xdrs, &objp->status))
+ return FALSE;
+ switch (objp->status) {
+ case NFS3_OK:
+ if (!xdr_REMOVE3resok(xdrs, &objp->REMOVE3res_u.resok))
+ return FALSE;
+ break;
+ default:
+ if (!xdr_REMOVE3resfail(xdrs, &objp->REMOVE3res_u.resfail))
+ return FALSE;
+ break;
+ }
+ return TRUE;
+}
+
+bool_t xdr_RMDIR3args(XDR * xdrs, RMDIR3args * objp)
+{
+ if (!xdr_diropargs3(xdrs, &objp->object))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t xdr_RMDIR3resok(XDR * xdrs, RMDIR3resok * objp)
+{
+ if (!xdr_wcc_data(xdrs, &objp->dir_wcc))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t xdr_RMDIR3resfail(XDR * xdrs, RMDIR3resfail * objp)
+{
+ if (!xdr_wcc_data(xdrs, &objp->dir_wcc))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t xdr_RMDIR3res(XDR * xdrs, RMDIR3res * objp)
+{
+ if (!xdr_nfsstat3(xdrs, &objp->status))
+ return FALSE;
+ switch (objp->status) {
+ case NFS3_OK:
+ if (!xdr_RMDIR3resok(xdrs, &objp->RMDIR3res_u.resok))
+ return FALSE;
+ break;
+ default:
+ if (!xdr_RMDIR3resfail(xdrs, &objp->RMDIR3res_u.resfail))
+ return FALSE;
+ break;
+ }
+ return TRUE;
+}
+
+bool_t xdr_RENAME3args(XDR * xdrs, RENAME3args * objp)
+{
+ if (!xdr_diropargs3(xdrs, &objp->from))
+ return FALSE;
+ if (!xdr_diropargs3(xdrs, &objp->to))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t xdr_RENAME3resok(XDR * xdrs, RENAME3resok * objp)
+{
+ if (!xdr_wcc_data(xdrs, &objp->fromdir_wcc))
+ return FALSE;
+ if (!xdr_wcc_data(xdrs, &objp->todir_wcc))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t xdr_RENAME3resfail(XDR * xdrs, RENAME3resfail * objp)
+{
+ if (!xdr_wcc_data(xdrs, &objp->fromdir_wcc))
+ return FALSE;
+ if (!xdr_wcc_data(xdrs, &objp->todir_wcc))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t xdr_RENAME3res(XDR * xdrs, RENAME3res * objp)
+{
+ if (!xdr_nfsstat3(xdrs, &objp->status))
+ return FALSE;
+ switch (objp->status) {
+ case NFS3_OK:
+ if (!xdr_RENAME3resok(xdrs, &objp->RENAME3res_u.resok))
+ return FALSE;
+ break;
+ default:
+ if (!xdr_RENAME3resfail(xdrs, &objp->RENAME3res_u.resfail))
+ return FALSE;
+ break;
+ }
+ return TRUE;
+}
+
+bool_t xdr_LINK3args(XDR * xdrs, LINK3args * objp)
+{
+ if (!xdr_nfs_fh3(xdrs, &objp->file))
+ return FALSE;
+ if (!xdr_diropargs3(xdrs, &objp->link))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t xdr_LINK3resok(XDR * xdrs, LINK3resok * objp)
+{
+ if (!xdr_post_op_attr(xdrs, &objp->file_attributes))
+ return FALSE;
+ if (!xdr_wcc_data(xdrs, &objp->linkdir_wcc))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t xdr_LINK3resfail(XDR * xdrs, LINK3resfail * objp)
+{
+ if (!xdr_post_op_attr(xdrs, &objp->file_attributes))
+ return FALSE;
+ if (!xdr_wcc_data(xdrs, &objp->linkdir_wcc))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t xdr_LINK3res(XDR * xdrs, LINK3res * objp)
+{
+ if (!xdr_nfsstat3(xdrs, &objp->status))
+ return FALSE;
+ switch (objp->status) {
+ case NFS3_OK:
+ if (!xdr_LINK3resok(xdrs, &objp->LINK3res_u.resok))
+ return FALSE;
+ break;
+ default:
+ if (!xdr_LINK3resfail(xdrs, &objp->LINK3res_u.resfail))
+ return FALSE;
+ break;
+ }
+ return TRUE;
+}
+
+bool_t xdr_READDIR3args(XDR * xdrs, READDIR3args * objp)
+{
+ if (!xdr_nfs_fh3(xdrs, &objp->dir))
+ return FALSE;
+ if (!xdr_cookie3(xdrs, &objp->cookie))
+ return FALSE;
+ if (!xdr_cookieverf3(xdrs, objp->cookieverf))
+ return FALSE;
+ if (!xdr_count3(xdrs, &objp->count))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t xdr_entry3(XDR * xdrs, entry3 * objp)
+{
+ if (!xdr_fileid3(xdrs, &objp->fileid))
+ return FALSE;
+ if (!xdr_filename3(xdrs, &objp->name))
+ return FALSE;
+ if (!xdr_cookie3(xdrs, &objp->cookie))
+ return FALSE;
+ if (!xdr_pointer
+ (xdrs, (char **) (void *) &objp->nextentry, sizeof(entry3),
+ (xdrproc_t) xdr_entry3))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t xdr_dirlist3(XDR * xdrs, dirlist3 * objp)
+{
+ if (!xdr_pointer
+ (xdrs, (char **) (void *) &objp->entries, sizeof(entry3),
+ (xdrproc_t) xdr_entry3))
+ return FALSE;
+ if (!xdr_bool(xdrs, &objp->eof))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t xdr_READDIR3resok(XDR * xdrs, READDIR3resok * objp)
+{
+ if (!xdr_post_op_attr(xdrs, &objp->dir_attributes))
+ return FALSE;
+ if (!xdr_cookieverf3(xdrs, objp->cookieverf))
+ return FALSE;
+ if (!xdr_dirlist3(xdrs, &objp->reply))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t xdr_READDIR3resfail(XDR * xdrs, READDIR3resfail * objp)
+{
+ if (!xdr_post_op_attr(xdrs, &objp->dir_attributes))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t xdr_READDIR3res(XDR * xdrs, READDIR3res * objp)
+{
+ if (!xdr_nfsstat3(xdrs, &objp->status))
+ return FALSE;
+ switch (objp->status) {
+ case NFS3_OK:
+ if (!xdr_READDIR3resok(xdrs, &objp->READDIR3res_u.resok))
+ return FALSE;
+ break;
+ default:
+ if (!xdr_READDIR3resfail(xdrs, &objp->READDIR3res_u.resfail))
+ return FALSE;
+ break;
+ }
+ return TRUE;
+}
+
+bool_t xdr_READDIRPLUS3args(XDR * xdrs, READDIRPLUS3args * objp)
+{
+ if (!xdr_nfs_fh3(xdrs, &objp->dir))
+ return FALSE;
+ if (!xdr_cookie3(xdrs, &objp->cookie))
+ return FALSE;
+ if (!xdr_cookieverf3(xdrs, objp->cookieverf))
+ return FALSE;
+ if (!xdr_count3(xdrs, &objp->dircount))
+ return FALSE;
+ if (!xdr_count3(xdrs, &objp->maxcount))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t xdr_entryplus3(XDR * xdrs, entryplus3 * objp)
+{
+ if (!xdr_fileid3(xdrs, &objp->fileid))
+ return FALSE;
+ if (!xdr_filename3(xdrs, &objp->name))
+ return FALSE;
+ if (!xdr_cookie3(xdrs, &objp->cookie))
+ return FALSE;
+ if (!xdr_post_op_attr(xdrs, &objp->name_attributes))
+ return FALSE;
+ if (!xdr_post_op_fh3(xdrs, &objp->name_handle))
+ return FALSE;
+ if (!xdr_pointer
+ (xdrs, (char **) (void *) &objp->nextentry, sizeof(entryplus3),
+ (xdrproc_t) xdr_entryplus3))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t xdr_dirlistplus3(XDR * xdrs, dirlistplus3 * objp)
+{
+ if (!xdr_pointer
+ (xdrs, (char **) (void *) &objp->entries, sizeof(entryplus3),
+ (xdrproc_t) xdr_entryplus3))
+ return FALSE;
+ if (!xdr_bool(xdrs, &objp->eof))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t xdr_READDIRPLUS3resok(XDR * xdrs, READDIRPLUS3resok * objp)
+{
+ if (!xdr_post_op_attr(xdrs, &objp->dir_attributes))
+ return FALSE;
+ if (!xdr_cookieverf3(xdrs, objp->cookieverf))
+ return FALSE;
+ if (!xdr_dirlistplus3(xdrs, &objp->reply))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t xdr_READDIRPLUS3resfail(XDR * xdrs, READDIRPLUS3resfail * objp)
+{
+ if (!xdr_post_op_attr(xdrs, &objp->dir_attributes))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t xdr_READDIRPLUS3res(XDR * xdrs, READDIRPLUS3res * objp)
+{
+ if (!xdr_nfsstat3(xdrs, &objp->status))
+ return FALSE;
+ switch (objp->status) {
+ case NFS3_OK:
+ if (!xdr_READDIRPLUS3resok(xdrs, &objp->READDIRPLUS3res_u.resok))
+ return FALSE;
+ break;
+ default:
+ if (!xdr_READDIRPLUS3resfail
+ (xdrs, &objp->READDIRPLUS3res_u.resfail))
+ return FALSE;
+ break;
+ }
+ return TRUE;
+}
+
+bool_t xdr_FSSTAT3args(XDR * xdrs, FSSTAT3args * objp)
+{
+ if (!xdr_nfs_fh3(xdrs, &objp->fsroot))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t xdr_FSSTAT3resok(XDR * xdrs, FSSTAT3resok * objp)
+{
+ if (!xdr_post_op_attr(xdrs, &objp->obj_attributes))
+ return FALSE;
+ if (!xdr_size3(xdrs, &objp->tbytes))
+ return FALSE;
+ if (!xdr_size3(xdrs, &objp->fbytes))
+ return FALSE;
+ if (!xdr_size3(xdrs, &objp->abytes))
+ return FALSE;
+ if (!xdr_size3(xdrs, &objp->tfiles))
+ return FALSE;
+ if (!xdr_size3(xdrs, &objp->ffiles))
+ return FALSE;
+ if (!xdr_size3(xdrs, &objp->afiles))
+ return FALSE;
+ if (!xdr_uint32(xdrs, &objp->invarsec))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t xdr_FSSTAT3resfail(XDR * xdrs, FSSTAT3resfail * objp)
+{
+ if (!xdr_post_op_attr(xdrs, &objp->obj_attributes))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t xdr_FSSTAT3res(XDR * xdrs, FSSTAT3res * objp)
+{
+ if (!xdr_nfsstat3(xdrs, &objp->status))
+ return FALSE;
+ switch (objp->status) {
+ case NFS3_OK:
+ if (!xdr_FSSTAT3resok(xdrs, &objp->FSSTAT3res_u.resok))
+ return FALSE;
+ break;
+ default:
+ if (!xdr_FSSTAT3resfail(xdrs, &objp->FSSTAT3res_u.resfail))
+ return FALSE;
+ break;
+ }
+ return TRUE;
+}
+
+bool_t xdr_FSINFO3args(XDR * xdrs, FSINFO3args * objp)
+{
+ if (!xdr_nfs_fh3(xdrs, &objp->fsroot))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t xdr_FSINFO3resok(XDR * xdrs, FSINFO3resok * objp)
+{
+ if (!xdr_post_op_attr(xdrs, &objp->obj_attributes))
+ return FALSE;
+ if (!xdr_uint32(xdrs, &objp->rtmax))
+ return FALSE;
+ if (!xdr_uint32(xdrs, &objp->rtpref))
+ return FALSE;
+ if (!xdr_uint32(xdrs, &objp->rtmult))
+ return FALSE;
+ if (!xdr_uint32(xdrs, &objp->wtmax))
+ return FALSE;
+ if (!xdr_uint32(xdrs, &objp->wtpref))
+ return FALSE;
+ if (!xdr_uint32(xdrs, &objp->wtmult))
+ return FALSE;
+ if (!xdr_uint32(xdrs, &objp->dtpref))
+ return FALSE;
+ if (!xdr_size3(xdrs, &objp->maxfilesize))
+ return FALSE;
+ if (!xdr_nfstime3(xdrs, &objp->time_delta))
+ return FALSE;
+ if (!xdr_uint32(xdrs, &objp->properties))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t xdr_FSINFO3resfail(XDR * xdrs, FSINFO3resfail * objp)
+{
+ if (!xdr_post_op_attr(xdrs, &objp->obj_attributes))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t xdr_FSINFO3res(XDR * xdrs, FSINFO3res * objp)
+{
+ if (!xdr_nfsstat3(xdrs, &objp->status))
+ return FALSE;
+ switch (objp->status) {
+ case NFS3_OK:
+ if (!xdr_FSINFO3resok(xdrs, &objp->FSINFO3res_u.resok))
+ return FALSE;
+ break;
+ default:
+ if (!xdr_FSINFO3resfail(xdrs, &objp->FSINFO3res_u.resfail))
+ return FALSE;
+ break;
+ }
+ return TRUE;
+}
+
+bool_t xdr_PATHCONF3args(XDR * xdrs, PATHCONF3args * objp)
+{
+ if (!xdr_nfs_fh3(xdrs, &objp->object))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t xdr_PATHCONF3resok(XDR * xdrs, PATHCONF3resok * objp)
+{
+ if (!xdr_post_op_attr(xdrs, &objp->obj_attributes))
+ return FALSE;
+ if (!xdr_uint32(xdrs, &objp->linkmax))
+ return FALSE;
+ if (!xdr_uint32(xdrs, &objp->name_max))
+ return FALSE;
+ if (!xdr_bool(xdrs, &objp->no_trunc))
+ return FALSE;
+ if (!xdr_bool(xdrs, &objp->chown_restricted))
+ return FALSE;
+ if (!xdr_bool(xdrs, &objp->case_insensitive))
+ return FALSE;
+ if (!xdr_bool(xdrs, &objp->case_preserving))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t xdr_PATHCONF3resfail(XDR * xdrs, PATHCONF3resfail * objp)
+{
+ if (!xdr_post_op_attr(xdrs, &objp->obj_attributes))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t xdr_PATHCONF3res(XDR * xdrs, PATHCONF3res * objp)
+{
+ if (!xdr_nfsstat3(xdrs, &objp->status))
+ return FALSE;
+ switch (objp->status) {
+ case NFS3_OK:
+ if (!xdr_PATHCONF3resok(xdrs, &objp->PATHCONF3res_u.resok))
+ return FALSE;
+ break;
+ default:
+ if (!xdr_PATHCONF3resfail(xdrs, &objp->PATHCONF3res_u.resfail))
+ return FALSE;
+ break;
+ }
+ return TRUE;
+}
+
+bool_t xdr_COMMIT3args(XDR * xdrs, COMMIT3args * objp)
+{
+ if (!xdr_nfs_fh3(xdrs, &objp->file))
+ return FALSE;
+ if (!xdr_offset3(xdrs, &objp->offset))
+ return FALSE;
+ if (!xdr_count3(xdrs, &objp->count))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t xdr_COMMIT3resok(XDR * xdrs, COMMIT3resok * objp)
+{
+ if (!xdr_wcc_data(xdrs, &objp->file_wcc))
+ return FALSE;
+ if (!xdr_writeverf3(xdrs, objp->verf))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t xdr_COMMIT3resfail(XDR * xdrs, COMMIT3resfail * objp)
+{
+ if (!xdr_wcc_data(xdrs, &objp->file_wcc))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t xdr_COMMIT3res(XDR * xdrs, COMMIT3res * objp)
+{
+ if (!xdr_nfsstat3(xdrs, &objp->status))
+ return FALSE;
+ switch (objp->status) {
+ case NFS3_OK:
+ if (!xdr_COMMIT3resok(xdrs, &objp->COMMIT3res_u.resok))
+ return FALSE;
+ break;
+ default:
+ if (!xdr_COMMIT3resfail(xdrs, &objp->COMMIT3res_u.resfail))
+ return FALSE;
+ break;
+ }
+ return TRUE;
+}
diff --git a/external/fs/unfs3-0.9.22/xdr.h b/external/fs/unfs3-0.9.22/xdr.h
new file mode 100644
index 0000000..3296c59
--- /dev/null
+++ b/external/fs/unfs3-0.9.22/xdr.h
@@ -0,0 +1,165 @@
+/*
+ * UNFS3 XDR routine prototypes
+ * Generated by rpcgen
+ */
+
+#ifndef UNFS3_XDR_H
+#define UNFS3_XDR_H
+
+/* MOUNT protocol */
+
+extern bool_t xdr_fhandle3 (XDR *, fhandle3*);
+extern bool_t xdr_mountstat3 (XDR *, mountstat3*);
+extern bool_t xdr_mountres3_ok (XDR *, mountres3_ok*);
+extern bool_t xdr_mountres3 (XDR *, mountres3*);
+extern bool_t xdr_dirpath (XDR *, dirpath*);
+extern bool_t xdr_name (XDR *, name*);
+extern bool_t xdr_mountlist (XDR *, mountlist*);
+extern bool_t xdr_mountbody (XDR *, mountbody*);
+extern bool_t xdr_groups (XDR *, groups*);
+extern bool_t xdr_groupnode (XDR *, groupnode*);
+extern bool_t xdr_exports (XDR *, exports*);
+extern bool_t xdr_exportnode (XDR *, exportnode*);
+
+/* NFS protocol */
+
+extern bool_t xdr_filename (XDR *, filename*);
+extern bool_t xdr_nfspath (XDR *, nfspath*);
+#if HAVE_XDR_UINT64 == 0
+extern bool_t xdr_uint64 (XDR *, uint64*);
+#endif
+#if HAVE_XDR_UINT32 == 0
+extern bool_t xdr_uint32 (XDR *, uint32*);
+#endif
+#if HAVE_XDR_INT32 == 0
+extern bool_t xdr_int32 (XDR *, int32*);
+#endif
+extern bool_t xdr_filename3 (XDR *, filename3*);
+extern bool_t xdr_nfspath3 (XDR *, nfspath3*);
+extern bool_t xdr_fileid3 (XDR *, fileid3*);
+extern bool_t xdr_cookie3 (XDR *, cookie3*);
+extern bool_t xdr_cookieverf3 (XDR *, cookieverf3);
+extern bool_t xdr_createverf3 (XDR *, createverf3);
+extern bool_t xdr_writeverf3 (XDR *, writeverf3);
+extern bool_t xdr_uid3 (XDR *, uid3*);
+extern bool_t xdr_gid3 (XDR *, gid3*);
+extern bool_t xdr_size3 (XDR *, size3*);
+extern bool_t xdr_offset3 (XDR *, offset3*);
+extern bool_t xdr_mode3 (XDR *, mode3*);
+extern bool_t xdr_count3 (XDR *, count3*);
+extern bool_t xdr_nfsstat3 (XDR *, nfsstat3*);
+extern bool_t xdr_ftype3 (XDR *, ftype3*);
+extern bool_t xdr_specdata3 (XDR *, specdata3*);
+extern bool_t xdr_nfs_fh3 (XDR *, nfs_fh3*);
+extern bool_t xdr_nfstime3 (XDR *, nfstime3*);
+extern bool_t xdr_fattr3 (XDR *, fattr3*);
+extern bool_t xdr_post_op_attr (XDR *, post_op_attr*);
+extern bool_t xdr_wcc_attr (XDR *, wcc_attr*);
+extern bool_t xdr_pre_op_attr (XDR *, pre_op_attr*);
+extern bool_t xdr_wcc_data (XDR *, wcc_data*);
+extern bool_t xdr_post_op_fh3 (XDR *, post_op_fh3*);
+extern bool_t xdr_time_how (XDR *, time_how*);
+extern bool_t xdr_set_mode3 (XDR *, set_mode3*);
+extern bool_t xdr_set_uid3 (XDR *, set_uid3*);
+extern bool_t xdr_set_gid3 (XDR *, set_gid3*);
+extern bool_t xdr_set_size3 (XDR *, set_size3*);
+extern bool_t xdr_set_atime (XDR *, set_atime*);
+extern bool_t xdr_set_mtime (XDR *, set_mtime*);
+extern bool_t xdr_sattr3 (XDR *, sattr3*);
+extern bool_t xdr_diropargs3 (XDR *, diropargs3*);
+extern bool_t xdr_GETATTR3args (XDR *, GETATTR3args*);
+extern bool_t xdr_GETATTR3resok (XDR *, GETATTR3resok*);
+extern bool_t xdr_GETATTR3res (XDR *, GETATTR3res*);
+extern bool_t xdr_sattrguard3 (XDR *, sattrguard3*);
+extern bool_t xdr_SETATTR3args (XDR *, SETATTR3args*);
+extern bool_t xdr_SETATTR3resok (XDR *, SETATTR3resok*);
+extern bool_t xdr_SETATTR3resfail (XDR *, SETATTR3resfail*);
+extern bool_t xdr_SETATTR3res (XDR *, SETATTR3res*);
+extern bool_t xdr_LOOKUP3args (XDR *, LOOKUP3args*);
+extern bool_t xdr_LOOKUP3resok (XDR *, LOOKUP3resok*);
+extern bool_t xdr_LOOKUP3resfail (XDR *, LOOKUP3resfail*);
+extern bool_t xdr_LOOKUP3res (XDR *, LOOKUP3res*);
+extern bool_t xdr_ACCESS3args (XDR *, ACCESS3args*);
+extern bool_t xdr_ACCESS3resok (XDR *, ACCESS3resok*);
+extern bool_t xdr_ACCESS3resfail (XDR *, ACCESS3resfail*);
+extern bool_t xdr_ACCESS3res (XDR *, ACCESS3res*);
+extern bool_t xdr_READLINK3args (XDR *, READLINK3args*);
+extern bool_t xdr_READLINK3resok (XDR *, READLINK3resok*);
+extern bool_t xdr_READLINK3resfail (XDR *, READLINK3resfail*);
+extern bool_t xdr_READLINK3res (XDR *, READLINK3res*);
+extern bool_t xdr_READ3args (XDR *, READ3args*);
+extern bool_t xdr_READ3resok (XDR *, READ3resok*);
+extern bool_t xdr_READ3resfail (XDR *, READ3resfail*);
+extern bool_t xdr_READ3res (XDR *, READ3res*);
+extern bool_t xdr_stable_how (XDR *, stable_how*);
+extern bool_t xdr_WRITE3args (XDR *, WRITE3args*);
+extern bool_t xdr_WRITE3resok (XDR *, WRITE3resok*);
+extern bool_t xdr_WRITE3resfail (XDR *, WRITE3resfail*);
+extern bool_t xdr_WRITE3res (XDR *, WRITE3res*);
+extern bool_t xdr_createmode3 (XDR *, createmode3*);
+extern bool_t xdr_createhow3 (XDR *, createhow3*);
+extern bool_t xdr_CREATE3args (XDR *, CREATE3args*);
+extern bool_t xdr_CREATE3resok (XDR *, CREATE3resok*);
+extern bool_t xdr_CREATE3resfail (XDR *, CREATE3resfail*);
+extern bool_t xdr_CREATE3res (XDR *, CREATE3res*);
+extern bool_t xdr_MKDIR3args (XDR *, MKDIR3args*);
+extern bool_t xdr_MKDIR3resok (XDR *, MKDIR3resok*);
+extern bool_t xdr_MKDIR3resfail (XDR *, MKDIR3resfail*);
+extern bool_t xdr_MKDIR3res (XDR *, MKDIR3res*);
+extern bool_t xdr_symlinkdata3 (XDR *, symlinkdata3*);
+extern bool_t xdr_SYMLINK3args (XDR *, SYMLINK3args*);
+extern bool_t xdr_SYMLINK3resok (XDR *, SYMLINK3resok*);
+extern bool_t xdr_SYMLINK3resfail (XDR *, SYMLINK3resfail*);
+extern bool_t xdr_SYMLINK3res (XDR *, SYMLINK3res*);
+extern bool_t xdr_devicedata3 (XDR *, devicedata3*);
+extern bool_t xdr_mknoddata3 (XDR *, mknoddata3*);
+extern bool_t xdr_MKNOD3args (XDR *, MKNOD3args*);
+extern bool_t xdr_MKNOD3resok (XDR *, MKNOD3resok*);
+extern bool_t xdr_MKNOD3resfail (XDR *, MKNOD3resfail*);
+extern bool_t xdr_MKNOD3res (XDR *, MKNOD3res*);
+extern bool_t xdr_REMOVE3args (XDR *, REMOVE3args*);
+extern bool_t xdr_REMOVE3resok (XDR *, REMOVE3resok*);
+extern bool_t xdr_REMOVE3resfail (XDR *, REMOVE3resfail*);
+extern bool_t xdr_REMOVE3res (XDR *, REMOVE3res*);
+extern bool_t xdr_RMDIR3args (XDR *, RMDIR3args*);
+extern bool_t xdr_RMDIR3resok (XDR *, RMDIR3resok*);
+extern bool_t xdr_RMDIR3resfail (XDR *, RMDIR3resfail*);
+extern bool_t xdr_RMDIR3res (XDR *, RMDIR3res*);
+extern bool_t xdr_RENAME3args (XDR *, RENAME3args*);
+extern bool_t xdr_RENAME3resok (XDR *, RENAME3resok*);
+extern bool_t xdr_RENAME3resfail (XDR *, RENAME3resfail*);
+extern bool_t xdr_RENAME3res (XDR *, RENAME3res*);
+extern bool_t xdr_LINK3args (XDR *, LINK3args*);
+extern bool_t xdr_LINK3resok (XDR *, LINK3resok*);
+extern bool_t xdr_LINK3resfail (XDR *, LINK3resfail*);
+extern bool_t xdr_LINK3res (XDR *, LINK3res*);
+extern bool_t xdr_READDIR3args (XDR *, READDIR3args*);
+extern bool_t xdr_entry3 (XDR *, entry3*);
+extern bool_t xdr_dirlist3 (XDR *, dirlist3*);
+extern bool_t xdr_READDIR3resok (XDR *, READDIR3resok*);
+extern bool_t xdr_READDIR3resfail (XDR *, READDIR3resfail*);
+extern bool_t xdr_READDIR3res (XDR *, READDIR3res*);
+extern bool_t xdr_READDIRPLUS3args (XDR *, READDIRPLUS3args*);
+extern bool_t xdr_entryplus3 (XDR *, entryplus3*);
+extern bool_t xdr_dirlistplus3 (XDR *, dirlistplus3*);
+extern bool_t xdr_READDIRPLUS3resok (XDR *, READDIRPLUS3resok*);
+extern bool_t xdr_READDIRPLUS3resfail (XDR *, READDIRPLUS3resfail*);
+extern bool_t xdr_READDIRPLUS3res (XDR *, READDIRPLUS3res*);
+extern bool_t xdr_FSSTAT3args (XDR *, FSSTAT3args*);
+extern bool_t xdr_FSSTAT3resok (XDR *, FSSTAT3resok*);
+extern bool_t xdr_FSSTAT3resfail (XDR *, FSSTAT3resfail*);
+extern bool_t xdr_FSSTAT3res (XDR *, FSSTAT3res*);
+extern bool_t xdr_FSINFO3args (XDR *, FSINFO3args*);
+extern bool_t xdr_FSINFO3resok (XDR *, FSINFO3resok*);
+extern bool_t xdr_FSINFO3resfail (XDR *, FSINFO3resfail*);
+extern bool_t xdr_FSINFO3res (XDR *, FSINFO3res*);
+extern bool_t xdr_PATHCONF3args (XDR *, PATHCONF3args*);
+extern bool_t xdr_PATHCONF3resok (XDR *, PATHCONF3resok*);
+extern bool_t xdr_PATHCONF3resfail (XDR *, PATHCONF3resfail*);
+extern bool_t xdr_PATHCONF3res (XDR *, PATHCONF3res*);
+extern bool_t xdr_COMMIT3args (XDR *, COMMIT3args*);
+extern bool_t xdr_COMMIT3resok (XDR *, COMMIT3resok*);
+extern bool_t xdr_COMMIT3resfail (XDR *, COMMIT3resfail*);
+extern bool_t xdr_COMMIT3res (XDR *, COMMIT3res*);
+
+#endif
--
2.6.2

Benoît Canet

unread,
Nov 26, 2015, 3:22:56 PM11/26/15
to osv...@googlegroups.com, Benoît Canet
---
.gitignore | 2 +
Makefile | 23 +-
core/mmu.cc | 27 +-
external/fs/nfs-ganesha | 1 +
fs/nfs/nfs.cc | 84 ++++
fs/nfs/nfs.hh | 70 +++
fs/nfs/nfs_null_vfsops.cc | 36 ++
fs/nfs/nfs_vfsops.cc | 79 ++++
fs/nfs/nfs_vnops.cc | 612 ++++++++++++++++++++++++++
fs/vfs/vfs_conf.cc | 3 +
modules/tests/Makefile | 8 +-
scripts/test.py | 39 +-
tests-nfs/fsx-linux.c | 1064 +++++++++++++++++++++++++++++++++++++++++++++
tests-nfs/tst-nfs.cc | 316 ++++++++++++++
14 files changed, 2354 insertions(+), 10 deletions(-)
create mode 160000 external/fs/nfs-ganesha
create mode 100644 fs/nfs/nfs.cc
create mode 100644 fs/nfs/nfs.hh
create mode 100644 fs/nfs/nfs_null_vfsops.cc
create mode 100644 fs/nfs/nfs_vfsops.cc
create mode 100644 fs/nfs/nfs_vnops.cc
create mode 100644 tests-nfs/fsx-linux.c
create mode 100644 tests-nfs/tst-nfs.cc

diff --git a/.gitignore b/.gitignore
index b76d37e..436d0fe 100644
--- a/.gitignore
+++ b/.gitignore
@@ -32,3 +32,5 @@ modules/httpserver-jolokia-plugin/obj/
modules/httpserver-jvm-plugin/autogen/
modules/httpserver-jvm-plugin/jvm.so
modules/httpserver-jvm-plugin/obj/
+
+external/fs/unfs3-0.9.22/*
diff --git a/Makefile b/Makefile
index 5488aee..a531792 100644
--- a/Makefile
+++ b/Makefile
@@ -146,11 +146,18 @@ check:

libnfs-path = $(shell pwd)/external/fs/libnfs/

-$(out)/libnfs.a:
+$(out)/unfsd:
+ $(call quiet, cd external/fs/unfs3-0.9.22/) && \
+ $(call quiet, ./configure) && \
+ $(call quiet, make) && \
+ $(call quiet, cd ../../../)
+
+$(out)/libnfs.a: $(out)/unfsd
cd $(libnfs-path) && \
- $(call quiet, $(libnfs-path)/bootstrap) && \
- $(call quiet, $(libnfs-path)/configure --enable-shared=no --enable-static=yes --enable-silent-rules) && \
- $(call quiet, make -f $(libnfs-path)/Makefile)
+ $(call quiet, ./bootstrap) && \
+ $(call quiet, ./configure --enable-shared=no --enable-static=yes --enable-silent-rules) && \
+ $(call quiet, make) && \
+ $(call quiet, cd ../../../) && \
$(call quiet, cp -a $(libnfs-path)/lib/.libs/libnfs.a $(out)/libnfs.a)

clean-libnfs:
@@ -1774,8 +1781,13 @@ boost-libs := $(boost-lib-dir)/libboost_program_options$(boost-mt).a \
nfs-lib =
ifeq ($(NFS), true)
nfs-lib += $(out)/libnfs.a
+ nfs = nfs.o nfs_vfsops.o nfs_vnops.o
+else
+ nfs = nfs_null_vfsops.o
endif

+nfs-objects += $(addprefix fs/nfs/, $(nfs))
+
nfs-library: $(nfs-lib)
@@ -1785,14 +1797,13 @@ nfs-library: $(nfs-lib)
$(out)/dummy-shlib.so: $(out)/dummy-shlib.o
$(call quiet, $(CXX) -nodefaultlibs -shared $(gcc-sysroot) -o $@ $^, LINK $@)

-$(out)/loader.elf: $(out)/arch/$(arch)/boot.o arch/$(arch)/loader.ld $(out)/loader.o $(out)/runtime.o $(drivers:%=$(out)/%) $(objects:%=$(out)/%) $(out)/bootfs.bin $(out)/dummy-shlib.so $(nfs-lib)
+$(out)/loader.elf: $(out)/arch/$(arch)/boot.o arch/$(arch)/loader.ld $(out)/loader.o $(out)/runtime.o $(drivers:%=$(out)/%) $(objects:%=$(out)/%) $(nfs-objects:%=$(out)/%) $(out)/bootfs.bin $(out)/dummy-shlib.so $(nfs-lib)
$(call quiet, $(LD) -o $@ --defsym=OSV_KERNEL_BASE=$(kernel_base) \
-Bdynamic --export-dynamic --eh-frame-hdr --enable-new-dtags \
$(filter-out %.bin, $(^:%.ld=-T %.ld)) \
--whole-archive \
$(libstdc++.a) $(libgcc.a) $(libgcc_eh.a) \
$(boost-libs) \
- $(nfs-lib) \
--no-whole-archive, \
LINK loader.elf)
@# Build libosv.so matching this loader.elf. This is not a separate
diff --git a/core/mmu.cc b/core/mmu.cc
index 7135b6f..b366603 100644
--- a/core/mmu.cc
+++ b/core/mmu.cc
@@ -1660,13 +1660,38 @@ void file_vma::split(uintptr_t edge)
vma_list.insert(*n);
}

+#include <iostream>
error file_vma::sync(uintptr_t start, uintptr_t end)
{
if (!has_flags(mmap_shared))
return make_error(ENOMEM);

try {
- _file->sync(_offset + start - _range.start(), _offset + end - _range.start());
+ off_t my_start = _offset + start - _range.start();
+ off_t my_end = _offset + end - _range.start();
+ size_t my_size = end - start;
+ ssize_t my_ssize = end - start;
+
+ off_t file_size = _file->f_dentry->d_vnode->v_size;
+
+ if (my_start > file_size) {
+ my_start = file_size;
+ }
+
+ if (my_end > file_size) {
+ my_end = file_size;
+ }
+
+ off_t expected_size = my_start + my_ssize;
+ if (expected_size > file_size) {
+ off_t delta = expected_size - file_size;
+ my_size -= delta;
+ my_ssize -= delta;
+ }
+ iovec iovec {(void *)(_range.start()), my_size};
+ uio data {&iovec, 1, my_start, my_ssize, UIO_WRITE};
+ _file->write(&data, FOF_OFFSET);
+ _file->sync(my_start, my_end);
} catch (error& err) {
return err;
}
diff --git a/external/fs/nfs-ganesha b/external/fs/nfs-ganesha
new file mode 160000
index 0000000..6dd95ab
--- /dev/null
+++ b/external/fs/nfs-ganesha
@@ -0,0 +1 @@
+Subproject commit 6dd95abf3ef4cf8ffda11967cd085068ccfbfdc6
diff --git a/fs/nfs/nfs.cc b/fs/nfs/nfs.cc
new file mode 100644
index 0000000..0bd818a
--- /dev/null
+++ b/fs/nfs/nfs.cc
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2015 Scylla, Ltd.
+ *
+ * Based on ramfs code Copyright (c) 2006-2007, Kohsuke Ohtani
+ *
+ * This work is open source software, licensed under the terms of the
+ * BSD license as described in the LICENSE file in the top-level directory.
+ */
+
+#include <osv/debug.hh>
+
+#include <osv/mount.h>
+
+#include "nfs.hh"
+
+#include <iostream>
+
+#include <osv/mutex.h>
+
+mount_context::mount_context(const char *url)
+ : _valid(false)
+ , _errno(0)
+ , _raw_url(url)
+ , _nfs(nullptr, nfs_destroy_context)
+ , _url(nullptr, nfs_destroy_url)
+{
+ /* Create the NFS context */
+ _nfs.reset(nfs_init_context());
+ if (!_nfs) {
+ debug("mount_context(): failed to create NFS context\n");
+ _errno = ENOMEM;
+ return;
+ }
+
+ // parse the url while taking care of freeing it when needed
+ _url.reset(nfs_parse_url_dir(_nfs.get(), url));
+ if (!_url) {
+ debug(std::string("mount_context():g: ") +
+ nfs_get_error(_nfs.get()) + "\n");
+ _errno = EINVAL;
+ return;
+ }
+
+ _errno = -nfs_mount(_nfs.get(), _url->server, _url->path);
+ if (_errno) {
+ return;
+ }
+
+ _valid = true;
+}
+
+thread_local mutex _lock;
+thread_local std::unordered_map<std::string,
+ std::unique_ptr<mount_context>> _map;
+
+struct mount_context *get_mount_context(struct mount *mp, int &err_no)
+{
+ auto m_path = static_cast<const char*>(mp->m_path);
+ std::string mount_point(m_path);
+ err_no = 0;
+
+ SCOPE_LOCK(_lock);
+
+ // if not mounted at all mount it
+ if (!_map.count(mount_point)) {
+ _map[mount_point] =
+ std::unique_ptr<mount_context>(new mount_context(mp->m_special));
+ }
+
+ // if we remounted with a different url change the mount point
+ if (!_map[mount_point]->same_url(mp->m_special)) {
+ _map.erase(mount_point);
+ _map[mount_point] =
+ std::unique_ptr<mount_context>(new mount_context(mp->m_special));
+ }
+
+ // clear the mess if the mount point is invalid
+ if (!_map[mount_point]->is_valid(err_no)) {
+ _map.erase(mount_point);
+ return nullptr;
+ }
+
+ return _map[mount_point].get();
+}
diff --git a/fs/nfs/nfs.hh b/fs/nfs/nfs.hh
new file mode 100644
index 0000000..1816d76
--- /dev/null
+++ b/fs/nfs/nfs.hh
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2015 Scylla, Ltd.
+ *
+ * Based on ramfs code Copyright (c) 2006-2007, Kohsuke Ohtani
+ *
+ * This work is open source software, licensed under the terms of the
+ * BSD license as described in the LICENSE file in the top-level directory.
+ */
+
+#ifndef FS_NFS_NFS_HH
+#define FS_NFS_NFS_HH
+
+#include <sys/stat.h>
+#include <dirent.h>
+#include <sys/param.h>
+
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <fcntl.h>
+
+#include "../../external/fs/libnfs/include/nfsc/libnfs.h"
+
+#ifdef __cplusplus
+
+#include <memory>
+#include <string>
+
+#include <atomic>
+#include <memory>
+#include <thread>
+#include <unordered_map>
+
+#include <osv/mutex.h>
+
+class mount_context {
+public:
+ mount_context(const char *url);
+ struct nfs_context *nfs() {
+ return _nfs.get();
+ };
+ bool is_valid(int &err_no) {
+ err_no = _errno;
+ return _valid;
+ };
+ std::string server() {
+ return std::string(_url->server);
+ }
+ std::string share() {
+ return std::string(_url->path);
+ }
+ bool same_url(std::string url) {
+ return url == _raw_url;
+ }
+private:
+ bool _valid;
+ int _errno;
+ std::string _raw_url;
+ std::unique_ptr<struct nfs_context,
+ void (*)(struct nfs_context *)> _nfs;
+ std::unique_ptr<struct nfs_url, void (*)(struct nfs_url *)> _url;
+};
+
+struct mount_point *get_mount_point(struct mount *mp);
+
+struct mount_context *get_mount_context(struct mount *mp, int &err_no);
+
+#endif
+
+#endif
diff --git a/fs/nfs/nfs_null_vfsops.cc b/fs/nfs/nfs_null_vfsops.cc
new file mode 100644
index 0000000..eef09fd
--- /dev/null
+++ b/fs/nfs/nfs_null_vfsops.cc
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2015 Scylla, Ltd.
+ *
+ * Based on ramfs code Copyright (c) 2006-2007, Kohsuke Ohtani
+ *
+ * This work is open source software, licensed under the terms of the
+ * BSD license as described in the LICENSE file in the top-level directory.
+ */
+
+#include <osv/mount.h>
+
+#define nfs_mount ((vfsop_mount_t)vfs_nullop)
+#define nfs_umount ((vfsop_umount_t)vfs_nullop)
+#define nfs_sync ((vfsop_sync_t)vfs_nullop)
+#define nfs_vget ((vfsop_vget_t)vfs_nullop)
+#define nfs_statfs ((vfsop_statfs_t)vfs_nullop)
+
+/*
+ * File system operations
+ *
+ * This desactivate the NFS file system when libnfs is not compiled in.
+ *
+ */
+struct vfsops nfs_vfsops = {
+ nfs_mount, /* mount */
+ nfs_umount, /* umount */
+ nfs_sync, /* sync */
+ nfs_vget, /* vget */
+ nfs_statfs, /* statfs */
+ nullptr, /* vnops */
+};
+
+int nfs_init(void)
+{
+ return 0;
+}
diff --git a/fs/nfs/nfs_vfsops.cc b/fs/nfs/nfs_vfsops.cc
new file mode 100644
index 0000000..1434c61
--- /dev/null
+++ b/fs/nfs/nfs_vfsops.cc
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2015 Scylla, Ltd.
+ *
+ * Based on ramfs code Copyright (c) 2006-2007, Kohsuke Ohtani
+ *
+ * This work is open source software, licensed under the terms of the
+ * BSD license as described in the LICENSE file in the top-level directory.
+ */
+
+#include <cassert>
+#include <cerrno>
+
+#include <osv/debug.hh>
+#include <osv/vnode.h>
+#include <osv/mount.h>
+#include <osv/dentry.h>
+
+#include <string>
+#include <memory>
+
+#include "nfs.hh"
+
+extern struct vnops nfs_vnops;
+
+/*
+ * Mount a file system.
+ */
+static int nfs_op_mount(struct mount *mp, const char *dev, int flags,
+ const void *data)
+{
+ assert(mp);
+
+ // build a temporary mount context to check the NFS server is alive
+ int err_no;
+ std::unique_ptr<mount_context> ctx =
+ std::unique_ptr<mount_context>(new mount_context(mp->m_special));
+
+ if (!ctx->is_valid(err_no)) {
+ return err_no;
+ }
+
+ return 0;
+}
+
+/*
+ * Unmount a file system.
+ *
+ * Note: There is no nfs_unmount in nfslib.
+ *
+ */
+static int nfs_op_unmount(struct mount *mp, int flags)
+{
+ assert(mp);
+
+ return 0;
+}
+
+int nfs_init(void)
+{
+ return 0;
+}
+
+// For the following let's rely on operations on individual files
+#define nfs_op_sync ((vfsop_sync_t)vfs_nullop)
+#define nfs_op_vget ((vfsop_vget_t)vfs_nullop)
+#define nfs_op_statfs ((vfsop_statfs_t)vfs_nullop)
+
+/*
+ * File system operations
+ */
+struct vfsops nfs_vfsops = {
+ nfs_op_mount, /* mount */
+ nfs_op_unmount, /* unmount */
+ nfs_op_sync, /* sync */
+ nfs_op_vget, /* vget */
+ nfs_op_statfs, /* statfs */
+ &nfs_vnops, /* vnops */
+};
+
diff --git a/fs/nfs/nfs_vnops.cc b/fs/nfs/nfs_vnops.cc
new file mode 100644
index 0000000..329c336
--- /dev/null
+++ b/fs/nfs/nfs_vnops.cc
@@ -0,0 +1,612 @@
+/*
+ * Copyright (C) 2015 Scylla, Ltd.
+ *
+ * Based on nfs code Copyright (c) 2006-2007, Kohsuke Ohtani
+ *
+ * This work is open source software, licensed under the terms of the
+ * BSD license as described in the LICENSE file in the top-level directory.
+ */
+
+#include <osv/prex.h>
+#include <osv/vnode.h>
+#include <osv/file.h>
+#include <osv/mount.h>
+
+#include <iostream>
+
+#include "nfs.hh"
+
+static inline struct nfs_context *get_nfs_context(struct vnode *node,
+ int &err_no)
+{
+ return get_mount_context(node->v_mount, err_no)->nfs();
+}
+
+static inline struct nfsfh *get_handle(struct vnode *node)
+{
+ return static_cast<struct nfsfh *>(node->v_data);
+}
+
+static inline struct nfsdir *get_dir_handle(struct vnode *node)
+{
+ return static_cast<struct nfsdir *>(node->v_data);
+}
+
+
+static const char *get_node_name(struct vnode *node)
+{
+ if (LIST_EMPTY(&node->v_names) == 1) {
+ return nullptr;
+ }
+
+ return LIST_FIRST(&node->v_names)->d_path;
+}
+
+static inline std::string mkpath(struct vnode *node, const char *name)
+{
+ std::string path(get_node_name(node));
+ return path + "/" + name;
+}
+
+int nfs_open(struct file *fp)
+{
+ struct vnode *vp = file_dentry(fp)->d_vnode;
+ std::string path(fp->f_dentry->d_path);
+ int err_no;
+ auto nfs = get_nfs_context(vp, err_no);
+ int flags = file_flags(fp);
+ int ret = 0;
+
+ if (err_no) {
+ return err_no;
+ }
+
+ if (path == "/") {
+ return 0;
+ }
+
+ int type = vp->v_type;
+
+ // It's a directory or a file.
+ if (type == VDIR) {
+ struct nfsdir *handle = nullptr;
+ ret = nfs_opendir(nfs, path.c_str(), &handle);
+ vp->v_data = handle;
+ } else if (type == VREG) {
+ struct nfsfh *handle = nullptr;
+ ret = nfs_open(nfs, path.c_str(), flags, &handle);
+ vp->v_data = handle;
+ } else {
+ return EIO;
+ }
+
+ if (ret) {
+ return -ret;
+ }
+
+ return 0;
+}
+
+int nfs_close(struct vnode *dvp, struct file *file)
+{
+ int err_no;
+ auto nfs = get_nfs_context(dvp, err_no);
+ int type = dvp->v_type;
+ int ret = 0;
+
+ if (err_no) {
+ return err_no;
+ }
+
+ if (type == VDIR) {
+ auto handle = get_dir_handle(dvp);
+ nfs_closedir(nfs, handle);
+ } else if (type == VREG) {
+ auto handle = get_handle(dvp);
+ ret = nfs_close(nfs, handle);
+ } else {
+ return EIO;
+ }
+
+ return -ret;
+}
+
+static int nfs_read(struct vnode *vp, struct file *fp, struct uio *uio,
+ int ioflag)
+{
+ int err_no;
+ auto nfs = get_nfs_context(vp, err_no);
+ auto handle = get_handle(vp);
+
+ if (err_no) {
+ return err_no;
+ }
+
+ // From here to // END_PASTE comes from fs/ramfs/ramfs_vnops.cc
+ if (vp->v_type == VDIR) {
+ return EISDIR;
+ }
+
+ if (vp->v_type != VREG) {
+ return EINVAL;
+ }
+
+ if (uio->uio_offset < 0) {
+ return EINVAL;
+ }
+
+ if (uio->uio_resid == 0) {
+ return 0;
+ }
+
+ if (uio->uio_offset >= (off_t)vp->v_size) {
+ return 0;
+ }
+
+ size_t len;
+ if (vp->v_size - uio->uio_offset < uio->uio_resid)
+ len = vp->v_size - uio->uio_offset;
+ else
+ len = uio->uio_resid;
+ // END_PASTE
+
+ // FIXME: remove this temporary buffer
+ auto buf = std::unique_ptr<char>(new char[len + 1]());
+
+ int ret = nfs_pread(nfs, handle, uio->uio_offset, len, buf.get());
+ if (ret < 0) {
+ return -ret;
+ }
+
+ // Handle short read.
+ return uiomove(buf.get(), ret, uio);
+}
+
+static int nfs_write(struct vnode *vp, struct uio *uio, int ioflag)
+{
+ int err_no;
+ auto nfs = get_nfs_context(vp, err_no);
+ auto handle = get_handle(vp);
+
+ if (err_no) {
+ return err_no;
+ }
+
+ // From here to // END_PASTE comes from fs/ramfs/ramfs_vnops.cc
+ if (vp->v_type == VDIR) {
+ return EISDIR;
+ }
+ if (vp->v_type != VREG) {
+ return EINVAL;
+ }
+ if (uio->uio_offset < 0) {
+ return EINVAL;
+ }
+
+ if (uio->uio_resid == 0) {
+ return 0;
+ }
+
+ int ret = 0;
+ size_t new_size = vp->v_size;
+ if (ioflag & IO_APPEND) {
+
+ uio->uio_offset = vp->v_size;
+ new_size = vp->v_size + uio->uio_resid;
+ // NFS does not support happening to a file so let's truncate ourselve
+ ret = nfs_ftruncate(nfs, handle, new_size);
+ } else if ((uio->uio_offset + uio->uio_resid) > vp->v_size) {
+ new_size = uio->uio_offset + uio->uio_resid;
+ ret = nfs_ftruncate(nfs, handle, new_size);
+ }
+
+ if (ret) {
+ return -ret;
+ }
+
+ // make a copy of these since uimove will touch them.
+ size_t size = uio->uio_resid;
+ size_t offset = uio->uio_offset;
+
+ // END_PASTE
+
+ auto buf = std::unique_ptr<char>(new char[size]());
+
+ auto buffp = buf.get();
+
+ ret = uiomove(buffp, size, uio);
+ assert(!ret);
+
+ // Handle short writes.
+ while (size > 0) {
+ ret = nfs_pwrite(nfs, handle, offset, size, buffp);
+ if (ret < 0) {
+ return -ret;
+ }
+
+ buffp += ret;
+ offset += ret;
+ size -= ret;
+ }
+
+ vp->v_size = new_size;
+
+ return 0;
+}
+
+static int nfs_seek(struct vnode *vp, struct file *fp, off_t ooff, off_t noffp)
+{
+ return 0;
+}
+
+static int nfs_fsync(vnode *vp, struct file *fp)
+{
+ int err_no;
+ auto nfs = get_nfs_context(vp, err_no);
+ auto handle = get_handle(vp);
+
+ if (err_no) {
+ return err_no;
+ }
+
+
+ return -nfs_fsync(nfs, handle);
+}
+
+static int nfs_readdir(struct vnode *vp, struct file *fp, struct dirent *dir)
+{
+ int err_no;
+ auto nfs = get_nfs_context(vp, err_no);
+ auto handle = get_dir_handle(vp);
+
+ if (err_no) {
+ return err_no;
+ }
+
+ // query the NFS server about this directory entry.
+ auto nfsdirent = nfs_readdir(nfs, handle);
+
+ // We finished iterating on the directory.
+ if (!nfsdirent) {
+ return ENOENT;
+ }
+
+ // Fill dirent infos
+ assert(sizeof(ino_t) == sizeof(nfsdirent->inode));
+ dir->d_ino = nfsdirent->inode;
+ // FIXME: not filling dir->d_off
+ // FIXME: not filling dir->d_reclen
+ dir->d_type = IFTODT(nfsdirent->mode & S_IFMT);;
+ strlcpy((char *) &dir->d_name, nfsdirent->name, sizeof(dir->d_name));
+
+ // iterate
+ fp->f_offset++;
+
+ return 0;
+}
+
+// This function is called by the namei() family before nfsen()
+static int nfs_lookup(struct vnode *dvp, char *p, struct vnode **vpp)
+{
+ int err_no;
+ auto nfs = get_nfs_context(dvp, err_no);
+ struct nfs_stat_64 st;
+ std::string path = mkpath(dvp, p);
+ struct vnode *vp;
+
+ if (err_no) {
+ return err_no;
+ }
+
+ // Make sure we don't accidentally return garbage.
+ *vpp = nullptr;
+
+ // Following 4 checks inspired by ZFS code
+ if (!path.size())
+ return ENOENT;
+
+ if (dvp->v_type != VDIR)
+ return ENOTDIR;
+
+ assert(path != ".");
+ assert(path != "..");
+
+ // We must get the inode number so we query the NFS server.
+ int ret = nfs_stat64(nfs, path.c_str(), &st);
+ if (ret) {
+ return -ret;
+ }
+
+ // Get the file type.
+ uint64_t type = st.nfs_mode & S_IFMT;
+
+ // Filter by inode type: only keep files, directories and symbolic links.
+ if (S_ISCHR(type) || S_ISBLK(type) || S_ISFIFO(type) || S_ISSOCK(type)) {
+ // FIXME: Not sure it's the right error code.
+ return EINVAL;
+ }
+
+ // Create the new vnode or get it from the cache.
+ if (vget(dvp->v_mount, st.nfs_ino, &vp)) {
+ // Present in the cache
+ *vpp = vp;
+ return 0;
+ }
+
+ if (!vp) {
+ return ENOMEM;
+ }
+
+ uint64_t mode = st.nfs_mode & ~S_IFMT;
+
+ // Fill in the new vnode informations.
+ vp->v_type = IFTOVT(type);
+ vp->v_mode = mode;
+ vp->v_size = st.nfs_size;
+ vp->v_mount = dvp->v_mount;
+
+ *vpp = vp;
+
+ return 0;
+}
+
+static int nfs_create(struct vnode *dvp, char *name, mode_t mode)
+{
+ int err_no;
+ auto nfs = get_nfs_context(dvp, err_no);
+ struct nfsfh *handle = nullptr;
+ auto path = mkpath(dvp, name);
+
+
+ if (err_no) {
+ return err_no;
+ }
+
+
+ if (!S_ISREG(mode)) {
+ return EINVAL;
+ }
+
+ int ret = nfs_creat(nfs, path.c_str(), mode, &handle);
+ if (ret) {
+ return -ret;
+ }
+
+ dvp->v_data = handle;
+ return 0;
+}
+
+static int nfs_remove(struct vnode *dvp, struct vnode *vp, char *name)
+{
+ int err_no;
+ auto nfs = get_nfs_context(vp, err_no);
+ auto path = mkpath(dvp, name);
+
+ if (err_no) {
+ return err_no;
+ }
+
+ return -nfs_unlink(nfs, path.c_str());
+}
+
+static int nfs_rename(struct vnode *dvp1, struct vnode *vp1, char *old_path,
+ struct vnode *dvp2, struct vnode *vp2, char *new_path)
+{
+ int err_no;
+ auto nfs = get_nfs_context(dvp1, err_no);
+ auto src = mkpath(dvp1, old_path);
+ auto dst = mkpath(dvp2, new_path);
+
+ if (err_no) {
+ return err_no;
+ }
+
+ return -nfs_rename(nfs, src.c_str(), dst.c_str());
+}
+
+// FIXME: Set permissions
+static int nfs_mkdir(struct vnode *dvp, char *name, mode_t mode)
+{
+ int err_no;
+ auto nfs = get_nfs_context(dvp, err_no);
+ auto path = mkpath(dvp, name);
+
+ if (err_no) {
+ return err_no;
+ }
+
+ return -nfs_mkdir(nfs, path.c_str());
+}
+
+static int nfs_rmdir(struct vnode *dvp, struct vnode *vp, char *name)
+{
+ int err_no;
+ auto nfs = get_nfs_context(vp, err_no);
+ auto path = mkpath(dvp, name);
+
+ if (err_no) {
+ return err_no;
+ }
+
+ return -nfs_rmdir(nfs, path.c_str());
+}
+
+
+static inline struct timespec to_timespec(uint64_t sec, uint64_t nsec)
+{
+ struct timespec t;
+
+ t.tv_sec = sec;
+ t.tv_nsec = nsec;
+
+ return std::move(t);
+}
+
+static int nfs_getattr(struct vnode *vp, struct vattr *attr)
+{
+ int err_no;
+ auto nfs = get_nfs_context(vp, err_no);
+ struct nfs_stat_64 st;
+
+ if (err_no) {
+ return err_no;
+ }
+
+ auto path = get_node_name(vp);
+ if (!path) {
+ return ENOENT;
+ }
+
+ // Get the file infos.
+ int ret = nfs_stat64(nfs, path, &st);
+ if (ret) {
+ return -ret;
+ }
+
+ uint64_t type = st.nfs_mode & S_IFMT;
+ uint64_t mode = st.nfs_mode & ~S_IFMT;
+
+ // Copy the file infos.
+ //attr->va_mask =;
+ attr->va_type = IFTOVT(type);
+ attr->va_mode = mode;;
+ attr->va_nlink = st.nfs_nlink;
+ attr->va_uid = st.nfs_uid;
+ attr->va_gid = st.nfs_gid;
+ attr->va_fsid = st.nfs_dev; // FIXME: not sure about this one
+ attr->va_nodeid = st.nfs_ino;
+ attr->va_atime = to_timespec(st.nfs_atime, st.nfs_atime_nsec);
+ attr->va_mtime = to_timespec(st.nfs_mtime, st.nfs_mtime_nsec);
+ attr->va_ctime = to_timespec(st.nfs_ctime, st.nfs_ctime_nsec);
+ attr->va_rdev = st.nfs_rdev;
+ attr->va_nblocks = st.nfs_blocks;
+ attr->va_size = st.nfs_size;
+
+ return 0;
+}
+
+static int nfs_setattr(struct vnode *vp, struct vattr *attr)
+{
+ int err_no;
+ auto nfs = get_nfs_context(vp, err_no);
+ int ret = 0;
+
+ if (err_no) {
+ return err_no;
+ }
+
+ auto path = get_node_name(vp);
+ if (!path) {
+ return ENOENT;
+ }
+
+ // Change all that we can change with libnfs.
+
+ ret = nfs_chmod(nfs, path, attr->va_mode);
+ if (ret) {
+ return -ret;
+ }
+
+ ret = nfs_chown(nfs, path, attr->va_uid, attr->va_gid);
+ if (ret) {
+ return -ret;
+ }
+
+ return 0;
+}
+
+static int nfs_truncate(struct vnode *vp, off_t length)
+{
+ int err_no;
+ auto nfs = get_nfs_context(vp, err_no);
+ auto handle = get_handle(vp);
+
+ if (err_no) {
+ return err_no;
+ }
+
+ int ret = nfs_ftruncate(nfs, handle, length);
+ if (ret) {
+ return -ret;
+ }
+
+ vp->v_size = length;
+
+ return 0;
+}
+
+static int nfs_readlink(struct vnode *vp, struct uio *uio)
+{
+ int err_no;
+ auto nfs = get_nfs_context(vp, err_no);
+ char buf[PATH_MAX + 1];
+
+ if (err_no) {
+ return err_no;
+ }
+
+ auto path = get_node_name(vp);
+
+ memset(buf, 0, sizeof(buf));
+ int ret = nfs_readlink(nfs, path, buf, sizeof(buf));
+ if (ret) {
+ return -ret;
+ }
+
+ size_t sz = MIN(uio->uio_iov->iov_len, strlen(buf) + 1);
+
+ return uiomove(buf, sz, uio);
+}
+
+static int nfs_symlink(struct vnode *dvp, char *l, char *t)
+{
+ int err_no;
+ auto nfs = get_nfs_context(dvp, err_no);
+ auto target = mkpath(dvp, t);
+ auto link = mkpath(dvp, l);
+
+ if (err_no) {
+ return err_no;
+ }
+
+ return -nfs_symlink(nfs, target.c_str(), link.c_str());
+}
+
+static int nfs_inactive(struct vnode *)
+{
+ return 0;
+}
+
+#define nfs_ioctl ((vnop_ioctl_t)vop_einval) // not a device
+#define nfs_link ((vnop_link_t)vop_eperm) // not in NFS
+#define nfs_fallocate ((vnop_fallocate_t)vop_nullop) // not in NFS
+
+
+/*
+ * vnode operations
+ */
+struct vnops nfs_vnops = {
+ nfs_open, /* open */
+ nfs_close, /* close */
+ nfs_read, /* read */
+ nfs_write, /* write */
+ nfs_seek, /* seek */
+ nfs_ioctl, /* ioctl */
+ nfs_fsync, /* fsync */
+ nfs_readdir, /* readdir */
+ nfs_lookup, /* lookup */
+ nfs_create, /* create */
+ nfs_remove, /* remove */
+ nfs_rename, /* remame */
+ nfs_mkdir, /* mkdir */
+ nfs_rmdir, /* rmdir */
+ nfs_getattr, /* getattr */
+ nfs_setattr, /* setattr */
+ nfs_inactive, /* inactive */
+ nfs_truncate, /* truncate */
+ nfs_link, /* link */
+ (vnop_cache_t) nullptr, /* arc */
+ nfs_fallocate, /* fallocate */
+ nfs_readlink, /* read link */
+ nfs_symlink, /* symbolic link */
+};
diff --git a/fs/vfs/vfs_conf.cc b/fs/vfs/vfs_conf.cc
index 1c92f4e..59e1b79 100644
--- a/fs/vfs/vfs_conf.cc
+++ b/fs/vfs/vfs_conf.cc
@@ -47,11 +47,13 @@

extern struct vfsops ramfs_vfsops;
extern struct vfsops devfs_vfsops;
+extern struct vfsops nfs_vfsops;
extern struct vfsops procfs_vfsops;
extern struct vfsops zfs_vfsops;

extern int ramfs_init(void);
extern int devfs_init(void);
+extern int nfs_init(void);
extern int procfs_init(void);
extern "C" int zfs_init(void);

@@ -61,6 +63,7 @@ extern "C" int zfs_init(void);
const struct vfssw vfssw[] = {
{"ramfs", ramfs_init, &ramfs_vfsops},
{"devfs", devfs_init, &devfs_vfsops},
+ {"nfs", nfs_init, &nfs_vfsops},
{"procfs", procfs_init, &procfs_vfsops},
{"zfs", zfs_init, &zfs_vfsops},
{nullptr, fs_noop, nullptr},
diff --git a/modules/tests/Makefile b/modules/tests/Makefile
index 1c42767..f7c5290 100644
--- a/modules/tests/Makefile
+++ b/modules/tests/Makefile
@@ -83,6 +83,8 @@ tests := tst-pthread.so tst-ramdisk.so tst-vblk.so tst-bsd-evh.so \
tst-namespace.so tst-without-namespace.so payload-env.so \
payload-merge-env.so testrunner.so

+tests-nfs := tst-nfs.so fsx-linux.so
+
# libstatic-thread-variable.so tst-static-thread-variable.so \

tests += testrunner.so
@@ -142,15 +144,19 @@ $(solaris-tests:%=$(out)/tests/%): COMMON+= \

all_tests := $(tests:%=tests/%)

+all_nfs_tests := $(tests-nfs:%=tests-nfs/%)
+
# Automatically generate usr.manifest which includes all tests.
-usr.manifest: $(all_tests:%=$(out)/%) $(lastword $(MAKEFILE_LIST)) usr.manifest.skel
+usr.manifest: $(all_tests:%=$(out)/%) $(all_nfs_tests:%=$(out)/%) $(lastword $(MAKEFILE_LIST)) usr.manifest.skel
@echo " generating modules/tests/usr.manifest"
@cat $@.skel > $@
@echo $(all_tests) | tr ' ' '\n' | awk '{print "/" $$0 ": ./" $$0}' >> $@
+ @echo $(all_nfs_tests) | tr ' ' '\n' | awk '{print "/" $$0 ": ./" $$0}' >> $@

clean:
-rm -f usr.manifest

ifneq ($(MAKECMDGOALS),clean)
include $(shell test -d $(out)/tests && find $(out)/tests -name '*.d')
+include $(shell test -d $(out)/tests-nfs && find $(out)/tests-nfs -name '*.d')
endif
diff --git a/scripts/test.py b/scripts/test.py
index f60df33..33b8f22 100755
--- a/scripts/test.py
+++ b/scripts/test.py
@@ -1,6 +1,7 @@
#!/usr/bin/env python
import subprocess
import argparse
+import tempfile
import glob
import time
import sys
@@ -73,10 +74,22 @@ def pluralize(word, count):
return word
return word + 's'

+def make_export_and_conf():
+ export_dir = tempfile.mkdtemp(prefix='share')
+ os.chmod(export_dir, 0777)
+ (conf_fd, conf_path) = tempfile.mkstemp(prefix='export')
+ conf = os.fdopen(conf_fd, "w")
+ conf.write("%s 127.0.0.1(insecure,rw)\n" % export_dir)
+ conf.flush()
+ conf.close()
+ return (conf_path, export_dir)
+
def run_tests():
start = time.time()

- if cmdargs.name:
+ if cmdargs.nfs:
+ pass
+ elif cmdargs.name:
tests_to_run = list((t for t in tests if re.match('^' + cmdargs.name + '$', t.name)))
if not tests_to_run:
print('No test matches: ' + cmdargs.name)
@@ -84,7 +97,28 @@ def run_tests():
else:
tests_to_run = tests

- if cmdargs.single:
+ if cmdargs.nfs:
+ (conf_path, export_dir) = make_export_and_conf()
+ proc = subprocess.Popen([ "sudo",
+ os.path.join(os.getcwd(),
+ "./external/fs/unfs3-0.9.22/unfsd"),
+ "-t",
+ "-d",
+ "-s",
+ "-l", "127.0.0.1",
+ "-e", conf_path ],
+ stdin = sys.stdin,
+ stdout = sys.stdout,
+ stderr = sys.stderr,
+ shell = False)
+ tests_to_run = [ SingleCommandTest('nfs-test',
+ "/tests-nfs/tst-nfs.so --server 192.168.122.1 --share %s" %
+ export_dir) ]
+
+ run(tests_to_run)
+ subprocess.call(["sudo", "kill", "-9", str(proc.pid)])
+ proc.communicate()
+ elif cmdargs.single:
if tests_to_run != tests:
print('Cannot restrict the set of tests when --single option is used')
exit(1)
@@ -108,6 +142,7 @@ if __name__ == "__main__":
parser.add_argument("-v", "--verbose", action="store_true", help="verbose test output")
parser.add_argument("-r", "--repeat", action="store_true", help="repeat until test fails")
parser.add_argument("-s", "--single", action="store_true", help="run as much tests as possible in a single OSv instance")
+ parser.add_argument("-n", "--nfs", action="store_true", help="run nfs test in a single OSv instance")
parser.add_argument("--name", action="store", help="run all tests whose names match given regular expression")
cmdargs = parser.parse_args()
set_verbose_output(cmdargs.verbose)
diff --git a/tests-nfs/fsx-linux.c b/tests-nfs/fsx-linux.c
new file mode 100644
index 0000000..3df089b
--- /dev/null
+++ b/tests-nfs/fsx-linux.c
@@ -0,0 +1,1064 @@
+/*
+ * Copyright (C) 1991, NeXT Computer, Inc. All Rights Reserverd.
+ *
+ * File: fsx.c
+ * Author: Avadis Tevanian, Jr.
+ *
+ * File system exerciser.
+ *
+ * Rewritten 8/98 by Conrad Minshall.
+ *
+ * Small changes to work under Linux -- da...@suse.de
+ *
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#ifdef _UWIN
+# include <sys/param.h>
+# include <limits.h>
+# include <time.h>
+# include <strings.h>
+# define MAP_FILE 0
+#else
+#ifndef linux
+# include <sys/dirent.h>
+#endif
+#endif
+#include <sys/file.h>
+#include <sys/mman.h>
+#include <limits.h>
+#include <err.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include <errno.h>
+
+#define NUMPRINTCOLUMNS 32 /* # columns of data to print on each line */
+
+/*
+ * A log entry is an operation and a bunch of arguments.
+ */
+
+struct log_entry {
+ int operation;
+ int args[3];
+};
+
+#define LOGSIZE 1000
+
+struct log_entry oplog[LOGSIZE]; /* the log */
+int logptr = 0; /* current position in log */
+int logcount = 0; /* total ops */
+
+/*
+ * Define operations
+ */
+
+#define OP_READ 1
+#define OP_WRITE 2
+#define OP_TRUNCATE 3
+#define OP_CLOSEOPEN 4
+#define OP_MAPREAD 5
+#define OP_MAPWRITE 6
+#define OP_SKIPPED 7
+
+#ifndef PAGE_SIZE
+#define PAGE_SIZE 4096
+#endif
+#define PAGE_MASK (PAGE_SIZE - 1)
+
+char *original_buf; /* a pointer to the original data */
+char *good_buf; /* a pointer to the correct data */
+char *temp_buf; /* a pointer to the current data */
+char *fname; /* name of our test file */
+int fd; /* fd for our test file */
+
+off_t file_size = 0;
+off_t biggest = 0;
+char state[256];
+unsigned long testcalls = 0; /* calls to function "test" */
+
+unsigned long simulatedopcount = 0; /* -b flag */
+int closeprob = 0; /* -c flag */
+int debug = 0; /* -d flag */
+unsigned long debugstart = 0; /* -D flag */
+unsigned long maxfilelen = 256 * 1024; /* -l flag */
+int sizechecks = 1; /* -n flag disables them */
+int maxoplen = 64 * 1024; /* -o flag */
+int quiet = 0; /* -q flag */
+unsigned long progressinterval = 0; /* -p flag */
+int readbdy = 1; /* -r flag */
+int style = 0; /* -s flag */
+int truncbdy = 1; /* -t flag */
+int writebdy = 1; /* -w flag */
+long monitorstart = -1; /* -m flag */
+long monitorend = -1; /* -m flag */
+int lite = 0; /* -L flag */
+long numops = -1; /* -N flag */
+int randomoplen = 1; /* -O flag disables it */
+int seed = 1; /* -S flag */
+int mapped_writes = 1; /* -W flag disables */
+int mapped_reads = 1; /* -R flag disables it */
+int fsxgoodfd = 0;
+FILE * fsxlogf = NULL;
+int badoff = -1;
+int closeopen = 0;
+
+
+void
+prt(char *fmt, ...)
+{
+ va_list args;
+
+ va_start(args, fmt);
+ vfprintf(stdout, fmt, args);
+ if (fsxlogf)
+ vfprintf(fsxlogf, fmt, args);
+ va_end(args);
+}
+
+void
+prterr(char *prefix)
+{
+ prt("%s%s%s\n", prefix, prefix ? ": " : "", strerror(errno));
+}
+
+
+void
+log4(int operation, int arg0, int arg1, int arg2)
+{
+ struct log_entry *le;
+
+ le = &oplog[logptr];
+ le->operation = operation;
+ if (closeopen)
+ le->operation = ~ le->operation;
+ le->args[0] = arg0;
+ le->args[1] = arg1;
+ le->args[2] = arg2;
+ logptr++;
+ logcount++;
+ if (logptr >= LOGSIZE)
+ logptr = 0;
+}
+
+
+void
+logdump(void)
+{
+ int i, count, down;
+ struct log_entry *lp;
+
+ prt("LOG DUMP (%d total operations):\n", logcount);
+ if (logcount < LOGSIZE) {
+ i = 0;
+ count = logcount;
+ } else {
+ i = logptr;
+ count = LOGSIZE;
+ }
+ for ( ; count > 0; count--) {
+ int opnum;
+
+ opnum = i+1 + (logcount/LOGSIZE)*LOGSIZE;
+ prt("%d(%d mod 256): ", opnum, opnum%256);
+ lp = &oplog[i];
+ if ((closeopen = lp->operation < 0))
+ lp->operation = ~ lp->operation;
+
+ switch (lp->operation) {
+ case OP_MAPREAD:
+ prt("MAPREAD\t0x%x thru 0x%x\t(0x%x bytes)",
+ lp->args[0], lp->args[0] + lp->args[1] - 1,
+ lp->args[1]);
+ if (badoff >= lp->args[0] && badoff <
+ lp->args[0] + lp->args[1])
+ prt("\t***RRRR***");
+ break;
+ case OP_MAPWRITE:
+ prt("MAPWRITE 0x%x thru 0x%x\t(0x%x bytes)",
+ lp->args[0], lp->args[0] + lp->args[1] - 1,
+ lp->args[1]);
+ if (badoff >= lp->args[0] && badoff <
+ lp->args[0] + lp->args[1])
+ prt("\t******WWWW");
+ break;
+ case OP_READ:
+ prt("READ\t0x%x thru 0x%x\t(0x%x bytes)",
+ lp->args[0], lp->args[0] + lp->args[1] - 1,
+ lp->args[1]);
+ if (badoff >= lp->args[0] &&
+ badoff < lp->args[0] + lp->args[1])
+ prt("\t***RRRR***");
+ break;
+ case OP_WRITE:
+ prt("WRITE\t0x%x thru 0x%x\t(0x%x bytes)",
+ lp->args[0], lp->args[0] + lp->args[1] - 1,
+ lp->args[1]);
+ if (lp->args[0] > lp->args[2])
+ prt(" HOLE");
+ else if (lp->args[0] + lp->args[1] > lp->args[2])
+ prt(" EXTEND");
+ if ((badoff >= lp->args[0] || badoff >=lp->args[2]) &&
+ badoff < lp->args[0] + lp->args[1])
+ prt("\t***WWWW");
+ break;
+ case OP_TRUNCATE:
+ down = lp->args[0] < lp->args[1];
+ prt("TRUNCATE %s\tfrom 0x%x to 0x%x",
+ down ? "DOWN" : "UP", lp->args[1], lp->args[0]);
+ if (badoff >= lp->args[!down] &&
+ badoff < lp->args[!!down])
+ prt("\t******WWWW");
+ break;
+ case OP_SKIPPED:
+ prt("SKIPPED (no operation)");
+ break;
+ default:
+ prt("BOGUS LOG ENTRY (operation code = %d)!",
+ lp->operation);
+ }
+ if (closeopen)
+ prt("\n\t\tCLOSE/OPEN");
+ prt("\n");
+ i++;
+ if (i == LOGSIZE)
+ i = 0;
+ }
+}
+
+void
+save_buffer(char *buffer, off_t bufferlength, int fd)
+{
+ off_t ret;
+ ssize_t byteswritten;
+
+ if (fd <= 0 || bufferlength == 0)
+ return;
+
+ if (bufferlength > SSIZE_MAX) {
+ prt("fsx flaw: overflow in save_buffer\n");
+ exit(67);
+ }
+ if (lite) {
+ off_t size_by_seek = lseek(fd, (off_t)0, L_XTND);
+ if (size_by_seek == (off_t)-1)
+ prterr("save_buffer: lseek eof");
+ else if (bufferlength > size_by_seek) {
+ warn("save_buffer: .fsxgood file too short... will save 0x%qx bytes instead of 0x%qx\n", (unsigned long long)size_by_seek,
+ (unsigned long long)bufferlength);
+ bufferlength = size_by_seek;
+ }
+ }
+
+ ret = lseek(fd, (off_t)0, SEEK_SET);
+ if (ret == (off_t)-1)
+ prterr("save_buffer: lseek 0");
+
+ byteswritten = write(fd, buffer, (size_t)bufferlength);
+ if (byteswritten != bufferlength) {
+ if (byteswritten == -1)
+ prterr("save_buffer write");
+ else
+ warn("save_buffer: short write, 0x%x bytes instead of 0x%qx\n",
+ (unsigned)byteswritten,
+ (unsigned long long)bufferlength);
+ }
+}
+
+
+void
+report_failure(int status)
+{
+ logdump();
+
+ if (fsxgoodfd) {
+ if (good_buf) {
+
+ save_buffer(good_buf, file_size, fsxgoodfd);
+ prt("Correct content saved for comparison\n");
+ prt("(maybe hexdump \"%s\" vs \"%s.fsxgood\")\n",
+ fname, fname);
+ }
+ close(fsxgoodfd);
+ }
+ exit(status);
+}
+
+
+#define short_at(cp) ((unsigned short)((*((unsigned char *)(cp)) << 8) | \
+ *(((unsigned char *)(cp)) + 1)))
+
+void
+check_buffers(unsigned offset, unsigned size)
+{
+ unsigned char c, t;
+ unsigned i = 0;
+ unsigned n = 0;
+ unsigned op = 0;
+ unsigned bad = 0;
+
+ if (bcmp(good_buf + offset, temp_buf, size) != 0) {
+ prt("READ BAD DATA: offset = 0x%x, size = 0x%x\n",
+ offset, size);
+ prt("OFFSET\tGOOD\tBAD\tRANGE\n");
+ while (size > 0) {
+ c = good_buf[offset];
+ t = temp_buf[i];
+ if (c != t) {
+ if (n == 0) {
+ bad = short_at(&temp_buf[i]);
+ prt("0x%5x\t0x%04x\t0x%04x", offset,
+ short_at(&good_buf[offset]), bad);
+ op = temp_buf[offset & 1 ? i+1 : i];
+ }
+ n++;
+ badoff = offset;
+ }
+ offset++;
+ i++;
+ size--;
+ }
+ if (n) {
+ prt("\t0x%5x\n", n);
+ if (bad)
+ prt("operation# (mod 256) for the bad data may be %u\n", ((unsigned)op & 0xff));
+ else
+ prt("operation# (mod 256) for the bad data unknown, check HOLE and EXTEND ops\n");
+ } else
+ prt("????????????????\n");
+ report_failure(110);
+ }
+}
+
+
+void
+check_size(void)
+{
+ struct stat statbuf;
+ off_t size_by_seek;
+
+ if (fstat(fd, &statbuf)) {
+ prterr("check_size: fstat");
+ statbuf.st_size = -1;
+ }
+ size_by_seek = lseek(fd, (off_t)0, L_XTND);
+ if (file_size != statbuf.st_size || file_size != size_by_seek) {
+ prt("Size error: expected 0x%qx stat 0x%qx seek 0x%qx\n",
+ (unsigned long long)file_size,
+ (unsigned long long)statbuf.st_size,
+ (unsigned long long)size_by_seek);
+ report_failure(120);
+ }
+}
+
+
+void
+check_trunc_hack(void)
+{
+ struct stat statbuf;
+
+ ftruncate(fd, (off_t)0);
+ ftruncate(fd, (off_t)100000);
+ fstat(fd, &statbuf);
+ if (statbuf.st_size != (off_t)100000) {
+ prt("no extend on truncate! not posix!\n");
+ exit(130);
+ }
+ ftruncate(fd, 0);
+}
+
+
+void
+doread(unsigned offset, unsigned size)
+{
+ off_t ret;
+ unsigned iret;
+
+ offset -= offset % readbdy;
+ if (size == 0) {
+ if (!quiet && testcalls > simulatedopcount)
+ prt("skipping zero size read\n");
+ log4(OP_SKIPPED, OP_READ, offset, size);
+ return;
+ }
+ if (size + offset > file_size) {
+ if (!quiet && testcalls > simulatedopcount)
+ prt("skipping seek/read past end of file\n");
+ log4(OP_SKIPPED, OP_READ, offset, size);
+ return;
+ }
+
+ log4(OP_READ, offset, size, 0);
+
+ if (testcalls <= simulatedopcount)
+ return;
+
+ if (!quiet && (progressinterval && testcalls % progressinterval == 0 ||
+ debug &&
+ (monitorstart == -1 ||
+ offset + size > monitorstart &&
+ (monitorend == -1 || offset <= monitorend))))
+ prt("%lu read\t0x%x thru\t0x%x\t(0x%x bytes)\n", testcalls,
+ offset, offset + size - 1, size);
+ ret = lseek(fd, (off_t)offset, SEEK_SET);
+ if (ret == (off_t)-1) {
+ prterr("doread: lseek");
+ report_failure(140);
+ }
+ iret = read(fd, temp_buf, size);
+ if (iret != size) {
+ if (iret == -1)
+ prterr("doread: read");
+ else
+ prt("short read: 0x%x bytes instead of 0x%x\n",
+ iret, size);
+ report_failure(141);
+ }
+ check_buffers(offset, size);
+}
+
+
+void
+domapread(unsigned offset, unsigned size)
+{
+ unsigned pg_offset;
+ unsigned map_size;
+ char *p;
+
+ offset -= offset % readbdy;
+ if (size == 0) {
+ if (!quiet && testcalls > simulatedopcount)
+ prt("skipping zero size read\n");
+ log4(OP_SKIPPED, OP_MAPREAD, offset, size);
+ return;
+ }
+ if (size + offset > file_size) {
+ if (!quiet && testcalls > simulatedopcount)
+ prt("skipping seek/read past end of file\n");
+ log4(OP_SKIPPED, OP_MAPREAD, offset, size);
+ return;
+ }
+
+ log4(OP_MAPREAD, offset, size, 0);
+
+ if (testcalls <= simulatedopcount)
+ return;
+
+ if (!quiet && (progressinterval && testcalls % progressinterval == 0 ||
+ debug &&
+ (monitorstart == -1 ||
+ offset + size > monitorstart &&
+ (monitorend == -1 || offset <= monitorend))))
+ prt("%lu mapread\t0x%x thru\t0x%x\t(0x%x bytes)\n", testcalls,
+ offset, offset + size - 1, size);
+
+ pg_offset = offset & PAGE_MASK;
+ map_size = pg_offset + size;
+
+#ifdef linux
+ if ((p = (char *)mmap(0, map_size, PROT_READ, MAP_SHARED, fd,
+#else
+ if ((p = (char *)mmap(0, map_size, PROT_READ, MAP_FILE, fd,
+#endif
+ (off_t)(offset - pg_offset))) == (char *)-1) {
+ prterr("domapread: mmap");
+ report_failure(190);
+ }
+ memcpy(temp_buf, p + pg_offset, size);
+ if (munmap(p, map_size) != 0) {
+ prterr("domapread: munmap");
+ report_failure(191);
+ }
+
+ check_buffers(offset, size);
+}
+
+
+void
+gendata(char *original_buf, char *good_buf, unsigned offset, unsigned size)
+{
+ while (size--) {
+ good_buf[offset] = testcalls % 256;
+ if (offset % 2)
+ good_buf[offset] += original_buf[offset];
+ offset++;
+ }
+}
+
+
+void
+dowrite(unsigned offset, unsigned size)
+{
+ off_t ret;
+ unsigned iret;
+
+ offset -= offset % writebdy;
+ if (size == 0) {
+ if (!quiet && testcalls > simulatedopcount)
+ prt("skipping zero size write\n");
+ log4(OP_SKIPPED, OP_WRITE, offset, size);
+ return;
+ }
+
+ log4(OP_WRITE, offset, size, file_size);
+
+ gendata(original_buf, good_buf, offset, size);
+ if (file_size < offset + size) {
+ if (file_size < offset)
+ bzero(good_buf + file_size, offset - file_size);
+ file_size = offset + size;
+ if (lite) {
+ warn("Lite file size bug in fsx!");
+ report_failure(149);
+ }
+ }
+
+ if (testcalls <= simulatedopcount)
+ return;
+
+ if (!quiet && (progressinterval && testcalls % progressinterval == 0 ||
+ debug &&
+ (monitorstart == -1 ||
+ offset + size > monitorstart &&
+ (monitorend == -1 || offset <= monitorend))))
+ prt("%lu write\t0x%x thru\t0x%x\t(0x%x bytes)\n", testcalls,
+ offset, offset + size - 1, size);
+ ret = lseek(fd, (off_t)offset, SEEK_SET);
+ if (ret == (off_t)-1) {
+ prterr("dowrite: lseek");
+ report_failure(150);
+ }
+ iret = write(fd, good_buf + offset, size);
+ if (iret != size) {
+ if (iret == -1)
+ prterr("dowrite: write");
+ else
+ prt("short write: 0x%x bytes instead of 0x%x\n",
+ iret, size);
+ report_failure(151);
+ }
+}
+
+
+void
+domapwrite(unsigned offset, unsigned size)
+{
+ unsigned pg_offset;
+ unsigned map_size;
+ off_t cur_filesize;
+ char *p;
+
+ offset -= offset % writebdy;
+ if (size == 0) {
+ if (!quiet && testcalls > simulatedopcount)
+ prt("skipping zero size write\n");
+ log4(OP_SKIPPED, OP_MAPWRITE, offset, size);
+ return;
+ }
+ cur_filesize = file_size;
+
+ log4(OP_MAPWRITE, offset, size, 0);
+
+ gendata(original_buf, good_buf, offset, size);
+ if (file_size < offset + size) {
+ if (file_size < offset)
+ bzero(good_buf + file_size, offset - file_size);
+ file_size = offset + size;
+ if (lite) {
+ warn("Lite file size bug in fsx!");
+ report_failure(200);
+ }
+ }
+
+ if (testcalls <= simulatedopcount)
+ return;
+
+ if (!quiet && (progressinterval && testcalls % progressinterval == 0 ||
+ debug &&
+ (monitorstart == -1 ||
+ offset + size > monitorstart &&
+ (monitorend == -1 || offset <= monitorend))))
+ prt("%lu mapwrite\t0x%x thru\t0x%x\t(0x%x bytes)\n", testcalls,
+ offset, offset + size - 1, size);
+
+ if (file_size > cur_filesize) {
+ if (ftruncate(fd, file_size) == -1) {
+ prterr("domapwrite: ftruncate");
+ exit(201);
+ }
+ }
+ pg_offset = offset & PAGE_MASK;
+ map_size = pg_offset + size;
+
+ if ((p = (char *)mmap(0, map_size, PROT_READ | PROT_WRITE,
+ MAP_FILE | MAP_SHARED, fd,
+ (off_t)(offset - pg_offset))) == (char *)-1) {
+ prterr("domapwrite: mmap");
+ report_failure(202);
+ }
+ memcpy(p + pg_offset, good_buf + offset, size);
+ if (msync(p, map_size, 0) != 0) {
+ prterr("domapwrite: msync");
+ report_failure(203);
+ }
+ if (munmap(p, map_size) != 0) {
+ prterr("domapwrite: munmap");
+ report_failure(204);
+ }
+}
+
+
+void
+dotruncate(unsigned size)
+{
+ int oldsize = file_size;
+
+ size -= size % truncbdy;
+ if (size > biggest) {
+ biggest = size;
+ if (!quiet && testcalls > simulatedopcount)
+ prt("truncating to largest ever: 0x%x\n", size);
+ }
+
+ log4(OP_TRUNCATE, size, (unsigned)file_size, 0);
+
+ if (size > file_size)
+ bzero(good_buf + file_size, size - file_size);
+ file_size = size;
+
+ if (testcalls <= simulatedopcount)
+ return;
+
+ if (progressinterval && testcalls % progressinterval == 0 ||
+ debug && (monitorstart == -1 || monitorend == -1 ||
+ size <= monitorend))
+ prt("%lu trunc\tfrom 0x%x to 0x%x\n", testcalls, oldsize, size);
+ if (ftruncate(fd, (off_t)size) == -1) {
+ prt("ftruncate1: %x\n", size);
+ prterr("dotruncate: ftruncate");
+ report_failure(160);
+ }
+}
+
+
+void
+writefileimage()
+{
+ ssize_t iret;
+
+ if (lseek(fd, (off_t)0, SEEK_SET) == (off_t)-1) {
+ prterr("writefileimage: lseek");
+ report_failure(171);
+ }
+ iret = write(fd, good_buf, file_size);
+ if ((off_t)iret != file_size) {
+ if (iret == -1)
+ prterr("writefileimage: write");
+ else
+ prt("short write: 0x%x bytes instead of 0x%qx\n",
+ iret, (unsigned long long)file_size);
+ report_failure(172);
+ }
+ if (lite ? 0 : ftruncate(fd, file_size) == -1) {
+ prt("ftruncate2: %qx\n", (unsigned long long)file_size);
+ prterr("writefileimage: ftruncate");
+ report_failure(173);
+ }
+}
+
+
+void
+docloseopen(void)
+{
+ if (testcalls <= simulatedopcount)
+ return;
+
+ if (debug)
+ prt("%lu close/open\n", testcalls);
+ if (close(fd)) {
+ prterr("docloseopen: close");
+ report_failure(180);
+ }
+ fd = open(fname, O_RDWR, 0);
+ if (fd < 0) {
+ prterr("docloseopen: open");
+ report_failure(181);
+ }
+}
+
+
+void
+test(void)
+{
+ unsigned long offset;
+ unsigned long size = maxoplen;
+ unsigned long rv = random();
+ unsigned long op = rv % (3 + !lite + mapped_writes);
+
+ /* turn off the map read if necessary */
+
+ if (op == 2 && !mapped_reads)
+ op = 0;
+
+ if (simulatedopcount > 0 && testcalls == simulatedopcount)
+ writefileimage();
+
+ testcalls++;
+
+ if (closeprob)
+ closeopen = (rv >> 3) < (1 << 28) / closeprob;
+
+ if (debugstart > 0 && testcalls >= debugstart)
+ debug = 1;
+
+ if (!quiet && testcalls < simulatedopcount && testcalls % 100000 == 0)
+ prt("%lu...\n", testcalls);
+
+ /*
+ * READ: op = 0
+ * WRITE: op = 1
+ * MAPREAD: op = 2
+ * TRUNCATE: op = 3
+ * MAPWRITE: op = 3 or 4
+ */
+ if (lite ? 0 : op == 3 && (style & 1) == 0) /* vanilla truncate? */
+ dotruncate(random() % maxfilelen);
+ else {
+ if (randomoplen)
+ size = random() % (maxoplen+1);
+ if (lite ? 0 : op == 3)
+ dotruncate(size);
+ else {
+ offset = random();
+ if (op == 1 || op == (lite ? 3 : 4)) {
+ offset %= maxfilelen;
+ if (offset + size > maxfilelen)
+ size = maxfilelen - offset;
+ if (op != 1)
+ domapwrite(offset, size);
+ else
+ dowrite(offset, size);
+ } else {
+ if (file_size)
+ offset %= file_size;
+ else
+ offset = 0;
+ if (offset + size > file_size)
+ size = file_size - offset;
+ if (op != 0)
+ domapread(offset, size);
+ else
+ doread(offset, size);
+ }
+ }
+ }
+ if (sizechecks && testcalls > simulatedopcount)
+ check_size();
+ if (closeopen)
+ docloseopen();
+}
+
+
+void
+cleanup(int sig)
+{
+ if (sig)
+ prt("signal %d\n", sig);
+ prt("testcalls = %lu\n", testcalls);
+ exit(sig);
+}
+
+
+void
+usage(void)
+{
+ fprintf(stdout, "usage: %s",
+ "fsx [-dnqLOW] [-b opnum] [-c Prob] [-l flen] [-m start:end] [-o oplen] [-p progressinterval] [-r readbdy] [-s style] [-t truncbdy] [-w writebdy] [-D startingop] [-N numops] [-P dirpath] [-S seed] fname\n\
+ -b opnum: beginning operation number (default 1)\n\
+ -c P: 1 in P chance of file close+open at each op (default infinity)\n\
+ -d: debug output for all operations\n\
+ -l flen: the upper bound on file size (default 262144)\n\
+ -m startop:endop: monitor (print debug output) specified byte range (default 0:infinity)\n\
+ -n: no verifications of file size\n\
+ -o oplen: the upper bound on operation size (default 65536)\n\
+ -p progressinterval: debug output at specified operation interval\n\
+ -q: quieter operation\n\
+ -r readbdy: 4096 would make reads page aligned (default 1)\n\
+ -s style: 1 gives smaller truncates (default 0)\n\
+ -t truncbdy: 4096 would make truncates page aligned (default 1)\n\
+ -w writebdy: 4096 would make writes page aligned (default 1)\n\
+ -D startingop: debug output starting at specified operation\n\
+ -L: fsxLite - no file creations & no file size changes\n\
+ -N numops: total # operations to do (default infinity)\n\
+ -O: use oplen (see -o flag) for every op (default random)\n\
+ -P: save .fsxlog and .fsxgood files in dirpath (default ./)\n\
+ -S seed: for random # generator (default 1) 0 gets timestamp\n\
+ -W: mapped write operations DISabled\n\
+ -R: read() system calls only (mapped reads disabled)\n\
+ fname: this filename is REQUIRED (no default)\n");
+ exit(90);
+}
+
+
+int
+getnum(char *s, char **e)
+{
+ int ret = -1;
+
+ *e = (char *) 0;
+ ret = strtol(s, e, 0);
+ if (*e)
+ switch (**e) {
+ case 'b':
+ case 'B':
+ ret *= 512;
+ *e = *e + 1;
+ break;
+ case 'k':
+ case 'K':
+ ret *= 1024;
+ *e = *e + 1;
+ break;
+ case 'm':
+ case 'M':
+ ret *= 1024*1024;
+ *e = *e + 1;
+ break;
+ case 'w':
+ case 'W':
+ ret *= 4;
+ *e = *e + 1;
+ break;
+ }
+ return (ret);
+}
+
+
+int
+main(int argc, char **argv)
+{
+ int i, style, ch;
+ char *endp;
+ char goodfile[1024];
+ char logfile[1024];
+
+ goodfile[0] = 0;
+ logfile[0] = 0;
+
+ setvbuf(stdout, (char *)0, _IOLBF, 0); /* line buffered stdout */
+
+ while ((ch = getopt(argc, argv, "b:c:dl:m:no:p:qr:s:t:w:D:LN:OP:RS:W"))
+ != EOF)
+ switch (ch) {
+ case 'b':
+ simulatedopcount = getnum(optarg, &endp);
+ if (!quiet)
+ fprintf(stdout, "Will begin at operation %ld\n",
+ simulatedopcount);
+ if (simulatedopcount == 0)
+ usage();
+ simulatedopcount -= 1;
+ break;
+ case 'c':
+ closeprob = getnum(optarg, &endp);
+ if (!quiet)
+ fprintf(stdout,
+ "Chance of close/open is 1 in %d\n",
+ closeprob);
+ if (closeprob <= 0)
+ usage();
+ break;
+ case 'd':
+ debug = 1;
+ break;
+ case 'l':
+ maxfilelen = getnum(optarg, &endp);
+ if (maxfilelen <= 0)
+ usage();
+ break;
+ case 'm':
+ monitorstart = getnum(optarg, &endp);
+ if (monitorstart < 0)
+ usage();
+ if (!endp || *endp++ != ':')
+ usage();
+ monitorend = getnum(endp, &endp);
+ if (monitorend < 0)
+ usage();
+ if (monitorend == 0)
+ monitorend = -1; /* aka infinity */
+ debug = 1;
+ case 'n':
+ sizechecks = 0;
+ break;
+ case 'o':
+ maxoplen = getnum(optarg, &endp);
+ if (maxoplen <= 0)
+ usage();
+ break;
+ case 'p':
+ progressinterval = getnum(optarg, &endp);
+ if (progressinterval < 0)
+ usage();
+ break;
+ case 'q':
+ quiet = 1;
+ break;
+ case 'r':
+ readbdy = getnum(optarg, &endp);
+ if (readbdy <= 0)
+ usage();
+ break;
+ case 's':
+ style = getnum(optarg, &endp);
+ if (style < 0 || style > 1)
+ usage();
+ break;
+ case 't':
+ truncbdy = getnum(optarg, &endp);
+ if (truncbdy <= 0)
+ usage();
+ break;
+ case 'w':
+ writebdy = getnum(optarg, &endp);
+ if (writebdy <= 0)
+ usage();
+ break;
+ case 'D':
+ debugstart = getnum(optarg, &endp);
+ if (debugstart < 1)
+ usage();
+ break;
+ case 'L':
+ lite = 1;
+ break;
+ case 'N':
+ numops = getnum(optarg, &endp);
+ if (numops < 0)
+ usage();
+ break;
+ case 'O':
+ randomoplen = 0;
+ break;
+ case 'P':
+ strncpy(goodfile, optarg, sizeof(goodfile));
+ strcat(goodfile, "/");
+ strncpy(logfile, optarg, sizeof(logfile));
+ strcat(logfile, "/");
+ break;
+ case 'R':
+ mapped_reads = 0;
+ break;
+ case 'S':
+ seed = getnum(optarg, &endp);
+ if (seed == 0)
+ seed = time(0) % 10000;
+ if (!quiet)
+ fprintf(stdout, "Seed set to %d\n", seed);
+ if (seed < 0)
+ usage();
+ break;
+ case 'W':
+ mapped_writes = 0;
+ if (!quiet)
+ fprintf(stdout, "mapped writes DISABLED\n");
+ break;
+
+ default:
+ usage();
+ /* NOTREACHED */
+ }
+ argc -= optind;
+ argv += optind;
+ if (argc != 1)
+ usage();
+ fname = argv[0];
+
+ signal(SIGHUP, cleanup);
+ signal(SIGINT, cleanup);
+ signal(SIGPIPE, cleanup);
+ signal(SIGALRM, cleanup);
+ signal(SIGTERM, cleanup);
+ signal(SIGXCPU, cleanup);
+ signal(SIGXFSZ, cleanup);
+ signal(SIGVTALRM, cleanup);
+ signal(SIGUSR1, cleanup);
+ signal(SIGUSR2, cleanup);
+
+ initstate(seed, state, 256);
+ setstate(state);
+ fd = open(fname, O_RDWR|(lite ? 0 : O_CREAT|O_TRUNC), 0666);
+ if (fd < 0) {
+ prterr(fname);
+ exit(91);
+ }
+ strncat(goodfile, fname, 256);
+ strcat (goodfile, ".fsxgood");
+ fsxgoodfd = open(goodfile, O_RDWR|O_CREAT|O_TRUNC, 0666);
+ if (fsxgoodfd < 0) {
+ prterr(goodfile);
+ exit(92);
+ }
+ strncat(logfile, fname, 256);
+ strcat (logfile, ".fsxlog");
+ fsxlogf = fopen(logfile, "w");
+ if (fsxlogf == NULL) {
+ prterr(logfile);
+ exit(93);
+ }
+ if (lite) {
+ off_t ret;
+ file_size = maxfilelen = lseek(fd, (off_t)0, L_XTND);
+ if (file_size == (off_t)-1) {
+ prterr(fname);
+ warn("main: lseek eof");
+ exit(94);
+ }
+ ret = lseek(fd, (off_t)0, SEEK_SET);
+ if (ret == (off_t)-1) {
+ prterr(fname);
+ warn("main: lseek 0");
+ exit(95);
+ }
+ }
+ original_buf = (char *) malloc(maxfilelen);
+ for (i = 0; i < maxfilelen; i++)
+ original_buf[i] = random() % 256;
+ good_buf = (char *) malloc(maxfilelen);
+ bzero(good_buf, maxfilelen);
+ temp_buf = (char *) malloc(maxoplen);
+ bzero(temp_buf, maxoplen);
+ if (lite) { /* zero entire existing file */
+ ssize_t written;
+
+ written = write(fd, good_buf, (size_t)maxfilelen);
+ if (written != maxfilelen) {
+ if (written == -1) {
+ prterr(fname);
+ warn("main: error on write");
+ } else
+ warn("main: short write, 0x%x bytes instead of 0x%x\n",
+ (unsigned)written, maxfilelen);
+ exit(98);
+ }
+ } else
+ check_trunc_hack();
+
+ while (numops == -1 || numops--)
+ test();
+
+ if (close(fd)) {
+ prterr("close");
+ report_failure(99);
+ }
+ prt("All operations completed A-OK!\n");
+
+ exit(0);
+ return 0;
+}
diff --git a/tests-nfs/tst-nfs.cc b/tests-nfs/tst-nfs.cc
new file mode 100644
index 0000000..a806710
--- /dev/null
+++ b/tests-nfs/tst-nfs.cc
@@ -0,0 +1,316 @@
+#include <cassert>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/mount.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <time.h>
+
+#include <iostream>
+#include <fstream>
+#include <string>
+
+#include <boost/program_options.hpp>
+
+#include <osv/run.hh>
+
+namespace po = boost::program_options;
+
+void assert_mount_error(int ret)
+{
+ assert(ret != EACCES);
+ assert(ret != EBUSY);
+ assert(ret != EFAULT);
+ assert(ret != EINVAL);
+ assert(ret != ELOOP);
+ assert(ret != EMFILE);
+ assert(ret != ENAMETOOLONG);
+ assert(ret != ENODEV);
+ assert(ret != ENOENT);
+ assert(ret != ENOMEM);
+ assert(ret != ENOTBLK);
+ assert(ret != ENOTDIR);
+ assert(ret != ENXIO);
+ assert(ret != EPERM);
+}
+
+static void test_bogus_url_mount(std::string server, std::string share)
+{
+ std::string mount_point("/bogus");
+ mkdir(mount_point.c_str(), 0777);
+ // Did you notice OSv didn't supported gluster ?
+ std::string url("gluster://" + server + share);
+ int ret = mount(url.c_str(), mount_point.c_str(), "nfs", 0, nullptr);
+ assert(ret && errno == EINVAL);
+}
+
+static void test_mount(std::string server, std::string share,
+ std::string mount_point)
+{
+ mkdir(mount_point.c_str(), 0777);
+ std::string url("nfs://" + server + share);
+ int ret = mount(url.c_str(), mount_point.c_str(), "nfs", 0, nullptr);
+ if (ret) {
+ int my_errno = errno;
+ std::cout << "Error: " << strerror(my_errno) << "(" << my_errno << ")"
+ << std::endl;
+ assert_mount_error(my_errno);
+ }
+ assert(!ret);
+}
+
+static void test_umount(std::string &mount_point)
+{
+ int ret = umount(mount_point.c_str());
+ assert(!ret);
+}
+
+static void test_mkdir(std::string mount_point, std::string dir)
+{
+ std::string path = mount_point + "/" + dir;
+ int ret = mkdir(path.c_str(), 0777);
+ assert(!ret);
+}
+
+static void test_rmdir(std::string mount_point, std::string dir,
+ int result, int err_no)
+{
+ std::string path = mount_point + "/" + dir;
+ int ret = rmdir(path.c_str());
+ assert(ret == result);
+ if (ret) {
+ assert(err_no = errno);
+ }
+}
+
+static void test_creat_and_close(std::string mount_point, std::string path)
+{
+ std::string full_path = mount_point + "/" + path;
+ int fd = creat(full_path.c_str(), 0500);
+ assert(fd != -1);
+ int ret = close(fd);
+ assert(!ret);
+}
+
+static void test_remove(std::string mount_point, std::string path)
+{
+ std::string full_path = mount_point + "/" + path;
+ int ret = unlink(full_path.c_str());
+ assert(!ret);
+}
+
+static void test_rename(std::string mount_point, std::string src,
+ std::string dst)
+{
+ std::string full_src = mount_point + "/" + src;
+ std::string full_dst = mount_point + "/" + dst;
+ int fd = creat(full_src.c_str(), 0500);
+ assert(fd != -1);
+
+ int ret = rename(full_src.c_str(), full_dst.c_str());
+ assert(!ret);
+
+ ret = close(fd);
+ assert(!ret);
+ ret = unlink(full_dst.c_str());
+ assert(!ret);
+}
+
+static void test_truncate(std::string mount_point, std::string path)
+{
+ std::string full_path = mount_point + "/" + path;
+ int fd = creat(full_path.c_str(), 0500);
+ struct stat st;
+
+ assert(fd != -1);
+
+ int ret = ftruncate(fd, 333);
+ assert(!ret);
+
+ ret = close(fd);
+ assert(!ret);
+
+ ret = stat(full_path.c_str(), &st);
+ assert(!ret);
+ assert(st.st_size == 333);
+
+ ret = unlink(full_path.c_str());
+ assert(!ret);
+}
+
+//
+// Cannot be tested with unfsd3 because it does not export symlink as they are.
+//
+//static void test_symlink_readlink(std::string mount_point, std::string path,
+// std::string alias)
+//{
+// std::string full_path = mount_point + "/" + path;
+// std::string full_alias = mount_point + "/" + alias;
+// int fd = creat(full_path.c_str(), 0500);
+// assert(fd != -1);
+// int ret = close(fd);
+// assert(!ret);
+//
+// ret = symlink(full_path.c_str(), full_alias.c_str());
+// assert(!ret);
+//
+// char buf[PATH_MAX];
+// ret = readlink(full_alias.c_str(), buf, sizeof(buf));
+// assert(ret != -1);
+// assert(full_alias == std::string(buf));
+//
+// ret = unlink(full_alias.c_str());
+// assert(!ret);
+//
+// ret = unlink(full_path.c_str());
+// assert(!ret);
+//}
+
+void test_write_read(std::string mount_point, std::string path)
+{
+ std::string full_path = mount_point + "/" + path;
+ const std::string msg("hadok, tournesol et milou");
+
+ std::ofstream f;
+ assert(f);
+ f.open (full_path, std::ofstream::out | std::ofstream::app);
+ f << msg;
+ f.flush();
+ f.close();
+
+ std::ifstream g(full_path);
+ assert(g);
+ std::string result((std::istreambuf_iterator<char>(g)),
+ std::istreambuf_iterator<char>());
+ g.close();
+
+ assert(result == msg);
+}
+
+void test_readdir(std::string mount_point, std::string path)
+{
+ std::set<std::string> set;
+ set.insert(".");
+ set.insert("..");
+ set.insert("alan");
+ set.insert("dupont");
+
+ std::string full_path = mount_point + "/" + path;
+ // create the directory and fill it
+ int ret = mkdir(full_path.c_str(), 0755);
+ assert(!ret);
+
+ std::string alan = full_path + "/" + "alan";
+ std::string dupont = full_path + "/" + "dupont";
+
+ int fd = creat(alan.c_str(), 0444);
+ assert(fd != -1);
+ ret = close(fd);
+ assert(!ret);
+
+ fd = creat(dupont.c_str(), 0444);
+ assert(fd != -1);
+ ret = close(fd);
+ assert(!ret);
+
+ // open the directory and list the name of the files in it
+ auto dir = opendir(full_path.c_str());
+ assert(dir);
+
+ while (auto dirent = readdir(dir)) {
+ assert(set.count(std::string(dirent->d_name)) == 1);
+ }
+
+ // close the directory
+ ret = closedir(dir);
+ assert(!ret);
+}
+
+void test_fsx(std::string mount_point, std::string path)
+{
+ std::string full_path = mount_point + "/" + path;
+ std::vector<std::string> args;
+
+ args.push_back("tests-nfs/fsx-linux.so");
+ args.push_back("-d");
+ args.push_back("-N");
+ args.push_back("100");
+ args.push_back(full_path);
+
+ int ret = 0;
+ auto app = osv::run("/tests-nfs/fsx-linux.so", args, &ret, true);
+ assert(!ret);
+}
+
+int main(int argc, char **argv)
+{
+ po::options_description desc("Allowed options");
+ desc.add_options()
+ ("help", "produce help message")
+ ("server", po::value<std::string>(), "set server ip")
+ ("share", po::value<std::string>(), "set remote share")
+ ;
+
+ po::variables_map vm;
+ po::store(po::parse_command_line(argc, argv, desc), vm);
+ po::notify(vm);
+
+ if (vm.count("help")) {
+ std::cout << desc << std::endl;
+ return 1;
+ }
+
+ std::string server;
+ if (vm.count("server")) {
+ server = vm["server"].as<std::string>();
+ } else {
+ std::cout << desc << std::endl;
+ return 1;
+ }
+
+ std::string share;
+ if (vm.count("share")) {
+ share = vm["share"].as<std::string>();
+ } else {
+ std::cout << desc << std::endl;
+ return 1;
+ }
+
+ test_bogus_url_mount(server, share);
+
+ std::string mount_point("/nfs");
+
+ // Testing mount/umount
+ test_mount(server, share, mount_point);
+ test_umount(mount_point);
+
+ // Testing mkdir and rmdir
+ test_mount(server, share, mount_point);
+ // Test to rmdir something not existing
+ test_rmdir(mount_point, "bar", -1, ENOENT);
+ // mkdir followed by rmdir
+ test_mkdir(mount_point, "foo");
+ test_rmdir(mount_point, "foo", 0, 0);
+
+ // Testing creat and close
+ test_creat_and_close(mount_point, "zorglub");
+
+ // Testing remove
+ test_remove(mount_point, "zorglub");
+
+ test_rename(mount_point, "fantasio", "spirou");
+
+ test_truncate(mount_point, "secotine");
+
+ // Cannot be tested with unsfd3
+ //test_symlink_readlink(mount_point, "champignac", "zorglonde");
+
+ test_write_read(mount_point, "tintin");
+
+ test_readdir(mount_point, "castafiore");
+
+ test_fsx(mount_point, "sanzo");
+
+ test_umount(mount_point);
+ return 0;
+}
--
2.6.2

Dor Laor

unread,
Nov 26, 2015, 3:38:44 PM11/26/15
to Benoît Canet, Osv Dev, Benoît Canet
On Thu, Nov 26, 2015 at 10:23 PM, Benoît Canet <benoit.can...@gmail.com> wrote:
It was just plain wrong probably because nobody
ever used it.

Is this the only OSv side change that was needed to get the external NFS to work? (impressive compatiblity)
 
--
2.6.2

--
You received this message because you are subscribed to the Google Groups "OSv Development" group.
To unsubscribe from this group and stop receiving emails from it, send an email to osv-dev+u...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Nadav Har'El

unread,
Nov 26, 2015, 4:07:57 PM11/26/15
to Benoît Canet, Osv Dev, Benoît Canet
Reviewed-by: Nadav Har'El <n...@scylladb.com>


--
Nadav Har'El
n...@scylladb.com

On Thu, Nov 26, 2015 at 10:23 PM, Benoît Canet <benoit.can...@gmail.com> wrote:
--
2.6.2

Nadav Har'El

unread,
Nov 26, 2015, 4:43:51 PM11/26/15
to Benoît Canet, Avi Kivity, Osv Dev, Benoît Canet
Thanks, impressive that you got NFS working so quickly!

Some comments inline below.

On Thu, Nov 26, 2015 at 10:23 PM, Benoît Canet <benoit.can...@gmail.com> wrote:
libnfs is an LGPL licensed nfs client implementation
that will be handy to implement the OSv nfs client
required by HLRS.

Most HPC use cases require an NFS mount to
regularly save data.

HLRS and HPC will of course not be the only possible use cases of an NFS client, but I guess it is ok for you to mention the first user in the commit message ;-)
 

To build it do:

make NFS=true

Signed-off-by: Benoît Canet <ben...@scylladb.com>
---
 .gitmodules        |  3 +++
 Makefile           | 29 ++++++++++++++++++++++++++---
 external/fs/libnfs |  1 +
 3 files changed, 30 insertions(+), 3 deletions(-)
 create mode 160000 external/fs/libnfs

diff --git a/.gitmodules b/.gitmodules
index ea8f06f..c0cfc52 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -48,3 +48,6 @@
 [submodule "modules/httpserver/osv-gui"]
        path = modules/httpserver/osv-gui
        url = ../../cloudius-systems/osv-gui.git
+[submodule "external/fs/libnfs"]
+       path = external/fs/libnfs
+       url = https://github.com/sahlberg/libnfs.git

Avi, would you like the submodule to point to this upstream git as Benoit did here, or should we maintain our own fork of this repository (and get some control on when we update it)?
 

diff --git a/Makefile b/Makefile
index b6ce8f7..5488aee 100644
--- a/Makefile
+++ b/Makefile
@@ -144,10 +144,25 @@ check:
        ./scripts/build check
 .PHONY: check

+libnfs-path = $(shell pwd)/external/fs/libnfs/

I don't think there is a real need for "$(shell pwd)" here, I think a simple
    libnfs-path = external/fs/libnfs

should work just as well (and save us a call to the shell).
(see also my suggestions below).

+
+$(out)/libnfs.a:

So you're compiling libnfs.a, not libnfs.so?
Can you say a few words about this choice?
 
+       cd $(libnfs-path) && \
+       $(call quiet, $(libnfs-path)/bootstrap) && \

There's something I don't understand here - does $(call quiet) actuall work on partial command lines like you use it here?
I am guessing it doesn't, and you need to wrap the entire shell command which spans several lines separated by backslashes with it - not every partial line.

An unrelated request:
I think you should use ./bootstrap here (and similarly in the lines below) instead of repeating this $(libnfs-path) on every line.
But don't remove that "./", because many people don't have the current directory in their PATH.
This change I'm suggesting here will allow $(libnfs-path) to not be an absolute path.
 
+       $(call quiet, $(libnfs-path)/configure --enable-shared=no --enable-static=yes --enable-silent-rules) && \
+       $(call quiet, make -f $(libnfs-path)/Makefile)

Here you don't even need ./, or even "-f": a simple

   $(call quiet, make)

should do the same (it uses "./Makefile" by default...).
 
+       $(call quiet, cp -a $(libnfs-path)/lib/.libs/libnfs.a $(out)/libnfs.a)
+
+clean-libnfs:
+       if [ -f $(out)/libnfs.a ] ; then \
+       cd $(libnfs-path) && \
+       make distclean; \
+       fi

I would really love it if we didn't have to do this, and instead, we put all the build output of libnfs
in $(out) so the regular "make clean" that deletes the build directory would do the right thing....

Would it be difficult to run libnfs's "configure" or "make" in a way that causes the compilation
directory to be in the $(out) directory? Alternatively, does it make sense to avoid their makefile
altogether and compile their source code with out own Makefile (this is what we did for the
acpi library, for example)?
 
+
 # Remember that "make clean" needs the same parameters that set $(out) in
 # the first place, so to clean the output of "make mode=debug" you need to
 # do "make mode=debug clean".
-clean:
+clean: clean-libnfs
        rm -rf $(out)
        rm -f $(outlink) $(outlink2)
 .PHONY: clean
@@ -481,7 +496,6 @@ endif # aarch64
 $(out)/bsd/sys/crypto/sha2/sha2.o: CFLAGS+=-Wno-strict-aliasing
 $(out)/bsd/sys/crypto/rijndael/rijndael-api-fst.o: CFLAGS+=-Wno-strict-aliasing

-
 bsd  = bsd/init.o
 bsd += bsd/net.o
 bsd += bsd/$(arch)/machine/in_cksum.o
@@ -1319,6 +1333,7 @@ libc += network/h_errno.o
 musl += network/getservbyname_r.o
 musl += network/getservbyname.o
 musl += network/getservbyport_r.o
+musl += network/getservbyport.o

Can you please move this change to a separate patch?
 
 musl += network/getifaddrs.o
 musl += network/if_nameindex.o
 musl += network/if_freenameindex.o
@@ -1756,6 +1771,13 @@ endif
 boost-libs := $(boost-lib-dir)/libboost_program_options$(boost-mt).a \
               $(boost-lib-dir)/libboost_system$(boost-mt).a

+nfs-lib =
+ifeq ($(NFS), true)
+       nfs-lib += $(out)/libnfs.a
+endif

Is there a reason why you wanted this +=? Looks to me like the following is simpler (and one line shorter)

ifeq ($(NFS), true)
nfs-lib = $(out)/libnfs.a
endif

We'll need to document this "NFS" flag somewhere in the Makefile - it is the first time we added a compile-time optional feature to OSv.

+
+nfs-library: $(nfs-lib)

This is a ".PHONY" rule.
I'm not even sure why you need this rule at all, because I see below you use $(nfs-lib), not "nfs-library".
 
+
 # ld has a known bug (https://sourceware.org/bugzilla/show_bug.cgi?id=6468)
 # where if the executable doesn't use shared libraries, its .dynamic section
 # is dropped, even when we use the "--export-dynamic" (which is silently
@@ -1763,13 +1785,14 @@ boost-libs := $(boost-lib-dir)/libboost_program_options$(boost-mt).a \
 $(out)/dummy-shlib.so: $(out)/dummy-shlib.o
        $(call quiet, $(CXX) -nodefaultlibs -shared $(gcc-sysroot) -o $@ $^, LINK $@)

-$(out)/loader.elf: $(out)/arch/$(arch)/boot.o arch/$(arch)/loader.ld $(out)/loader.o $(out)/runtime.o $(drivers:%=$(out)/%) $(objects:%=$(out)/%) $(out)/bootfs.bin $(out)/dummy-shlib.so
+$(out)/loader.elf: $(out)/arch/$(arch)/boot.o arch/$(arch)/loader.ld $(out)/loader.o $(out)/runtime.o $(drivers:%=$(out)/%) $(objects:%=$(out)/%) $(out)/bootfs.bin $(out)/dummy-shlib.so $(nfs-lib)
        $(call quiet, $(LD) -o $@ --defsym=OSV_KERNEL_BASE=$(kernel_base) \
                -Bdynamic --export-dynamic --eh-frame-hdr --enable-new-dtags \
            $(filter-out %.bin, $(^:%.ld=-T %.ld)) \
            --whole-archive \
              $(libstdc++.a) $(libgcc.a) $(libgcc_eh.a) \
              $(boost-libs) \
+             $(nfs-lib) \

I think you should move nfs-lib out of the "whole-archive" section - if we don't use parts of the NFS library in OSv, why would we want these parts in the kernel? Is it possible that a user-space application might want to use them?
 
            --no-whole-archive, \
                LINK loader.elf)
        @# Build libosv.so matching this loader.elf. This is not a separate
diff --git a/external/fs/libnfs b/external/fs/libnfs
new file mode 160000
index 0000000..dc8d866
--- /dev/null
+++ b/external/fs/libnfs
@@ -0,0 +1 @@
+Subproject commit dc8d86628d2f67cb4b7a9e5e5d7a1259f065b3c7
--
2.6.2

Nadav Har'El

unread,
Nov 26, 2015, 4:53:07 PM11/26/15
to Benoît Canet, Osv Dev, Benoît Canet
I don't understand this patch...
Why do we need an NFS *server* in our repository?
And if it is in external/, why is in the main osv.git and not in a submodule - like you did for the NFS library?

I am guessing that you only need this NFS server for running it on the host for *testing* the NFS client in OSv.

If so, why not make the NFS test optional (not part of the "make check" suite) and running it will require the user to install this unfs - or any other NFS server - himself? Do you know if nfs-ganesha (which can be easily installed on Fedora, for example) could equally serve for testing purposes?
The NFS test will anyway need to be optional, because not every build will even include the NFS client.



--
Nadav Har'El
n...@scylladb.com

On Thu, Nov 26, 2015 at 10:23 PM, Benoît Canet <benoit.can...@gmail.com> wrote:
--
2.6.2

Benoît Canet

unread,
Nov 26, 2015, 5:58:54 PM11/26/15
to Dor Laor, Benoît Canet, Osv Dev, Benoît Canet

There is also a mmu hack that Nadav helped me to come with.

Benoît Canet

unread,
Nov 26, 2015, 6:03:18 PM11/26/15
to Nadav Har'El, Benoît Canet, Avi Kivity, Osv Dev, Benoît Canet
Thanks for this comment an the followings as I already said make is not my strong point.
 
should work just as well (and save us a call to the shell).
(see also my suggestions below).

+
+$(out)/libnfs.a:

So you're compiling libnfs.a, not libnfs.so?
Can you say a few words about this choice?

There is a static array with the filesystems list somewhere in the VFS code.
So this bring in the nfs fs code and also libnfs.a.

I wonder how zfs does it since a .so.

I will look at that tomorow.
Yes right now it's a code dump I will splits the various patches accordingly.

Benoît Canet

unread,
Nov 26, 2015, 6:09:36 PM11/26/15
to Nadav Har'El, Benoît Canet, Osv Dev, Benoît Canet

On Debian/systemd the NFS servers packages are just broken they will not start.
So I embedded an NFS server since I run Debian.

On Thu, Nov 26, 2015 at 10:53 PM, Nadav Har'El <n...@scylladb.com> wrote:
I don't understand this patch...
Why do we need an NFS *server* in our repository?
And if it is in external/, why is in the main osv.git and not in a submodule - like you did for the NFS library?


Ok I will create a git repos with this code.
 
I am guessing that you only need this NFS server for running it on the host for *testing* the NFS client in OSv.

If so, why not make the NFS test optional (not part of the "make check" suite) and running it will require the user to install this unfs - or any other NFS server - himself? Do you know if nfs-ganesha (which can be easily installed on Fedora, for example) could equally serve for testing purposes?

I initialy tried to use ganesha but the current upstream version required that his own pet .so file be in /usr/something
neither LD_LIBRARY_PATH nor the special ganesha directive done to tell the thing where his so where working.

So I rage deleted the ganesha submodule and used unfsd since I wanted to start writting the tests and the actual code and not
wasting time on this.


 
The NFS test will anyway need to be optional, because not every build will even include the NFS client.



ok

Nadav Har'El

unread,
Nov 26, 2015, 6:32:27 PM11/26/15
to Benoît Canet, Osv Dev, Benoît Canet
This is a really big patch, would have been nice to split it. One obvious way is to move the tests to a separate patch.

I'll try to review it anyway, hoping gmail doesn't fail on me mid-way :-)


--
Nadav Har'El
n...@scylladb.com

On Thu, Nov 26, 2015 at 10:23 PM, Benoît Canet <benoit.can...@gmail.com> wrote:
---
 .gitignore                |    2 +
 Makefile                  |   23 +-
 core/mmu.cc               |   27 +-
 external/fs/nfs-ganesha   |    1 +

What is this doing in this patch?

I'm still not sure why we need those files, but if we do, this change probably needs to go to that patch - not to this patch.

diff --git a/Makefile b/Makefile
index 5488aee..a531792 100644
--- a/Makefile
+++ b/Makefile
@@ -146,11 +146,18 @@ check:

 libnfs-path = $(shell pwd)/external/fs/libnfs/

-$(out)/libnfs.a:
+$(out)/unfsd:
+       $(call quiet, cd external/fs/unfs3-0.9.22/) && \
+       $(call quiet, ./configure) && \
+       $(call quiet, make) && \
+       $(call quiet, cd ../../../)
+
+$(out)/libnfs.a: $(out)/unfsd

Why does compiling libnfs.a require unfsd? I don't see any place in this rule where you really need unfsd to be compiled before libnfs.a.
 
        cd $(libnfs-path) && \
-       $(call quiet, $(libnfs-path)/bootstrap) && \
-       $(call quiet, $(libnfs-path)/configure --enable-shared=no --enable-static=yes --enable-silent-rules) && \
-       $(call quiet, make -f $(libnfs-path)/Makefile)
+       $(call quiet, ./bootstrap) && \
+       $(call quiet, ./configure --enable-shared=no --enable-static=yes --enable-silent-rules) && \
+       $(call quiet, make) && \

Interesting, it seems you already did the changes I suggested in my review of your previous patch, in this patch.
Please conflate these parts of the two patches, so the correct version will appear in the first patch.
 
+       $(call quiet, cd ../../../) && \

Please don't do that... Why "../../.." - who said that $(libnfs-path) has exactly 3 directories? A much simpler workaround is just to drop the "&& \" so the next line is a separate command, starting again in the right directory.
 
        $(call quiet, cp -a $(libnfs-path)/lib/.libs/libnfs.a $(out)/libnfs.a)

 clean-libnfs:
@@ -1774,8 +1781,13 @@ boost-libs := $(boost-lib-dir)/libboost_program_options$(boost-mt).a \
 nfs-lib =
 ifeq ($(NFS), true)
        nfs-lib += $(out)/libnfs.a
+       nfs = nfs.o nfs_vfsops.o nfs_vnops.o
+else
+       nfs = nfs_null_vfsops.o

I've yet to see this "nfs_null_vfsops.o" but I wonder why we need any file at all in order not to support NFS?
 
 endif

+nfs-objects += $(addprefix fs/nfs/, $(nfs))

If instead of this "nfs-objects", you would have modified "objects" directly, e.g.,

objects += $(addprefix fs/nfs/, $(nfs))

you wouldn't need to make more modifications you needed to do below (to use $(nfs-objects) every time $(objects) was used).

You could keep both nfs-objects *and* also append to objects if you needed the nfs-objects list as well (e.g., to use different compilation parameters for them), but I don't think you really need that.

+
 nfs-library: $(nfs-lib)

 # ld has a known bug (https://sourceware.org/bugzilla/show_bug.cgi?id=6468)
@@ -1785,14 +1797,13 @@ nfs-library: $(nfs-lib)
 $(out)/dummy-shlib.so: $(out)/dummy-shlib.o
        $(call quiet, $(CXX) -nodefaultlibs -shared $(gcc-sysroot) -o $@ $^, LINK $@)

-$(out)/loader.elf: $(out)/arch/$(arch)/boot.o arch/$(arch)/loader.ld $(out)/loader.o $(out)/runtime.o $(drivers:%=$(out)/%) $(objects:%=$(out)/%) $(out)/bootfs.bin $(out)/dummy-shlib.so $(nfs-lib)
+$(out)/loader.elf: $(out)/arch/$(arch)/boot.o arch/$(arch)/loader.ld $(out)/loader.o $(out)/runtime.o $(drivers:%=$(out)/%) $(objects:%=$(out)/%) $(nfs-objects:%=$(out)/%) $(out)/bootfs.bin $(out)/dummy-shlib.so $(nfs-lib)
        $(call quiet, $(LD) -o $@ --defsym=OSV_KERNEL_BASE=$(kernel_base) \
                -Bdynamic --export-dynamic --eh-frame-hdr --enable-new-dtags \
            $(filter-out %.bin, $(^:%.ld=-T %.ld)) \
            --whole-archive \
              $(libstdc++.a) $(libgcc.a) $(libgcc_eh.a) \
              $(boost-libs) \
-             $(nfs-lib) \


Again, this was added in the previous patch, so instead of adding it and then removing it, please do the right thing in the first patch.
There's something I don't understand, though - if you didn't add nfs-lib, how does it work? I guess you added it somewhere else I didn't find yet....
 
            --no-whole-archive, \
                LINK loader.elf)
        @# Build libosv.so matching this loader.elf. This is not a separate
diff --git a/core/mmu.cc b/core/mmu.cc
index 7135b6f..b366603 100644
--- a/core/mmu.cc
+++ b/core/mmu.cc
@@ -1660,13 +1660,38 @@ void file_vma::split(uintptr_t edge)
     vma_list.insert(*n);
 }

+#include <iostream>

I guess you needed this for debugging? You probably don't need it in the final version.
 
 error file_vma::sync(uintptr_t start, uintptr_t end)
 {
     if (!has_flags(mmap_shared))
         return make_error(ENOMEM);

     try {
-        _file->sync(_offset + start - _range.start(), _offset + end - _range.start());


As we discussed earlier, it is true that this code was missing the memory's write into the disk.
However, this code could use a comment... When is this code path reached? It is *not* reached in ZFS, right? Because there the cache layer takes care of writing back the dirty pages to disk, not this code? So before NFS, this code was basicallly unused? It would be nice to explain the scenarios where this code gets used.
 
+        off_t my_start = _offset + start - _range.start();
+        off_t my_end = _offset + end - _range.start();
+        size_t my_size = end - start;
+        ssize_t my_ssize = end - start;

Do we really need both? It looks pretty strange.
 
+
+        off_t file_size = _file->f_dentry->d_vnode->v_size;
+
+        if (my_start > file_size) {
+            my_start = file_size;
+        }
+
+        if (my_end > file_size) {
+            my_end = file_size;
+        }
+
+        off_t expected_size = my_start + my_ssize;

This is, by definition, my_end's original value (before it was cut above)?
If this is true, then the if (my_end > file_size) above, and the if (expected_size > file_size) is the same case.
But maybe I'm missing something. I found it hard to follow this code, so maybe I got confused.
 
+        if (expected_size > file_size) {
+            off_t delta = expected_size - file_size;
+            my_size -= delta;
+            my_ssize -= delta;
+        }
+        iovec iovec {(void *)(_range.start()), my_size};

This code *always* re-writes the entire mmap'ed range to disk - even if only a small part - or nothing - of it has been actually written.

I would accept such code if it had a "FIXME" comment, and if I was sure it was only used in the NFS case (and not in the other cases we supported in the past). But a more efficient solution (which should be mentioned in the FIXME comment) would need to look at the page table for "dirty" pages (with the dirty bit enabled) and only write back those pages.

 
+        uio data {&iovec, 1, my_start, my_ssize, UIO_WRITE};
+        _file->write(&data, FOF_OFFSET);
+        _file->sync(my_start, my_end);
 
     } catch (error& err) {
         return err;
     }
diff --git a/external/fs/nfs-ganesha b/external/fs/nfs-ganesha
new file mode 160000
index 0000000..6dd95ab
--- /dev/null
+++ b/external/fs/nfs-ganesha
@@ -0,0 +1 @@
+Subproject commit 6dd95abf3ef4cf8ffda11967cd085068ccfbfdc6

Now I'm confused. So you wanted to add both unfs3 and nfs-ganesha? Why add nfs-ganesha at all, and if you do, why in this patch?
 
diff --git a/fs/nfs/nfs.cc b/fs/nfs/nfs.cc
new file mode 100644
index 0000000..0bd818a
--- /dev/null
+++ b/fs/nfs/nfs.cc
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2015 Scylla, Ltd.
+ *
+ * Based on ramfs code Copyright (c) 2006-2007, Kohsuke Ohtani
+ *
+ * This work is open source software, licensed under the terms of the
+ * BSD license as described in the LICENSE file in the top-level directory.
+ */
+
+#include <osv/debug.hh>
+
+#include <osv/mount.h>
+
+#include "nfs.hh"
+
+#include <iostream>
+
+#include <osv/mutex.h>

Too many empty lines ;-)

Do you really need all the header files above? iostream? Please verify you still need them, and not only needed them for debugging.
For mutex, you can use __thread instead of thread_local, because mutexes have a constexpr constructor and no destructor.
__thread is slightly more efficient than thread_local.
 
+thread_local std::unordered_map<std::string,
+                                std::unique_ptr<mount_context>> _map;

I'm a bit confused about the key of this map. It's the mount-point? What if a directory gets unmounted and then mounted again using a different server?

Perhaps we need to find a way when unmounting an NFS mountpoint to get rid of this context from all the existing threads?

I see you mentioned this case ("mess") below, but I didn't understand the solution with the invalid flag.
 
+
+struct mount_context *get_mount_context(struct mount *mp, int &err_no)
+{
+    auto m_path = static_cast<const char*>(mp->m_path);
+    std::string mount_point(m_path);
+    err_no = 0;
+
+    SCOPE_LOCK(_lock);
+
+    // if not mounted at all mount it
+    if (!_map.count(mount_point)) {
+        _map[mount_point] =
+            std::unique_ptr<mount_context>(new mount_context(mp->m_special));
+    }
+
+    // if we remounted with a different url change the mount point
+    if (!_map[mount_point]->same_url(mp->m_special)) {
+        _map.erase(mount_point);
+        _map[mount_point] =
+            std::unique_ptr<mount_context>(new mount_context(mp->m_special));
+    }
+
+    // clear the mess if the mount point is invalid
+    if (!_map[mount_point]->is_valid(err_no)) {

What does err_no do?  It's not returned, it always is initialized to 0... What am I missing?

Wouldn't a simple "external/fs/libnfs/include/nfsc/libnfs.h" work? (I think the top directory is in our include path?)
 
+
+#ifdef    __cplusplus

Do we include this nfs.hh when not in C++?
 
+
+#include <memory>
+#include <string>
+
+#include <atomic>
+#include <memory>

This is the second time you have <memory> here.
 
Simpler to write in just:

std::unique_ptr<mount_context> ctx(new mount_context(mp->m_special));
 
+
+    if (!ctx->is_valid(err_no)) {
+        return err_no;
+    }
+
+    return 0;
+}
+
+/*
+ * Unmount a file system.
+ *
+ * Note: There is no nfs_unmount in nfslib.
+ *
+ */
+static int nfs_op_unmount(struct mount *mp, int flags)
+{
+    assert(mp);
+
+    return 0;

I'm not familiar enough with the relevant code paths to tell what ensures that you cannot unmount before mmap()ed files are unmapped, open files are closed, and so on. I hope this gets called only after ensuring those things.
Why this special case?
 
+    }
+
+    int type = vp->v_type;
+
+    // It's a directory or a file.
+    if (type == VDIR) {
+        struct nfsdir *handle = nullptr;
+        ret = nfs_opendir(nfs, path.c_str(), &handle);
+        vp->v_data = handle;
+    } else if (type == VREG) {
+        struct nfsfh *handle = nullptr;
+        ret = nfs_open(nfs, path.c_str(), flags, &handle);
+        vp->v_data = handle;
+    } else {
+        return EIO;

Can't we have things like named pipes, device files, etc., on NFS? But nevermind, let's ignore that for now. It's probably a security faux-pas to allow it anyway.

Does libnfs not have a scatter-gather read capability (reading into a list of buffers instead of one contiguous buffer)?
 
+    auto buf = std::unique_ptr<char>(new char[len + 1]());
+
+    int ret = nfs_pread(nfs, handle, uio->uio_offset, len, buf.get());
+    if (ret < 0) {
+        return -ret;
+    }
+
+    // Handle short read.

Why is this for "short" read? Isn't just to copy the tempory buffer into uio?

 
happening -> appending.

What did you mean by NFS not supporting append?

 
+        ret = nfs_ftruncate(nfs, handle, new_size);
+    } else if ((uio->uio_offset + uio->uio_resid) > vp->v_size) {
+        new_size = uio->uio_offset + uio->uio_resid;
+        ret = nfs_ftruncate(nfs, handle, new_size);
+    }
+
+    if (ret) {
+        return -ret;
+    }
+
+    // make a copy of these since uimove will touch them.
+    size_t size = uio->uio_resid;
+    size_t offset = uio->uio_offset;
+
+    // END_PASTE
+
+    auto buf = std::unique_ptr<char>(new char[size]());

Is there a nfs_pwritev(), to avoid the need for this additional copy?
 
I don't remember these fields, does it make sense not to set them?
 
I think "return t" would do exactly the same (this optimization is always done when returning a local variable).
 
If I remember correctly, you have attr->mask which tells you
what you're supposed to change. You're not supposed to change all of these things unconditionally.
 
Why is this necessary? Just for setting the final null?
 
When reading this code, I found it confusing sometimes what functions (called nfs_*) are part of libnfs, and what other functions (also called nfs_*) part of your code.
 
Can you please check what is the difference between the existing misc-fsx.cc and your fsx-linux.cc? Are the differences deliberate?

This patch is becoming too long for me for one continuous review. I'll review the tests part when you split the patch. Sorry about that.
 
--
2.6.2

Commit Bot

unread,
Nov 27, 2015, 3:38:53 AM11/27/15
to osv...@googlegroups.com, Beno?t Canet
From: Benoît Canet <benoit.can...@gmail.com>
Committer: Pekka Enberg <pen...@scylladb.com>

vfs: Fix vfsop_umount_t prototype declaration

It was just plain wrong probably because nobody
ever used it.

Signed-off-by: Benoît Canet <ben...@scylladb.com>
Reviewed-by: Nadav Har'El <n...@scylladb.com>
Signed-off-by: Pekka Enberg <pen...@scylladb.com>

---
diff --git a/include/osv/mount.h b/include/osv/mount.h

Benoît Canet

unread,
Nov 27, 2015, 7:13:38 AM11/27/15
to Nadav Har'El, Benoît Canet, Osv Dev, Benoît Canet

Thanks for the review.

This version was something like a code dump done to show progress was made.
I will clean it up and split it up for the next revision.

Best regards

Benoît

hw.cl...@gmail.com

unread,
Nov 30, 2015, 7:22:33 AM11/30/15
to OSv Development, n...@scylladb.com, benoit.can...@gmail.com, ben...@scylladb.com
On Friday, 27 November 2015 13:13:38 UTC+1, Benoît Canet wrote:
> Thanks for the review.
>
>
> This version was something like a code dump done to show progress was made.
> I will clean it up and split it up for the next revision.
>
>
> Best regards
>
>
> Benoît

Does this benefit ARM64 as well, or is there something X86-specific in this?

Thanks

Claudio

Benoît Canet

unread,
Dec 14, 2015, 2:01:14 PM12/14/15
to OSv Development, benoit.can...@gmail.com, a...@cloudius-systems.com, ben...@scylladb.com
Somewhere in the VFS layer there is an array of structure pointing to each filesystem.

So it's not possible to build libnfs as a .so since the nfs driver will be right in the middle
of the kernel .so.

The path I choose is to provide an empty stub filesystem driver when libnfs is not compiled in.
 
 
+       cd $(libnfs-path) && \
+       $(call quiet, $(libnfs-path)/bootstrap) && \

There's something I don't understand here - does $(call quiet) actuall work on partial command lines like you use it here?
I am guessing it doesn't, and you need to wrap the entire shell command which spans several lines separated by backslashes with it - not every partial line.

An unrelated request:
I think you should use ./bootstrap here (and similarly in the lines below) instead of repeating this $(libnfs-path) on every line.
But don't remove that "./", because many people don't have the current directory in their PATH.
This change I'm suggesting here will allow $(libnfs-path) to not be an absolute path.
 
+       $(call quiet, $(libnfs-path)/configure --enable-shared=no --enable-static=yes --enable-silent-rules) && \
+       $(call quiet, make -f $(libnfs-path)/Makefile)

Here you don't even need ./, or even "-f": a simple

   $(call quiet, make)

should do the same (it uses "./Makefile" by default...).
 
+       $(call quiet, cp -a $(libnfs-path)/lib/.libs/libnfs.a $(out)/libnfs.a)
+
+clean-libnfs:
+       if [ -f $(out)/libnfs.a ] ; then \
+       cd $(libnfs-path) && \
+       make distclean; \
+       fi

I would really love it if we didn't have to do this, and instead, we put all the build output of libnfs
in $(out) so the regular "make clean" that deletes the build directory would do the right thing

Alas not libnfs nor unfsd are able to build out of tree. 
....

Would it be difficult to run libnfs's "configure" or "make" in a way that causes the compilation
directory to be in the $(out) directory? Alternatively, does it make sense to avoid their makefile
altogether and compile their source code with out own Makefile (this is what we did for the
acpi library, for example)?

Maybe it worth the work to create an extra makefile yes.

But this work will need to be done twice one for libnfs and one for unfsd. 
I don't think it make sence to move libnfs out of the kernel archive because there is an indirect reference to
it in a static array in the VFS layer code.

Benoît Canet

unread,
Dec 14, 2015, 3:19:27 PM12/14/15
to OSv Development, benoit.can...@gmail.com, ben...@scylladb.com
The only other alternative would be a #ifdef right in the middle of the VFS code where the filesystems are
declared.

Since I don't like the preprocessor that much I choose to use a stub to disable the feature.
The invalid flag is here due to my great distaste of exceptions especially in constructor.
So if the class build itself correctly is_valid(errno) will return true else it will return false
and fill in the errno by reference.
Is passed by reference in Qt style.
Alas it does not have one.
 
 
+    auto buf = std::unique_ptr<char>(new char[len + 1]());
+
+    int ret = nfs_pread(nfs, handle, uio->uio_offset, len, buf.get());
+    if (ret < 0) {
+        return -ret;
+    }
+
+    // Handle short read.

Why is this for "short" read? Isn't just to copy the tempory buffer into uio?

This comment is garbage you are right.
Seen here: (grep NFS)
 


 

 
+        ret = nfs_ftruncate(nfs, handle, new_size);
+    } else if ((uio->uio_offset + uio->uio_resid) > vp->v_size) {
+        new_size = uio->uio_offset + uio->uio_resid;
+        ret = nfs_ftruncate(nfs, handle, new_size);
+    }
+
+    if (ret) {
+        return -ret;
+    }
+
+    // make a copy of these since uimove will touch them.
+    size_t size = uio->uio_resid;
+    size_t offset = uio->uio_offset;
+
+    // END_PASTE
+
+    auto buf = std::unique_ptr<char>(new char[size]());

Is there a nfs_pwritev(), to avoid the need for this additional copy?*

Nope.
 
...

Benoît Canet

unread,
Dec 14, 2015, 3:23:46 PM12/14/15
to hw.cl...@gmail.com, OSv Development, Nadav Har'El, Benoît Canet, Benoît Canet
Hi Claudio,

I think it could run in ARM64.

Best regards

Benoît 

Thanks

Claudio

Nadav Har'El

unread,
Dec 14, 2015, 4:48:49 PM12/14/15
to Benoît Canet, OSv Development, Benoît Canet
On Mon, Dec 14, 2015 at 10:19 PM, Benoît Canet <ben...@scylladb.com> wrote:
        $(call quiet, cp -a $(libnfs-path)/lib/.libs/libnfs.a $(out)/libnfs.a)

 clean-libnfs:
@@ -1774,8 +1781,13 @@ boost-libs := $(boost-lib-dir)/libboost_program_options$(boost-mt).a \
 nfs-lib =
 ifeq ($(NFS), true)
        nfs-lib += $(out)/libnfs.a
+       nfs = nfs.o nfs_vfsops.o nfs_vnops.o
+else
+       nfs = nfs_null_vfsops.o

I've yet to see this "nfs_null_vfsops.o" but I wonder why we need any file at all in order not to support NFS?

The only other alternative would be a #ifdef right in the middle of the VFS code where the filesystems are
declared.

Since I don't like the preprocessor that much I choose to use a stub to disable the feature.

Ok, I guess we can start with this.

I think that in the long run, when we have many different optional features, we'll need something like Linux's configuration system, where turning on some CONFIG_SOMETHING both compiles additional source files, *and* also enables #ifdef CONFIG_SOMETHING. In the long run, making changes in the middle of existing code is something you cannot really avoid.
 
 
 
+thread_local std::unordered_map<std::string,
+                                std::unique_ptr<mount_context>> _map;

I'm a bit confused about the key of this map. It's the mount-point? What if a directory gets unmounted and then mounted again using a different server?

Perhaps we need to find a way when unmounting an NFS mountpoint to get rid of this context from all the existing threads?

I see you mentioned this case ("mess") below, but I didn't understand the solution with the invalid flag.

The invalid flag is here due to my great distaste of exceptions especially in constructor.

I am not following the details (too long since I reviewed this patch....) but exceptions are an important part of C++, you shouldn't have a distaste for them... Throwing an exception in a constructor is also fine.  But I guess we can also use your return-error-as-pass-by-reference-argument, if you prefer.
 
So if the class build itself correctly is_valid(errno) will return true else it will return false
and fill in the errno by reference.

+        uio->uio_offset = vp->v_size;
+        new_size = vp->v_size + uio->uio_resid;
+        // NFS does not support happening to a file so let's truncate ourselve

happening -> appending.

What did you mean by NFS not supporting append?

Seen here: (grep NFS)
 


So I guess you mean NFS doesn't support the O_APPEND option, and the kernel needs to "fake" it.
I'm not sure I understand, though, how this relates to your call to nfs_ftruncate. If you want to emulate O_APPEND, don't you need to check if uioflag & IO_APPEND (we have such code in ramfs_vnops.cc, but I have no idea if it's correct).

Maybe what you're doing here is correct, but I just don't understand it :-)

Nadav Har'El

unread,
Dec 14, 2015, 5:20:53 PM12/14/15
to Benoît Canet, OSv Development, Benoît Canet, Avi Kivity
On Mon, Dec 14, 2015 at 9:01 PM, Benoît Canet <ben...@scylladb.com> wrote:


On Thursday, November 26, 2015 at 10:43:51 PM UTC+1, Nadav Har'El wrote:


Somewhere in the VFS layer there is an array of structure pointing to each filesystem.

So it's not possible to build libnfs as a .so since the nfs driver will be right in the middle
of the kernel .so.

If we really wanted for NFS support to be a loadable module, I guess the solution would have been to make the "vfssw" array (fs/vfs/vfs_conf.cc) non-constant, and rather something to which nfs is added when the NFS module is loaded (and removed when unloaded). I think doing this should be pretty straightforward, but we don't need to do this now, and I think we can start with compiled-in code like you did.

By the way, doing something when a shared object is loaded and undoing it when unloaded is very easy to do in C++: Simply create a global object, whose constructor does something and destructor does something else. OSv will correctly call the constructor of global objects defined in a shared object when the shared object is loaded - and call the destructors when the shared-object is finally unloaded. If you're curious, this is elf.cc's run_init_funcs() and run_fini_funcs().
 

The path I choose is to provide an empty stub filesystem driver when libnfs is not compiled in.
 
 
+

+clean-libnfs:
+       if [ -f $(out)/libnfs.a ] ; then \
+       cd $(libnfs-path) && \
+       make distclean; \
+       fi

I would really love it if we didn't have to do this, and instead, we put all the build output of libnfs
in $(out) so the regular "make clean" that deletes the build directory would do the right thing
Alas not libnfs nor unfsd are able to build out of tree. 
....

Would it be difficult to run libnfs's "configure" or "make" in a way that causes the compilation
directory to be in the $(out) directory? Alternatively, does it make sense to avoid their makefile
altogether and compile their source code with out own Makefile (this is what we did for the
acpi library, for example)?

Maybe it worth the work to create an extra makefile yes.

But this work will need to be done twice one for libnfs and one for unfsd. 

I still don't understand the unfsd thing - if it's just for testing, it won't be part of the main Makefile anyway, and I still don't understand why we need to compile it at all (why can't the testing code use whatever NFS server exists on the system - nfs-ganesha or whatever?).

For libnfs I simply don't know the complexity involved. Is something trivial like we did for the ACPI library (compile a list of source code files) too simplistic for libnfs?

-$(out)/loader.elf: $(out)/arch/$(arch)/boot.o arch/$(arch)/loader.ld $(out)/loader.o $(out)/runtime.o $(drivers:%=$(out)/%) $(objects:%=$(out)/%) $(out)/bootfs.bin $(out)/dummy-shlib.so
+$(out)/loader.elf: $(out)/arch/$(arch)/boot.o arch/$(arch)/loader.ld $(out)/loader.o $(out)/runtime.o $(drivers:%=$(out)/%) $(objects:%=$(out)/%) $(out)/bootfs.bin $(out)/dummy-shlib.so $(nfs-lib)
        $(call quiet, $(LD) -o $@ --defsym=OSV_KERNEL_BASE=$(kernel_base) \
                -Bdynamic --export-dynamic --eh-frame-hdr --enable-new-dtags \
            $(filter-out %.bin, $(^:%.ld=-T %.ld)) \
            --whole-archive \
              $(libstdc++.a) $(libgcc.a) $(libgcc_eh.a) \
              $(boost-libs) \
+             $(nfs-lib) \

I think you should move nfs-lib out of the "whole-archive" section - if we don't use parts of the NFS library in OSv, why would we want these parts in the kernel? Is it possible that a user-space application might want to use them?
 

I don't think it make sence to move libnfs out of the kernel archive because there is an indirect reference to
it in a static array in the VFS layer code.

I'm not sure I understand why this is an "indirect" reference. Can you check if the whole-archive is really needed in practice?

Thanks,
Nadav.

Benoît Canet

unread,
Dec 14, 2015, 9:59:47 PM12/14/15
to Nadav Har'El, Benoît Canet, OSv Development, Benoît Canet
On Mon, Dec 14, 2015 at 10:48 PM, Nadav Har'El <n...@scylladb.com> wrote:

On Mon, Dec 14, 2015 at 10:19 PM, Benoît Canet <ben...@scylladb.com> wrote:
        $(call quiet, cp -a $(libnfs-path)/lib/.libs/libnfs.a $(out)/libnfs.a)

 clean-libnfs:
@@ -1774,8 +1781,13 @@ boost-libs := $(boost-lib-dir)/libboost_program_options$(boost-mt).a \
 nfs-lib =
 ifeq ($(NFS), true)
        nfs-lib += $(out)/libnfs.a
+       nfs = nfs.o nfs_vfsops.o nfs_vnops.o
+else
+       nfs = nfs_null_vfsops.o

I've yet to see this "nfs_null_vfsops.o" but I wonder why we need any file at all in order not to support NFS?

The only other alternative would be a #ifdef right in the middle of the VFS code where the filesystems are
declared.

Since I don't like the preprocessor that much I choose to use a stub to disable the feature.

Ok, I guess we can start with this.

I think that in the long run, when we have many different optional features, we'll need something like Linux's configuration system, where turning on some CONFIG_SOMETHING both compiles additional source files, *and* also enables #ifdef CONFIG_SOMETHING. In the long run, making changes in the middle of existing code is something you cannot really avoid.

ok,

I will make the switch as soon as there is another optional feature. 
 
 
 
+thread_local std::unordered_map<std::string,
+                                std::unique_ptr<mount_context>> _map;

I'm a bit confused about the key of this map. It's the mount-point? What if a directory gets unmounted and then mounted again using a different server?

Perhaps we need to find a way when unmounting an NFS mountpoint to get rid of this context from all the existing threads?

I see you mentioned this case ("mess") below, but I didn't understand the solution with the invalid flag.

The invalid flag is here due to my great distaste of exceptions especially in constructor.

I am not following the details (too long since I reviewed this patch....) but exceptions are an important part of C++, you shouldn't have a distaste for them... Throwing an exception in a constructor is also fine.  But I guess we can also use your return-error-as-pass-by-reference-argument, if you prefer.

Thanks :)
 
 
So if the class build itself correctly is_valid(errno) will return true else it will return false
and fill in the errno by reference.

+        uio->uio_offset = vp->v_size;
+        new_size = vp->v_size + uio->uio_resid;
+        // NFS does not support happening to a file so let's truncate ourselve

happening -> appending.

What did you mean by NFS not supporting append?

Seen here: (grep NFS)
 


So I guess you mean NFS doesn't support the O_APPEND option, and the kernel needs to "fake" it.
I'm not sure I understand, though, how this relates to your call to nfs_ftruncate. If you want to emulate O_APPEND, don't you need to check if uioflag & IO_APPEND (we have such code in ramfs_vnops.cc, but I have no idea if it's correct).

Maybe what you're doing here is correct, but I just don't understand it :-)

The NFS code does check for IO_APPEND.
I think it's correct and anyway excepted wasting a few ms it could not hurt.
If we establish that it's unusefull we can always remove it later instead of
risking data loss in the first place.

Best regards

Benoît

Benoît Canet

unread,
Dec 14, 2015, 10:26:50 PM12/14/15
to Nadav Har'El, Benoît Canet, OSv Development, Benoît Canet, Avi Kivity
On Mon, Dec 14, 2015 at 11:20 PM, Nadav Har'El <n...@scylladb.com> wrote:

On Mon, Dec 14, 2015 at 9:01 PM, Benoît Canet <ben...@scylladb.com> wrote:


On Thursday, November 26, 2015 at 10:43:51 PM UTC+1, Nadav Har'El wrote:


Somewhere in the VFS layer there is an array of structure pointing to each filesystem.

So it's not possible to build libnfs as a .so since the nfs driver will be right in the middle
of the kernel .so.

If we really wanted for NFS support to be a loadable module, I guess the solution would have been to make the "vfssw" array (fs/vfs/vfs_conf.cc) non-constant, and rather something to which nfs is added when the NFS module is loaded (and removed when unloaded). I think doing this should be pretty straightforward, but we don't need to do this now, and I think we can start with compiled-in code like you did.

By the way, doing something when a shared object is loaded and undoing it when unloaded is very easy to do in C++: Simply create a global object, whose constructor does something and destructor does something else. OSv will correctly call the constructor of global objects defined in a shared object when the shared object is loaded - and call the destructors when the shared-object is finally unloaded. If you're curious, this is elf.cc's run_init_funcs() and run_fini_funcs().

Good trick to know. Thanks.
 
 

The path I choose is to provide an empty stub filesystem driver when libnfs is not compiled in.
 
 
+
+clean-libnfs:
+       if [ -f $(out)/libnfs.a ] ; then \
+       cd $(libnfs-path) && \
+       make distclean; \
+       fi

I would really love it if we didn't have to do this, and instead, we put all the build output of libnfs
in $(out) so the regular "make clean" that deletes the build directory would do the right thing

Alas not libnfs nor unfsd are able to build out of tree. 
....

Would it be difficult to run libnfs's "configure" or "make" in a way that causes the compilation
directory to be in the $(out) directory? Alternatively, does it make sense to avoid their makefile
altogether and compile their source code with out own Makefile (this is what we did for the
acpi library, for example)?

Maybe it worth the work to create an extra makefile yes.

But this work will need to be done twice one for libnfs and one for unfsd. 

I still don't understand the unfsd thing - if it's just for testing, it won't be part of the main Makefile anyway, and I still don't understand why we need to compile it at all (why can't the testing code use whatever NFS server exists on the system - nfs-ganesha or whatever?).

I think I will ship a unfsd binary that will be simpler than compiling it everytime.
 

For libnfs I simply don't know the complexity involved. Is something trivial like we did for the ACPI library (compile a list of source code files) too simplistic for libnfs?

-$(out)/loader.elf: $(out)/arch/$(arch)/boot.o arch/$(arch)/loader.ld $(out)/loader.o $(out)/runtime.o $(drivers:%=$(out)/%) $(objects:%=$(out)/%) $(out)/bootfs.bin $(out)/dummy-shlib.so
+$(out)/loader.elf: $(out)/arch/$(arch)/boot.o arch/$(arch)/loader.ld $(out)/loader.o $(out)/runtime.o $(drivers:%=$(out)/%) $(objects:%=$(out)/%) $(out)/bootfs.bin $(out)/dummy-shlib.so $(nfs-lib)
        $(call quiet, $(LD) -o $@ --defsym=OSV_KERNEL_BASE=$(kernel_base) \
                -Bdynamic --export-dynamic --eh-frame-hdr --enable-new-dtags \
            $(filter-out %.bin, $(^:%.ld=-T %.ld)) \
            --whole-archive \
              $(libstdc++.a) $(libgcc.a) $(libgcc_eh.a) \
              $(boost-libs) \
+             $(nfs-lib) \

I think you should move nfs-lib out of the "whole-archive" section - if we don't use parts of the NFS library in OSv, why would we want these parts in the kernel? Is it possible that a user-space application might want to use them?
 

I don't think it make sence to move libnfs out of the kernel archive because there is an indirect reference to
it in a static array in the VFS layer code.

I'm not sure I understand why this is an "indirect" reference. Can you check if the whole-archive is really needed in practice?

I means the nfs driver use this library and the nfs driver is declared in the static arrays. Hence indirect reference.

I tried to hand compile libnfs in the main Makefile and it look difficult to do.

Best regards

Benoît
 

Thanks,
Nadav.

Reply all
Reply to author
Forward
0 new messages