about summary refs log tree commit diff
path: root/glibc-compat
diff options
context:
space:
mode:
Diffstat (limited to 'glibc-compat')
-rw-r--r--glibc-compat/.cvsignore1
-rw-r--r--glibc-compat/Banner1
-rw-r--r--glibc-compat/ChangeLog37
-rw-r--r--glibc-compat/Depend3
-rw-r--r--glibc-compat/Makefile150
-rw-r--r--glibc-compat/Versions106
-rw-r--r--glibc-compat/Versions.def15
-rwxr-xr-xglibc-compat/configure3
-rw-r--r--glibc-compat/include/aliases.h20
-rw-r--r--glibc-compat/include/grp.h29
-rw-r--r--glibc-compat/include/netdb.h178
-rw-r--r--glibc-compat/include/pwd.h25
-rw-r--r--glibc-compat/include/rpc/netdb.h24
-rw-r--r--glibc-compat/include/shadow.h24
-rw-r--r--glibc-compat/nss-nis.h58
-rw-r--r--glibc-compat/nss_compat/compat-grp.c769
-rw-r--r--glibc-compat/nss_compat/compat-pwd.c1199
-rw-r--r--glibc-compat/nss_compat/compat-spwd.c915
-rw-r--r--glibc-compat/nss_db/db-XXX.c257
-rw-r--r--glibc-compat/nss_db/db-alias.c208
-rw-r--r--glibc-compat/nss_db/db-netgrp.c101
-rw-r--r--glibc-compat/nss_db/db-open.c1
-rw-r--r--glibc-compat/nss_db/dummy-db.h1
-rw-r--r--glibc-compat/nss_db/nss_db.h1
-rw-r--r--glibc-compat/nss_dns/dns-host.c641
-rw-r--r--glibc-compat/nss_dns/dns-network.c420
-rw-r--r--glibc-compat/nss_files/files-XXX.c311
-rw-r--r--glibc-compat/nss_files/files-alias.c451
-rw-r--r--glibc-compat/nss_files/files-ethers.c75
-rw-r--r--glibc-compat/nss_files/files-grp.c45
-rw-r--r--glibc-compat/nss_files/files-hosts.c107
-rw-r--r--glibc-compat/nss_files/files-netgrp.c268
-rw-r--r--glibc-compat/nss_files/files-network.c56
-rw-r--r--glibc-compat/nss_files/files-parse.c252
-rw-r--r--glibc-compat/nss_files/files-proto.c47
-rw-r--r--glibc-compat/nss_files/files-pwd.c45
-rw-r--r--glibc-compat/nss_files/files-rpc.c47
-rw-r--r--glibc-compat/nss_files/files-service.c60
-rw-r--r--glibc-compat/nss_files/files-spwd.c38
-rw-r--r--glibc-compat/nss_nis/nis-alias.c278
-rw-r--r--glibc-compat/nss_nis/nis-ethers.c299
-rw-r--r--glibc-compat/nss_nis/nis-grp.c249
-rw-r--r--glibc-compat/nss_nis/nis-hosts.c417
-rw-r--r--glibc-compat/nss_nis/nis-netgrp.c128
-rw-r--r--glibc-compat/nss_nis/nis-network.c318
-rw-r--r--glibc-compat/nss_nis/nis-proto.c280
-rw-r--r--glibc-compat/nss_nis/nis-pwd.c407
-rw-r--r--glibc-compat/nss_nis/nis-rpc.c295
-rw-r--r--glibc-compat/nss_nis/nis-service.c280
-rw-r--r--glibc-compat/nss_nis/nis-spwd.c201
-rw-r--r--glibc-compat/oldfileops.c774
-rw-r--r--glibc-compat/oldiofclose.c60
-rw-r--r--glibc-compat/oldiofdopen.c140
-rw-r--r--glibc-compat/oldiofopen.c71
-rw-r--r--glibc-compat/oldiopopen.c289
-rw-r--r--glibc-compat/oldpclose.c48
-rw-r--r--glibc-compat/oldstdfiles.c97
-rw-r--r--glibc-compat/oldtmpfile.c55
-rw-r--r--glibc-compat/rpcsvc/yp.h621
-rw-r--r--glibc-compat/rpcsvc/ypclnt.h90
-rw-r--r--glibc-compat/shlib-versions19
-rw-r--r--glibc-compat/stubs.c57
62 files changed, 12462 insertions, 0 deletions
diff --git a/glibc-compat/.cvsignore b/glibc-compat/.cvsignore
new file mode 100644
index 0000000000..6eaa1d38eb
--- /dev/null
+++ b/glibc-compat/.cvsignore
@@ -0,0 +1 @@
+glibc-compat*.tar.gz
diff --git a/glibc-compat/Banner b/glibc-compat/Banner
new file mode 100644
index 0000000000..7d4bde6291
--- /dev/null
+++ b/glibc-compat/Banner
@@ -0,0 +1 @@
+Glibc-2.0 compatibility add-on by Cristian Gafton 
diff --git a/glibc-compat/ChangeLog b/glibc-compat/ChangeLog
new file mode 100644
index 0000000000..e61c488926
--- /dev/null
+++ b/glibc-compat/ChangeLog
@@ -0,0 +1,37 @@
+2000-04-13  Jakub Jelinek  <jakub@redhat.com>
+
+	* Makefile (services): revert last change.
+	(libnss1_db-routines): Add db-open.
+	(libnss1_db.so): Remove libdb dependencies, add libdl.
+	* nss_db/db-open.c: New file.
+	* nss_db/dummy-db.h: New file.
+	* nss_db/nss_db.h: New file.
+	* nss_db/db-XXX.c: Update from glibc 2.1.90 nss_db/db-XXX.c,
+	remove errnop passing and EXTRA_ARGS.
+	* nss_db/db-alias.c: Likewise.
+	* nss_db/db-netgrp.c: Likewise.
+
+2000-01-04  Cristian Gafton  <gafton@redhat.com>
+
+	* Makefile (services): disable the compat NSS module for 
+	Berkeley DB (nss_db). Berkeley BD is not part of the glibc anymore.
+
+1999-07-08  Cristian Gafton  <gafton@redhat.com>
+
+	* stubs.c (__setfpucw): New function
+	* Makefile: Use -include, not include
+	(archive): New target.
+
+1999-04-09  Andreas Jaeger  <aj@arthur.rhein-neckar.de>
+	* glibc-compat/Makefile: Add rules to link libnss_*.so.1 to libnss1_*.so.2.
+	
+1998-11-18  Cristian Gafton  <gafton@redhat.com>
+
+	* shlib-versions: added alpha versions
+
+	* Makefile (services): Added libnss_dns
+
+1998-11-16  Cristian Gafton  <gafton@redhat.com>
+
+	* makedist (archive): remove old tar file just in case
+
diff --git a/glibc-compat/Depend b/glibc-compat/Depend
new file mode 100644
index 0000000000..89d8e5bfec
--- /dev/null
+++ b/glibc-compat/Depend
@@ -0,0 +1,3 @@
+resolv
+nss
+nis
diff --git a/glibc-compat/Makefile b/glibc-compat/Makefile
new file mode 100644
index 0000000000..8c60483524
--- /dev/null
+++ b/glibc-compat/Makefile
@@ -0,0 +1,150 @@
+# Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc.
+
+# This is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Library General Public License as
+# published by the Free Software Foundation; either version 2 of the
+# License, or (at your option) any later version.
+
+# The GNU C Library 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
+# Library General Public License for more details.
+
+# You should have received a copy of the GNU Library General Public
+# License along with the GNU C Library; see the file COPYING.LIB.  If not,
+# write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+# Boston, MA 02111-1307, USA.
+
+# $Id$
+
+subdir	:= glibc-compat
+
+distribute		:= nss-nis.h
+
+# This is the trivial part which goes into libc itself.
+routines		=
+
+# These are the databases that go through nss dispatch.
+# Caution: if you add a database here, you must add its real name
+# in databases.def, too.
+databases		= proto service hosts network grp pwd rpc ethers \
+			  spwd netgrp alias
+
+# Specify rules for the nss_* modules.  We have some services.
+services		:= files nis compat dns
+
+extra-libs		:= $(services:%=libnss1_%) libNoVersion
+# These libraries will be built in the `others' pass rather than
+# the `lib' pass, because they depend on libc.so being built already.
+extra-libs-others	= $(extra-libs)
+
+# The sources are found in the appropriate subdir.
+subdir-dirs = $(services:%=nss_%)
+vpath %.c $(subdir-dirs)
+
+libnss1_files-routines	:= $(addprefix files-,$(databases))
+libnss1_compat-routines	:= $(addprefix compat-,grp pwd spwd)
+libnss1_nis-routines	:= $(addprefix nis-,$(databases))
+libnss1_dns-routines	:= $(addprefix dns-, host network)
+
+libcompat-routines	:= $(addprefix old, fileops iofdopen iopopen stdfiles \
+					    iofclose  iofopen pclose tmpfile)
+libNoVersion-routines	:= stubs
+
+libnss1_files-inhibit-o	= $(filter-out .os,$(object-suffixes))
+libnss1_compat-inhibit-o = $(filter-out .os,$(object-suffixes))
+libnss1_nis-inhibit-o	= $(filter-out .os,$(object-suffixes))
+libnss1_dns-inhibit-o	= $(filter-out .os,$(object-suffixes))
+
+-include ../Rules
+
+# Force the soname to be libnss_*.so.1 for compatibility.
+LDFLAGS-nss1_files.so	= -Wl,-soname=lib$(libprefix)nss_files.so$($(@F)-version)
+LDFLAGS-nss1_nis.so	= -Wl,-soname=lib$(libprefix)nss_nis.so$($(@F)-version)
+LDFLAGS-nss1_compat.so	= -Wl,-soname=lib$(libprefix)nss_compat.so$($(@F)-version)
+LDFLAGS-nss1_dns.so	= -Wl,-soname=lib$(libprefix)nss_dns.so$($(@F)-version)
+
+-include ../Makeconfig
+
+ifeq (yes,$(build-shared))
+install-others	+= $(inst_slibdir)/libnss_files.so$(libnss1_files.so-version) \
+		   $(inst_slibdir)/libnss_nis.so$(libnss1_nis.so-version) \
+		   $(inst_slibdir)/libnss_compat.so$(libnss1_compat.so-version) \
+		   $(inst_slibdir)/libnss_dns.so$(libnss1_dns.so-version)
+endif
+
+$(inst_slibdir)/libnss_files.so$(libnss1_files.so-version): $(inst_slibdir)/libnss1_files-$(version).so $(+force)
+	rm -f $@
+	$(LN_S) $(<F) $@
+
+$(inst_slibdir)/libnss_nis.so$(libnss1_nis.so-version): $(inst_slibdir)/libnss1_nis-$(version).so $(+force)
+	rm -f $@
+	$(LN_S) $(<F) $@
+
+$(inst_slibdir)/libnss_compat.so$(libnss1_compat.so-version): $(inst_slibdir)/libnss1_compat-$(version).so $(+force)
+	rm -f $@
+	$(LN_S) $(<F) $@
+
+$(inst_slibdir)/libnss_dns.so$(libnss1_dns.so-version): $(inst_slibdir)/libnss1_dns-$(version).so $(+force)
+	rm -f $@
+	$(LN_S) $(<F) $@
+
+
+$(objpfx)libnss1_compat.so: $(common-objpfx)nis/libnsl.so$(libnsl.so-version) \
+			   $(objpfx)libnss1_files.so
+$(objpfx)libnss1_nis.so: $(common-objpfx)nis/libnsl.so$(libnsl.so-version) \
+			$(objpfx)libnss1_files.so
+
+# The DNS NSS modules needs the resolver.
+#$(objpfx)libnss1_dns.so: $(filter-out $(common-objpfx)resolv/stamp.os, \
+#				$(wildcard $(common-objpfx)resolv/*.os)) \
+#			$(common-objpfx)libc.so
+$(objpfx)libnss1_dns.so: $(common-objpfx)resolv/libresolv.so $(common-objpfx)libc.so
+
+# Depend on libc.so so a DT_NEEDED is generated in the shared objects.
+# This ensures they will load libc.so for needed symbols if loaded by
+# a statically-linked program that hasn't already loaded it.
+$(objpfx)libnss1_compat.so: $(common-objpfx)nis/libnsl.so$(libnsl.so-version) \
+                            $(objpfx)libnss1_files.so $(common-objpfx)libc.so
+$(objpfx)libnss1_dns.so: $(common-objpfx)resolv/libresolv.so \
+                         $(common-objpfx)libc.so
+$(objpfs)libnss1_files.so: $(common-objpfx)libc.so
+$(objpfx)libnss1_nis.so: $(common-objpfx)nis/libnsl.so$(libnsl.so-version) \
+                         $(objpfx)libnss1_files.so $(common-objpfx)libc.so
+
+check-abi-libNoVersion: $(..)scripts/extract-abilist.awk
+	@:
+update-abi-libNoVersion: $(..)scripts/merge-abilist.awk
+	@:
+check-abi-libnss1_compat: $(..)scripts/extract-abilist.awk
+	@:
+update-abi-libnss1_compat: $(..)scripts/merge-abilist.awk
+	@:
+check-abi-libnss1_dns: $(..)scripts/extract-abilist.awk
+	@:
+update-abi-libnss1_dns: $(..)scripts/merge-abilist.awk
+	@:
+check-abi-libnss1_files: $(..)scripts/extract-abilist.awk
+	@:
+update-abi-libnss1_files: $(..)scripts/merge-abilist.awk
+	@:
+check-abi-libnss1_nis: $(..)scripts/extract-abilist.awk
+	@:
+update-abi-libnss1_nis: $(..)scripts/merge-abilist.awk
+	@:
+
+#
+# This is needed to build the separate tarball
+#
+pkgNAME		= $(subdir)
+pkgVERSION	= 2.1.3
+pkgCVSTAG	= $(pkgNAME)_$(subst .,-,$(pkgVERSION))
+
+archive:
+	@rm -f *.tar.gz *~
+	cvs tag -F $(pkgCVSTAG) .
+	@rm -rf /tmp/$(pkgNAME)-$(pkgVERSION) /tmp/$(pkgNAME) $(pkgNAME)-$(pkgVERSION).tar.gz
+	@cd /tmp; cvs export -r$(pkgCVSTAG) $(pkgNAME)
+	@pkgDIR=$$PWD; cd /tmp; tar cvzf $$pkgDIR/$(pkgNAME)-$(pkgVERSION).tar.gz $(pkgNAME)
+	@rm -rf /tmp/$(pkgNAME)
+	@echo "The archive is in $(pkgNAME)-$(pkgVERSION).tar.gz"
diff --git a/glibc-compat/Versions b/glibc-compat/Versions
new file mode 100644
index 0000000000..354d5b62a6
--- /dev/null
+++ b/glibc-compat/Versions
@@ -0,0 +1,106 @@
+libnss1_db {
+  GLIBC_2.0 {
+    _nss_db_endaliasent; _nss_db_endetherent; _nss_db_endgrent;
+    _nss_db_endnetgrent; _nss_db_endprotoent; _nss_db_endpwent;
+    _nss_db_endrpcent; _nss_db_endservent; _nss_db_endspent;
+    _nss_db_getaliasbyname_r; _nss_db_getaliasent_r; _nss_db_getetherent_r;
+    _nss_db_getgrent_r; _nss_db_getgrgid_r; _nss_db_getgrnam_r;
+    _nss_db_gethostton_r; _nss_db_getnetgrent_r; _nss_db_getntohost_r;
+    _nss_db_getprotobyname_r; _nss_db_getprotobynumber_r;
+    _nss_db_getprotoent_r; _nss_db_getpwent_r; _nss_db_getpwnam_r;
+    _nss_db_getpwuid_r; _nss_db_getrpcbyname_r; _nss_db_getrpcbynumber_r;
+    _nss_db_getrpcent_r; _nss_db_getservbyname_r; _nss_db_getservbyport_r;
+    _nss_db_getservent_r; _nss_db_getspent_r; _nss_db_getspnam_r;
+    _nss_db_setaliasent; _nss_db_setetherent; _nss_db_setgrent;
+    _nss_db_setnetgrent; _nss_db_setprotoent; _nss_db_setpwent;
+    _nss_db_setrpcent; _nss_db_setservent; _nss_db_setspent;
+  }
+}
+
+libnss1_dns {
+  GLIBC_2.0 {
+    _nss_dns_gethostbyaddr_r; _nss_dns_gethostbyname2_r;
+    _nss_dns_gethostbyname_r; _nss_dns_getnetbyaddr_r;
+    _nss_dns_getnetbyname_r;
+  }
+}
+
+libnss1_files {
+  GLIBC_2.0 {
+    _nss_files_setaliasent; _nss_files_endaliasent;
+    _nss_files_getaliasbyname_r; _nss_files_getaliasent_r;
+
+    _nss_files_setetherent; _nss_files_endetherent;
+    _nss_files_getetherent_r; _nss_files_parse_etherent;
+
+    _nss_files_setgrent; _nss_files_endgrent;
+    _nss_files_getgrent_r; _nss_files_getgrgid_r; _nss_files_getgrnam_r;
+
+    _nss_files_sethostent; _nss_files_endhostent;
+    _nss_files_gethostbyaddr_r; _nss_files_gethostbyname2_r; _nss_files_gethostbyname_r;
+     _nss_files_gethostent_r; _nss_files_gethostton_r;
+
+    _nss_files_setnetent; _nss_files_endnetent;
+    _nss_files_getnetbyaddr_r; _nss_files_getnetbyname_r;
+    _nss_files_getnetent_r; _nss_files_getntohost_r;
+    _nss_files_parse_netent;
+
+    _nss_files_setnetgrent; _nss_files_endnetgrent; _nss_files_getnetgrent_r;
+
+    _nss_files_setprotoent; _nss_files_endprotoent;
+    _nss_files_getprotobyname_r; _nss_files_getprotobynumber_r;
+    _nss_files_getprotoent_r;  _nss_files_parse_protoent;
+
+    _nss_files_setpwent; _nss_files_endpwent;
+    _nss_files_getpwent_r; _nss_files_getpwnam_r; _nss_files_getpwuid_r;
+
+    _nss_files_setrpcent; _nss_files_endrpcent;
+    _nss_files_getrpcbyname_r; _nss_files_getrpcbynumber_r;
+    _nss_files_getrpcent_r;
+    _nss_files_parse_rpcent;
+
+    _nss_files_setservent; _nss_files_endservent;
+    _nss_files_getservbyname_r; _nss_files_getservbyport_r;
+    _nss_files_getservent_r;
+    _nss_files_parse_servent;
+
+    _nss_files_setspent; _nss_files_endspent;
+    _nss_files_getspent_r; _nss_files_getspnam_r;
+
+    _nss_netgroup_parseline;
+  }
+}
+
+libnss1_compat {
+  GLIBC_2.0 {
+    _nss_compat_endgrent; _nss_compat_endpwent; _nss_compat_endspent;
+    _nss_compat_getgrent_r; _nss_compat_getgrgid_r; _nss_compat_getgrnam_r;
+    _nss_compat_getpwent_r; _nss_compat_getpwnam_r; _nss_compat_getpwuid_r;
+    _nss_compat_getspent_r; _nss_compat_getspnam_r; _nss_compat_initgroups;
+    _nss_compat_setgrent; _nss_compat_setpwent; _nss_compat_setspent;
+  }
+}
+
+libnss1_nis {
+  GLIBC_2.0 {
+    _nss_nis_endaliasent; _nss_nis_endetherent; _nss_nis_endgrent;
+    _nss_nis_endhostent; _nss_nis_endnetent; _nss_nis_endnetgrent;
+    _nss_nis_endprotoent; _nss_nis_endpwent; _nss_nis_endrpcent;
+    _nss_nis_endservent; _nss_nis_endspent; _nss_nis_getaliasbyname_r;
+    _nss_nis_getaliasent_r; _nss_nis_getetherent_r; _nss_nis_getgrent_r;
+    _nss_nis_getgrgid_r; _nss_nis_getgrnam_r; _nss_nis_gethostbyaddr_r;
+    _nss_nis_gethostbyname2_r; _nss_nis_gethostbyname_r; _nss_nis_gethostent_r;
+    _nss_nis_gethostton_r; _nss_nis_getnetbyaddr_r; _nss_nis_getnetbyname_r;
+    _nss_nis_getnetent_r; _nss_nis_getnetgrent_r; _nss_nis_getntohost_r;
+    _nss_nis_getprotobyname_r; _nss_nis_getprotobynumber_r;
+    _nss_nis_getprotoent_r; _nss_nis_getpublickey; _nss_nis_getpwent_r;
+    _nss_nis_getpwnam_r; _nss_nis_getpwuid_r; _nss_nis_getrpcbyname_r;
+    _nss_nis_getrpcbynumber_r; _nss_nis_getrpcent_r; _nss_nis_getsecretkey;
+    _nss_nis_getservbyname_r; _nss_nis_getservbyport_r; _nss_nis_getservent_r;
+    _nss_nis_getspent_r; _nss_nis_getspnam_r; _nss_nis_initgroups;
+    _nss_nis_netname2user; _nss_nis_setaliasent; _nss_nis_setetherent;
+    _nss_nis_setgrent; _nss_nis_sethostent; _nss_nis_setnetent;
+    _nss_nis_setnetgrent; _nss_nis_setprotoent; _nss_nis_setpwent;
+    _nss_nis_setrpcent; _nss_nis_setservent; _nss_nis_setspent;
+  }
+}
diff --git a/glibc-compat/Versions.def b/glibc-compat/Versions.def
new file mode 100644
index 0000000000..742eda0f2c
--- /dev/null
+++ b/glibc-compat/Versions.def
@@ -0,0 +1,15 @@
+libnss1_files {
+  GLIBC_2.0
+}
+libnss1_db {
+  GLIBC_2.0
+}
+libnss1_dns {
+  GLIBC_2.0
+}
+libnss1_nis {
+  GLIBC_2.0
+}
+libnss1_compat {
+  GLIBC_2.0
+}
diff --git a/glibc-compat/configure b/glibc-compat/configure
new file mode 100755
index 0000000000..53d0dcd67e
--- /dev/null
+++ b/glibc-compat/configure
@@ -0,0 +1,3 @@
+# This is only to keep the GNU C library configure mechanism happy.
+# This is a shell script fragment sourced by the main configure script.
+# We have nothing we need to add here.
diff --git a/glibc-compat/include/aliases.h b/glibc-compat/include/aliases.h
new file mode 100644
index 0000000000..3932e52097
--- /dev/null
+++ b/glibc-compat/include/aliases.h
@@ -0,0 +1,20 @@
+#ifndef _ALIASES_H
+#include <inet/aliases.h>
+
+extern int __getaliasent_r (struct aliasent *__restrict __result_buf,
+			    char *__restrict __buffer, size_t __buflen,
+			    struct aliasent **__restrict __result);
+extern int __old_getaliasent_r (struct aliasent *__restrict __result_buf,
+				char *__restrict __buffer, size_t __buflen,
+				struct aliasent **__restrict __result);
+
+extern int __getaliasbyname_r (__const char *__restrict __name,
+			       struct aliasent *__restrict __result_buf,
+			       char *__restrict __buffer, size_t __buflen,
+			       struct aliasent **__restrict __result);
+extern int __old_getaliasbyname_r (__const char *__restrict __name,
+				   struct aliasent *__restrict __result_buf,
+				   char *__restrict __buffer, size_t __buflen,
+				   struct aliasent **__restrict __result);
+
+#endif
diff --git a/glibc-compat/include/grp.h b/glibc-compat/include/grp.h
new file mode 100644
index 0000000000..aba77c6e8c
--- /dev/null
+++ b/glibc-compat/include/grp.h
@@ -0,0 +1,29 @@
+#ifndef _GRP_H
+#include <grp/grp.h>
+
+/* Now define the internal interfaces.  */
+extern int __getgrent_r (struct group *__resultbuf, char *buffer,
+			 size_t __buflen, struct group **__result);
+extern int __old_getgrent_r (struct group *__resultbuf, char *buffer,
+			     size_t __buflen, struct group **__result);
+extern int __fgetgrent_r (FILE * __stream, struct group *__resultbuf,
+			  char *buffer, size_t __buflen,
+			  struct group **__result);
+
+/* Search for an entry with a matching group ID.  */
+extern int __getgrgid_r (__gid_t __gid, struct group *__resultbuf,
+			 char *__buffer, size_t __buflen,
+			 struct group **__result);
+extern int __old_getgrgid_r (__gid_t __gid, struct group *__resultbuf,
+			     char *__buffer, size_t __buflen,
+			     struct group **__result);
+
+/* Search for an entry with a matching group name.  */
+extern int __getgrnam_r (__const char *__name, struct group *__resultbuf,
+			 char *__buffer, size_t __buflen,
+			 struct group **__result);
+extern int __old_getgrnam_r (__const char *__name, struct group *__resultbuf,
+			     char *__buffer, size_t __buflen,
+			     struct group **__result);
+
+#endif
diff --git a/glibc-compat/include/netdb.h b/glibc-compat/include/netdb.h
new file mode 100644
index 0000000000..85ab234177
--- /dev/null
+++ b/glibc-compat/include/netdb.h
@@ -0,0 +1,178 @@
+#ifndef	_NETDB_H
+#include <glibc-compat/include/rpc/netdb.h>
+#include <resolv/netdb.h>
+
+/* Macros for accessing h_errno from inside libc.  */
+# ifdef _LIBC_REENTRANT
+#  include <tls.h>
+#  if USE___THREAD
+#   undef  h_errno
+#   ifndef NOT_IN_libc
+#    define h_errno __libc_h_errno
+#   else
+#    define h_errno h_errno	/* For #ifndef h_errno tests.  */
+#   endif
+extern __thread int h_errno attribute_tls_model_ie;
+#   define __set_h_errno(x)	(h_errno = (x))
+#  else
+static inline int
+__set_h_errno (int __err)
+{
+  return *__h_errno_location () = __err;
+}
+#  endif
+# else
+#  undef  h_errno
+#  define __set_h_errno(x) (h_errno = (x))
+extern int h_errno;
+# endif	/* _LIBC_REENTRANT */
+
+/* Document internal interfaces.  */
+extern int __gethostent_r (struct hostent *__restrict __result_buf,
+			   char *__restrict __buf, size_t __buflen,
+			   struct hostent **__restrict __result,
+			   int *__restrict __h_errnop);
+extern int __old_gethostent_r (struct hostent *__restrict __result_buf,
+			       char *__restrict __buf, size_t __buflen,
+			       struct hostent **__restrict __result,
+			       int *__restrict __h_errnop);
+
+extern int __gethostbyaddr_r (__const void *__restrict __addr,
+			      socklen_t __len, int __type,
+			      struct hostent *__restrict __result_buf,
+			      char *__restrict __buf, size_t __buflen,
+			      struct hostent **__restrict __result,
+			      int *__restrict __h_errnop);
+extern int __old_gethostbyaddr_r (__const void *__restrict __addr,
+				  socklen_t __len, int __type,
+				  struct hostent *__restrict __result_buf,
+				  char *__restrict __buf, size_t __buflen,
+				  struct hostent **__restrict __result,
+				  int *__restrict __h_errnop);
+
+extern int __gethostbyname_r (__const char *__restrict __name,
+			      struct hostent *__restrict __result_buf,
+			      char *__restrict __buf, size_t __buflen,
+			      struct hostent **__restrict __result,
+			      int *__restrict __h_errnop);
+extern int __old_gethostbyname_r (__const char *__restrict __name,
+				  struct hostent *__restrict __result_buf,
+				  char *__restrict __buf, size_t __buflen,
+				  struct hostent **__restrict __result,
+				  int *__restrict __h_errnop);
+
+extern int __gethostbyname2_r (__const char *__restrict __name, int __af,
+			       struct hostent *__restrict __result_buf,
+			       char *__restrict __buf, size_t __buflen,
+			       struct hostent **__restrict __result,
+			       int *__restrict __h_errnop);
+extern int __old_gethostbyname2_r (__const char *__restrict __name, int __af,
+				   struct hostent *__restrict __result_buf,
+				   char *__restrict __buf, size_t __buflen,
+				   struct hostent **__restrict __result,
+				   int *__restrict __h_errnop);
+
+extern int __getnetent_r (struct netent *__restrict __result_buf,
+			  char *__restrict __buf, size_t __buflen,
+			  struct netent **__restrict __result,
+			  int *__restrict __h_errnop);
+extern int __old_getnetent_r (struct netent *__restrict __result_buf,
+			      char *__restrict __buf, size_t __buflen,
+			      struct netent **__restrict __result,
+			      int *__restrict __h_errnop);
+
+extern int __getnetbyaddr_r (uint32_t __net, int __type,
+			     struct netent *__restrict __result_buf,
+			     char *__restrict __buf, size_t __buflen,
+			     struct netent **__restrict __result,
+			     int *__restrict __h_errnop);
+extern int __old_getnetbyaddr_r (uint32_t __net, int __type,
+				 struct netent *__restrict __result_buf,
+				 char *__restrict __buf, size_t __buflen,
+				 struct netent **__restrict __result,
+				 int *__restrict __h_errnop);
+
+extern int __getnetbyname_r (__const char *__restrict __name,
+			     struct netent *__restrict __result_buf,
+			     char *__restrict __buf, size_t __buflen,
+			     struct netent **__restrict __result,
+			     int *__restrict __h_errnop);
+extern int __old_getnetbyname_r (__const char *__restrict __name,
+				 struct netent *__restrict __result_buf,
+				 char *__restrict __buf, size_t __buflen,
+				 struct netent **__restrict __result,
+				 int *__restrict __h_errnop);
+
+extern int __getservent_r (struct servent *__restrict __result_buf,
+			   char *__restrict __buf, size_t __buflen,
+			   struct servent **__restrict __result);
+extern int __old_getservent_r (struct servent *__restrict __result_buf,
+			       char *__restrict __buf, size_t __buflen,
+			       struct servent **__restrict __result);
+
+extern int __getservbyname_r (__const char *__restrict __name,
+			      __const char *__restrict __proto,
+			      struct servent *__restrict __result_buf,
+			      char *__restrict __buf, size_t __buflen,
+			      struct servent **__restrict __result);
+extern int __old_getservbyname_r (__const char *__restrict __name,
+				  __const char *__restrict __proto,
+				  struct servent *__restrict __result_buf,
+				  char *__restrict __buf, size_t __buflen,
+				  struct servent **__restrict __result);
+
+extern int __getservbyport_r (int __port,
+			      __const char *__restrict __proto,
+			      struct servent *__restrict __result_buf,
+			      char *__restrict __buf, size_t __buflen,
+			      struct servent **__restrict __result);
+extern int __old_getservbyport_r (int __port,
+				  __const char *__restrict __proto,
+				  struct servent *__restrict __result_buf,
+				  char *__restrict __buf, size_t __buflen,
+				  struct servent **__restrict __result);
+
+extern int __getprotoent_r (struct protoent *__restrict __result_buf,
+			    char *__restrict __buf, size_t __buflen,
+			    struct protoent **__restrict __result);
+extern int __old_getprotoent_r (struct protoent *__restrict __result_buf,
+				char *__restrict __buf, size_t __buflen,
+				struct protoent **__restrict __result);
+
+extern int __getprotobyname_r (__const char *__restrict __name,
+			       struct protoent *__restrict __result_buf,
+			       char *__restrict __buf, size_t __buflen,
+			       struct protoent **__restrict __result);
+extern int __old_getprotobyname_r (__const char *__restrict __name,
+				   struct protoent *__restrict __result_buf,
+				   char *__restrict __buf, size_t __buflen,
+				   struct protoent **__restrict __result);
+
+extern int __getprotobynumber_r (int __proto,
+				 struct protoent *__restrict __res_buf,
+				 char *__restrict __buf, size_t __buflen,
+				 struct protoent **__restrict __result);
+extern int __old_getprotobynumber_r (int __proto,
+				     struct protoent *__restrict __res_buf,
+				     char *__restrict __buf, size_t __buflen,
+				     struct protoent **__restrict __result);
+
+extern int __getnetgrent_r (char **__restrict __hostp,
+			    char **__restrict __userp,
+			    char **__restrict __domainp,
+			    char *__restrict __buffer, size_t __buflen);
+
+extern int ruserpass (const char *host, const char **aname,
+		      const char **apass);
+
+
+/* The following declarations and definitions have been removed from
+   the public header since we don't want people to use them.  */
+
+#define AI_V4MAPPED	0x0008	/* IPv4-mapped addresses are acceptable.  */
+#define AI_ALL		0x0010	/* Return both IPv4 and IPv6 addresses.	 */
+#define AI_ADDRCONFIG	0x0020	/* Use configuration of this host to choose
+				  returned address type.  */
+#define AI_DEFAULT    (AI_V4MAPPED | AI_ADDRCONFIG)
+
+#endif /* !_NETDB_H */
diff --git a/glibc-compat/include/pwd.h b/glibc-compat/include/pwd.h
new file mode 100644
index 0000000000..a0e94e6631
--- /dev/null
+++ b/glibc-compat/include/pwd.h
@@ -0,0 +1,25 @@
+#ifndef _PWD_H
+#include <pwd/pwd.h>
+
+/* Now define the internal interfaces.  */
+extern int __getpwent_r (struct passwd *__resultbuf, char *__buffer,
+			 size_t __buflen, struct passwd **__result);
+extern int __old_getpwent_r (struct passwd *__resultbuf, char *__buffer,
+			     size_t __buflen, struct passwd **__result);
+extern int __getpwuid_r (__uid_t __uid, struct passwd *__resultbuf,
+			 char *__buffer, size_t __buflen,
+			 struct passwd **__result);
+extern int __old_getpwuid_r (__uid_t __uid, struct passwd *__resultbuf,
+			     char *__buffer, size_t __buflen,
+			     struct passwd **__result);
+extern int __getpwnam_r (__const char *__name, struct passwd *__resultbuf,
+			 char *__buffer, size_t __buflen,
+			 struct passwd **__result);
+extern int __old_getpwnam_r (__const char *__name, struct passwd *__resultbuf,
+			     char *__buffer, size_t __buflen,
+			     struct passwd **__result);
+extern int __fgetpwent_r (FILE * __stream, struct passwd *__resultbuf,
+			  char *__buffer, size_t __buflen,
+			  struct passwd **__result);
+
+#endif
diff --git a/glibc-compat/include/rpc/netdb.h b/glibc-compat/include/rpc/netdb.h
new file mode 100644
index 0000000000..54a4b70052
--- /dev/null
+++ b/glibc-compat/include/rpc/netdb.h
@@ -0,0 +1,24 @@
+#ifndef _RPC_NETDB_H
+#include <sunrpc/rpc/netdb.h>
+
+extern int __getrpcbyname_r (__const char *__name, struct rpcent *__result_buf,
+			     char *__buffer, size_t __buflen,
+			     struct rpcent **__result);
+extern int __old_getrpcbyname_r (__const char *__name,
+				 struct rpcent *__result_buf,
+				 char *__buffer, size_t __buflen,
+				 struct rpcent **__result);
+
+extern int __getrpcbynumber_r (int __number, struct rpcent *__result_buf,
+			       char *__buffer, size_t __buflen,
+			       struct rpcent **__result);
+extern int __old_getrpcbynumber_r (int __number, struct rpcent *__result_buf,
+				   char *__buffer, size_t __buflen,
+				   struct rpcent **__result);
+
+extern int __getrpcent_r (struct rpcent *__result_buf, char *__buffer,
+			  size_t __buflen, struct rpcent **__result);
+extern int __old_getrpcent_r (struct rpcent *__result_buf, char *__buffer,
+			      size_t __buflen, struct rpcent **__result);
+
+#endif
diff --git a/glibc-compat/include/shadow.h b/glibc-compat/include/shadow.h
new file mode 100644
index 0000000000..e9429d7369
--- /dev/null
+++ b/glibc-compat/include/shadow.h
@@ -0,0 +1,24 @@
+#ifndef _SHADOW_H
+#include <shadow/shadow.h>
+
+/* Now define the internal interfaces.  */
+extern int __getspent_r (struct spwd *__result_buf, char *__buffer,
+			 size_t __buflen, struct spwd **__result);
+extern int __old_getspent_r (struct spwd *__result_buf, char *__buffer,
+			     size_t __buflen, struct spwd **__result);
+extern int __getspnam_r (__const char *__name, struct spwd *__result_buf,
+			 char *__buffer, size_t __buflen,
+			 struct spwd **__result);
+extern int __old_getspnam_r (__const char *__name, struct spwd *__result_buf,
+			     char *__buffer, size_t __buflen,
+			     struct spwd **__result);
+extern int __sgetspent_r (__const char *__string,
+			  struct spwd *__result_buf, char *__buffer,
+			  size_t __buflen, struct spwd **__result);
+extern int __fgetspent_r (FILE *__stream, struct spwd *__result_buf,
+			  char *__buffer, size_t __buflen,
+			  struct spwd **__result);
+extern int __lckpwdf (void);
+extern int __ulckpwdf (void);
+
+#endif
diff --git a/glibc-compat/nss-nis.h b/glibc-compat/nss-nis.h
new file mode 100644
index 0000000000..13ba62ed9f
--- /dev/null
+++ b/glibc-compat/nss-nis.h
@@ -0,0 +1,58 @@
+/* Copyright (C) 1996 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#ifndef _NIS_NSS_NIS_H
+#define _NIS_NSS_NIS_H	1
+
+#include <rpcsvc/ypclnt.h>
+
+#include "nsswitch.h"
+
+
+/* Convert YP error number to NSS error number.  */
+static enum nss_status yperr2nss_tab[] =
+{
+  [YPERR_SUCCESS] = NSS_STATUS_SUCCESS,
+  [YPERR_BADARGS] = NSS_STATUS_UNAVAIL,
+  [YPERR_RPC]     = NSS_STATUS_UNAVAIL,
+  [YPERR_DOMAIN]  = NSS_STATUS_UNAVAIL,
+  [YPERR_MAP]     = NSS_STATUS_UNAVAIL,
+  [YPERR_KEY]     = NSS_STATUS_NOTFOUND,
+  [YPERR_YPERR]   = NSS_STATUS_UNAVAIL,
+  [YPERR_RESRC]   = NSS_STATUS_TRYAGAIN,
+  [YPERR_NOMORE]  = NSS_STATUS_NOTFOUND,
+  [YPERR_PMAP]    = NSS_STATUS_UNAVAIL,
+  [YPERR_YPBIND]  = NSS_STATUS_UNAVAIL,
+  [YPERR_YPSERV]  = NSS_STATUS_UNAVAIL,
+  [YPERR_NODOM]   = NSS_STATUS_UNAVAIL,
+  [YPERR_BADDB]   = NSS_STATUS_UNAVAIL,
+  [YPERR_VERS]    = NSS_STATUS_UNAVAIL,
+  [YPERR_ACCESS]  = NSS_STATUS_UNAVAIL,
+  [YPERR_BUSY]    = NSS_STATUS_TRYAGAIN
+};
+#define YPERR_COUNT (sizeof (yperr2nss_tab) / sizeof (yperr2nss_tab[0]))
+
+static inline enum nss_status
+yperr2nss (int errval)
+{
+  if ((unsigned int) errval > YPERR_COUNT)
+    return NSS_STATUS_UNAVAIL;
+  return yperr2nss_tab[errval];
+}
+
+#endif /* nis/nss-nis.h */
diff --git a/glibc-compat/nss_compat/compat-grp.c b/glibc-compat/nss_compat/compat-grp.c
new file mode 100644
index 0000000000..d0780c4081
--- /dev/null
+++ b/glibc-compat/nss_compat/compat-grp.c
@@ -0,0 +1,769 @@
+/* Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1996.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <nss.h>
+#include <glibc-compat/include/grp.h>
+#include <ctype.h>
+#include <bits/libc-lock.h>
+#include <string.h>
+#include <rpcsvc/yp.h>
+#include <rpcsvc/ypclnt.h>
+#include <nsswitch.h>
+
+/* Get the declaration of the parser function.  */
+#define ENTNAME grent
+#define STRUCTURE group
+#define EXTERN_PARSER
+#include "../nss_files/files-parse.c"
+
+/* Structure for remembering -group members ... */
+#define BLACKLIST_INITIAL_SIZE 512
+#define BLACKLIST_INCREMENT 256
+struct blacklist_t
+  {
+    char *data;
+    int current;
+    int size;
+  };
+
+struct ent_t
+  {
+    bool_t nis;
+    bool_t nis_first;
+    char *oldkey;
+    int oldkeylen;
+    FILE *stream;
+    struct blacklist_t blacklist;
+};
+typedef struct ent_t ent_t;
+
+static ent_t ext_ent = {0, 0, NULL, 0, NULL, {NULL, 0, 0}};
+
+/* Protect global state against multiple changers.  */
+__libc_lock_define_initialized (static, lock)
+
+/* Prototypes for local functions.  */
+static void blacklist_store_name (const char *, ent_t *);
+static int in_blacklist (const char *, int, ent_t *);
+
+static enum nss_status
+internal_setgrent (ent_t *ent)
+{
+  enum nss_status status = NSS_STATUS_SUCCESS;
+
+  ent->nis = ent->nis_first = 0;
+
+  if (ent->oldkey != NULL)
+    {
+      free (ent->oldkey);
+      ent->oldkey = NULL;
+      ent->oldkeylen = 0;
+    }
+
+  if (ent->blacklist.data != NULL)
+    {
+      ent->blacklist.current = 1;
+      ent->blacklist.data[0] = '|';
+      ent->blacklist.data[1] = '\0';
+    }
+  else
+    ent->blacklist.current = 0;
+
+  if (ent->stream == NULL)
+    {
+      ent->stream = fopen ("/etc/group", "r");
+
+      if (ent->stream == NULL)
+	status = errno == EAGAIN ? NSS_STATUS_TRYAGAIN : NSS_STATUS_UNAVAIL;
+      else
+	{
+	  /* We have to make sure the file is  `closed on exec'.  */
+	  int result, flags;
+
+	  result = flags = fcntl (fileno (ent->stream), F_GETFD, 0);
+	  if (result >= 0)
+	    {
+	      flags |= FD_CLOEXEC;
+	      result = fcntl (fileno (ent->stream), F_SETFD, flags);
+	    }
+	  if (result < 0)
+	    {
+	      /* Something went wrong.  Close the stream and return a
+		 failure.  */
+	      fclose (ent->stream);
+	      ent->stream = NULL;
+	      status = NSS_STATUS_UNAVAIL;
+	    }
+	}
+    }
+  else
+    rewind (ent->stream);
+
+  return status;
+}
+
+
+enum nss_status
+_nss_compat_setgrent (void)
+{
+  enum nss_status result;
+
+  __libc_lock_lock (lock);
+
+  result = internal_setgrent (&ext_ent);
+
+  __libc_lock_unlock (lock);
+
+  return result;
+}
+
+
+static enum nss_status
+internal_endgrent (ent_t *ent)
+{
+  if (ent->stream != NULL)
+    {
+      fclose (ent->stream);
+      ent->stream = NULL;
+    }
+
+  ent->nis = ent->nis_first = 0;
+
+  if (ent->oldkey != NULL)
+    {
+      free (ent->oldkey);
+      ent->oldkey = NULL;
+      ent->oldkeylen = 0;
+    }
+
+  if (ent->blacklist.data != NULL)
+    {
+      ent->blacklist.current = 1;
+      ent->blacklist.data[0] = '|';
+      ent->blacklist.data[1] = '\0';
+    }
+  else
+    ent->blacklist.current = 0;
+
+  return NSS_STATUS_SUCCESS;
+}
+
+enum nss_status
+_nss_compat_endgrent (void)
+{
+  enum nss_status result;
+
+  __libc_lock_lock (lock);
+
+  result = internal_endgrent (&ext_ent);
+
+  __libc_lock_unlock (lock);
+
+  return result;
+}
+
+static enum nss_status
+getgrent_next_nis (struct group *result, ent_t *ent, char *buffer,
+		   size_t buflen)
+{
+  struct parser_data *data = (void *) buffer;
+  char *domain;
+  char *outkey, *outval;
+  int outkeylen, outvallen, parse_res;
+  char *p;
+
+  if (yp_get_default_domain (&domain) != YPERR_SUCCESS)
+    {
+      ent->nis = 0;
+      return NSS_STATUS_NOTFOUND;
+    }
+
+  do
+    {
+      char *save_oldkey;
+      int save_oldlen;
+      bool_t save_nis_first;
+
+      if (ent->nis_first)
+	{
+	  if (yp_first (domain, "group.byname", &outkey, &outkeylen,
+			&outval, &outvallen) != YPERR_SUCCESS)
+	    {
+	      ent->nis = 0;
+	      return NSS_STATUS_UNAVAIL;
+	    }
+	  save_oldkey = ent->oldkey;
+	  save_oldlen = ent->oldkeylen;
+	  save_nis_first = TRUE;
+	  ent->oldkey = outkey;
+	  ent->oldkeylen = outkeylen;
+	  ent->nis_first = FALSE;
+	}
+      else
+	{
+	  if (yp_next (domain, "group.byname", ent->oldkey, ent->oldkeylen,
+		       &outkey, &outkeylen, &outval, &outvallen)
+	      != YPERR_SUCCESS)
+	    {
+	      ent->nis = 0;
+	      return NSS_STATUS_NOTFOUND;
+	    }
+
+	  save_oldkey = ent->oldkey;
+	  save_oldlen = ent->oldkeylen;
+	  save_nis_first = FALSE;
+	  ent->oldkey = outkey;
+	  ent->oldkeylen = outkeylen;
+	}
+
+      /* Copy the found data to our buffer  */
+      p = strncpy (buffer, outval, buflen);
+
+      /* ...and free the data.  */
+      free (outval);
+
+      while (isspace (*p))
+	++p;
+
+      if ((parse_res = _nss_files_parse_grent (p, result, data, buflen)) == -1)
+	{
+	  free (ent->oldkey);
+	  ent->oldkey = save_oldkey;
+	  ent->oldkeylen = save_oldlen;
+	  ent->nis_first = save_nis_first;
+	  __set_errno (ERANGE);
+	  return NSS_STATUS_TRYAGAIN;
+	}
+      else
+	{
+	  if (!save_nis_first)
+	    free (save_oldkey);
+	}
+
+      if (parse_res &&
+	  in_blacklist (result->gr_name, strlen (result->gr_name), ent))
+	parse_res = 0; /* if result->gr_name in blacklist,search next entry */
+    }
+  while (!parse_res);
+
+  return NSS_STATUS_SUCCESS;
+}
+
+/* This function handle the +group entrys in /etc/group */
+static enum nss_status
+getgrnam_plusgroup (const char *name, struct group *result, char *buffer,
+		    size_t buflen)
+{
+  struct parser_data *data = (void *) buffer;
+  int parse_res;
+  char *domain, *outval, *p;
+  int outvallen;
+
+  if (yp_get_default_domain (&domain) != YPERR_SUCCESS)
+    return NSS_STATUS_NOTFOUND;
+
+  if (yp_match (domain, "group.byname", name, strlen (name),
+		&outval, &outvallen) != YPERR_SUCCESS)
+    return NSS_STATUS_NOTFOUND;
+  p = strncpy (buffer, outval,
+	       buflen < (size_t) outvallen ? buflen : (size_t) outvallen);
+  free (outval);
+  while (isspace (*p))
+    p++;
+  if ((parse_res = _nss_files_parse_grent (p, result, data, buflen)) == -1)
+    {
+      __set_errno (ERANGE);
+      return NSS_STATUS_TRYAGAIN;
+    }
+
+  if (parse_res)
+    /* We found the entry.  */
+    return NSS_STATUS_SUCCESS;
+  else
+    return NSS_STATUS_RETURN;
+}
+
+static enum nss_status
+getgrent_next_file (struct group *result, ent_t *ent,
+		    char *buffer, size_t buflen)
+{
+  struct parser_data *data = (void *) buffer;
+  while (1)
+    {
+      fpos_t pos;
+      int parse_res = 0;
+      char *p;
+
+      do
+	{
+	  fgetpos (ent->stream, &pos);
+	  buffer[buflen - 1] = '\xff';
+	  p = fgets (buffer, buflen, ent->stream);
+	  if (p == NULL && feof (ent->stream))
+	    return NSS_STATUS_NOTFOUND;
+	  if (p == NULL || buffer[buflen - 1] != '\xff')
+	    {
+	      fsetpos (ent->stream, &pos);
+	      __set_errno (ERANGE);
+	      return NSS_STATUS_TRYAGAIN;
+	    }
+
+	  /* Terminate the line for any case.  */
+	  buffer[buflen - 1] = '\0';
+
+	  /* Skip leading blanks.  */
+	  while (isspace (*p))
+	    ++p;
+	}
+      while (*p == '\0' || *p == '#' || /* Ignore empty and comment lines. */
+      /* Parse the line.  If it is invalid, loop to
+         get the next line of the file to parse.  */
+	     !(parse_res = _nss_files_parse_grent (p, result, data, buflen)));
+
+      if (parse_res == -1)
+	{
+	  /* The parser ran out of space.  */
+	  fsetpos (ent->stream, &pos);
+	  __set_errno (ERANGE);
+	  return NSS_STATUS_TRYAGAIN;
+	}
+
+      if (result->gr_name[0] != '+' && result->gr_name[0] != '-')
+	/* This is a real entry.  */
+	break;
+
+      /* -group */
+      if (result->gr_name[0] == '-' && result->gr_name[1] != '\0'
+	  && result->gr_name[1] != '@')
+	{
+	  blacklist_store_name (&result->gr_name[1], ent);
+	  continue;
+	}
+
+      /* +group */
+      if (result->gr_name[0] == '+' && result->gr_name[1] != '\0'
+	  && result->gr_name[1] != '@')
+	{
+          enum nss_status status;
+
+ 	  /* Store the group in the blacklist for the "+" at the end of
+	     /etc/group */
+	  blacklist_store_name (&result->gr_name[1], ent);
+	  status = getgrnam_plusgroup (&result->gr_name[1], result, buffer,
+				       buflen);
+          if (status == NSS_STATUS_SUCCESS) /* We found the entry. */
+            break;
+          else
+            if (status == NSS_STATUS_RETURN /* We couldn't parse the entry */
+		|| status == NSS_STATUS_NOTFOUND) /* No group in NIS */
+              continue;
+            else
+	      {
+		if (status == NSS_STATUS_TRYAGAIN)
+		  /* The parser ran out of space.  */
+		  fsetpos (ent->stream, &pos);
+		return status;
+	      }
+	}
+
+      /* +:... */
+      if (result->gr_name[0] == '+' && result->gr_name[1] == '\0')
+	{
+	  ent->nis = TRUE;
+	  ent->nis_first = TRUE;
+
+	  return getgrent_next_nis (result, ent, buffer, buflen);
+	}
+    }
+
+  return NSS_STATUS_SUCCESS;
+}
+
+
+static enum nss_status
+internal_getgrent_r (struct group *gr, ent_t *ent, char *buffer,
+		     size_t buflen)
+{
+  if (ent->nis)
+    {
+      return getgrent_next_nis (gr, ent, buffer, buflen);
+    }
+  else
+    return getgrent_next_file (gr, ent, buffer, buflen);
+}
+
+enum nss_status
+_nss_compat_getgrent_r (struct group *grp, char *buffer, size_t buflen)
+{
+  enum nss_status status = NSS_STATUS_SUCCESS;
+
+  __libc_lock_lock (lock);
+
+  /* Be prepared that the setgrent function was not called before.  */
+  if (ext_ent.stream == NULL)
+    status = internal_setgrent (&ext_ent);
+
+  if (status == NSS_STATUS_SUCCESS)
+    status = internal_getgrent_r (grp, &ext_ent, buffer, buflen);
+
+  __libc_lock_unlock (lock);
+
+  return status;
+}
+
+/* Searches in /etc/group and the NIS/NIS+ map for a special group */
+static enum nss_status
+internal_getgrnam_r (const char *name, struct group *result, ent_t *ent,
+		     char *buffer, size_t buflen)
+{
+  struct parser_data *data = (void *) buffer;
+  while (1)
+    {
+      fpos_t pos;
+      int parse_res = 0;
+      char *p;
+
+      do
+	{
+	  fgetpos (ent->stream, &pos);
+	  buffer[buflen - 1] = '\xff';
+	  p = fgets (buffer, buflen, ent->stream);
+	  if (p == NULL && feof (ent->stream))
+	    return NSS_STATUS_NOTFOUND;
+	  if (p == NULL || buffer[buflen - 1] != '\xff')
+	    {
+	      fsetpos (ent->stream, &pos);
+	      __set_errno (ERANGE);
+	      return NSS_STATUS_TRYAGAIN;
+	    }
+
+	  /* Terminate the line for any case.  */
+	  buffer[buflen - 1] = '\0';
+
+	  /* Skip leading blanks.  */
+	  while (isspace (*p))
+	    ++p;
+	}
+      while (*p == '\0' || *p == '#' || /* Ignore empty and comment lines. */
+      /* Parse the line.  If it is invalid, loop to
+         get the next line of the file to parse.  */
+	     !(parse_res = _nss_files_parse_grent (p, result, data, buflen)));
+
+      if (parse_res == -1)
+	{
+	  /* The parser ran out of space.  */
+	  fsetpos (ent->stream, &pos);
+	  __set_errno (ERANGE);
+	  return NSS_STATUS_TRYAGAIN;
+	}
+
+      /* This is a real entry.  */
+      if (result->gr_name[0] != '+' && result->gr_name[0] != '-')
+	{
+	  if (strcmp (result->gr_name, name) == 0)
+	    return NSS_STATUS_SUCCESS;
+	  else
+	    continue;
+	}
+
+      /* -group */
+      if (result->gr_name[0] == '-' && result->gr_name[1] != '\0')
+	{
+	  if (strcmp (&result->gr_name[1], name) == 0)
+	    return NSS_STATUS_NOTFOUND;
+	  else
+	    continue;
+	}
+
+      /* +group */
+      if (result->gr_name[0] == '+' && result->gr_name[1] != '\0')
+	{
+	  if (strcmp (name, &result->gr_name[1]) == 0)
+	    {
+	      enum nss_status status;
+
+	      status = getgrnam_plusgroup (name, result, buffer, buflen);
+	      if (status == NSS_STATUS_RETURN)
+		/* We couldn't parse the entry */
+		continue;
+	      else
+		return status;
+	    }
+	}
+      /* +:... */
+      if (result->gr_name[0] == '+' && result->gr_name[1] == '\0')
+	{
+	  enum nss_status status;
+
+	  status = getgrnam_plusgroup (name, result, buffer, buflen);
+	  if (status == NSS_STATUS_RETURN)
+	    /* We couldn't parse the entry */
+	    continue;
+	  else
+	    return status;
+	}
+    }
+
+  return NSS_STATUS_SUCCESS;
+}
+
+enum nss_status
+_nss_compat_getgrnam_r (const char *name, struct group *grp,
+			char *buffer, size_t buflen)
+{
+  ent_t ent = {0, 0, NULL, 0, NULL, {NULL, 0, 0}};
+  enum nss_status status;
+
+  if (name[0] == '-' || name[0] == '+')
+    return NSS_STATUS_NOTFOUND;
+
+  __libc_lock_lock (lock);
+
+  status = internal_setgrent (&ent);
+
+  __libc_lock_unlock (lock);
+
+  if (status != NSS_STATUS_SUCCESS)
+    return status;
+
+  status = internal_getgrnam_r (name, grp, &ent, buffer, buflen);
+
+  internal_endgrent (&ent);
+
+  return status;
+}
+
+/* This function handle the + entry in /etc/group */
+static enum nss_status
+getgrgid_plusgroup (gid_t gid, struct group *result, char *buffer,
+		    size_t buflen)
+{
+  struct parser_data *data = (void *) buffer;
+  int parse_res;
+  char buf[1024];
+  char *domain, *outval, *p;
+  int outvallen;
+
+  if (yp_get_default_domain (&domain) != YPERR_SUCCESS)
+    return NSS_STATUS_TRYAGAIN;
+
+  snprintf (buf, sizeof (buf), "%d", gid);
+
+  if (yp_match (domain, "group.bygid", buf, strlen (buf),
+		&outval, &outvallen) != YPERR_SUCCESS)
+    return NSS_STATUS_TRYAGAIN;
+  p = strncpy (buffer, outval,
+	       buflen < (size_t) outvallen ? buflen : (size_t) outvallen);
+  free (outval);
+  while (isspace (*p))
+    p++;
+  if ((parse_res = _nss_files_parse_grent (p, result, data, buflen)) == -1)
+    {
+      __set_errno (ERANGE);
+      return NSS_STATUS_TRYAGAIN;
+    }
+
+  if (parse_res)
+    /* We found the entry.  */
+    return NSS_STATUS_SUCCESS;
+  else
+    return NSS_STATUS_RETURN;
+}
+
+/* Searches in /etc/group and the NIS/NIS+ map for a special group id */
+static enum nss_status
+internal_getgrgid_r (gid_t gid, struct group *result, ent_t *ent,
+		     char *buffer, size_t buflen)
+{
+  struct parser_data *data = (void *) buffer;
+  while (1)
+    {
+      fpos_t pos;
+      int parse_res = 0;
+      char *p;
+
+      do
+	{
+	  fgetpos (ent->stream, &pos);
+	  buffer[buflen - 1] = '\xff';
+	  p = fgets (buffer, buflen, ent->stream);
+	  if (p == NULL && feof (ent->stream))
+	    return NSS_STATUS_NOTFOUND;
+	  if (p == NULL || buffer[buflen - 1] != '\xff')
+	    {
+	      fsetpos (ent->stream, &pos);
+	      __set_errno (ERANGE);
+	      return NSS_STATUS_TRYAGAIN;
+	    }
+
+	  /* Terminate the line for any case.  */
+	  buffer[buflen - 1] = '\0';
+
+	  /* Skip leading blanks.  */
+	  while (isspace (*p))
+	    ++p;
+	}
+      while (*p == '\0' || *p == '#' || /* Ignore empty and comment lines. */
+      /* Parse the line.  If it is invalid, loop to
+         get the next line of the file to parse.  */
+	     !(parse_res = _nss_files_parse_grent (p, result, data, buflen)));
+
+      if (parse_res == -1)
+	{
+	  /* The parser ran out of space.  */
+	  fsetpos (ent->stream, &pos);
+	  __set_errno (ERANGE);
+	  return NSS_STATUS_TRYAGAIN;
+	}
+
+      /* This is a real entry.  */
+      if (result->gr_name[0] != '+' && result->gr_name[0] != '-')
+	{
+	  if (result->gr_gid == gid)
+	    return NSS_STATUS_SUCCESS;
+	  else
+	    continue;
+	}
+
+      /* -group */
+      if (result->gr_name[0] == '-' && result->gr_name[1] != '\0')
+	{
+          blacklist_store_name (&result->gr_name[1], ent);
+          continue;
+	}
+
+      /* +group */
+      if (result->gr_name[0] == '+' && result->gr_name[1] != '\0')
+	{
+	  enum nss_status status;
+
+	  /* Store the group in the blacklist for the "+" at the end of
+             /etc/group */
+          blacklist_store_name (&result->gr_name[1], ent);
+	  status = getgrnam_plusgroup (&result->gr_name[1], result, buffer,
+				      buflen);
+	  if (status == NSS_STATUS_SUCCESS && result->gr_gid == gid)
+	    break;
+	  else
+	    continue;
+	}
+      /* +:... */
+      if (result->gr_name[0] == '+' && result->gr_name[1] == '\0')
+	{
+	  enum nss_status status;
+
+	  status = getgrgid_plusgroup (gid, result, buffer, buflen);
+	  if (status == NSS_STATUS_RETURN) /* We couldn't parse the entry */
+	    return NSS_STATUS_NOTFOUND;
+	  else
+	    return status;
+	}
+    }
+
+  return NSS_STATUS_SUCCESS;
+}
+
+enum nss_status
+_nss_compat_getgrgid_r (gid_t gid, struct group *grp,
+			char *buffer, size_t buflen)
+{
+  ent_t ent = {0, 0, NULL, 0, NULL, {NULL, 0, 0}};
+  enum nss_status status;
+
+  __libc_lock_lock (lock);
+
+  status = internal_setgrent (&ent);
+
+  __libc_lock_unlock (lock);
+
+  if (status != NSS_STATUS_SUCCESS)
+    return status;
+
+  status = internal_getgrgid_r (gid, grp, &ent, buffer, buflen);
+
+  internal_endgrent (&ent);
+
+  return status;
+}
+
+
+/* Support routines for remembering -@netgroup and -user entries.
+   The names are stored in a single string with `|' as separator. */
+static void
+blacklist_store_name (const char *name, ent_t *ent)
+{
+  int namelen = strlen (name);
+  char *tmp;
+
+  /* first call, setup cache */
+  if (ent->blacklist.size == 0)
+    {
+      ent->blacklist.size = MAX (BLACKLIST_INITIAL_SIZE, 2 * namelen);
+      ent->blacklist.data = malloc (ent->blacklist.size);
+      if (ent->blacklist.data == NULL)
+	return;
+      ent->blacklist.data[0] = '|';
+      ent->blacklist.data[1] = '\0';
+      ent->blacklist.current = 1;
+    }
+  else
+    {
+      if (in_blacklist (name, namelen, ent))
+	return;			/* no duplicates */
+
+      if (ent->blacklist.current + namelen + 1 >= ent->blacklist.size)
+	{
+	  ent->blacklist.size += MAX (BLACKLIST_INCREMENT, 2 * namelen);
+	  tmp = realloc (ent->blacklist.data, ent->blacklist.size);
+	  if (tmp == NULL)
+	    {
+	      free (ent->blacklist.data);
+	      ent->blacklist.size = 0;
+	      return;
+	    }
+	  ent->blacklist.data = tmp;
+	}
+    }
+
+  tmp = stpcpy (ent->blacklist.data + ent->blacklist.current, name);
+  *tmp++ = '|';
+  *tmp = '\0';
+  ent->blacklist.current += namelen + 1;
+
+  return;
+}
+
+/* returns TRUE if ent->blacklist contains name, else FALSE */
+static bool_t
+in_blacklist (const char *name, int namelen, ent_t *ent)
+{
+  char buf[namelen + 3];
+  char *cp;
+
+  if (ent->blacklist.data == NULL)
+    return FALSE;
+
+  buf[0] = '|';
+  cp = stpcpy (&buf[1], name);
+  *cp++= '|';
+  *cp = '\0';
+  return strstr (ent->blacklist.data, buf) != NULL;
+}
diff --git a/glibc-compat/nss_compat/compat-pwd.c b/glibc-compat/nss_compat/compat-pwd.c
new file mode 100644
index 0000000000..5857bf9f78
--- /dev/null
+++ b/glibc-compat/nss_compat/compat-pwd.c
@@ -0,0 +1,1199 @@
+/* Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1996.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include <nss.h>
+#include <glibc-compat/include/pwd.h>
+#include <errno.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <glibc-compat/include/netdb.h>
+#include <string.h>
+#include <bits/libc-lock.h>
+#include <rpcsvc/yp.h>
+#include <rpcsvc/ypclnt.h>
+#include <nsswitch.h>
+
+#include "netgroup.h"
+
+/* Get the declaration of the parser function.  */
+#define ENTNAME pwent
+#define STRUCTURE passwd
+#define EXTERN_PARSER
+#include "../nss_files/files-parse.c"
+
+/* Structure for remembering -@netgroup and -user members ... */
+#define BLACKLIST_INITIAL_SIZE 512
+#define BLACKLIST_INCREMENT 256
+struct blacklist_t
+  {
+    char *data;
+    int current;
+    int size;
+  };
+
+struct ent_t
+  {
+    bool_t netgroup;
+    bool_t nis;
+    bool_t first;
+    char *oldkey;
+    int oldkeylen;
+    FILE *stream;
+    struct blacklist_t blacklist;
+    struct passwd pwd;
+    struct __netgrent netgrdata;
+  };
+typedef struct ent_t ent_t;
+
+static ent_t ext_ent = {0, 0, 0, NULL, 0, NULL, {NULL, 0, 0},
+			{NULL, NULL, 0, 0, NULL, NULL, NULL}};
+
+/* Protect global state against multiple changers.  */
+__libc_lock_define_initialized (static, lock)
+
+/* Prototypes for local functions.  */
+static void blacklist_store_name (const char *, ent_t *);
+static int in_blacklist (const char *, int, ent_t *);
+
+static void
+give_pwd_free (struct passwd *pwd)
+{
+  if (pwd->pw_name != NULL)
+    free (pwd->pw_name);
+  if (pwd->pw_passwd != NULL)
+    free (pwd->pw_passwd);
+  if (pwd->pw_gecos != NULL)
+    free (pwd->pw_gecos);
+  if (pwd->pw_dir != NULL)
+    free (pwd->pw_dir);
+  if (pwd->pw_shell != NULL)
+    free (pwd->pw_shell);
+
+  memset (pwd, '\0', sizeof (struct passwd));
+}
+
+static size_t
+pwd_need_buflen (struct passwd *pwd)
+{
+  size_t len = 0;
+
+  if (pwd->pw_passwd != NULL)
+    len += strlen (pwd->pw_passwd) + 1;
+
+  if (pwd->pw_gecos != NULL)
+    len += strlen (pwd->pw_gecos) + 1;
+
+  if (pwd->pw_dir != NULL)
+    len += strlen (pwd->pw_dir) + 1;
+
+  if (pwd->pw_shell != NULL)
+    len += strlen (pwd->pw_shell) + 1;
+
+  return len;
+}
+
+static void
+copy_pwd_changes (struct passwd *dest, struct passwd *src,
+		  char *buffer, size_t buflen)
+{
+  if (src->pw_passwd != NULL && strlen (src->pw_passwd))
+    {
+      if (buffer == NULL)
+	dest->pw_passwd = strdup (src->pw_passwd);
+      else if (dest->pw_passwd &&
+	       strlen (dest->pw_passwd) >= strlen (src->pw_passwd))
+	strcpy (dest->pw_passwd, src->pw_passwd);
+      else
+	{
+	  dest->pw_passwd = buffer;
+	  strcpy (dest->pw_passwd, src->pw_passwd);
+	  buffer += strlen (dest->pw_passwd) + 1;
+	  buflen = buflen - (strlen (dest->pw_passwd) + 1);
+	}
+    }
+
+  if (src->pw_gecos != NULL && strlen (src->pw_gecos))
+    {
+      if (buffer == NULL)
+	dest->pw_gecos = strdup (src->pw_gecos);
+      else if (dest->pw_gecos &&
+	       strlen (dest->pw_gecos) >= strlen (src->pw_gecos))
+	strcpy (dest->pw_gecos, src->pw_gecos);
+      else
+	{
+	  dest->pw_gecos = buffer;
+	  strcpy (dest->pw_gecos, src->pw_gecos);
+	  buffer += strlen (dest->pw_gecos) + 1;
+	  buflen = buflen - (strlen (dest->pw_gecos) + 1);
+	}
+    }
+  if (src->pw_dir != NULL && strlen (src->pw_dir))
+    {
+      if (buffer == NULL)
+	dest->pw_dir = strdup (src->pw_dir);
+      else if (dest->pw_dir &&
+	       strlen (dest->pw_dir) >= strlen (src->pw_dir))
+	strcpy (dest->pw_dir, src->pw_dir);
+      else
+	{
+	  dest->pw_dir = buffer;
+	  strcpy (dest->pw_dir, src->pw_dir);
+	  buffer += strlen (dest->pw_dir) + 1;
+	  buflen = buflen - (strlen (dest->pw_dir) + 1);
+	}
+    }
+
+  if (src->pw_shell != NULL && strlen (src->pw_shell))
+    {
+      if (buffer == NULL)
+	dest->pw_shell = strdup (src->pw_shell);
+      else if (dest->pw_shell &&
+	       strlen (dest->pw_shell) >= strlen (src->pw_shell))
+	strcpy (dest->pw_shell, src->pw_shell);
+      else
+	{
+	  dest->pw_shell = buffer;
+	  strcpy (dest->pw_shell, src->pw_shell);
+	  buffer += strlen (dest->pw_shell) + 1;
+	  buflen = buflen - (strlen (dest->pw_shell) + 1);
+	}
+    }
+}
+
+static enum nss_status
+internal_setpwent (ent_t *ent)
+{
+  enum nss_status status = NSS_STATUS_SUCCESS;
+
+  ent->nis = ent->first = ent->netgroup = 0;
+
+  /* If something was left over free it.  */
+  if (ent->netgroup)
+    __internal_endnetgrent (&ent->netgrdata);
+
+  if (ent->oldkey != NULL)
+    {
+      free (ent->oldkey);
+      ent->oldkey = NULL;
+      ent->oldkeylen = 0;
+    }
+
+  if (ent->blacklist.data != NULL)
+    {
+      ent->blacklist.current = 1;
+      ent->blacklist.data[0] = '|';
+      ent->blacklist.data[1] = '\0';
+    }
+  else
+    ent->blacklist.current = 0;
+
+  if (ent->stream == NULL)
+    {
+      ent->stream = fopen ("/etc/passwd", "r");
+
+      if (ent->stream == NULL)
+	status = errno == EAGAIN ? NSS_STATUS_TRYAGAIN : NSS_STATUS_UNAVAIL;
+      else
+	{
+	  /* We have to make sure the file is  `closed on exec'.  */
+	  int result, flags;
+
+	  result = flags = fcntl (fileno (ent->stream), F_GETFD, 0);
+	  if (result >= 0)
+	    {
+	      flags |= FD_CLOEXEC;
+	      result = fcntl (fileno (ent->stream), F_SETFD, flags);
+	    }
+	  if (result < 0)
+	    {
+	      /* Something went wrong.  Close the stream and return a
+		 failure.  */
+	      fclose (ent->stream);
+	      ent->stream = NULL;
+	      status = NSS_STATUS_UNAVAIL;
+	    }
+	}
+    }
+  else
+    rewind (ent->stream);
+
+  give_pwd_free (&ent->pwd);
+
+  return status;
+}
+
+
+enum nss_status
+_nss_compat_setpwent (void)
+{
+  enum nss_status result;
+
+  __libc_lock_lock (lock);
+
+  result = internal_setpwent (&ext_ent);
+
+  __libc_lock_unlock (lock);
+
+  return result;
+}
+
+
+static enum nss_status
+internal_endpwent (ent_t *ent)
+{
+  if (ent->stream != NULL)
+    {
+      fclose (ent->stream);
+      ent->stream = NULL;
+    }
+
+  if (ent->netgroup)
+    __internal_endnetgrent (&ent->netgrdata);
+
+  ent->nis = ent->first = ent->netgroup = 0;
+
+  if (ent->oldkey != NULL)
+    {
+      free (ent->oldkey);
+      ent->oldkey = NULL;
+      ent->oldkeylen = 0;
+    }
+
+  if (ent->blacklist.data != NULL)
+    {
+      ent->blacklist.current = 1;
+      ent->blacklist.data[0] = '|';
+      ent->blacklist.data[1] = '\0';
+    }
+  else
+    ent->blacklist.current = 0;
+
+  give_pwd_free (&ent->pwd);
+
+  return NSS_STATUS_SUCCESS;
+}
+
+enum nss_status
+_nss_compat_endpwent (void)
+{
+  enum nss_status result;
+
+  __libc_lock_lock (lock);
+
+  result = internal_endpwent (&ext_ent);
+
+  __libc_lock_unlock (lock);
+
+  return result;
+}
+
+static enum nss_status
+getpwent_next_nis_netgr (const char *name, struct passwd *result, ent_t *ent,
+			 char *group, char *buffer, size_t buflen)
+{
+  struct parser_data *data = (void *) buffer;
+  char *ypdomain, *host, *user, *domain, *outval, *p, *p2;
+  int status, outvallen;
+  size_t p2len;
+
+  if (yp_get_default_domain (&ypdomain) != YPERR_SUCCESS)
+    {
+      ent->netgroup = 0;
+      ent->first = 0;
+      give_pwd_free (&ent->pwd);
+      return NSS_STATUS_UNAVAIL;
+    }
+
+  if (ent->first == TRUE)
+    {
+      memset (&ent->netgrdata, 0, sizeof (struct __netgrent));
+      __internal_setnetgrent (group, &ent->netgrdata);
+      ent->first = FALSE;
+    }
+
+  while (1)
+    {
+      char *saved_cursor;
+      int parse_res;
+
+      saved_cursor = ent->netgrdata.cursor;
+      status = __internal_getnetgrent_r (&host, &user, &domain,
+					 &ent->netgrdata, buffer, buflen,
+					 &errno);
+      if (status != 1)
+	{
+	  __internal_endnetgrent (&ent->netgrdata);
+	  ent->netgroup = 0;
+	  give_pwd_free (&ent->pwd);
+	  return NSS_STATUS_RETURN;
+	}
+
+      if (user == NULL || user[0] == '-')
+	continue;
+
+      if (domain != NULL && strcmp (ypdomain, domain) != 0)
+	continue;
+
+      /* If name != NULL, we are called from getpwnam */
+      if (name != NULL)
+	if (strcmp (user, name) != 0)
+	  continue;
+
+      if (yp_match (ypdomain, "passwd.byname", user,
+		    strlen (user), &outval, &outvallen)
+	  != YPERR_SUCCESS)
+	continue;
+
+      p2len = pwd_need_buflen (&ent->pwd);
+      if (p2len > buflen)
+	{
+	  __set_errno (ERANGE);
+	  return NSS_STATUS_TRYAGAIN;
+	}
+      p2 = buffer + (buflen - p2len);
+      buflen -= p2len;
+      p = strncpy (buffer, outval, buflen);
+      while (isspace (*p))
+	p++;
+      free (outval);
+      if ((parse_res = _nss_files_parse_pwent (p, result, data, buflen)) == -1)
+	{
+	  ent->netgrdata.cursor = saved_cursor;
+	  return NSS_STATUS_TRYAGAIN;
+	}
+
+      if (parse_res)
+	{
+	  /* Store the User in the blacklist for the "+" at the end of
+	     /etc/passwd */
+	  blacklist_store_name (result->pw_name, ent);
+	  copy_pwd_changes (result, &ent->pwd, p2, p2len);
+	  break;
+	}
+    }
+
+  return NSS_STATUS_SUCCESS;
+}
+
+static enum nss_status
+getpwent_next_nis (struct passwd *result, ent_t *ent, char *buffer,
+		   size_t buflen)
+{
+  struct parser_data *data = (void *) buffer;
+  char *domain, *outkey, *outval, *p, *p2;
+  int outkeylen, outvallen, parse_res;
+  size_t p2len;
+
+  if (yp_get_default_domain (&domain) != YPERR_SUCCESS)
+    {
+      ent->nis = 0;
+      give_pwd_free (&ent->pwd);
+      return NSS_STATUS_UNAVAIL;
+    }
+
+  p2len = pwd_need_buflen (&ent->pwd);
+  if (p2len > buflen)
+    {
+      __set_errno (ERANGE);
+      return NSS_STATUS_TRYAGAIN;
+    }
+  p2 = buffer + (buflen - p2len);
+  buflen -= p2len;
+  do
+    {
+      bool_t saved_first;
+      char *saved_oldkey;
+      int saved_oldlen;
+
+      if (ent->first)
+	{
+	  if (yp_first (domain, "passwd.byname", &outkey, &outkeylen,
+			&outval, &outvallen) != YPERR_SUCCESS)
+	    {
+	      ent->nis = 0;
+	      give_pwd_free (&ent->pwd);
+	      return NSS_STATUS_UNAVAIL;
+	    }
+
+	  saved_first = TRUE;
+	  saved_oldkey = ent->oldkey;
+	  saved_oldlen = ent->oldkeylen;
+	  ent->oldkey = outkey;
+	  ent->oldkeylen = outkeylen;
+	  ent->first = FALSE;
+	}
+      else
+	{
+	  if (yp_next (domain, "passwd.byname", ent->oldkey, ent->oldkeylen,
+		       &outkey, &outkeylen, &outval, &outvallen)
+	      != YPERR_SUCCESS)
+	    {
+	      ent->nis = 0;
+	      give_pwd_free (&ent->pwd);
+	      return NSS_STATUS_NOTFOUND;
+	    }
+
+	  saved_first = FALSE;
+	  saved_oldkey = ent->oldkey;
+	  saved_oldlen = ent->oldkeylen;
+	  ent->oldkey = outkey;
+	  ent->oldkeylen = outkeylen;
+	}
+
+      /* Copy the found data to our buffer  */
+      p = strncpy (buffer, outval, buflen);
+
+      /* ...and free the data.  */
+      free (outval);
+
+      while (isspace (*p))
+	++p;
+      if ((parse_res = _nss_files_parse_pwent (p, result, data, buflen)) == -1)
+	{
+	  free (ent->oldkey);
+	  ent->oldkey = saved_oldkey;
+	  ent->oldkeylen = saved_oldlen;
+	  ent->first = saved_first;
+	  __set_errno (ERANGE);
+	  return NSS_STATUS_TRYAGAIN;
+	}
+      else
+	{
+	  if (!saved_first)
+	    free (saved_oldkey);
+	}
+      if (parse_res &&
+	  in_blacklist (result->pw_name, strlen (result->pw_name), ent))
+	parse_res = 0;
+    }
+  while (!parse_res);
+
+  copy_pwd_changes (result, &ent->pwd, p2, p2len);
+
+  return NSS_STATUS_SUCCESS;
+}
+
+/* This function handle the +user entrys in /etc/passwd */
+static enum nss_status
+getpwnam_plususer (const char *name, struct passwd *result, char *buffer,
+		   size_t buflen)
+{
+  struct parser_data *data = (void *) buffer;
+  struct passwd pwd;
+  int parse_res;
+  char *p;
+  size_t plen;
+  char *domain, *outval, *ptr;
+  int outvallen;
+
+  memset (&pwd, '\0', sizeof (struct passwd));
+
+  copy_pwd_changes (&pwd, result, NULL, 0);
+
+  plen = pwd_need_buflen (&pwd);
+  if (plen > buflen)
+    {
+      __set_errno (ERANGE);
+      return NSS_STATUS_TRYAGAIN;
+    }
+  p = buffer + (buflen - plen);
+  buflen -= plen;
+
+
+  if (yp_get_default_domain (&domain) != YPERR_SUCCESS)
+    return NSS_STATUS_NOTFOUND;
+
+  if (yp_match (domain, "passwd.byname", name, strlen (name),
+		&outval, &outvallen) != YPERR_SUCCESS)
+    return NSS_STATUS_NOTFOUND;
+  ptr = strncpy (buffer, outval, buflen < (size_t) outvallen ?
+		 buflen : (size_t) outvallen);
+  buffer[buflen < (size_t) outvallen ? buflen : (size_t) outvallen] = '\0';
+  free (outval);
+  while (isspace (*ptr))
+    ptr++;
+  if ((parse_res = _nss_files_parse_pwent (ptr, result, data, buflen))
+      == -1)
+    {
+      __set_errno (ERANGE);
+      return NSS_STATUS_TRYAGAIN;
+    }
+
+  if (parse_res > 0)
+    {
+      copy_pwd_changes (result, &pwd, p, plen);
+      give_pwd_free (&pwd);
+      /* We found the entry.  */
+      return NSS_STATUS_SUCCESS;
+    }
+  else
+    {
+      /* Give buffer the old len back */
+      buflen += plen;
+      give_pwd_free (&pwd);
+    }
+  return NSS_STATUS_RETURN;
+}
+
+/* get the next user from NIS+  (+ entry) */
+static enum nss_status
+getpwent_next_file (struct passwd *result, ent_t *ent,
+		    char *buffer, size_t buflen)
+{
+  struct parser_data *data = (void *) buffer;
+  while (1)
+    {
+      fpos_t pos;
+      char *p;
+      int parse_res;
+
+      do
+	{
+	  fgetpos (ent->stream, &pos);
+	  buffer[buflen - 1] = '\xff';
+	  p = fgets (buffer, buflen, ent->stream);
+	  if (p == NULL && feof (ent->stream))
+	    return NSS_STATUS_NOTFOUND;
+	  if (p == NULL || buffer[buflen - 1] != '\xff')
+	    {
+	      fsetpos (ent->stream, &pos);
+	      __set_errno (ERANGE);
+	      return NSS_STATUS_TRYAGAIN;
+ 	    }
+
+	  /* Terminate the line for any case.  */
+	  buffer[buflen - 1] = '\0';
+
+	  /* Skip leading blanks.  */
+	  while (isspace (*p))
+	    ++p;
+	}
+      while (*p == '\0' || *p == '#' || /* Ignore empty and comment lines.  */
+      /* Parse the line.  If it is invalid, loop to
+         get the next line of the file to parse.  */
+	     !(parse_res = _nss_files_parse_pwent (p, result, data, buflen)));
+
+      if (parse_res == -1)
+	{
+	  /* The parser ran out of space.  */
+	  fsetpos (ent->stream, &pos);
+	  __set_errno (ERANGE);
+	  return NSS_STATUS_TRYAGAIN;
+	}
+
+      if (result->pw_name[0] != '+' && result->pw_name[0] != '-')
+	/* This is a real entry.  */
+	break;
+
+      /* -@netgroup */
+      if (result->pw_name[0] == '-' && result->pw_name[1] == '@'
+	  && result->pw_name[2] != '\0')
+	{
+	  char buf2[1024];
+	  char *user, *host, *domain;
+	  struct __netgrent netgrdata;
+
+	  bzero (&netgrdata, sizeof (struct __netgrent));
+	  __internal_setnetgrent (&result->pw_name[2], &netgrdata);
+	  while (__internal_getnetgrent_r (&host, &user, &domain,
+					   &netgrdata, buf2, sizeof (buf2),
+					   &errno))
+	    {
+	      if (user != NULL && user[0] != '-')
+		blacklist_store_name (user, ent);
+	    }
+	  __internal_endnetgrent (&netgrdata);
+	  continue;
+	}
+
+      /* +@netgroup */
+      if (result->pw_name[0] == '+' && result->pw_name[1] == '@'
+	  && result->pw_name[2] != '\0')
+	{
+	  int status;
+
+	  ent->netgroup = TRUE;
+	  ent->first = TRUE;
+	  copy_pwd_changes (&ent->pwd, result, NULL, 0);
+
+	  status =  getpwent_next_nis_netgr (NULL, result, ent,
+					     &result->pw_name[2],
+					     buffer, buflen);
+	  if (status == NSS_STATUS_RETURN)
+	    continue;
+	  else
+	    return status;
+	}
+
+      /* -user */
+      if (result->pw_name[0] == '-' && result->pw_name[1] != '\0'
+	  && result->pw_name[1] != '@')
+	{
+	  blacklist_store_name (&result->pw_name[1], ent);
+	  continue;
+	}
+
+      /* +user */
+      if (result->pw_name[0] == '+' && result->pw_name[1] != '\0'
+	  && result->pw_name[1] != '@')
+	{
+	  enum nss_status status;
+
+	  /* Store the User in the blacklist for the "+" at the end of
+	     /etc/passwd */
+	  blacklist_store_name (&result->pw_name[1], ent);
+	  status = getpwnam_plususer (&result->pw_name[1], result, buffer,
+				      buflen);
+	  if (status == NSS_STATUS_SUCCESS) /* We found the entry. */
+	    break;
+	  else
+	    if (status == NSS_STATUS_RETURN) /* We couldn't parse the entry */
+	      continue;
+	    else
+	      return status;
+	}
+
+      /* +:... */
+      if (result->pw_name[0] == '+' && result->pw_name[1] == '\0')
+	{
+	  ent->nis = TRUE;
+	  ent->first = TRUE;
+	  copy_pwd_changes (&ent->pwd, result, NULL, 0);
+
+	  return getpwent_next_nis (result, ent, buffer, buflen);
+	}
+    }
+
+  return NSS_STATUS_SUCCESS;
+}
+
+
+/* get the next user from NIS (+ entry) */
+static enum nss_status
+internal_getpwent_r (struct passwd *pw, ent_t *ent, char *buffer,
+		     size_t buflen)
+{
+  if (ent->netgroup)
+    {
+      int status;
+
+      /* We are searching members in a netgroup */
+      /* Since this is not the first call, we don't need the group name */
+      status = getpwent_next_nis_netgr (NULL, pw, ent, NULL, buffer, buflen);
+      if (status == NSS_STATUS_RETURN)
+	return getpwent_next_file (pw, ent, buffer, buflen);
+      else
+	return status;
+    }
+  else
+    if (ent->nis)
+      {
+	return getpwent_next_nis (pw, ent, buffer, buflen);
+      }
+    else
+      return getpwent_next_file (pw, ent, buffer, buflen);
+}
+
+enum nss_status
+_nss_compat_getpwent_r (struct passwd *pwd, char *buffer, size_t buflen)
+{
+  enum nss_status status = NSS_STATUS_SUCCESS;
+
+  __libc_lock_lock (lock);
+
+  /* Be prepared that the setpwent function was not called before.  */
+  if (ext_ent.stream == NULL)
+    status = internal_setpwent (&ext_ent);
+
+  if (status == NSS_STATUS_SUCCESS)
+    status = internal_getpwent_r (pwd, &ext_ent, buffer, buflen);
+
+  __libc_lock_unlock (lock);
+
+  return status;
+}
+
+/* Searches in /etc/passwd and the NIS/NIS+ map for a special user */
+static enum nss_status
+internal_getpwnam_r (const char *name, struct passwd *result, ent_t *ent,
+		     char *buffer, size_t buflen)
+{
+  struct parser_data *data = (void *) buffer;
+
+  while (1)
+    {
+      fpos_t pos;
+      char *p;
+      int parse_res;
+
+      do
+	{
+	  fgetpos (ent->stream, &pos);
+	  buffer[buflen - 1] = '\xff';
+	  p = fgets (buffer, buflen, ent->stream);
+	  if (p == NULL && feof (ent->stream))
+	    return NSS_STATUS_NOTFOUND;
+	  if (p == NULL || buffer[buflen - 1] != '\xff')
+	    {
+	      fsetpos (ent->stream, &pos);
+	      __set_errno (ERANGE);
+	      return NSS_STATUS_TRYAGAIN;
+	    }
+
+	  /* Terminate the line for any case.  */
+	  buffer[buflen - 1] = '\0';
+
+	  /* Skip leading blanks.  */
+	  while (isspace (*p))
+	    ++p;
+	}
+      while (*p == '\0' || *p == '#' || /* Ignore empty and comment lines.  */
+	     /* Parse the line.  If it is invalid, loop to
+		get the next line of the file to parse.  */
+	     !(parse_res = _nss_files_parse_pwent (p, result, data, buflen)));
+
+      if (parse_res == -1)
+	{
+	  /* The parser ran out of space.  */
+	  fsetpos (ent->stream, &pos);
+	  __set_errno (ERANGE);
+	  return NSS_STATUS_TRYAGAIN;
+	}
+
+      /* This is a real entry.  */
+      if (result->pw_name[0] != '+' && result->pw_name[0] != '-')
+	{
+	  if (strcmp (result->pw_name, name) == 0)
+	    return NSS_STATUS_SUCCESS;
+	  else
+	    continue;
+	}
+
+      /* -@netgroup */
+      if (result->pw_name[0] == '-' && result->pw_name[1] == '@'
+	  && result->pw_name[2] != '\0')
+	{
+	  char buf2[1024];
+	  char *user, *host, *domain;
+	  struct __netgrent netgrdata;
+
+	  bzero (&netgrdata, sizeof (struct __netgrent));
+	  __internal_setnetgrent (&result->pw_name[2], &netgrdata);
+	  while (__internal_getnetgrent_r (&host, &user, &domain,
+					   &netgrdata, buf2, sizeof (buf2),
+					   &errno))
+	    {
+	      if (user != NULL && user[0] != '-')
+		if (strcmp (user, name) == 0)
+		  return NSS_STATUS_NOTFOUND;
+	    }
+	  __internal_endnetgrent (&netgrdata);
+	  continue;
+	}
+
+      /* +@netgroup */
+      if (result->pw_name[0] == '+' && result->pw_name[1] == '@'
+	  && result->pw_name[2] != '\0')
+	{
+	  char buf[strlen (result->pw_name)];
+	  int status;
+
+	  strcpy (buf, &result->pw_name[2]);
+	  ent->netgroup = TRUE;
+	  ent->first = TRUE;
+	  copy_pwd_changes (&ent->pwd, result, NULL, 0);
+
+	  do
+	    {
+	      status = getpwent_next_nis_netgr (name, result, ent, buf,
+						buffer, buflen);
+	      if (status == NSS_STATUS_RETURN)
+		continue;
+
+	      if (status == NSS_STATUS_SUCCESS &&
+		  strcmp (result->pw_name, name) == 0)
+		return NSS_STATUS_SUCCESS;
+	    } while (status == NSS_STATUS_SUCCESS);
+	  continue;
+	}
+
+      /* -user */
+      if (result->pw_name[0] == '-' && result->pw_name[1] != '\0'
+	  && result->pw_name[1] != '@')
+	{
+	  if (strcmp (&result->pw_name[1], name) == 0)
+	    return NSS_STATUS_NOTFOUND;
+	  else
+	    continue;
+	}
+
+      /* +user */
+      if (result->pw_name[0] == '+' && result->pw_name[1] != '\0'
+	  && result->pw_name[1] != '@')
+	{
+	  if (strcmp (name, &result->pw_name[1]) == 0)
+	    {
+	      enum nss_status status;
+
+	      status = getpwnam_plususer (name, result, buffer, buflen);
+	      if (status == NSS_STATUS_RETURN)
+		/* We couldn't parse the entry */
+		return NSS_STATUS_NOTFOUND;
+	      else
+		return status;
+	    }
+	}
+
+      /* +:... */
+      if (result->pw_name[0] == '+' && result->pw_name[1] == '\0')
+	{
+	  enum nss_status status;
+
+	  status = getpwnam_plususer (name, result, buffer, buflen);
+	  if (status == NSS_STATUS_SUCCESS) /* We found the entry. */
+	    break;
+	  else
+	    if (status == NSS_STATUS_RETURN) /* We couldn't parse the entry */
+	      return NSS_STATUS_NOTFOUND;
+	    else
+	      return status;
+	}
+    }
+  return NSS_STATUS_SUCCESS;
+}
+
+enum nss_status
+_nss_compat_getpwnam_r (const char *name, struct passwd *pwd,
+			char *buffer, size_t buflen)
+{
+  ent_t ent = {0, 0, 0, NULL, 0, NULL, {NULL, 0, 0},
+	       {NULL, NULL, 0, 0, NULL, NULL, NULL}};
+  enum nss_status status;
+
+  if (name[0] == '-' || name[0] == '+')
+    return NSS_STATUS_NOTFOUND;
+
+  status = internal_setpwent (&ent);
+  if (status != NSS_STATUS_SUCCESS)
+    return status;
+
+  status = internal_getpwnam_r (name, pwd, &ent, buffer, buflen);
+
+  internal_endpwent (&ent);
+
+  return status;
+}
+
+/* This function handle the + entry in /etc/passwd for getpwuid */
+static enum nss_status
+getpwuid_plususer (uid_t uid, struct passwd *result, char *buffer,
+		   size_t buflen)
+{
+  struct parser_data *data = (void *) buffer;
+  struct passwd pwd;
+  int parse_res;
+  char *p;
+  size_t plen;
+  char buf[1024];
+  char *domain, *outval, *ptr;
+  int outvallen;
+
+  memset (&pwd, '\0', sizeof (struct passwd));
+
+  copy_pwd_changes (&pwd, result, NULL, 0);
+
+  plen = pwd_need_buflen (&pwd);
+  if (plen > buflen)
+    {
+      __set_errno (ERANGE);
+      return NSS_STATUS_TRYAGAIN;
+    }
+  p = buffer + (buflen - plen);
+  buflen -= plen;
+
+
+  if (yp_get_default_domain (&domain) != YPERR_SUCCESS)
+    return NSS_STATUS_TRYAGAIN;
+
+  sprintf (buf, "%d", uid);
+  if (yp_match (domain, "passwd.byuid", buf, strlen (buf),
+		&outval, &outvallen)
+      != YPERR_SUCCESS)
+    return NSS_STATUS_TRYAGAIN;
+  ptr = strncpy (buffer, outval, buflen < (size_t) outvallen ?
+		 buflen : (size_t) outvallen);
+  buffer[buflen < (size_t) outvallen ? buflen : (size_t) outvallen] = '\0';
+  free (outval);
+  while (isspace (*ptr))
+    ptr++;
+  if ((parse_res = _nss_files_parse_pwent (ptr, result, data, buflen))
+      == -1)
+    {
+      __set_errno (ERANGE);
+      return NSS_STATUS_TRYAGAIN;
+    }
+
+  if (parse_res > 0)
+    {
+      copy_pwd_changes (result, &pwd, p, plen);
+      give_pwd_free (&pwd);
+      /* We found the entry.  */
+      return NSS_STATUS_SUCCESS;
+    }
+  else
+    {
+      /* Give buffer the old len back */
+      buflen += plen;
+      give_pwd_free (&pwd);
+    }
+  return NSS_STATUS_RETURN;
+}
+
+/* Searches in /etc/passwd and the NIS/NIS+ map for a special user id */
+static enum nss_status
+internal_getpwuid_r (uid_t uid, struct passwd *result, ent_t *ent,
+		     char *buffer, size_t buflen)
+{
+  struct parser_data *data = (void *) buffer;
+
+  while (1)
+    {
+      fpos_t pos;
+      char *p;
+      int parse_res;
+
+      do
+	{
+	  fgetpos (ent->stream, &pos);
+	  buffer[buflen - 1] = '\xff';
+	  p = fgets (buffer, buflen, ent->stream);
+	  if (p == NULL && feof (ent->stream))
+	    return NSS_STATUS_NOTFOUND;
+	  if (p == NULL || buffer[buflen - 1] != '\xff')
+	    {
+	      fsetpos (ent->stream, &pos);
+	      __set_errno (ERANGE);
+	      return NSS_STATUS_TRYAGAIN;
+	    }
+
+	  /* Terminate the line for any case.  */
+	  buffer[buflen - 1] = '\0';
+
+	  /* Skip leading blanks.  */
+	  while (isspace (*p))
+	    ++p;
+	}
+      while (*p == '\0' || *p == '#' || /* Ignore empty and comment lines.  */
+	     /* Parse the line.  If it is invalid, loop to
+		get the next line of the file to parse.  */
+	     !(parse_res = _nss_files_parse_pwent (p, result, data, buflen)));
+
+      if (parse_res == -1)
+	{
+	  /* The parser ran out of space.  */
+	  fsetpos (ent->stream, &pos);
+	  __set_errno (ERANGE);
+	  return NSS_STATUS_TRYAGAIN;
+	}
+
+      /* This is a real entry.  */
+      if (result->pw_name[0] != '+' && result->pw_name[0] != '-')
+	{
+	  if (result->pw_uid == uid)
+	    return NSS_STATUS_SUCCESS;
+	  else
+	    continue;
+	}
+
+      /* -@netgroup */
+      if (result->pw_name[0] == '-' && result->pw_name[1] == '@'
+	  && result->pw_name[2] != '\0')
+	{
+	  char buf2[1024];
+	  char *user, *host, *domain;
+	  struct __netgrent netgrdata;
+
+	  bzero (&netgrdata, sizeof (struct __netgrent));
+	  __internal_setnetgrent (&result->pw_name[2], &netgrdata);
+	  while (__internal_getnetgrent_r (&host, &user, &domain,
+					   &netgrdata, buf2, sizeof (buf2),
+					   &errno))
+	    {
+              if (user != NULL && user[0] != '-')
+                blacklist_store_name (user, ent);
+	    }
+	  __internal_endnetgrent (&netgrdata);
+	  continue;
+	}
+
+      /* +@netgroup */
+      if (result->pw_name[0] == '+' && result->pw_name[1] == '@'
+	  && result->pw_name[2] != '\0')
+	{
+	  char buf[strlen (result->pw_name)];
+	  int status;
+
+	  strcpy (buf, &result->pw_name[2]);
+	  ent->netgroup = TRUE;
+	  ent->first = TRUE;
+	  copy_pwd_changes (&ent->pwd, result, NULL, 0);
+
+	  do
+	    {
+	      status = getpwent_next_nis_netgr (NULL, result, ent, buf,
+						  buffer, buflen);
+	      if (status == NSS_STATUS_RETURN)
+		continue;
+
+	      if (status == NSS_STATUS_SUCCESS && uid == result->pw_uid)
+		return NSS_STATUS_SUCCESS;
+	    } while (status == NSS_STATUS_SUCCESS);
+	  continue;
+	}
+
+      /* -user */
+      if (result->pw_name[0] == '-' && result->pw_name[1] != '\0'
+	  && result->pw_name[1] != '@')
+	{
+          blacklist_store_name (&result->pw_name[1], ent);
+          continue;
+	}
+
+      /* +user */
+      if (result->pw_name[0] == '+' && result->pw_name[1] != '\0'
+	  && result->pw_name[1] != '@')
+	{
+	  enum nss_status status;
+
+	  /* Store the User in the blacklist for the "+" at the end of
+             /etc/passwd */
+          blacklist_store_name (&result->pw_name[1], ent);
+	  status = getpwnam_plususer (&result->pw_name[1], result, buffer,
+				      buflen);
+	  if (status == NSS_STATUS_SUCCESS && result->pw_uid == uid)
+	    break;
+	  else
+	    continue;
+	}
+
+      /* +:... */
+      if (result->pw_name[0] == '+' && result->pw_name[1] == '\0')
+	{
+	  enum nss_status status;
+
+	  status = getpwuid_plususer (uid, result, buffer, buflen);
+	  if (status == NSS_STATUS_SUCCESS) /* We found the entry. */
+	    break;
+	  else
+	    if (status == NSS_STATUS_RETURN) /* We couldn't parse the entry */
+	      return NSS_STATUS_NOTFOUND;
+	    else
+	      {
+		if (status == NSS_STATUS_TRYAGAIN)
+		  /* The parser ran out of space */
+		  fsetpos (ent->stream, &pos);
+		return status;
+	      }
+	}
+    }
+  return NSS_STATUS_SUCCESS;
+}
+
+enum nss_status
+_nss_compat_getpwuid_r (uid_t uid, struct passwd *pwd,
+			char *buffer, size_t buflen)
+{
+  ent_t ent = {0, 0, 0, NULL, 0, NULL, {NULL, 0, 0},
+	       {NULL, NULL, 0, 0, NULL, NULL, NULL}};
+  enum nss_status status;
+
+  status = internal_setpwent (&ent);
+  if (status != NSS_STATUS_SUCCESS)
+    return status;
+
+  status = internal_getpwuid_r (uid, pwd, &ent, buffer, buflen);
+
+  internal_endpwent (&ent);
+
+  return status;
+}
+
+
+/* Support routines for remembering -@netgroup and -user entries.
+   The names are stored in a single string with `|' as separator. */
+static void
+blacklist_store_name (const char *name, ent_t *ent)
+{
+  int namelen = strlen (name);
+  char *tmp;
+
+  /* first call, setup cache */
+  if (ent->blacklist.size == 0)
+    {
+      ent->blacklist.size = MAX (BLACKLIST_INITIAL_SIZE, 2 * namelen);
+      ent->blacklist.data = malloc (ent->blacklist.size);
+      if (ent->blacklist.data == NULL)
+	return;
+      ent->blacklist.data[0] = '|';
+      ent->blacklist.data[1] = '\0';
+      ent->blacklist.current = 1;
+    }
+  else
+    {
+      if (in_blacklist (name, namelen, ent))
+	return;			/* no duplicates */
+
+      if (ent->blacklist.current + namelen + 1 >= ent->blacklist.size)
+	{
+	  ent->blacklist.size += MAX (BLACKLIST_INCREMENT, 2 * namelen);
+	  tmp = realloc (ent->blacklist.data, ent->blacklist.size);
+	  if (tmp == NULL)
+	    {
+	      free (ent->blacklist.data);
+	      ent->blacklist.size = 0;
+	      return;
+	    }
+	  ent->blacklist.data = tmp;
+	}
+    }
+
+  tmp = stpcpy (ent->blacklist.data + ent->blacklist.current, name);
+  *tmp++ = '|';
+  *tmp = '\0';
+  ent->blacklist.current += namelen + 1;
+
+  return;
+}
+
+/* returns TRUE if ent->blacklist contains name, else FALSE */
+static bool_t
+in_blacklist (const char *name, int namelen, ent_t *ent)
+{
+  char buf[namelen + 3];
+  char *cp;
+
+  if (ent->blacklist.data == NULL)
+    return FALSE;
+
+  buf[0] = '|';
+  cp = stpcpy (&buf[1], name);
+  *cp++= '|';
+  *cp = '\0';
+  return strstr (ent->blacklist.data, buf) != NULL;
+}
diff --git a/glibc-compat/nss_compat/compat-spwd.c b/glibc-compat/nss_compat/compat-spwd.c
new file mode 100644
index 0000000000..2c33d80688
--- /dev/null
+++ b/glibc-compat/nss_compat/compat-spwd.c
@@ -0,0 +1,915 @@
+/* Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1996.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include <nss.h>
+#include <errno.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <glibc-compat/include/netdb.h>
+#include <glibc-compat/include/shadow.h>
+#include <string.h>
+#include <bits/libc-lock.h>
+#include <rpcsvc/yp.h>
+#include <rpcsvc/ypclnt.h>
+#include <nsswitch.h>
+
+#include "netgroup.h"
+
+/* Get the declaration of the parser function.  */
+#define ENTNAME spent
+#define STRUCTURE spwd
+#define EXTERN_PARSER
+#include "../nss_files/files-parse.c"
+
+/* Structure for remembering -@netgroup and -user members ... */
+#define BLACKLIST_INITIAL_SIZE 512
+#define BLACKLIST_INCREMENT 256
+struct blacklist_t
+  {
+    char *data;
+    int current;
+    int size;
+  };
+
+struct ent_t
+  {
+    bool_t netgroup;
+    bool_t nis;
+    bool_t first;
+    char *oldkey;
+    int oldkeylen;
+    FILE *stream;
+    struct blacklist_t blacklist;
+    struct spwd pwd;
+    struct __netgrent netgrdata;
+  };
+typedef struct ent_t ent_t;
+
+static ent_t ext_ent = {0, 0, 0, NULL, 0, NULL, {NULL, 0, 0},
+			{NULL, NULL, 0, 0, 0, 0, 0, 0, 0}};
+
+/* Protect global state against multiple changers.  */
+__libc_lock_define_initialized (static, lock)
+
+/* Prototypes for local functions.  */
+static void blacklist_store_name (const char *, ent_t *);
+static int in_blacklist (const char *, int, ent_t *);
+
+static void
+give_spwd_free (struct spwd *pwd)
+{
+  if (pwd->sp_namp != NULL)
+    free (pwd->sp_namp);
+  if (pwd->sp_pwdp != NULL)
+    free (pwd->sp_pwdp);
+
+  memset (pwd, '\0', sizeof (struct spwd));
+}
+
+static int
+spwd_need_buflen (struct spwd *pwd)
+{
+  int len = 0;
+
+  if (pwd->sp_pwdp != NULL)
+    len += strlen (pwd->sp_pwdp) + 1;
+
+  return len;
+}
+
+static void
+copy_spwd_changes (struct spwd *dest, struct spwd *src,
+		   char *buffer, size_t buflen)
+{
+  if (src->sp_pwdp != NULL && strlen (src->sp_pwdp))
+    {
+      if (buffer == NULL)
+	dest->sp_pwdp = strdup (src->sp_pwdp);
+      else if (dest->sp_pwdp &&
+	       strlen (dest->sp_pwdp) >= strlen (src->sp_pwdp))
+	strcpy (dest->sp_pwdp, src->sp_pwdp);
+      else
+	{
+	  dest->sp_pwdp = buffer;
+	  strcpy (dest->sp_pwdp, src->sp_pwdp);
+	  buffer += strlen (dest->sp_pwdp) + 1;
+	  buflen = buflen - (strlen (dest->sp_pwdp) + 1);
+	}
+    }
+  if (src->sp_lstchg != 0)
+    dest->sp_lstchg = src->sp_lstchg;
+  if (src->sp_min != 0)
+    dest->sp_min = src->sp_min;
+  if (src->sp_max != 0)
+    dest->sp_max = src->sp_max;
+  if (src->sp_warn != 0)
+    dest->sp_warn = src->sp_warn;
+  if (src->sp_inact != 0)
+    dest->sp_inact = src->sp_inact;
+  if (src->sp_expire != 0)
+    dest->sp_expire = src->sp_expire;
+  if (src->sp_flag != 0)
+    dest->sp_flag = src->sp_flag;
+}
+
+static enum nss_status
+internal_setspent (ent_t *ent)
+{
+  enum nss_status status = NSS_STATUS_SUCCESS;
+
+  ent->nis = ent->first = ent->netgroup = 0;
+
+  /* If something was left over free it.  */
+  if (ent->netgroup)
+    __internal_endnetgrent (&ent->netgrdata);
+
+  if (ent->oldkey != NULL)
+    {
+      free (ent->oldkey);
+      ent->oldkey = NULL;
+      ent->oldkeylen = 0;
+    }
+
+  if (ent->blacklist.data != NULL)
+    {
+      ent->blacklist.current = 1;
+      ent->blacklist.data[0] = '|';
+      ent->blacklist.data[1] = '\0';
+    }
+  else
+    ent->blacklist.current = 0;
+
+  if (ent->stream == NULL)
+    {
+      ent->stream = fopen ("/etc/shadow", "r");
+
+      if (ent->stream == NULL)
+	status = errno == EAGAIN ? NSS_STATUS_TRYAGAIN : NSS_STATUS_UNAVAIL;
+      else
+	{
+	  /* We have to make sure the file is  `closed on exec'.  */
+	  int result, flags;
+
+	  result = flags = fcntl (fileno (ent->stream), F_GETFD, 0);
+	  if (result >= 0)
+	    {
+	      flags |= FD_CLOEXEC;
+	      result = fcntl (fileno (ent->stream), F_SETFD, flags);
+	    }
+	  if (result < 0)
+	    {
+	      /* Something went wrong.  Close the stream and return a
+		 failure.  */
+	      fclose (ent->stream);
+	      ent->stream = NULL;
+	      status = NSS_STATUS_UNAVAIL;
+	    }
+	}
+    }
+  else
+    rewind (ent->stream);
+
+  give_spwd_free (&ent->pwd);
+
+  return status;
+}
+
+
+enum nss_status
+_nss_compat_setspent (void)
+{
+  enum nss_status result;
+
+  __libc_lock_lock (lock);
+
+  result = internal_setspent (&ext_ent);
+
+  __libc_lock_unlock (lock);
+
+  return result;
+}
+
+
+static enum nss_status
+internal_endspent (ent_t *ent)
+{
+  if (ent->stream != NULL)
+    {
+      fclose (ent->stream);
+      ent->stream = NULL;
+    }
+
+  if (ent->netgroup)
+    __internal_endnetgrent (&ent->netgrdata);
+
+  ent->nis = ent->first = ent->netgroup = 0;
+
+  if (ent->oldkey != NULL)
+    {
+      free (ent->oldkey);
+      ent->oldkey = NULL;
+      ent->oldkeylen = 0;
+    }
+
+  if (ent->blacklist.data != NULL)
+    {
+      ent->blacklist.current = 1;
+      ent->blacklist.data[0] = '|';
+      ent->blacklist.data[1] = '\0';
+    }
+  else
+    ent->blacklist.current = 0;
+
+  give_spwd_free (&ent->pwd);
+
+  return NSS_STATUS_SUCCESS;
+}
+
+enum nss_status
+_nss_compat_endspent (void)
+{
+  enum nss_status result;
+
+  __libc_lock_lock (lock);
+
+  result = internal_endspent (&ext_ent);
+
+  __libc_lock_unlock (lock);
+
+  return result;
+}
+
+
+static enum nss_status
+getspent_next_nis_netgr (const char *name, struct spwd *result, ent_t *ent,
+			 char *group, char *buffer, size_t buflen)
+{
+  struct parser_data *data = (void *) buffer;
+  char *ypdomain, *host, *user, *domain, *outval, *p, *p2;
+  int status, outvallen;
+  size_t p2len;
+
+  if (yp_get_default_domain (&ypdomain) != YPERR_SUCCESS)
+    {
+      ent->netgroup = 0;
+      ent->first = 0;
+      give_spwd_free (&ent->pwd);
+      return NSS_STATUS_UNAVAIL;
+    }
+
+  if (ent->first == TRUE)
+    {
+      bzero (&ent->netgrdata, sizeof (struct __netgrent));
+      __internal_setnetgrent (group, &ent->netgrdata);
+      ent->first = FALSE;
+    }
+
+  while (1)
+    {
+      char *saved_cursor;
+      int parse_res;
+
+      saved_cursor = ent->netgrdata.cursor;
+      status = __internal_getnetgrent_r (&host, &user, &domain,
+					 &ent->netgrdata, buffer, buflen,
+					 &errno);
+      if (status != 1)
+	{
+	  __internal_endnetgrent (&ent->netgrdata);
+	  ent->netgroup = 0;
+	  give_spwd_free (&ent->pwd);
+	  return NSS_STATUS_RETURN;
+	}
+
+      if (user == NULL || user[0] == '-')
+	continue;
+
+      if (domain != NULL && strcmp (ypdomain, domain) != 0)
+	continue;
+
+      /* If name != NULL, we are called from getpwnam */
+      if (name != NULL)
+	if (strcmp (user, name) != 0)
+	  continue;
+
+      if (yp_match (ypdomain, "shadow.byname", user,
+		    strlen (user), &outval, &outvallen)
+	  != YPERR_SUCCESS)
+	continue;
+
+      p2len = spwd_need_buflen (&ent->pwd);
+      if (p2len > buflen)
+	{
+	  __set_errno (ERANGE);
+	  return NSS_STATUS_TRYAGAIN;
+	}
+      p2 = buffer + (buflen - p2len);
+      buflen -= p2len;
+      p = strncpy (buffer, outval, buflen);
+      while (isspace (*p))
+	p++;
+      free (outval);
+      if ((parse_res = _nss_files_parse_spent (p, result, data, buflen)) == -1)
+	{
+	  ent->netgrdata.cursor = saved_cursor;
+	  return NSS_STATUS_TRYAGAIN;
+	}
+
+      if (parse_res)
+	{
+	  /* Store the User in the blacklist for the "+" at the end of
+	     /etc/passwd */
+	  blacklist_store_name (result->sp_namp, ent);
+	  copy_spwd_changes (result, &ent->pwd, p2, p2len);
+	  break;
+	}
+    }
+
+  return NSS_STATUS_SUCCESS;
+}
+
+static enum nss_status
+getspent_next_nis (struct spwd *result, ent_t *ent,
+		   char *buffer, size_t buflen)
+{
+  struct parser_data *data = (void *) buffer;
+  char *domain, *outkey, *outval, *p, *p2;
+  int outkeylen, outvallen, parse_res;
+  size_t p2len;
+
+  if (yp_get_default_domain (&domain) != YPERR_SUCCESS)
+    {
+      ent->nis = 0;
+      give_spwd_free (&ent->pwd);
+      return NSS_STATUS_UNAVAIL;
+    }
+
+  p2len = spwd_need_buflen (&ent->pwd);
+  if (p2len > buflen)
+    {
+      __set_errno (ERANGE);
+      return NSS_STATUS_TRYAGAIN;
+    }
+  p2 = buffer + (buflen - p2len);
+  buflen -= p2len;
+  do
+    {
+      bool_t saved_first;
+      char *saved_oldkey;
+      int saved_oldlen;
+
+      if (ent->first)
+	{
+	  if (yp_first (domain, "shadow.byname", &outkey, &outkeylen,
+			&outval, &outvallen) != YPERR_SUCCESS)
+	    {
+	      ent->nis = 0;
+	      give_spwd_free (&ent->pwd);
+	      return NSS_STATUS_UNAVAIL;
+	    }
+	  saved_first = TRUE;
+	  saved_oldkey = ent->oldkey;
+	  saved_oldlen = ent->oldkeylen;
+	  ent->oldkey = outkey;
+	  ent->oldkeylen = outkeylen;
+	  ent->first = FALSE;
+	}
+      else
+	{
+	  if (yp_next (domain, "shadow.byname", ent->oldkey, ent->oldkeylen,
+		       &outkey, &outkeylen, &outval, &outvallen)
+	      != YPERR_SUCCESS)
+	    {
+	      ent->nis = 0;
+	      give_spwd_free (&ent->pwd);
+	      return NSS_STATUS_NOTFOUND;
+	    }
+
+	  saved_first = FALSE;
+	  saved_oldkey = ent->oldkey;
+	  saved_oldlen = ent->oldkeylen;
+	  ent->oldkey = outkey;
+	  ent->oldkeylen = outkeylen;
+	}
+
+      /* Copy the found data to our buffer  */
+      p = strncpy (buffer, outval, buflen);
+
+      /* ...and free the data.  */
+      free (outval);
+
+      while (isspace (*p))
+	++p;
+      if ((parse_res = _nss_files_parse_spent (p, result, data, buflen)) == -1)
+	{
+	  free (ent->oldkey);
+	  ent->oldkey = saved_oldkey;
+	  ent->oldkeylen = saved_oldlen;
+	  ent->first = saved_first;
+	  __set_errno (ERANGE);
+	  return NSS_STATUS_TRYAGAIN;
+	}
+      else
+	{
+	  if (!saved_first)
+	    free (saved_oldkey);
+	}
+      if (parse_res &&
+          in_blacklist (result->sp_namp, strlen (result->sp_namp), ent))
+        parse_res = 0;
+    }
+  while (!parse_res);
+
+  copy_spwd_changes (result, &ent->pwd, p2, p2len);
+
+  return NSS_STATUS_SUCCESS;
+}
+
+/* This function handle the +user entrys in /etc/shadow */
+static enum nss_status
+getspnam_plususer (const char *name, struct spwd *result, char *buffer,
+		   size_t buflen)
+{
+  struct parser_data *data = (void *) buffer;
+  struct spwd pwd;
+  int parse_res;
+  char *p;
+  size_t plen;
+  char *domain, *outval, *ptr;
+  int outvallen;
+
+
+  memset (&pwd, '\0', sizeof (struct spwd));
+
+  copy_spwd_changes (&pwd, result, NULL, 0);
+
+  plen = spwd_need_buflen (&pwd);
+  if (plen > buflen)
+    {
+      __set_errno (ERANGE);
+      return NSS_STATUS_TRYAGAIN;
+    }
+  p = buffer + (buflen - plen);
+  buflen -= plen;
+
+  if (yp_get_default_domain (&domain) != YPERR_SUCCESS)
+    return NSS_STATUS_NOTFOUND;
+
+  if (yp_match (domain, "shadow.byname", name, strlen (name),
+		&outval, &outvallen) != YPERR_SUCCESS)
+    return NSS_STATUS_NOTFOUND;
+  ptr = strncpy (buffer, outval, buflen < (size_t) outvallen ?
+		 buflen : (size_t) outvallen);
+  buffer[buflen < (size_t) outvallen ? buflen : (size_t) outvallen] = '\0';
+  free (outval);
+  while (isspace (*ptr))
+    ptr++;
+  if ((parse_res = _nss_files_parse_spent (ptr, result, data, buflen)) == -1)
+    {
+      __set_errno (ERANGE);
+      return NSS_STATUS_TRYAGAIN;
+    }
+
+  if (parse_res)
+    {
+      copy_spwd_changes (result, &pwd, p, plen);
+      give_spwd_free (&pwd);
+      /* We found the entry.  */
+      return NSS_STATUS_SUCCESS;
+    }
+  else
+    {
+      /* Give buffer the old len back */
+      buflen += plen;
+      give_spwd_free (&pwd);
+    }
+  return NSS_STATUS_RETURN;
+}
+
+static enum nss_status
+getspent_next_file (struct spwd *result, ent_t *ent,
+		    char *buffer, size_t buflen)
+{
+  struct parser_data *data = (void *) buffer;
+  while (1)
+    {
+      fpos_t pos;
+      int parse_res = 0;
+      char *p;
+
+      do
+	{
+	  fgetpos (ent->stream, &pos);
+	  buffer[buflen - 1] = '\xff';
+	  p = fgets (buffer, buflen, ent->stream);
+	  if (p == NULL && feof (ent->stream))
+	    return NSS_STATUS_NOTFOUND;
+	  if (p == NULL || buffer[buflen - 1] != '\xff')
+	    {
+	      fsetpos (ent->stream, &pos);
+	      __set_errno (ERANGE);
+	      return NSS_STATUS_TRYAGAIN;
+	    }
+
+	  /* Terminate the line for any case.  */
+	  buffer[buflen - 1] = '\0';
+
+	  /* Skip leading blanks.  */
+	  while (isspace (*p))
+	    ++p;
+	}
+      while (*p == '\0' || *p == '#'	/* Ignore empty and comment lines.  */
+      /* Parse the line.  If it is invalid, loop to
+         get the next line of the file to parse.  */
+	     || !(parse_res = _nss_files_parse_spent (p, result, data,
+						      buflen)));
+
+      if (parse_res == -1)
+        {
+          /* The parser ran out of space.  */
+          fsetpos (ent->stream, &pos);
+          __set_errno (ERANGE);
+          return NSS_STATUS_TRYAGAIN;
+        }
+
+      if (result->sp_namp[0] != '+' && result->sp_namp[0] != '-')
+	/* This is a real entry.  */
+	break;
+
+      /* -@netgroup */
+      if (result->sp_namp[0] == '-' && result->sp_namp[1] == '@'
+	  && result->sp_namp[2] != '\0')
+	{
+          char buf2[1024];
+ 	  char *user, *host, *domain;
+          struct __netgrent netgrdata;
+
+          bzero (&netgrdata, sizeof (struct __netgrent));
+          __internal_setnetgrent (&result->sp_namp[2], &netgrdata);
+	  while (__internal_getnetgrent_r (&host, &user, &domain,
+					   &netgrdata, buf2, sizeof (buf2),
+					   &errno))
+	    {
+	      if (user != NULL && user[0] != '-')
+		blacklist_store_name (user, ent);
+	    }
+	  __internal_endnetgrent (&netgrdata);
+	  continue;
+	}
+
+      /* +@netgroup */
+      if (result->sp_namp[0] == '+' && result->sp_namp[1] == '@'
+	  && result->sp_namp[2] != '\0')
+	{
+	  int status;
+
+	  ent->netgroup = TRUE;
+	  ent->first = TRUE;
+	  copy_spwd_changes (&ent->pwd, result, NULL, 0);
+
+	  status = getspent_next_nis_netgr (NULL, result, ent,
+					    &result->sp_namp[2],
+					    buffer, buflen);
+	  if (status == NSS_STATUS_RETURN)
+	    continue;
+	  else
+	    return status;
+	}
+
+      /* -user */
+      if (result->sp_namp[0] == '-' && result->sp_namp[1] != '\0'
+	  && result->sp_namp[1] != '@')
+	{
+	  blacklist_store_name (&result->sp_namp[1], ent);
+	  continue;
+	}
+
+      /* +user */
+      if (result->sp_namp[0] == '+' && result->sp_namp[1] != '\0'
+	  && result->sp_namp[1] != '@')
+	{
+          enum nss_status status;
+
+	  /* Store the User in the blacklist for the "+" at the end of
+	     /etc/passwd */
+	  blacklist_store_name (&result->sp_namp[1], ent);
+          status = getspnam_plususer (&result->sp_namp[1], result, buffer,
+				      buflen);
+          if (status == NSS_STATUS_SUCCESS) /* We found the entry. */
+            break;
+          else
+            if (status == NSS_STATUS_RETURN /* We couldn't parse the entry */
+		|| status == NSS_STATUS_NOTFOUND) /* entry doesn't exist */
+              continue;
+            else
+	      {
+		if (status == NSS_STATUS_TRYAGAIN)
+		  fsetpos (ent->stream, &pos);
+		return status;
+	      }
+	}
+
+      /* +:... */
+      if (result->sp_namp[0] == '+' && result->sp_namp[1] == '\0')
+	{
+	  ent->nis = TRUE;
+	  ent->first = TRUE;
+	  copy_spwd_changes (&ent->pwd, result, NULL, 0);
+
+	  return getspent_next_nis (result, ent, buffer, buflen);
+	}
+    }
+
+  return NSS_STATUS_SUCCESS;
+}
+
+
+static enum nss_status
+internal_getspent_r (struct spwd *pw, ent_t *ent,
+		     char *buffer, size_t buflen)
+{
+  if (ent->netgroup)
+    {
+      int status;
+
+      /* We are searching members in a netgroup */
+      /* Since this is not the first call, we don't need the group name */
+      status = getspent_next_nis_netgr (NULL, pw, ent, NULL, buffer, buflen);
+      if (status == NSS_STATUS_RETURN)
+	return getspent_next_file (pw, ent, buffer, buflen);
+      else
+	return status;
+    }
+  else
+    if (ent->nis)
+      {
+	return getspent_next_nis (pw, ent, buffer, buflen);
+      }
+    else
+      return getspent_next_file (pw, ent, buffer, buflen);
+}
+
+enum nss_status
+_nss_compat_getspent_r (struct spwd *pwd, char *buffer, size_t buflen)
+{
+  enum nss_status status = NSS_STATUS_SUCCESS;
+
+  __libc_lock_lock (lock);
+
+  if (ext_ent.stream == NULL)
+    status = internal_setspent (&ext_ent);
+
+  if (status == NSS_STATUS_SUCCESS)
+    status = internal_getspent_r (pwd, &ext_ent, buffer, buflen);
+
+  __libc_lock_unlock (lock);
+
+  return status;
+}
+
+/* Searches in /etc/passwd and the NIS/NIS+ map for a special user */
+static enum nss_status
+internal_getspnam_r (const char *name, struct spwd *result, ent_t *ent,
+		     char *buffer, size_t buflen)
+{
+  struct parser_data *data = (void *) buffer;
+
+  while (1)
+    {
+      fpos_t pos;
+      char *p;
+      int parse_res;
+
+      do
+	{
+	  fgetpos (ent->stream, &pos);
+	  buffer[buflen - 1] = '\xff';
+	  p = fgets (buffer, buflen, ent->stream);
+	  if (p == NULL && feof (ent->stream))
+	    return NSS_STATUS_NOTFOUND;
+	  if (p == NULL || buffer[buflen - 1] != '\xff')
+	    {
+	      fsetpos (ent->stream, &pos);
+	      __set_errno (ERANGE);
+	      return NSS_STATUS_TRYAGAIN;
+	    }
+
+	  /* Terminate the line for any case.  */
+	  buffer[buflen - 1] = '\0';
+
+	  /* Skip leading blanks.  */
+	  while (isspace (*p))
+	    ++p;
+	}
+      while (*p == '\0' || *p == '#' || /* Ignore empty and comment lines.  */
+	     /* Parse the line.  If it is invalid, loop to
+		get the next line of the file to parse.  */
+	     !(parse_res = _nss_files_parse_spent (p, result, data, buflen)));
+
+      if (parse_res == -1)
+	{
+	  /* The parser ran out of space.  */
+	  fsetpos (ent->stream, &pos);
+	  __set_errno (ERANGE);
+	  return NSS_STATUS_TRYAGAIN;
+	}
+
+      /* This is a real entry.  */
+      if (result->sp_namp[0] != '+' && result->sp_namp[0] != '-')
+	{
+	  if (strcmp (result->sp_namp, name) == 0)
+	    return NSS_STATUS_SUCCESS;
+	  else
+	    continue;
+	}
+
+      /* -@netgroup */
+      if (result->sp_namp[0] == '-' && result->sp_namp[1] == '@'
+	  && result->sp_namp[2] != '\0')
+	{
+	  char buf2[1024];
+	  char *user, *host, *domain;
+	  struct __netgrent netgrdata;
+
+	  bzero (&netgrdata, sizeof (struct __netgrent));
+	  __internal_setnetgrent (&result->sp_namp[2], &netgrdata);
+	  while (__internal_getnetgrent_r (&host, &user, &domain,
+					   &netgrdata, buf2, sizeof (buf2),
+					   &errno))
+	    {
+	      if (user != NULL && user[0] != '-')
+		if (strcmp (user, name) == 0)
+		  return NSS_STATUS_NOTFOUND;
+	    }
+	  __internal_endnetgrent (&netgrdata);
+	  continue;
+	}
+
+      /* +@netgroup */
+      if (result->sp_namp[0] == '+' && result->sp_namp[1] == '@'
+	  && result->sp_namp[2] != '\0')
+	{
+	  char buf[strlen (result->sp_namp)];
+	  int status;
+
+	  strcpy (buf, &result->sp_namp[2]);
+	  ent->netgroup = TRUE;
+	  ent->first = TRUE;
+	  copy_spwd_changes (&ent->pwd, result, NULL, 0);
+
+	  do
+	    {
+	      status = getspent_next_nis_netgr (name, result, ent, buf,
+						  buffer, buflen);
+	      if (status == NSS_STATUS_RETURN)
+		continue;
+
+	      if (status == NSS_STATUS_SUCCESS &&
+		  strcmp (result->sp_namp, name) == 0)
+		return NSS_STATUS_SUCCESS;
+	    } while (status == NSS_STATUS_SUCCESS);
+	  continue;
+	}
+
+      /* -user */
+      if (result->sp_namp[0] == '-' && result->sp_namp[1] != '\0'
+	  && result->sp_namp[1] != '@')
+	{
+	  if (strcmp (&result->sp_namp[1], name) == 0)
+	    return NSS_STATUS_NOTFOUND;
+	  else
+	    continue;
+	}
+
+      /* +user */
+      if (result->sp_namp[0] == '+' && result->sp_namp[1] != '\0'
+	  && result->sp_namp[1] != '@')
+	{
+	  if (strcmp (name, &result->sp_namp[1]) == 0)
+	    {
+	      enum nss_status status;
+
+	      status = getspnam_plususer (name, result, buffer, buflen);
+	      if (status == NSS_STATUS_RETURN)
+		/* We couldn't parse the entry */
+		return NSS_STATUS_NOTFOUND;
+	      else
+		return status;
+	    }
+	}
+
+      /* +:... */
+      if (result->sp_namp[0] == '+' && result->sp_namp[1] == '\0')
+	{
+	  enum nss_status status;
+
+	  status = getspnam_plususer (name, result, buffer, buflen);
+	  if (status == NSS_STATUS_RETURN) /* We couldn't parse the entry */
+	    return NSS_STATUS_NOTFOUND;
+	  else
+	    return status;
+	}
+    }
+  return NSS_STATUS_SUCCESS;
+}
+
+enum nss_status
+_nss_compat_getspnam_r (const char *name, struct spwd *pwd,
+			char *buffer, size_t buflen)
+{
+  ent_t ent = {0, 0, 0, NULL, 0, NULL, {NULL, 0, 0},
+	       {NULL, NULL, 0, 0, 0, 0, 0, 0, 0}};
+  enum nss_status status;
+
+  if (name[0] == '-' || name[0] == '+')
+    return NSS_STATUS_NOTFOUND;
+
+  status = internal_setspent (&ent);
+  if (status != NSS_STATUS_SUCCESS)
+    return status;
+
+  status = internal_getspnam_r (name, pwd, &ent, buffer, buflen);
+
+  internal_endspent (&ent);
+
+  return status;
+}
+
+/* Support routines for remembering -@netgroup and -user entries.
+   The names are stored in a single string with `|' as separator. */
+static void
+blacklist_store_name (const char *name, ent_t *ent)
+{
+  int namelen = strlen (name);
+  char *tmp;
+
+  /* first call, setup cache */
+  if (ent->blacklist.size == 0)
+    {
+      ent->blacklist.size = MAX (BLACKLIST_INITIAL_SIZE, 2 * namelen);
+      ent->blacklist.data = malloc (ent->blacklist.size);
+      if (ent->blacklist.data == NULL)
+	return;
+      ent->blacklist.data[0] = '|';
+      ent->blacklist.data[1] = '\0';
+      ent->blacklist.current = 1;
+    }
+  else
+    {
+      if (in_blacklist (name, namelen, ent))
+	return;			/* no duplicates */
+
+      if (ent->blacklist.current + namelen + 1 >= ent->blacklist.size)
+	{
+	  ent->blacklist.size += MAX (BLACKLIST_INCREMENT, 2 * namelen);
+	  tmp = realloc (ent->blacklist.data, ent->blacklist.size);
+	  if (tmp == NULL)
+	    {
+	      free (ent->blacklist.data);
+	      ent->blacklist.size = 0;
+	      return;
+	    }
+	  ent->blacklist.data = tmp;
+	}
+    }
+
+  tmp = stpcpy (ent->blacklist.data + ent->blacklist.current, name);
+  *tmp++ = '|';
+  *tmp = '\0';
+  ent->blacklist.current += namelen + 1;
+
+  return;
+}
+
+/* Returns TRUE if ent->blacklist contains name, else FALSE.  */
+static bool_t
+in_blacklist (const char *name, int namelen, ent_t *ent)
+{
+  char buf[namelen + 3];
+  char *cp;
+
+  if (ent->blacklist.data == NULL)
+    return FALSE;
+
+  buf[0] = '|';
+  cp = stpcpy (&buf[1], name);
+  *cp++= '|';
+  *cp = '\0';
+  return strstr (ent->blacklist.data, buf) != NULL;
+}
diff --git a/glibc-compat/nss_db/db-XXX.c b/glibc-compat/nss_db/db-XXX.c
new file mode 100644
index 0000000000..8c05829656
--- /dev/null
+++ b/glibc-compat/nss_db/db-XXX.c
@@ -0,0 +1,257 @@
+/* Common code for DB-based databases in nss_db module.
+   Copyright (C) 1996, 1997, 1998, 1999, 2000 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include <dlfcn.h>
+#include <fcntl.h>
+#include <bits/libc-lock.h>
+#include "nsswitch.h"
+#include "nss_db.h"
+
+/* These symbols are defined by the including source file:
+
+   ENTNAME -- database name of the structure and functions (hostent, pwent).
+   STRUCTURE -- struct name, define only if not ENTNAME (passwd, group).
+   DATABASE -- database file name, ("hosts", "passwd")
+
+   NEED_H_ERRNO - defined iff an arg `int *herrnop' is used.
+*/
+
+#define ENTNAME_r	CONCAT(ENTNAME,_r)
+
+#include <paths.h>
+#define	DBFILE		_PATH_VARDB DATABASE ".db"
+
+#ifdef NEED_H_ERRNO
+#define H_ERRNO_PROTO	, int *herrnop
+#define H_ERRNO_ARG	, herrnop
+#define H_ERRNO_SET(val) (*herrnop = (val))
+#else
+#define H_ERRNO_PROTO
+#define H_ERRNO_ARG
+#define H_ERRNO_SET(val) ((void) 0)
+#endif
+
+/* Locks the static variables in this file.  */
+__libc_lock_define_initialized (static, lock)
+
+/* Maintenance of the shared handle open on the database.  */
+
+static NSS_DB *db;
+static int keep_db;
+static int entidx;
+
+
+/* Open the database.  */
+enum nss_status
+CONCAT(_nss_db_set,ENTNAME) (int stayopen)
+{
+  enum nss_status status;
+
+  __libc_lock_lock (lock);
+
+  status = internal_setent (DBFILE, &db);
+
+  /* Remember STAYOPEN flag.  */
+  if (db != NULL)
+    keep_db |= stayopen;
+  /* Reset the sequential index.  */
+  entidx = 0;
+
+  __libc_lock_unlock (lock);
+
+  return status;
+}
+
+
+/* Close it again.  */
+enum nss_status
+CONCAT(_nss_db_end,ENTNAME) (void)
+{
+  __libc_lock_lock (lock);
+
+  internal_endent (&db);
+
+  /* Reset STAYOPEN flag.  */
+  keep_db = 0;
+
+  __libc_lock_unlock (lock);
+
+  return NSS_STATUS_SUCCESS;
+}
+
+/* Do a database lookup for KEY.  */
+static enum nss_status
+lookup (DBT *key, struct STRUCTURE *result,
+	void *buffer, int buflen H_ERRNO_PROTO)
+{
+  char *p;
+  enum nss_status status;
+  int err;
+  DBT value;
+
+  /* Open the database.  */
+  if (db == NULL)
+    {
+      status = internal_setent (DBFILE, &db);
+      if (status != NSS_STATUS_SUCCESS)
+	{
+	  H_ERRNO_SET (NETDB_INTERNAL);
+	  return status;
+	}
+    }
+
+  /* Succeed iff it matches a value that parses correctly.  */
+  value.flags = 0;
+  err = DL_CALL_FCT (db->get, (db->db, NULL, key, &value, 0));
+  if (err != 0)
+    {
+      if (err == db_notfound)
+	{
+	  H_ERRNO_SET (HOST_NOT_FOUND);
+	  status = NSS_STATUS_NOTFOUND;
+	}
+      else
+	{
+	  H_ERRNO_SET (NETDB_INTERNAL);
+	  status = NSS_STATUS_UNAVAIL;
+	}
+    }
+  else if (buflen < value.size)
+    {
+      /* No room to copy the data to.  */
+      __set_errno (ERANGE);
+      H_ERRNO_SET (NETDB_INTERNAL);
+      status = NSS_STATUS_TRYAGAIN;
+    }
+  else
+    {
+      /* Copy the result to a safe place.  */
+      p = (char *) memcpy (buffer, value.data, value.size);
+
+      /* Skip leading blanks.  */
+      while (isspace (*p))
+	++p;
+
+      err = parse_line (p, result, buffer, buflen);
+
+      if (err == 0)
+	{
+	  /* If the key begins with '0' we are trying to get the next
+	     entry.  We want to ignore unparsable lines in this case.  */
+	  if (((char *) key->data)[0] == '0')
+	    {
+	      /* Super magical return value.  We need to tell our caller
+		 that it should continue looping.  This value cannot
+		 happen in other cases.  */
+	      status = NSS_STATUS_RETURN;
+	    }
+	  else
+	    {
+	      H_ERRNO_SET (HOST_NOT_FOUND);
+	      status = NSS_STATUS_NOTFOUND;
+	    }
+	}
+      else if (err < 0)
+	{
+	  H_ERRNO_SET (NETDB_INTERNAL);
+	  status = NSS_STATUS_TRYAGAIN;
+	}
+      else
+	status = NSS_STATUS_SUCCESS;
+    }
+
+  if (! keep_db)
+    internal_endent (&db);
+
+  return status;
+}
+
+
+/* Macro for defining lookup functions for this DB-based database.
+
+   NAME is the name of the lookup; e.g. `pwnam'.
+
+   KEYPATTERN gives `printf' args to construct a key string;
+   e.g. `(".%s", name)'.
+
+   KEYSIZE gives the allocation size of a buffer to construct it in;
+   e.g. `1 + strlen (name)'.
+
+   PROTO describes the arguments for the lookup key;
+   e.g. `const char *name'.
+
+   BREAK_IF_MATCH is ignored, but used by ../nss_files/files-XXX.c.  */
+
+#define DB_LOOKUP(name, keysize, keypattern, break_if_match, proto...)	      \
+enum nss_status								      \
+_nss_db_get##name##_r (proto,						      \
+		       struct STRUCTURE *result,			      \
+		       char *buffer, size_t buflen H_ERRNO_PROTO)\
+{									      \
+  DBT key;								      \
+  enum nss_status status;						      \
+  const size_t size = (keysize) + 1;					      \
+  key.data = __alloca (size);						      \
+  key.size = KEYPRINTF keypattern;					      \
+  key.flags = 0;							      \
+  __libc_lock_lock (lock);						      \
+  status = lookup (&key, result, buffer, buflen H_ERRNO_ARG);	      	      \
+  __libc_lock_unlock (lock);						      \
+  return status;							      \
+}
+
+#define KEYPRINTF(pattern, args...) snprintf (key.data, size, pattern ,##args)
+
+
+
+
+/* Return the next entry from the database file, doing locking.  */
+enum nss_status
+CONCAT(_nss_db_get,ENTNAME_r) (struct STRUCTURE *result, char *buffer,
+			       size_t buflen H_ERRNO_PROTO)
+{
+  /* Return next entry in host file.  */
+  enum nss_status status;
+  char buf[20];
+  DBT key;
+
+  __libc_lock_lock (lock);
+
+  /* Loop until we find a valid entry or hit EOF.  See above for the
+     special meaning of the status value.  */
+  do
+    {
+      key.size = snprintf (key.data = buf, sizeof buf, "0%u", entidx++);
+      key.flags = 0;
+      status = lookup (&key, result, buffer, buflen H_ERRNO_ARG);
+      if (status == NSS_STATUS_TRYAGAIN
+#ifdef NEED_H_ERRNO
+	  && *herrnop == NETDB_INTERNAL
+#endif
+	  && errno == ERANGE)
+	/* Give the user a chance to get the same entry with a larger
+	   buffer.  */
+	--entidx;
+    }
+  while (status == NSS_STATUS_RETURN);
+
+  __libc_lock_unlock (lock);
+
+  return status;
+}
diff --git a/glibc-compat/nss_db/db-alias.c b/glibc-compat/nss_db/db-alias.c
new file mode 100644
index 0000000000..b9b9489989
--- /dev/null
+++ b/glibc-compat/nss_db/db-alias.c
@@ -0,0 +1,208 @@
+/* Mail alias file parser in nss_db module.
+   Copyright (C) 1996, 1997, 1998, 1999, 2000 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include <glibc-compat/include/aliases.h>
+#include <alloca.h>
+#include <ctype.h>
+#include <dlfcn.h>
+#include <errno.h>
+#include <bits/libc-lock.h>
+#include <paths.h>
+#include <string.h>
+
+#include "nsswitch.h"
+#include "nss_db.h"
+
+/* Locks the static variables in this file.  */
+__libc_lock_define_initialized (static, lock)
+
+/* Maintenance of the shared handle open on the database.  */
+
+static NSS_DB *db;
+static int keep_db;
+static unsigned int entidx;	/* Index for `getaliasent_r'. */
+
+
+/* Open database.  */
+enum nss_status
+_nss_db_setaliasent (int stayopen)
+{
+  enum nss_status status;
+
+  __libc_lock_lock (lock);
+
+  status = internal_setent (_PATH_VARDB "aliases.db", &db);
+
+  /* Remember STAYOPEN flag.  */
+  if (db != NULL)
+    keep_db |= stayopen;
+
+  /* Reset the sequential index.  */
+  entidx = 0;
+
+  __libc_lock_unlock (lock);
+
+  return status;
+}
+
+
+/* Close it again.  */
+enum nss_status
+_nss_db_endaliasent (void)
+{
+  __libc_lock_lock (lock);
+
+  internal_endent (&db);
+
+  /* Reset STAYOPEN flag.  */
+  keep_db = 0;
+
+  __libc_lock_unlock (lock);
+
+  return NSS_STATUS_SUCCESS;
+}
+
+/* We provide the parse function here.  The parser in libnss_files
+   cannot be used.  The generation of the db file already resolved all
+   :include: statements so we simply have to parse the list and store
+   the result.  */
+static enum nss_status
+lookup (DBT *key, struct aliasent *result, char *buffer,
+	size_t buflen)
+{
+  enum nss_status status;
+  DBT value;
+
+  /* Open the database.  */
+  if (db == NULL)
+    {
+      status = internal_setent (_PATH_VARDB "aliases.db", &db);
+      if (status != NSS_STATUS_SUCCESS)
+	return status;
+    }
+
+  value.flags = 0;
+  if (DL_CALL_FCT (db->get, (db->db, NULL, key, &value, 0)) == 0)
+    {
+      const char *src = value.data;
+      char *cp;
+      size_t cnt;
+
+      result->alias_members_len = 0;
+
+      /* We now have to fill the BUFFER with all the information. */
+      if (buflen < key->size + 1)
+	{
+	no_more_room:
+	  __set_errno (ERANGE);
+	  return NSS_STATUS_TRYAGAIN;
+	}
+
+      buffer = stpncpy (buffer, key->data, key->size) + 1;
+      buflen -= key->size + 1;
+
+      while (*src != '\0')
+	{
+	  const char *end, *upto;
+	  while (isspace (*src))
+	    ++src;
+
+	  end = strchr (src, ',');
+	  if (end == NULL)
+	    end = strchr (src, '\0');
+	  for (upto = end; upto > src && isspace (upto[-1]); --upto);
+
+	  if (upto != src)
+	    {
+	      if ((upto - src) + __alignof__ (char *) > buflen)
+		goto no_more_room;
+	      buffer = stpncpy (buffer, src, upto - src) + 1;
+	      buflen -= (upto - src) + __alignof (char *);
+	      ++result->alias_members_len;
+	    }
+	  src = end + (*end != '\0');
+	}
+
+      /* Now prepare the return.  Provide string pointers for the
+	 currently selected aliases.  */
+
+      /* Adjust the pointer so it is aligned for storing pointers.  */
+      buffer += __alignof__ (char *) - 1;
+      buffer -= ((buffer - (char *) 0) % __alignof__ (char *));
+      result->alias_members = (char **) buffer;
+
+      /* Compute addresses of alias entry strings.  */
+      cp = result->alias_name;
+      for (cnt = 0; cnt < result->alias_members_len; ++cnt)
+	{
+	  cp = strchr (cp, '\0') + 1;
+	  result->alias_members[cnt] = cp;
+	}
+
+      status = (result->alias_members_len == 0
+		? NSS_STATUS_RETURN : NSS_STATUS_SUCCESS);
+    }
+  else
+    status = NSS_STATUS_NOTFOUND;
+
+  if (! keep_db)
+    internal_endent (&db);
+
+  return status;
+}
+
+enum nss_status
+_nss_db_getaliasent_r (struct aliasent *result, char *buffer, size_t buflen)
+{
+  /* Return next entry in alias file.  */
+  enum nss_status status;
+  char buf[20];
+  DBT key;
+
+  __libc_lock_lock (lock);
+  key.size = snprintf (key.data = buf, sizeof buf, "0%u", entidx++);
+  key.flags = 0;
+  status = lookup (&key, result, buffer, buflen);
+  __libc_lock_unlock (lock);
+
+  return status;
+}
+
+
+enum nss_status
+_nss_db_getaliasbyname_r (const char *name, struct aliasent *result,
+			  char *buffer, size_t buflen)
+{
+  DBT key;
+  enum nss_status status;
+
+  key.size = 1 + strlen (name);
+
+  key.data = __alloca (key.size);
+  ((char *) key.data)[0] = '.';
+  memcpy (&((char *) key.data)[1], name, key.size - 1);
+  key.flags = 0;
+
+  __libc_lock_lock (lock);
+  status = lookup (&key, result, buffer, buflen);
+  __libc_lock_unlock (lock);
+
+  return status;
+}
diff --git a/glibc-compat/nss_db/db-netgrp.c b/glibc-compat/nss_db/db-netgrp.c
new file mode 100644
index 0000000000..73309077e1
--- /dev/null
+++ b/glibc-compat/nss_db/db-netgrp.c
@@ -0,0 +1,101 @@
+/* Netgroup file parser in nss_db modules.
+   Copyright (C) 1996, 1997, 1999, 2000 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include <dlfcn.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <netgroup.h>
+#include <string.h>
+#include <bits/libc-lock.h>
+#include <paths.h>
+
+#include "nsswitch.h"
+#include "nss_db.h"
+
+
+#define DBFILE		_PATH_VARDB "netgroup.db"
+
+
+/* Locks the static variables in this file.  */
+__libc_lock_define_initialized (static, lock)
+
+/* Maintenance of the shared handle open on the database.  */
+static NSS_DB *db;
+static char *entry;
+static char *cursor;
+
+enum nss_status
+_nss_db_setnetgrent (const char *group)
+{
+  enum nss_status status;
+
+  __libc_lock_lock (lock);
+
+  status = internal_setent (DBFILE, &db);
+
+  if (status == NSS_STATUS_SUCCESS)
+    {
+      DBT key = { data: (void *) group, size: strlen (group), flags: 0 };
+      DBT value;
+
+      value.flags = 0;
+      if (DL_CALL_FCT (db->get, (db->db, NULL, &key, &value, 0)) != 0)
+	status = NSS_STATUS_NOTFOUND;
+      else
+	cursor = entry = value.data;
+    }
+
+  __libc_lock_unlock (lock);
+
+  return status;
+
+}
+
+
+enum nss_status
+_nss_db_endnetgrent (void)
+{
+  __libc_lock_lock (lock);
+
+  internal_endent (&db);
+
+  __libc_lock_unlock (lock);
+
+  return NSS_STATUS_SUCCESS;
+}
+
+
+extern enum nss_status _nss_netgroup_parseline (char **cursor,
+						struct __netgrent *result,
+						char *buffer, int buflen);
+
+enum nss_status
+_nss_db_getnetgrent_r (struct __netgrent *result, char *buffer, size_t buflen)
+{
+  int status;
+
+  __libc_lock_lock (lock);
+
+  status = _nss_netgroup_parseline (&cursor, result, buffer, buflen);
+
+  __libc_lock_unlock (lock);
+  
+  return status;
+}
diff --git a/glibc-compat/nss_db/db-open.c b/glibc-compat/nss_db/db-open.c
new file mode 100644
index 0000000000..99ff3030f0
--- /dev/null
+++ b/glibc-compat/nss_db/db-open.c
@@ -0,0 +1 @@
+#include <nss/nss_db/db-open.c>
diff --git a/glibc-compat/nss_db/dummy-db.h b/glibc-compat/nss_db/dummy-db.h
new file mode 100644
index 0000000000..aed84621c1
--- /dev/null
+++ b/glibc-compat/nss_db/dummy-db.h
@@ -0,0 +1 @@
+#include <nss/nss_db/dummy-db.h>
diff --git a/glibc-compat/nss_db/nss_db.h b/glibc-compat/nss_db/nss_db.h
new file mode 100644
index 0000000000..0bd98b5866
--- /dev/null
+++ b/glibc-compat/nss_db/nss_db.h
@@ -0,0 +1 @@
+#include <nss/nss_db/nss_db.h>
diff --git a/glibc-compat/nss_dns/dns-host.c b/glibc-compat/nss_dns/dns-host.c
new file mode 100644
index 0000000000..5db030cde1
--- /dev/null
+++ b/glibc-compat/nss_dns/dns-host.c
@@ -0,0 +1,641 @@
+/* Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Extended from original form by Ulrich Drepper <drepper@cygnus.com>, 1996.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+/* Parts of this file are plain copies of the file `gethtnamadr.c' from
+   the bind package and it has the following copyright.  */
+
+/*
+ * ++Copyright++ 1985, 1988, 1993
+ * -
+ * Copyright (c) 1985, 1988, 1993
+ *    The Regents of the University of California.  All rights reserved.
+ *
+ * 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. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ * 	This product includes software developed by the University of
+ * 	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
+ * -
+ * Portions Copyright (c) 1993 by Digital Equipment Corporation.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies, and that
+ * the name of Digital Equipment Corporation not be used in advertising or
+ * publicity pertaining to distribution of the document or software without
+ * specific, written prior permission.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS.   IN NO EVENT SHALL DIGITAL EQUIPMENT
+ * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ * -
+ * --Copyright--
+ */
+
+#include <ctype.h>
+#include <errno.h>
+#include <glibc-compat/include/netdb.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+#include <sys/syslog.h>
+
+#include "nsswitch.h"
+
+/* Get implementation for some internal functions.  */
+#include "../resolv/mapv4v6addr.h"
+#include "../resolv/mapv4v6hostent.h"
+
+/* Maximum number of aliases we allow.  */
+#define MAX_NR_ALIASES	48
+#define MAX_NR_ADDRS	48
+
+#if PACKETSZ > 65536
+# define MAXPACKET	PACKETSZ
+#else
+# define MAXPACKET	65536
+#endif
+/* As per RFC 1034 and 1035 a host name cannot exceed 255 octets in length.  */
+#ifdef MAXHOSTNAMELEN
+# undef MAXHOSTNAMELEN
+#endif
+#define MAXHOSTNAMELEN 256
+
+static const char AskedForGot[] = "\
+gethostby*.getanswer: asked for \"%s\", got \"%s\"";
+
+
+/* We need this time later.  */
+typedef union querybuf
+{
+  HEADER hdr;
+  u_char buf[MAXPACKET];
+} querybuf;
+
+
+static enum nss_status getanswer_r (const querybuf *answer, int anslen,
+				    const char *qname, int qtype,
+				    struct hostent *result, char *buffer,
+				    size_t buflen, int *h_errnop);
+
+enum nss_status
+_nss_dns_gethostbyname2_r (const char *name, int af, struct hostent *result,
+			   char *buffer, size_t buflen, int *h_errnop)
+{
+  union
+    {
+      querybuf *buf;
+      u_char *ptr;
+    } host_buffer;
+  querybuf *orig_host_buffer;
+  int size, type, n;
+  const char *cp;
+  enum nss_status status;
+
+  if ((_res.options & RES_INIT) == 0 && res_init() == -1)
+    {
+      *h_errnop = NETDB_INTERNAL;
+      return NSS_STATUS_UNAVAIL;
+    }
+
+  switch (af) {
+  case AF_INET:
+    size = INADDRSZ;
+    type = T_A;
+    break;
+  case AF_INET6:
+    size = IN6ADDRSZ;
+    type = T_AAAA;
+    break;
+  default:
+    *h_errnop = NETDB_INTERNAL;
+    __set_errno (EAFNOSUPPORT);
+    return NSS_STATUS_UNAVAIL;
+  }
+
+  result->h_addrtype = af;
+  result->h_length = size;
+
+  /*
+   * if there aren't any dots, it could be a user-level alias.
+   * this is also done in res_query() since we are not the only
+   * function that looks up host names.
+   */
+  if (strchr (name, '.') == NULL && (cp = __hostalias (name)) != NULL)
+    name = cp;
+
+  host_buffer.buf = orig_host_buffer = (querybuf *) alloca (1024);
+
+  n = __libc_res_nsearch (&_res, name, C_IN, type, host_buffer.buf->buf, 1024,
+			  &host_buffer.ptr);
+  if (n < 0)
+    {
+      *h_errnop = h_errno;
+      if (host_buffer.buf != orig_host_buffer)
+	free (host_buffer.buf);
+      return errno == ECONNREFUSED ? NSS_STATUS_UNAVAIL : NSS_STATUS_NOTFOUND;
+    }
+
+  status = getanswer_r (host_buffer.buf, n, name, type, result, buffer, buflen,
+			h_errnop);
+  if (host_buffer.buf != orig_host_buffer)
+    free (host_buffer.buf);
+  return status;
+}
+
+
+enum nss_status
+_nss_dns_gethostbyname_r (const char *name, struct hostent *result,
+			  char *buffer, size_t buflen, int *h_errnop)
+{
+  enum nss_status status = NSS_STATUS_NOTFOUND;
+
+  if (_res.options & RES_USE_INET6)
+    status = _nss_dns_gethostbyname2_r (name, AF_INET6, result, buffer,
+					buflen, h_errnop);
+  if (status == NSS_STATUS_NOTFOUND)
+    status = _nss_dns_gethostbyname2_r (name, AF_INET, result, buffer,
+					buflen, h_errnop);
+
+  return status;
+}
+
+
+enum nss_status
+_nss_dns_gethostbyaddr_r (const char *addr, int len, int af,
+			  struct hostent *result, char *buffer, size_t buflen,
+			  int *h_errnop)
+{
+  static const u_char mapped[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0xff,0xff };
+  static const u_char tunnelled[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0,0 };
+  const u_char *uaddr = (const u_char *)addr;
+  struct host_data
+  {
+    char *aliases[MAX_NR_ALIASES];
+    unsigned char host_addr[16];	/* IPv4 or IPv6 */
+    char *h_addr_ptrs[MAX_NR_ADDRS + 1];
+    char linebuffer[0];
+  } *host_data = (struct host_data *) buffer;
+  union
+    {
+      querybuf *buf;
+      u_char *ptr;
+    } host_buffer;
+  querybuf *orig_host_buffer;
+  char qbuf[MAXDNAME+1], *qp;
+  int size, n, status;
+
+  if ((_res.options & RES_INIT) == 0 && res_init() == -1)
+    {
+      *h_errnop = NETDB_INTERNAL;
+      return NSS_STATUS_UNAVAIL;
+    }
+
+  if (af == AF_INET6 && len == IN6ADDRSZ &&
+      (memcmp (uaddr, mapped, sizeof mapped) == 0
+       || memcmp (uaddr, tunnelled, sizeof tunnelled) == 0))
+    {
+      /* Unmap. */
+      addr += sizeof mapped;
+      uaddr += sizeof mapped;
+      af = AF_INET;
+      len = INADDRSZ;
+    }
+
+  switch (af)
+    {
+    case AF_INET:
+      size = INADDRSZ;
+      break;
+    case AF_INET6:
+      size = IN6ADDRSZ;
+      break;
+    default:
+      __set_errno (EAFNOSUPPORT);
+      *h_errnop = NETDB_INTERNAL;
+      return NSS_STATUS_UNAVAIL;
+    }
+  if (size != len)
+    {
+      __set_errno (EAFNOSUPPORT);
+      *h_errnop = NETDB_INTERNAL;
+      return NSS_STATUS_UNAVAIL;
+    }
+
+  switch (af)
+    {
+    case AF_INET:
+      sprintf (qbuf, "%u.%u.%u.%u.in-addr.arpa", (uaddr[3] & 0xff),
+	       (uaddr[2] & 0xff), (uaddr[1] & 0xff), (uaddr[0] & 0xff));
+      break;
+    case AF_INET6:
+      qp = qbuf;
+      for (n = IN6ADDRSZ - 1; n >= 0; n--)
+	qp += sprintf (qp, "%x.%x.", uaddr[n] & 0xf, (uaddr[n] >> 4) & 0xf);
+      strcpy(qp, "ip6.int");
+      break;
+    default:
+      /* Cannot happen.  */
+      break;
+    }
+
+  host_buffer.buf = orig_host_buffer = (querybuf *) alloca (1024);
+
+  n = __libc_res_nquery (&_res, qbuf, C_IN, T_PTR, host_buffer.buf->buf,
+			 1024, &host_buffer.ptr);
+  if (n < 0)
+    {
+      *h_errnop = h_errno;
+      if (host_buffer.buf != orig_host_buffer)
+	free (host_buffer.buf);
+      return errno == ECONNREFUSED ? NSS_STATUS_UNAVAIL : NSS_STATUS_NOTFOUND;
+    }
+
+  status = getanswer_r (host_buffer.buf, n, qbuf, T_PTR, result, buffer, buflen,
+			h_errnop);
+  if (host_buffer.buf != orig_host_buffer)
+    free (host_buffer.buf);
+  if (status != NSS_STATUS_SUCCESS)
+    {
+      *h_errnop = h_errno;
+      return status;
+    }
+
+#ifdef SUNSECURITY
+  This is not implemented because it is not possible to use the current
+  source from bind in a multi-threaded program.
+#endif
+
+  result->h_addrtype = af;
+  result->h_length = len;
+  memcpy (host_data->host_addr, addr, len);
+  host_data->h_addr_ptrs[0] = (char *) host_data->host_addr;
+  host_data->h_addr_ptrs[1] = NULL;
+  if (af == AF_INET && (_res.options & RES_USE_INET6))
+    {
+      map_v4v6_address ((char *) host_data->host_addr,
+			(char *) host_data->host_addr);
+      result->h_addrtype = AF_INET6;
+      result->h_length = IN6ADDRSZ;
+    }
+  *h_errnop = NETDB_SUCCESS;
+  return NSS_STATUS_SUCCESS;
+}
+
+
+static enum nss_status
+getanswer_r (const querybuf *answer, int anslen, const char *qname, int qtype,
+	     struct hostent *result, char *buffer, size_t buflen,
+	     int *h_errnop)
+{
+  struct host_data
+  {
+    char *aliases[MAX_NR_ALIASES];
+    unsigned char host_addr[16];	/* IPv4 or IPv6 */
+    char *h_addr_ptrs[MAX_NR_ADDRS + 1];
+    char linebuffer[0];
+  } *host_data = (struct host_data *) buffer;
+  int linebuflen = buflen - offsetof (struct host_data, linebuffer);
+  register const HEADER *hp;
+  const u_char *end_of_message, *cp;
+  int n, ancount, qdcount;
+  int haveanswer, had_error;
+  char *bp, **ap, **hap;
+  char tbuf[MAXDNAME];
+  const char *tname;
+  int (*name_ok) (const char *);
+
+  tname = qname;
+  result->h_name = NULL;
+  end_of_message = answer->buf + anslen;
+  switch (qtype)
+    {
+    case T_A:
+    case T_AAAA:
+      name_ok = res_hnok;
+      break;
+    case T_PTR:
+      name_ok = res_dnok;
+      break;
+    default:
+      return NSS_STATUS_UNAVAIL;  /* XXX should be abort(); */
+    }
+
+  /*
+   * find first satisfactory answer
+   */
+  hp = &answer->hdr;
+  bp = host_data->linebuffer;
+  ancount = ntohs (hp->ancount);
+  qdcount = ntohs (hp->qdcount);
+  cp = answer->buf + HFIXEDSZ;
+  if (qdcount != 1)
+    {
+      *h_errnop = NO_RECOVERY;
+      return NSS_STATUS_UNAVAIL;
+    }
+
+  n = dn_expand (answer->buf, end_of_message, cp, bp, linebuflen);
+  if (n < 0 || (*name_ok) (bp) == 0)
+    {
+      *h_errnop = NO_RECOVERY;
+      return NSS_STATUS_UNAVAIL;
+    }
+  cp += n + QFIXEDSZ;
+
+  if (qtype == T_A || qtype == T_AAAA)
+    {
+      /* res_send() has already verified that the query name is the
+       * same as the one we sent; this just gets the expanded name
+       * (i.e., with the succeeding search-domain tacked on).
+       */
+      n = strlen (bp) + 1;             /* for the \0 */
+      if (n >= MAXHOSTNAMELEN)
+	{
+	  __set_h_errno (NO_RECOVERY);
+	  return NSS_STATUS_TRYAGAIN;
+	}
+      result->h_name = bp;
+      bp += n;
+      linebuflen -= n;
+      /* The qname can be abbreviated, but h_name is now absolute. */
+      qname = result->h_name;
+    }
+
+  ap = host_data->aliases;
+  *ap = NULL;
+  result->h_aliases = host_data->aliases;
+  hap = host_data->h_addr_ptrs;
+  *hap = NULL;
+  result->h_addr_list = host_data->h_addr_ptrs;
+  haveanswer = 0;
+  had_error = 0;
+
+  while (ancount-- > 0 && cp < end_of_message && had_error == 0)
+    {
+      int type, class;
+
+      n = dn_expand (answer->buf, end_of_message, cp, bp, linebuflen);
+      if (n < 0 || (*name_ok) (bp) == 0)
+	{
+	  ++had_error;
+	  continue;
+	}
+      cp += n;				/* name */
+      type = _getshort (cp);
+      cp += INT16SZ;			/* type */
+      class = _getshort(cp);
+      cp += INT16SZ + INT32SZ;		/* class, TTL */
+      n = _getshort(cp);
+      cp += INT16SZ;			/* len */
+      if (class != C_IN)
+	{
+	  /* XXX - debug? syslog? */
+	  cp += n;
+	  continue;			/* XXX - had_error++ ? */
+	}
+
+      if ((qtype ==T_A || qtype == T_AAAA) && type == T_CNAME)
+	{
+	  if (ap >= &host_data->aliases[MAX_NR_ALIASES - 1])
+	    continue;
+	  n = dn_expand (answer->buf, end_of_message, cp, tbuf, sizeof tbuf);
+	  if (n < 0 || (*name_ok) (tbuf) == 0)
+	    {
+	      ++had_error;
+	      continue;
+	    }
+	  cp += n;
+	  /* Store alias.  */
+	  *ap++ = bp;
+	  n = strlen (bp) + 1;		/* For the \0.  */
+	  if (n >= MAXHOSTNAMELEN)
+	    {
+	      ++had_error;
+	      continue;
+	    }
+	  bp += n;
+	  linebuflen -= n;
+	  /* Get canonical name.  */
+	  n = strlen (tbuf) + 1;	/* For the \0.  */
+	  if ((size_t) n > linebuflen || n >= MAXHOSTNAMELEN)
+	    {
+	      ++had_error;
+	      continue;
+	    }
+	  strcpy (bp, tbuf);		/* Cannot overflow.  */
+	  result->h_name = bp;
+	  bp += n;
+	  linebuflen -= n;
+	  continue;
+	}
+
+      if (qtype == T_PTR && type == T_CNAME)
+	{
+	  n = dn_expand (answer->buf, end_of_message, cp, tbuf, sizeof tbuf);
+	  if (n < 0 || res_dnok (tbuf) == 0)
+	    {
+	      ++had_error;
+	      continue;
+	    }
+	  cp += n;
+	  /* Get canonical name. */
+	  n = strlen (tbuf) + 1;   /* For the \0.  */
+	  if ((size_t) n > linebuflen || n >= MAXHOSTNAMELEN)
+	    {
+	      ++had_error;
+	      continue;
+	    }
+	  strcpy (bp, tbuf);		/* Cannot overflow.  */
+	  tname = bp;
+	  bp += n;
+	  linebuflen -= n;
+	  continue;
+	}
+      if (type != qtype)
+	{
+	  syslog (LOG_NOTICE | LOG_AUTH,
+	       "gethostby*.getanswer: asked for \"%s %s %s\", got type \"%s\"",
+		  qname, p_class (C_IN), p_type (qtype), p_type (type));
+	  cp += n;
+	  continue;			/* XXX - had_error++ ? */
+	}
+
+      switch (type)
+	{
+	case T_PTR:
+	  if (strcasecmp (tname, bp) != 0)
+	    {
+	      syslog (LOG_NOTICE | LOG_AUTH, AskedForGot, qname, bp);
+	      cp += n;
+	      continue;			/* XXX - had_error++ ? */
+	    }
+	  n = dn_expand (answer->buf, end_of_message, cp, bp, linebuflen);
+	  if (n < 0 || res_hnok (bp) == 0)
+	    {
+	      ++had_error;
+	      break;
+	    }
+#if MULTI_PTRS_ARE_ALIASES
+	  cp += n;
+	  if (haveanswer == 0)
+	    result->h_name = bp;
+	  else if (ap < &host_data->aliases[MAXALIASES-1])
+	    *ap++ = bp;
+	  else
+	    n = -1;
+	  if (n != -1)
+	    {
+	      n = strlen (bp) + 1;	/* for the \0 */
+	      if (n >= MAXHOSTNAMELEN)
+		{
+		  ++had_error;
+		  break;
+		}
+	      bp += n;
+	      linebuflen -= n;
+	    }
+	  break;
+#else
+	  result->h_name = bp;
+	  if (_res.options & RES_USE_INET6)
+	    {
+	      n = strlen (bp) + 1;	/* for the \0 */
+	      if (n >= MAXHOSTNAMELEN)
+		{
+		  ++had_error;
+		  break;
+		}
+	      bp += n;
+	      linebuflen -= n;
+	      map_v4v6_hostent (result, &bp, &linebuflen);
+	    }
+	  *h_errnop = NETDB_SUCCESS;
+	  return NSS_STATUS_SUCCESS;
+#endif
+	case T_A:
+	case T_AAAA:
+	  if (strcasecmp (result->h_name, bp) != 0)
+	    {
+	      syslog (LOG_NOTICE | LOG_AUTH, AskedForGot, result->h_name, bp);
+	      cp += n;
+	      continue;			/* XXX - had_error++ ? */
+	    }
+	  if (n != result->h_length)
+	    {
+	      cp += n;
+	      continue;
+	    }
+	  if (!haveanswer)
+	    {
+	      register int nn;
+
+	      result->h_name = bp;
+	      nn = strlen (bp) + 1;	/* for the \0 */
+	      bp += nn;
+	      linebuflen -= nn;
+	    }
+
+	  linebuflen -= sizeof (align) - ((u_long) bp % sizeof (align));
+	  bp += sizeof (align) - ((u_long) bp % sizeof (align));
+
+	  if (n >= linebuflen)
+	    {
+	      ++had_error;
+	      continue;
+	    }
+	  if (hap >= &host_data->h_addr_ptrs[MAX_NR_ADDRS-1])
+	    {
+	      cp += n;
+	      continue;
+	    }
+	  memcpy (*hap++ = bp, cp, n);
+	  bp += n;
+	  cp += n;
+	  linebuflen -= n;
+	  break;
+	default:
+	  abort ();
+	}
+      if (had_error == 0)
+	++haveanswer;
+    }
+
+  if (haveanswer > 0)
+    {
+      *ap = NULL;
+      *hap = NULL;
+#if defined(RESOLVSORT)
+      /*
+       * Note: we sort even if host can take only one address
+       * in its return structures - should give it the "best"
+       * address in that case, not some random one
+       */
+      if (_res.nsort && haveanswer > 1 && qtype == T_A)
+	addrsort (host_data->h_addr_ptrs, haveanswer);
+#endif /*RESOLVSORT*/
+
+      if (result->h_name == NULL)
+	{
+	  n = strlen (qname) + 1;	/* For the \0.  */
+	  if (n > linebuflen || n >= MAXHOSTNAMELEN)
+	    goto no_recovery;
+	  strcpy (bp, qname);		/* Cannot overflow.  */
+	  result->h_name = bp;
+	  bp += n;
+	  linebuflen -= n;
+	}
+
+      if (_res.options & RES_USE_INET6)
+	map_v4v6_hostent (result, &bp, &linebuflen);
+      *h_errnop = NETDB_SUCCESS;
+      return NSS_STATUS_SUCCESS;
+    }
+ no_recovery:
+  *h_errnop = NO_RECOVERY;
+  return NSS_STATUS_TRYAGAIN;
+}
diff --git a/glibc-compat/nss_dns/dns-network.c b/glibc-compat/nss_dns/dns-network.c
new file mode 100644
index 0000000000..b6c7a4fdc9
--- /dev/null
+++ b/glibc-compat/nss_dns/dns-network.c
@@ -0,0 +1,420 @@
+/* Copyright (C) 1996, 1997 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Extended from original form by Ulrich Drepper <drepper@cygnus.com>, 1996.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+/* Parts of this file are plain copies of the file `getnetnamadr.c' from
+   the bind package and it has the following copyright.  */
+
+/* Copyright (c) 1993 Carlos Leandro and Rui Salgueiro
+ *      Dep. Matematica Universidade de Coimbra, Portugal, Europe
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ */
+/*
+ * Copyright (c) 1983, 1993
+ *      The Regents of the University of California.  All rights reserved.
+ *
+ * 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. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *      This product includes software developed by the University of
+ *      California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
+ */
+
+#include <ctype.h>
+#include <errno.h>
+#include <glibc-compat/include/netdb.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "nsswitch.h"
+#include <arpa/inet.h>
+
+/* Maximum number of aliases we allow.  */
+#define MAX_NR_ALIASES	48
+
+
+#if PACKETSZ > 65536
+#define MAXPACKET       PACKETSZ
+#else
+#define MAXPACKET       65536
+#endif
+
+
+typedef enum
+{
+  BYADDR,
+  BYNAME
+} lookup_method;
+
+
+/* We need this time later.  */
+typedef union querybuf
+{
+  HEADER hdr;
+  u_char buf[MAXPACKET];
+} querybuf;
+
+
+/* Prototypes for local functions.  */
+static enum nss_status getanswer_r (const querybuf *answer, int anslen,
+				    struct netent *result, char *buffer,
+				    size_t buflen, lookup_method net_i);
+
+
+enum nss_status
+_nss_dns_getnetbyname_r (const char *name, struct netent *result,
+			 char *buffer, size_t buflen)
+{
+  /* Return entry for network with NAME.  */
+  union
+  {
+    querybuf *buf;
+    u_char *ptr;
+  } net_buffer;
+  querybuf *orig_net_buffer;
+  int anslen;
+  char *qbuf;
+  enum nss_status status;
+
+  if ((_res.options & RES_INIT) == 0 && res_init() == -1)
+    return NSS_STATUS_UNAVAIL;
+
+  qbuf = strdupa (name);
+
+  net_buffer.buf = orig_net_buffer = (querybuf *) alloca (1024);
+
+  anslen = __libc_res_nsearch (&_res, qbuf, C_IN, T_PTR, net_buffer.buf->buf,
+			       1024, &net_buffer.ptr);
+  if (anslen < 0)
+    {
+      if (net_buffer.buf != orig_net_buffer)
+	free (net_buffer.buf);
+      /* Nothing found.  */
+      return (errno == ECONNREFUSED
+	      || errno == EPFNOSUPPORT
+	      || errno == EAFNOSUPPORT)
+	      ? NSS_STATUS_UNAVAIL : NSS_STATUS_NOTFOUND;
+    }
+
+  status = getanswer_r (net_buffer.buf, anslen, result, buffer, buflen, BYNAME);
+  if (net_buffer.buf != orig_net_buffer)
+    free (net_buffer.buf);
+  return status;
+}
+
+
+enum nss_status
+_nss_dns_getnetbyaddr_r (long net, int type, struct netent *result,
+			 char *buffer, size_t buflen)
+{
+  /* Return entry for network with NAME.  */
+  enum nss_status status;
+  union
+  {
+    querybuf *buf;
+    u_char *ptr;
+  } net_buffer;
+  querybuf *orig_net_buffer;
+  unsigned int net_bytes[4];
+  char qbuf[MAXDNAME];
+  int cnt, anslen;
+  u_int32_t net2;
+
+  if ((_res.options & RES_INIT) == 0 && res_init() == -1)
+    return NSS_STATUS_UNAVAIL;
+
+  /* No net address lookup for IPv6 yet.  */
+  if (type != AF_INET)
+    return NSS_STATUS_UNAVAIL;
+
+  net2 = (u_int32_t) net;
+  for (cnt = 4; net2 != 0; net2 >>= 8)
+    net_bytes[--cnt] = net2 & 0xff;
+
+  switch (cnt)
+    {
+    case 3:
+      /* Class A network.  */
+      sprintf (qbuf, "0.0.0.%u.in-addr.arpa", net_bytes[3]);
+      break;
+    case 2:
+      /* Class B network.  */
+      sprintf (qbuf, "0.0.%u.%u.in-addr.arpa", net_bytes[3], net_bytes[2]);
+      break;
+    case 1:
+      /* Class C network.  */
+      sprintf (qbuf, "0.%u.%u.%u.in-addr.arpa", net_bytes[3], net_bytes[2],
+	       net_bytes[1]);
+      break;
+    case 0:
+      /* Class D - E network.  */
+      sprintf (qbuf, "%u.%u.%u.%u.in-addr.arpa", net_bytes[3], net_bytes[2],
+	       net_bytes[1], net_bytes[0]);
+      break;
+    }
+
+  net_buffer.buf = orig_net_buffer = (querybuf *) alloca (1024);
+
+  anslen = __libc_res_nquery (&_res, qbuf, C_IN, T_PTR, net_buffer.buf->buf,
+			      1024, &net_buffer.ptr);
+  if (anslen < 0)
+    {
+      if (net_buffer.buf != orig_net_buffer)
+	free (net_buffer.buf);
+      /* Nothing found.  */
+      return (errno == ECONNREFUSED
+	      || errno == EPFNOSUPPORT
+	      || errno == EAFNOSUPPORT)
+	      ? NSS_STATUS_UNAVAIL : NSS_STATUS_NOTFOUND;
+    }
+
+  status = getanswer_r (net_buffer.buf, anslen, result, buffer, buflen, BYADDR);
+  if (net_buffer.buf != orig_net_buffer)
+    free (net_buffer.buf);
+  if (status == NSS_STATUS_SUCCESS)
+    {
+      /* Strip trailing zeros.  */
+      unsigned int u_net = net;	/* Maybe net should be unsigned?  */
+
+      while ((u_net & 0xff) == 0 && u_net != 0)
+	u_net >>= 8;
+      result->n_net = u_net;
+    }
+
+  return status;
+}
+
+
+#undef offsetof
+#define offsetof(Type, Member) ((size_t) &((Type *) NULL)->Member)
+
+static enum nss_status
+getanswer_r (const querybuf *answer, int anslen, struct netent *result,
+	     char *buffer, size_t buflen, lookup_method net_i)
+{
+  /*
+   * Find first satisfactory answer
+   *
+   *      answer --> +------------+  ( MESSAGE )
+   *                 |   Header   |
+   *                 +------------+
+   *                 |  Question  | the question for the name server
+   *                 +------------+
+   *                 |   Answer   | RRs answering the question
+   *                 +------------+
+   *                 | Authority  | RRs pointing toward an authority
+   *                 | Additional | RRs holding additional information
+   *                 +------------+
+   */
+  struct net_data
+  {
+    char *aliases[MAX_NR_ALIASES];
+    char linebuffer[0];
+  } *net_data = (struct net_data *) buffer;
+  int linebuflen = buflen - offsetof (struct net_data, linebuffer);
+  const char *end_of_message = &answer->buf[anslen];
+  const HEADER *header_pointer = &answer->hdr;
+  /* #/records in the answer section.  */
+  int answer_count =  ntohs (header_pointer->ancount);
+  /* #/entries in the question section.  */
+  int question_count = ntohs (header_pointer->qdcount);
+  char *bp = net_data->linebuffer;
+  const char *cp = &answer->buf[HFIXEDSZ];
+  char **alias_pointer;
+  int have_answer;
+  char *ans;
+
+  if (question_count == 0)
+    {
+      /* FIXME: the Sun version uses for host name lookup an additional
+	 parameter for pointing to h_errno.  this is missing here.
+	 OSF/1 has a per-thread h_errno variable.  */
+      if (header_pointer->aa != 0)
+	{
+	  __set_h_errno (HOST_NOT_FOUND);
+	  return NSS_STATUS_NOTFOUND;
+	}
+      else
+	{
+	  __set_h_errno (TRY_AGAIN);
+	  return NSS_STATUS_TRYAGAIN;
+	}
+    }
+
+  /* Skip the question part.  */
+  while (question_count-- > 0)
+    {
+      int n = __dn_skipname (cp, end_of_message);
+      if (n < 0 || end_of_message - (cp + n) < QFIXEDSZ)
+       {
+         __set_h_errno (NO_RECOVERY);
+         return NSS_STATUS_UNAVAIL;
+       }
+      cp += n + QFIXEDSZ;
+    }
+
+  alias_pointer = result->n_aliases = &net_data->aliases[0];
+  *alias_pointer = NULL;
+  have_answer = 0;
+  ans = NULL;
+
+  while (--answer_count >= 0 && cp < end_of_message)
+    {
+      int n = dn_expand (answer->buf, end_of_message, cp, bp, linebuflen);
+      int type, class;
+
+      if (n < 0 || res_dnok (bp) == 0)
+	break;
+      cp += n;
+      ans = strdupa (bp);
+      GETSHORT (type, cp);
+      GETSHORT (class, cp);
+      cp += INT32SZ;		/* TTL */
+      GETSHORT (n, cp);
+
+      if (class == C_IN && type == T_PTR)
+	{
+	  n = dn_expand (answer->buf, end_of_message, cp, bp, linebuflen);
+	  if (n < 0 || !res_hnok (bp))
+	    {
+	      /* XXX What does this mean?  The original form from bind
+		 returns NULL. Incrementing cp has no effect in any case.
+		 What should I return here. ??? */
+	      cp += n;
+	      return NSS_STATUS_UNAVAIL;
+	    }
+	  cp += n;
+         if (alias_pointer + 2 < &net_data->aliases[MAX_NR_ALIASES])
+           {
+             *alias_pointer++ = bp;
+             n = strlen (bp) + 1;
+             bp += n;
+             linebuflen -= n;
+             result->n_addrtype = class == C_IN ? AF_INET : AF_UNSPEC;
+             ++have_answer;
+           }
+	}
+    }
+
+  if (have_answer)
+    {
+      *alias_pointer = NULL;
+      switch (net_i)
+	{
+	case BYADDR:
+	  result->n_name = *result->n_aliases++;
+	  result->n_net = 0L;
+	  return NSS_STATUS_SUCCESS;
+
+	case BYNAME:
+	  {
+	    char **ap = result->n_aliases++;
+	    while (*ap != NULL)
+	      {
+		/* Check each alias name for being of the forms:
+		   4.3.2.1.in-addr.arpa		= net 1.2.3.4
+		   3.2.1.in-addr.arpa		= net 0.1.2.3
+		   2.1.in-addr.arpa		= net 0.0.1.2
+		   1.in-addr.arpa		= net 0.0.0.1
+		*/
+		uint32_t val = 0;	/* Accumulator for n_net value.  */
+		unsigned int shift = 0; /* Which part we are parsing now.  */
+		const char *p = *ap; /* Consuming the string.  */
+		do
+		  {
+		    /* Match the leading 0 or 0[xX] base indicator.  */
+		    unsigned int base = 10;
+		    if (*p == '0' && p[1] != '.')
+		      {
+			base = 8;
+			++p;
+			if (*p == 'x' || *p == 'X')
+			  {
+			    base = 16;
+			    ++p;
+			    if (*p == '.')
+			      break; /* No digit here.  Give up on alias.  */
+			  }
+			if (*p == '\0')
+			  break;
+		      }
+
+		    uint32_t part = 0; /* Accumulates this part's number.  */
+		    do
+		      {
+			if (isdigit (*p) && (*p - '0' < base))
+			  part = (part * base) + (*p - '0');
+			else if (base == 16 && isxdigit (*p))
+			  part = (part << 4) + 10 + (tolower (*p) - 'a');
+			++p;
+		      } while (*p != '\0' && *p != '.');
+
+		    if (*p != '.')
+		      break;	/* Bad form.  Give up on this name.  */
+
+		    /* Install this as the next more significant byte.  */
+		    val |= part << shift;
+		    shift += 8;
+		    ++p;
+
+		    /* If we are out of digits now, there are two cases:
+		       1. We are done with digits and now see "in-addr.arpa".
+		       2. This is not the droid we are looking for.  */
+		    if (!isdigit (*p) && !strcasecmp (p, "in-addr.arpa"))
+		      {
+			result->n_net = val;
+			return NSS_STATUS_SUCCESS;
+		      }
+
+		    /* Keep going when we have seen fewer than 4 parts.  */
+		  } while (shift < 32);
+	      }
+	  }
+	  break;
+	}
+    }
+
+  __set_h_errno (TRY_AGAIN);
+  return NSS_STATUS_TRYAGAIN;
+}
diff --git a/glibc-compat/nss_files/files-XXX.c b/glibc-compat/nss_files/files-XXX.c
new file mode 100644
index 0000000000..fde75a87b4
--- /dev/null
+++ b/glibc-compat/nss_files/files-XXX.c
@@ -0,0 +1,311 @@
+/* Common code for file-based databases in nss_files module.
+   Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <assert.h>
+#include <errno.h>
+#include <bits/libc-lock.h>
+#include "nsswitch.h"
+
+/* These symbols are defined by the including source file:
+
+   ENTNAME -- database name of the structure and functions (hostent, pwent).
+   STRUCTURE -- struct name, define only if not ENTNAME (passwd, group).
+   DATABASE -- string of the database file's name ("hosts", "passwd").
+
+   NEED_H_ERRNO - defined iff an arg `int *herrnop' is used.
+
+   Also see files-parse.c.
+*/
+
+#define ENTNAME_r	CONCAT(ENTNAME,_r)
+
+#define DATAFILE	"/etc/" DATABASE
+
+#ifdef NEED_H_ERRNO
+# include <glibc-compat/include/netdb.h>
+# define H_ERRNO_PROTO	, int *herrnop
+# define H_ERRNO_ARG	, herrnop
+# define H_ERRNO_SET(val) (*herrnop = (val))
+#else
+# define H_ERRNO_PROTO
+# define H_ERRNO_ARG
+# define H_ERRNO_SET(val) ((void) 0)
+#endif
+
+/* Locks the static variables in this file.  */
+__libc_lock_define_initialized (static, lock)
+
+/* Maintenance of the shared stream open on the database file.  */
+
+static FILE *stream;
+static fpos_t position;
+static enum { none, getent, getby } last_use;
+static int keep_stream;
+
+/* Open database file if not already opened.  */
+static enum nss_status
+internal_setent (int stayopen)
+{
+  enum nss_status status = NSS_STATUS_SUCCESS;
+
+  if (stream == NULL)
+    {
+      stream = fopen (DATAFILE, "r");
+
+      if (stream == NULL)
+	status = errno == EAGAIN ? NSS_STATUS_TRYAGAIN : NSS_STATUS_UNAVAIL;
+      else
+	{
+	  /* We have to make sure the file is  `closed on exec'.  */
+	  int result, flags;
+
+	  result = flags = fcntl (fileno (stream), F_GETFD, 0);
+	  if (result >= 0)
+	    {
+	      flags |= FD_CLOEXEC;
+	      result = fcntl (fileno (stream), F_SETFD, flags);
+	    }
+	  if (result < 0)
+	    {
+	      /* Something went wrong.  Close the stream and return a
+		 failure.  */
+	      fclose (stream);
+	      stream = NULL;
+	      status = NSS_STATUS_UNAVAIL;
+	    }
+	}
+    }
+  else
+    rewind (stream);
+
+  /* Remember STAYOPEN flag.  */
+  if (stream != NULL)
+    keep_stream |= stayopen;
+
+  return status;
+}
+
+
+/* Thread-safe, exported version of that.  */
+enum nss_status
+CONCAT(_nss_files_set,ENTNAME) (int stayopen)
+{
+  enum nss_status status;
+
+  __libc_lock_lock (lock);
+
+  status = internal_setent (stayopen);
+
+  if (status == NSS_STATUS_SUCCESS && fgetpos (stream, &position) < 0)
+    {
+      fclose (stream);
+      stream = NULL;
+      status = NSS_STATUS_UNAVAIL;
+    }
+
+  last_use = getent;
+
+  __libc_lock_unlock (lock);
+
+  return status;
+}
+
+
+/* Close the database file.  */
+static void
+internal_endent (void)
+{
+  if (stream != NULL)
+    {
+      fclose (stream);
+      stream = NULL;
+    }
+}
+
+
+/* Thread-safe, exported version of that.  */
+enum nss_status
+CONCAT(_nss_files_end,ENTNAME) (void)
+{
+  __libc_lock_lock (lock);
+
+  internal_endent ();
+
+  /* Reset STAYOPEN flag.  */
+  keep_stream = 0;
+
+  __libc_lock_unlock (lock);
+
+  return NSS_STATUS_SUCCESS;
+}
+
+/* Parsing the database file into `struct STRUCTURE' data structures.  */
+
+static enum nss_status
+internal_getent (struct STRUCTURE *result,
+		 char *buffer, int buflen H_ERRNO_PROTO)
+{
+  char *p;
+  struct parser_data *data = (void *) buffer;
+  int linebuflen = buffer + buflen - data->linebuffer;
+  int parse_result;
+
+  if (buflen < (int) sizeof *data + 1)
+    {
+      __set_errno (ERANGE);
+      H_ERRNO_SET (NETDB_INTERNAL);
+      return NSS_STATUS_TRYAGAIN;
+    }
+
+  do
+    {
+      /* Terminate the line so that we can test for overflow.  */
+      data->linebuffer[linebuflen - 1] = '\xff';
+
+      p = fgets (data->linebuffer, linebuflen, stream);
+      if (p == NULL && feof (stream))
+	{
+	  /* End of file or read error.  */
+	  __set_errno (ENOENT);
+	  H_ERRNO_SET (HOST_NOT_FOUND);
+	  return NSS_STATUS_NOTFOUND;
+	}
+      else if (p == NULL || data->linebuffer[linebuflen - 1] != '\xff')
+	{
+	  /* The line is too long.  Give the user the opportunity to
+	     enlarge the buffer.  */
+	  __set_errno (ERANGE);
+	  H_ERRNO_SET (NETDB_INTERNAL);
+	  return NSS_STATUS_TRYAGAIN;
+	}
+
+      /* Skip leading blanks.  */
+      while (isspace (*p))
+	++p;
+    }
+  while (*p == '\0' || *p == '#' /* Ignore empty and comment lines.  */
+	 /* Parse the line.  If it is invalid, loop to get the next
+	    line of the file to parse.  */
+	 || ! (parse_result = parse_line (p, result, data, buflen)));
+
+  /* Filled in RESULT with the next entry from the database file.  */
+  return parse_result == -1 ? NSS_STATUS_TRYAGAIN : NSS_STATUS_SUCCESS;
+}
+
+
+/* Return the next entry from the database file, doing locking.  */
+enum nss_status
+CONCAT(_nss_files_get,ENTNAME_r) (struct STRUCTURE *result,
+				  char *buffer, size_t buflen H_ERRNO_PROTO)
+{
+  /* Return next entry in host file.  */
+  enum nss_status status = NSS_STATUS_SUCCESS;
+
+  __libc_lock_lock (lock);
+
+  /* Be prepared that the set*ent function was not called before.  */
+  if (stream == NULL)
+    {
+      status = internal_setent (0);
+
+      if (status == NSS_STATUS_SUCCESS && fgetpos (stream, &position) < 0)
+	{
+	  fclose (stream);
+	  stream = NULL;
+	  status = NSS_STATUS_UNAVAIL;
+	}
+    }
+
+  if (status == NSS_STATUS_SUCCESS)
+    {
+      /* If the last use was not by the getent function we need the
+	 position the stream.  */
+      if (last_use != getent)
+	{
+	  if (fsetpos (stream, &position) < 0)
+	    status = NSS_STATUS_UNAVAIL;
+	  else
+	    last_use = getent;
+	}
+
+      if (status == NSS_STATUS_SUCCESS)
+	{
+	  status = internal_getent (result, buffer, buflen H_ERRNO_ARG);
+
+	  /* Remember this position if we were successful.  If the
+	     operation failed we give the user a chance to repeat the
+	     operation (perhaps the buffer was too small).  */
+	  if (status == NSS_STATUS_SUCCESS)
+	    fgetpos (stream, &position);
+	  else
+	    /* We must make sure we reposition the stream the next call.  */
+	    last_use = none;
+	}
+    }
+
+  __libc_lock_unlock (lock);
+
+  return status;
+}
+
+/* Macro for defining lookup functions for this file-based database.
+
+   NAME is the name of the lookup; e.g. `hostbyname'.
+
+   KEYSIZE and KEYPATTERN are ignored here but used by ../nss_db/db-XXX.c.
+
+   PROTO describes the arguments for the lookup key;
+   e.g. `const char *hostname'.
+
+   BREAK_IF_MATCH is a block of code which compares `struct STRUCTURE *result'
+   to the lookup key arguments and does `break;' if they match.  */
+
+#define DB_LOOKUP(name, keysize, keypattern, break_if_match, proto...)	      \
+enum nss_status								      \
+_nss_files_get##name##_r (proto,					      \
+			  struct STRUCTURE *result,			      \
+			  char *buffer, size_t buflen H_ERRNO_PROTO)	      \
+{									      \
+  enum nss_status status;						      \
+									      \
+  __libc_lock_lock (lock);						      \
+									      \
+  /* Reset file pointer to beginning or open file.  */			      \
+  status = internal_setent (keep_stream);				      \
+									      \
+  if (status == NSS_STATUS_SUCCESS)					      \
+    {									      \
+      /* Tell getent function that we have repositioned the file pointer.  */ \
+      last_use = getby;							      \
+									      \
+      while ((status = internal_getent (result, buffer, buflen H_ERRNO_ARG))  \
+	     == NSS_STATUS_SUCCESS)					      \
+	{ break_if_match }						      \
+									      \
+      if (! keep_stream)						      \
+	internal_endent ();						      \
+    }									      \
+									      \
+  __libc_lock_unlock (lock);						      \
+									      \
+  return status;							      \
+}
diff --git a/glibc-compat/nss_files/files-alias.c b/glibc-compat/nss_files/files-alias.c
new file mode 100644
index 0000000000..d9e5549998
--- /dev/null
+++ b/glibc-compat/nss_files/files-alias.c
@@ -0,0 +1,451 @@
+/* Mail alias file parser in nss_files module.
+   Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include <glibc-compat/include/aliases.h>
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <bits/libc-lock.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "nsswitch.h"
+
+/* Locks the static variables in this file.  */
+__libc_lock_define_initialized (static, lock)
+
+/* Maintenance of the shared stream open on the database file.  */
+
+static FILE *stream;
+static fpos_t position;
+static enum { none, getent, getby } last_use;
+
+
+static enum nss_status
+internal_setent (void)
+{
+  enum nss_status status = NSS_STATUS_SUCCESS;
+
+  if (stream == NULL)
+    {
+      stream = fopen ("/etc/aliases", "r");
+
+      if (stream == NULL)
+	status = errno == EAGAIN ? NSS_STATUS_TRYAGAIN : NSS_STATUS_UNAVAIL;
+      else
+	{
+	  /* We have to make sure the file is  `closed on exec'.  */
+	  int result, flags;
+
+	  result = flags = fcntl (fileno (stream), F_GETFD, 0);
+	  if (result >= 0)
+	    {
+	      flags |= FD_CLOEXEC;
+	      result = fcntl (fileno (stream), F_SETFD, flags);
+	    }
+	  if (result < 0)
+	    {
+	      /* Something went wrong.  Close the stream and return a
+		 failure.  */
+	      fclose (stream);
+	      stream = NULL;
+	      status = NSS_STATUS_UNAVAIL;
+	    }
+	}
+    }
+  else
+    rewind (stream);
+
+  return status;
+}
+
+
+/* Thread-safe, exported version of that.  */
+enum nss_status
+_nss_files_setaliasent (void)
+{
+  enum nss_status status;
+
+  __libc_lock_lock (lock);
+
+  status = internal_setent ();
+
+  if (status == NSS_STATUS_SUCCESS && fgetpos (stream, &position) < 0)
+    {
+      fclose (stream);
+      stream = NULL;
+      status = NSS_STATUS_UNAVAIL;
+    }
+
+  last_use = getent;
+
+  __libc_lock_unlock (lock);
+
+  return status;
+}
+
+
+/* Close the database file.  */
+static void
+internal_endent (void)
+{
+  if (stream != NULL)
+    {
+      fclose (stream);
+      stream = NULL;
+    }
+}
+
+
+/* Thread-safe, exported version of that.  */
+enum nss_status
+_nss_files_endaliasent (void)
+{
+  __libc_lock_lock (lock);
+
+  internal_endent ();
+
+  __libc_lock_unlock (lock);
+
+  return NSS_STATUS_SUCCESS;
+}
+
+/* Parsing the database file into `struct aliasent' data structures.  */
+static enum nss_status
+get_next_alias (const char *match, struct aliasent *result,
+		char *buffer, size_t buflen)
+{
+  enum nss_status status = NSS_STATUS_NOTFOUND;
+  int ignore = 0;
+
+  result->alias_members_len = 0;
+
+  while (1)
+    {
+      /* Now we are ready to process the input.  We have to read a
+	 line and all its continuations and construct the array of
+	 string pointers.  This pointers and the names itself have to
+	 be placed in BUFFER.  */
+      char *first_unused = buffer;
+      size_t room_left = buflen - (buflen % __alignof__ (char *));
+      char *line;
+
+      /* Read the first line.  It must contain the alias name and
+	 possibly some alias names.  */
+      first_unused[room_left - 1] = '\xff';
+      line = fgets (first_unused, room_left, stream);
+      if (line == NULL && feof (stream))
+	/* Nothing to read.  */
+	break;
+      else if (line == NULL || first_unused[room_left - 1] != '\xff')
+	{
+	  /* The line is too long for our buffer.  */
+	no_more_room:
+	  __set_errno (ERANGE);
+	  status = NSS_STATUS_TRYAGAIN;
+	  break;
+	}
+      else
+	{
+	  char *cp;
+
+	  /* If we are in IGNORE mode and the first character in the
+	     line is a white space we ignore the line and start
+	     reading the next.  */
+	  if (ignore && isspace (*first_unused))
+	    continue;
+
+	  /* Terminate the line for any case.  */
+	  cp = strpbrk (first_unused, "#\n");
+	  if (cp != NULL)
+	    *cp = '\0';
+
+	  /* Skip leading blanks.  */
+	  while (isspace (*line))
+	    ++line;
+
+	  result->alias_name = first_unused;
+	  while (*line != '\0' && *line != ':')
+	    *first_unused++ = *line++;
+	  if (*line == '\0' || result->alias_name == first_unused)
+	    /* No valid name.  Ignore the line.  */
+	    continue;
+
+	  *first_unused++ = '\0';
+	  if (room_left < (size_t) (first_unused - result->alias_name))
+	    goto no_more_room;
+	  room_left -= first_unused - result->alias_name;
+	  ++line;
+
+	  /* When we search for a specific alias we can avoid all the
+	     difficult parts and compare now with the name we are
+	     looking for.  If it does not match we simply ignore all
+	     lines until the next line containing the start of a new
+	     alias is found.  */
+	  ignore = (match != NULL
+		    && __strcasecmp (result->alias_name, match) != 0);
+
+	  while (! ignore)
+	    {
+	      while (isspace (*line))
+		++line;
+
+	      cp = first_unused;
+	      while (*line != '\0' && *line != ',')
+		*first_unused++ = *line++;
+
+	      if (first_unused != cp)
+		{
+		  /* OK, we can have a regular entry or an include
+		     request.  */
+		  if (*line != '\0')
+		    ++line;
+		  *first_unused++ = '\0';
+
+		  if (strncmp (cp, ":include:", 9) != 0)
+		    {
+		      if (room_left < (first_unused - cp) + sizeof (char *))
+			goto no_more_room;
+		      room_left -= (first_unused - cp) + sizeof (char *);
+
+		      ++result->alias_members_len;
+		    }
+		  else
+		    {
+		      /* Oh well, we have to read the addressed file.  */
+		      FILE *listfile;
+		      char *old_line = NULL;
+
+		      first_unused = cp;
+
+		      listfile = fopen (&cp[9], "r");
+		      /* If the file does not exist we simply ignore
+			 the statement.  */
+		      if (listfile != NULL
+			  && (old_line = strdup (line)) != NULL)
+			{
+			  while (! feof (listfile))
+			    {
+			      first_unused[room_left - 1] = '\xff';
+			      line = fgets (first_unused, room_left, listfile);
+			      if (line == NULL && feof (listfile))
+				break;
+			      if (line == NULL
+				  || first_unused[room_left - 1] != '\xff')
+				{
+				  free (old_line);
+				  goto no_more_room;
+				}
+
+			      /* Parse the line.  */
+			      cp = strpbrk (line, "#\n");
+			      if (cp != NULL)
+				*cp = '\0';
+
+			      do
+				{
+				  while (isspace (*line))
+				    ++line;
+
+				  cp = first_unused;
+				  while (*line != '\0' && *line != ',')
+				    *first_unused++ = *line++;
+
+				  if (*line != '\0')
+				    ++line;
+
+				  if (first_unused != cp)
+				    {
+				      *first_unused++ = '\0';
+				      if (room_left < ((first_unused - cp)
+						       + __alignof__ (char *)))
+					{
+					  free (old_line);
+					  goto no_more_room;
+					}
+				      room_left -= ((first_unused - cp)
+						    + __alignof__ (char *));
+				      ++result->alias_members_len;
+				    }
+				}
+			      while (*line != '\0');
+			    }
+			  fclose (listfile);
+
+			  first_unused[room_left - 1] = '\0';
+			  strncpy (first_unused, old_line, room_left);
+
+			  if (old_line != NULL)
+			    free (old_line);
+
+			  if (first_unused[room_left - 1] != '\0')
+			    goto no_more_room;
+			}
+		    }
+		}
+
+	      if (*line == '\0')
+		{
+		  /* Get the next line.  But we must be careful.  We
+		     must not read the whole line at once since it
+		     might belong to the current alias.  Simply read
+		     the first character.  If it is a white space we
+		     have a continuation line.  Otherwise it is the
+		     beginning of a new alias and we can push back the
+		     just read character.  */
+		  int ch;
+
+		  ch = fgetc (stream);
+		  if (ch == EOF || ch == '\n' || !isspace (ch))
+		    {
+		      size_t cnt;
+
+		      /* Now prepare the return.  Provide string
+			 pointers for the currently selected aliases.  */
+		      if (ch != EOF)
+			ungetc (ch, stream);
+
+		      /* Adjust the pointer so it is aligned for
+			 storing pointers.  */
+		      first_unused += __alignof__ (char *) - 1;
+		      first_unused -= ((first_unused - (char *) 0)
+				       % __alignof__ (char *));
+		      result->alias_members = (char **) first_unused;
+
+		      /* Compute addresses of alias entry strings.  */
+		      cp = result->alias_name;
+		      for (cnt = 0; cnt < result->alias_members_len; ++cnt)
+			{
+			  cp = strchr (cp, '\0') + 1;
+			  result->alias_members[cnt] = cp;
+			}
+
+		      status = (result->alias_members_len == 0
+				? NSS_STATUS_RETURN : NSS_STATUS_SUCCESS);
+		      break;
+		    }
+
+		  /* The just read character is a white space and so
+		     can be ignored.  */
+		  first_unused[room_left - 1] = '\xff';
+		  line = fgets (first_unused, room_left, stream);
+		  if (line == NULL && feof (stream))
+		    break;
+		  if (line == NULL || first_unused[room_left - 1] != '\xff')
+		    goto no_more_room;
+		  cp = strpbrk (line, "#\n");
+		  if (cp != NULL)
+		    *cp = '\0';
+		}
+	    }
+	}
+
+      if (status != NSS_STATUS_NOTFOUND)
+	/* We read something.  In any case break here.  */
+	break;
+    }
+
+  return status;
+}
+
+
+enum nss_status
+_nss_files_getaliasent_r (struct aliasent *result, char *buffer, size_t buflen)
+{
+  /* Return next entry in host file.  */
+  enum nss_status status = NSS_STATUS_SUCCESS;
+
+  __libc_lock_lock (lock);
+
+  /* Be prepared that the set*ent function was not called before.  */
+  if (stream == NULL)
+    status = internal_setent ();
+
+  if (status == NSS_STATUS_SUCCESS)
+    {
+      /* If the last use was not by the getent function we need the
+	 position the stream.  */
+      if (last_use != getent)
+	{
+	  if (fsetpos (stream, &position) < 0)
+	    status = NSS_STATUS_UNAVAIL;
+	  else
+	    last_use = getent;
+	}
+
+      if (status == NSS_STATUS_SUCCESS)
+	{
+	  result->alias_local = 1;
+
+	  /* Read lines until we get a definite result.  */
+	  do
+	    status = get_next_alias (NULL, result, buffer, buflen);
+	  while (status == NSS_STATUS_RETURN);
+
+	  /* If we successfully read an entry remember this position.  */
+	  if (status == NSS_STATUS_SUCCESS)
+	    fgetpos (stream, &position);
+	  else
+	    last_use = none;
+	}
+    }
+
+  __libc_lock_unlock (lock);
+
+  return status;
+}
+
+
+enum nss_status
+_nss_files_getaliasbyname_r (const char *name, struct aliasent *result,
+			     char *buffer, size_t buflen)
+{
+  /* Return next entry in host file.  */
+  enum nss_status status = NSS_STATUS_SUCCESS;
+
+  if (name == NULL)
+    {
+      __set_errno (EINVAL);
+      return NSS_STATUS_UNAVAIL;
+    }
+
+  __libc_lock_lock (lock);
+
+  /* Open the stream or rest it.  */
+  status = internal_setent ();
+  last_use = getby;
+
+  if (status == NSS_STATUS_SUCCESS)
+    {
+      result->alias_local = 1;
+
+      /* Read lines until we get a definite result.  */
+      do
+	status = get_next_alias (name, result, buffer, buflen);
+      while (status == NSS_STATUS_RETURN);
+    }
+
+  internal_endent ();
+
+  __libc_lock_unlock (lock);
+
+  return status;
+}
diff --git a/glibc-compat/nss_files/files-ethers.c b/glibc-compat/nss_files/files-ethers.c
new file mode 100644
index 0000000000..290d931c97
--- /dev/null
+++ b/glibc-compat/nss_files/files-ethers.c
@@ -0,0 +1,75 @@
+/* Copyright (C) 1996 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+
+The GNU C Library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+The GNU C Library 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB.  If
+not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
+
+#include <string.h>
+#include <netinet/if_ether.h>
+
+/* Because the `ethers' lookup does not fit so well in the scheme so
+   we define a dummy struct here which helps us to use the available
+   functions.  */
+struct etherent
+{
+  const char *e_name;
+  struct ether_addr e_addr;
+};
+struct etherent_data {};
+
+#define ENTNAME		etherent
+#define DATABASE	"ethers"
+#include "files-parse.c"
+LINE_PARSER
+("#",
+ /* Read the ethernet address: 6 x 8bit hexadecimal number.  */
+ {
+   size_t cnt;
+
+   for (cnt = 0; cnt < 6; ++cnt)
+     {
+       unsigned int number;
+
+       if (cnt < 5)
+	 INT_FIELD (number, ISCOLON , 0, 16, (unsigned int))
+       else
+	 INT_FIELD (number, isspace, 0, 16, (unsigned int))
+
+       if (number > 0xff)
+	 return 0;
+       result->e_addr.ether_addr_octet[cnt] = number;
+     }
+ };
+ STRING_FIELD (result->e_name, isspace, 1);
+ )
+
+
+#include GENERIC
+
+DB_LOOKUP (hostton, 1 + strlen (name), (".%s", name),
+	   {
+	     if (strcmp (result->e_name, name) == 0)
+	       break;
+	   }, const char *name)
+
+DB_LOOKUP (ntohost, 18, ("=%x:%x:%x:%x:%x:%x",
+			 addr->ether_addr_octet[0], addr->ether_addr_octet[1],
+			 addr->ether_addr_octet[2], addr->ether_addr_octet[3],
+			 addr->ether_addr_octet[4], addr->ether_addr_octet[5]),
+	   {
+	     if (memcmp (&result->e_addr, addr,
+			 sizeof (struct ether_addr)) == 0)
+	       break;
+	   }, struct ether_addr *addr)
diff --git a/glibc-compat/nss_files/files-grp.c b/glibc-compat/nss_files/files-grp.c
new file mode 100644
index 0000000000..ac9b632d42
--- /dev/null
+++ b/glibc-compat/nss_files/files-grp.c
@@ -0,0 +1,45 @@
+/* Group file parser in nss_files module.
+   Copyright (C) 1996, 1997 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include <glibc-compat/include/grp.h>
+
+#define STRUCTURE	group
+#define ENTNAME		grent
+#define DATABASE	"group"
+struct grent_data {};
+
+/* Our parser function is already defined in fgetgrent.c, so use that.
+   to parse lines from the database file.  */
+#define EXTERN_PARSER
+#include "files-parse.c"
+#include GENERIC
+
+DB_LOOKUP (grnam, 1 + strlen (name), (".%s", name),
+	   {
+	     if (name[0] != '-' && name[0] != '+'
+		 && ! strcmp (name, result->gr_name))
+	       break;
+	   }, const char *name)
+
+DB_LOOKUP (grgid, 20, ("=%lu", (unsigned long int) gid),
+	   {
+	     if (result->gr_gid == gid && result->gr_name[0] != '+'
+		 && result->gr_name[0] != '-')
+	       break;
+	   }, gid_t gid)
diff --git a/glibc-compat/nss_files/files-hosts.c b/glibc-compat/nss_files/files-hosts.c
new file mode 100644
index 0000000000..1b96f74b35
--- /dev/null
+++ b/glibc-compat/nss_files/files-hosts.c
@@ -0,0 +1,107 @@
+/* Hosts file parser in nss_files module.
+   Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+#include <glibc-compat/include/netdb.h>
+#include <resolv.h>
+
+
+/* Get implementation for some internal functions.  */
+#include "../resolv/mapv4v6addr.h"
+
+
+#define ENTNAME		hostent
+#define DATABASE	"hosts"
+#define NEED_H_ERRNO
+
+#define ENTDATA hostent_data
+struct hostent_data
+  {
+    unsigned char host_addr[16]; /* IPv4 or IPv6 address.  */
+    char *h_addr_ptrs[2];	/* Points to that and null terminator.  */
+  };
+
+#define TRAILING_LIST_MEMBER		h_aliases
+#define TRAILING_LIST_SEPARATOR_P	isspace
+#include "files-parse.c"
+LINE_PARSER
+("#",
+ {
+   char *addr;
+
+   STRING_FIELD (addr, isspace, 1);
+
+   /* Parse address.  */
+   if (inet_pton (AF_INET, addr, entdata->host_addr) > 0)
+     {
+       if (_res.options & RES_USE_INET6)
+	 {
+	   map_v4v6_address ((char *) entdata->host_addr,
+			     (char *) entdata->host_addr);
+	   result->h_addrtype = AF_INET6;
+	   result->h_length = IN6ADDRSZ;
+	 }
+       else
+	 {
+	   result->h_addrtype = AF_INET;
+	   result->h_length = INADDRSZ;
+	 }
+     }
+   else if (inet_pton (AF_INET6, addr, entdata->host_addr) > 0)
+     {
+       result->h_addrtype = AF_INET6;
+       result->h_length = IN6ADDRSZ;
+     }
+   else
+     /* Illegal address: ignore line.  */
+     return 0;
+
+   /* Store a pointer to the address in the expected form.  */
+   entdata->h_addr_ptrs[0] = entdata->host_addr;
+   entdata->h_addr_ptrs[1] = NULL;
+   result->h_addr_list = entdata->h_addr_ptrs;
+
+   STRING_FIELD (result->h_name, isspace, 1);
+ })
+
+#include "files-XXX.c"
+
+DB_LOOKUP (hostbyname, ,,
+	   {
+	     if (result->h_addrtype != ((_res.options & RES_USE_INET6)
+					? AF_INET6 : AF_INET))
+	       continue;
+	     LOOKUP_NAME_CASE (h_name, h_aliases)
+	   }, const char *name)
+
+DB_LOOKUP (hostbyname2, ,,
+	   {
+	     if (result->h_addrtype != af)
+	       continue;
+	     LOOKUP_NAME_CASE (h_name, h_aliases)
+	   }, const char *name, int af)
+
+DB_LOOKUP (hostbyaddr, ,,
+	   {
+	     if (result->h_addrtype == type && result->h_length == len &&
+		 ! memcmp (addr, result->h_addr_list[0], len))
+	       break;
+	   }, const char *addr, int len, int type)
diff --git a/glibc-compat/nss_files/files-netgrp.c b/glibc-compat/nss_files/files-netgrp.c
new file mode 100644
index 0000000000..8820e6a02c
--- /dev/null
+++ b/glibc-compat/nss_files/files-netgrp.c
@@ -0,0 +1,268 @@
+/* Netgroup file parser in nss_files modules.
+   Copyright (C) 1996, 1997 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include <ctype.h>
+#include <errno.h>
+#include <glibc-compat/include/netdb.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "nsswitch.h"
+#include "netgroup.h"
+
+#define DATAFILE	"/etc/netgroup"
+
+
+#define EXPAND(needed)							      \
+  do									      \
+    {									      \
+      size_t old_cursor = result->cursor - result->data;		      \
+									      \
+      result->data_size += 512 > 2 * needed ? 512 : 2 * needed;		      \
+      result->data = realloc (result->data, result->data_size);		      \
+									      \
+      if (result->data == NULL)						      \
+	{								      \
+	  status = NSS_STATUS_UNAVAIL;					      \
+	  goto the_end;							      \
+	}								      \
+      									      \
+      result->cursor = result->data + old_cursor;			      \
+    }									      \
+  while (0)
+
+
+enum nss_status
+_nss_files_setnetgrent (const char *group, struct __netgrent *result)
+{
+  FILE *fp;
+  enum nss_status status;
+
+  if (group[0] == '\0')
+    return NSS_STATUS_UNAVAIL;
+
+  /* Find the netgroups file and open it.  */
+  fp = fopen (DATAFILE, "r");
+  if (fp == NULL)
+    status = errno == EAGAIN ? NSS_STATUS_TRYAGAIN : NSS_STATUS_UNAVAIL;
+  else
+    {
+      /* Read the file line by line and try to find the description
+	 GROUP.  We must take care for long lines.  */
+      char *line = NULL;
+      size_t line_len = 0;
+      const ssize_t group_len = strlen (group);
+
+      status = NSS_STATUS_NOTFOUND;
+      result->cursor = result->data;
+
+      while (!feof (fp))
+	{
+	  ssize_t curlen = getline (&line, &line_len, fp);
+	  int found;
+
+	  if (curlen < 0)
+	    {
+	      status = NSS_STATUS_NOTFOUND;
+	      break;
+	    }
+
+	  found = (curlen > group_len && strncmp (line, group, group_len) == 0
+		   && isspace (line[group_len]));
+
+	  /* Read the whole line (including continuation) and store it
+	     if FOUND in nonzero.  Otherwise we don't need it.  */
+	  if (found)
+	    {
+	      /* Store the data from the first line.  */
+	      EXPAND (curlen - group_len);
+	      memcpy (result->cursor, &line[group_len + 1],
+		      curlen - group_len);
+	      result->cursor += (curlen - group_len) - 1;
+	    }
+
+	  while (line[curlen - 1] == '\n' && line[curlen - 2] == '\\')
+	    {
+	      /* Yes, we have a continuation line.  */
+	      if (found)
+		/* Remove these characters from the stored line.  */
+		result->cursor -= 2;
+
+	      /* Get next line.  */
+	      curlen = getline (&line, &line_len, fp);
+	      if (curlen <= 0)
+		break;
+
+	      if (found)
+		{
+		  /* Make sure we have enough room.  */
+		  EXPAND (1 + curlen + 1);
+
+		  /* Add separator in case next line starts immediately.  */
+		  *result->cursor++ = ' ';
+
+		  /* Copy new line.  */
+		  memcpy (result->cursor, line, curlen + 1);
+		  result->cursor += curlen;
+		}
+	    }
+
+	  if (found)
+	    {
+	      /* Now we have read the line.  */
+	      status = NSS_STATUS_SUCCESS;
+	      result->cursor = result->data;
+	      result->first = 1;
+	      break;
+	    }
+	}
+
+    the_end:
+      /* We don't need the file and the line buffer anymore.  */
+      free (line);
+      fclose (fp);
+    }
+
+  return status;
+}
+
+
+int
+_nss_files_endnetgrent (struct __netgrent *result)
+{
+  /* Free allocated memory for data if some is present.  */
+  if (result->data != NULL)
+    {
+      free (result->data);
+      result->data = NULL;
+      result->data_size = 0;
+      result->cursor = NULL;
+    }
+
+  return NSS_STATUS_SUCCESS;
+}
+
+
+enum nss_status
+_nss_netgroup_parseline (char **cursor, struct __netgrent *result,
+			 char *buffer, int buflen)
+{
+  enum nss_status status;
+  const char *host, *user, *domain;
+  char *cp = *cursor;
+
+  /* Some sanity checks.  */
+  if (cp == NULL)
+    return NSS_STATUS_NOTFOUND;
+
+  /* First skip leading spaces.  */
+  while (isspace (*cp))
+    ++cp;
+
+  if (*cp != '(')
+    {
+      /* We have a list of other netgroups.  */
+      char *name = cp;
+
+      while (*cp != '\0' && ! isspace (*cp))
+	++cp;
+
+      if (name != cp)
+	{
+	  /* It is another netgroup name.  */
+	  int last = *cp == '\0';
+
+	  result->type = group_val;
+	  result->val.group = name;
+	  *cp = '\0';
+	  if (! last)
+	    ++cp;
+	  *cursor = cp;
+	  result->first = 0;
+
+	  return NSS_STATUS_SUCCESS;
+	}
+
+      return result->first ? NSS_STATUS_NOTFOUND : NSS_STATUS_RETURN;
+    }
+
+  /* Match host name.  */
+  host = ++cp;
+  while (*cp != ',')
+    if (*cp++ == '\0')
+      return result->first ? NSS_STATUS_NOTFOUND : NSS_STATUS_RETURN;
+
+  /* Match user name.  */
+  user = ++cp;
+  while (*cp != ',')
+    if (*cp++ == '\0')
+      return result->first ? NSS_STATUS_NOTFOUND : NSS_STATUS_RETURN;
+
+  /* Match domain name.  */
+  domain = ++cp;
+  while (*cp != ')')
+    if (*cp++ == '\0')
+      return result->first ? NSS_STATUS_NOTFOUND : NSS_STATUS_RETURN;
+  ++cp;
+
+
+  /* When we got here we have found an entry.  Before we can copy it
+     to the private buffer we have to make sure it is big enough.  */
+  if (cp - host > buflen)
+    {
+      __set_errno (ERANGE);
+      status = NSS_STATUS_UNAVAIL;
+    }
+  else
+    {
+      memcpy (buffer, host, cp - host);
+      result->type = triple_val;
+
+      buffer[(user - host) - 1] = '\0';
+      result->val.triple.host = *host == ',' ? NULL : buffer;
+
+      buffer[(domain - host) - 1] = '\0';
+      result->val.triple.user = *user == ',' ? NULL : buffer + (user - host);
+
+      buffer[(cp - host) - 1] = '\0';
+      result->val.triple.domain =
+	*domain == ')' ? NULL : buffer + (domain - host);
+
+      status = NSS_STATUS_SUCCESS;
+
+      /* Remember where we stopped reading.  */
+      *cursor = cp;
+
+      result->first = 0;
+    }
+
+  return status;
+}
+
+
+enum nss_status
+_nss_files_getnetgrent_r (struct __netgrent *result, char *buffer, int buflen)
+{
+  enum nss_status status;
+
+  status = _nss_netgroup_parseline (&result->cursor, result, buffer, buflen);
+
+  return status;
+}
diff --git a/glibc-compat/nss_files/files-network.c b/glibc-compat/nss_files/files-network.c
new file mode 100644
index 0000000000..45ded2fedf
--- /dev/null
+++ b/glibc-compat/nss_files/files-network.c
@@ -0,0 +1,56 @@
+/* Networks file parser in nss_files module.
+   Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <glibc-compat/include/netdb.h>
+
+#define ENTNAME		netent
+#define DATABASE	"networks"
+
+struct netent_data {};
+
+#define TRAILING_LIST_MEMBER		n_aliases
+#define TRAILING_LIST_SEPARATOR_P	isspace
+#include "files-parse.c"
+LINE_PARSER
+("#",
+ {
+   char *addr;
+
+   STRING_FIELD (result->n_name, isspace, 1);
+
+   STRING_FIELD (addr, isspace, 1);
+   result->n_net = inet_network (addr);
+   result->n_addrtype = AF_INET;
+
+ })
+
+#include "files-XXX.c"
+
+DB_LOOKUP (netbyname, ,,
+	   LOOKUP_NAME_CASE (n_name, n_aliases),
+	   const char *name)
+
+DB_LOOKUP (netbyaddr, ,,
+	   {
+	     if (result->n_addrtype == type && result->n_net == net)
+	       /* Bingo!  */
+	       break;
+	   }, unsigned long int net, int type)
diff --git a/glibc-compat/nss_files/files-parse.c b/glibc-compat/nss_files/files-parse.c
new file mode 100644
index 0000000000..49c08153c9
--- /dev/null
+++ b/glibc-compat/nss_files/files-parse.c
@@ -0,0 +1,252 @@
+/* Common code for file-based database parsers in nss_files module.
+   Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include <ctype.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+
+/* These symbols are defined by the including source file:
+
+   ENTNAME -- database name of the structure and functions (hostent, pwent).
+   STRUCTURE -- struct name, define only if not ENTNAME (passwd, group).
+   DATABASE -- string of the database file's name ("hosts", "passwd").
+
+   ENTDATA -- if defined, `struct ENTDATA' is used by the parser to store
+              things pointed to by the resultant `struct STRUCTURE'.
+
+   NEED_H_ERRNO - defined iff an arg `int *herrnop' is used.
+
+   Also see files-XXX.c.  */
+
+#define CONCAT(a,b) CONCAT1(a,b)
+#define CONCAT1(a,b) a##b
+
+#ifndef STRUCTURE
+# define STRUCTURE ENTNAME
+#endif
+
+
+struct parser_data
+  {
+#ifdef ENTDATA
+    struct ENTDATA entdata;
+# define ENTDATA_DECL(data) struct ENTDATA *const entdata = &data->entdata;
+#else
+# define ENTDATA_DECL(data)
+#endif
+    char linebuffer[0];
+  };
+
+#ifdef ENTDATA
+/* The function can't be exported, because the entdata structure
+   is defined only in files-foo.c.  */
+# define parser_stclass static
+#else
+/* Export the line parser function so it can be used in nss_db.  */
+# define parser_stclass /* Global */
+# define parse_line CONCAT(_nss_files_parse_,ENTNAME)
+#endif
+
+
+#ifdef EXTERN_PARSER
+
+/* The parser is defined in a different module.  */
+extern int parse_line (char *line, struct STRUCTURE *result,
+		       struct parser_data *data, size_t datalen);
+
+# define LINE_PARSER(EOLSET, BODY) /* Do nothing */
+
+#else
+
+/* Define a line parsing function.  */
+
+# define LINE_PARSER(EOLSET, BODY)					      \
+parser_stclass int							      \
+parse_line (char *line, struct STRUCTURE *result,			      \
+	    struct parser_data *data, size_t datalen)			      \
+{									      \
+  ENTDATA_DECL (data)							      \
+  char *p = strpbrk (line, EOLSET "\n");				      \
+  if (p != NULL)							      \
+    *p = '\0';								      \
+  BODY;									      \
+  TRAILING_LIST_PARSER;							      \
+  return 1;								      \
+}
+
+
+# define STRING_FIELD(variable, terminator_p, swallow)			      \
+  {									      \
+    variable = line;							      \
+    while (*line != '\0' && !terminator_p (*line))			      \
+      ++line;								      \
+    if (*line != '\0')							      \
+      {									      \
+	*line = '\0';							      \
+	do								      \
+	  ++line;							      \
+	while (swallow && terminator_p (*line));			      \
+      }									      \
+  }
+
+# define INT_FIELD(variable, terminator_p, swallow, base, convert)	      \
+  {									      \
+    char *endp;								      \
+    variable = convert (strtoul (line, &endp, base));			      \
+    if (endp == line)							      \
+      return 0;								      \
+    else if (terminator_p (*endp))					      \
+      do								      \
+	++endp;								      \
+      while (swallow && terminator_p (*endp));				      \
+    else if (*endp != '\0')						      \
+      return 0;								      \
+    line = endp;							      \
+  }
+
+# define INT_FIELD_MAYBE_NULL(variable, terminator_p, swallow, base, convert, default)	      \
+  {									      \
+    char *endp;								      \
+    if (*line == '\0')							      \
+      /* We expect some more input, so don't allow the string to end here. */ \
+      return 0;								      \
+    variable = convert (strtoul (line, &endp, base));			      \
+    if (endp == line)							      \
+      variable = default;						      \
+    if (terminator_p (*endp))						      \
+      do								      \
+	++endp;								      \
+      while (swallow && terminator_p (*endp));				      \
+    else if (*endp != '\0')						      \
+      return 0;								      \
+    line = endp;							      \
+  }
+
+# define ISCOLON(c) ((c) == ':')
+
+
+# ifndef TRAILING_LIST_MEMBER
+#  define TRAILING_LIST_PARSER /* Nothing to do.  */
+# else
+
+#  define TRAILING_LIST_PARSER						      \
+{									      \
+  char **list = parse_list (line, data, datalen);			      \
+  if (list)								      \
+    result->TRAILING_LIST_MEMBER = list;				      \
+  else 									      \
+    return -1;		/* -1 indicates we ran out of space.  */	      \
+}
+
+static inline char **
+__attribute ((always_inline))
+parse_list (char *line, struct parser_data *data, size_t datalen)
+{
+  char *eol, **list, **p;
+
+  if (line >= data->linebuffer && line < (char *) data + datalen)
+    /* Find the end of the line buffer, we will use the space in DATA after
+       it for storing the vector of pointers.  */
+    eol = strchr (line, '\0') + 1;
+  else
+    /* LINE does not point within DATA->linebuffer, so that space is
+       not being used for scratch space right now.  We can use all of
+       it for the pointer vector storage.  */
+    eol = data->linebuffer;
+  /* Adjust the pointer so it is aligned for storing pointers.  */
+  eol += __alignof__ (char *) - 1;
+  eol -= (eol - (char *) 0) % __alignof__ (char *);
+  /* We will start the storage here for the vector of pointers.  */
+  list = (char **) eol;
+
+  p = list;
+  while (1)
+    {
+      char *elt;
+
+      if ((size_t) ((char *) &p[1] - (char *) data) > datalen)
+	{
+	  /* We cannot fit another pointer in the buffer.  */
+	  __set_errno (ERANGE);
+	  return NULL;
+	}
+      if (*line == '\0')
+	break;
+
+      /* Skip leading white space.  This might not be portable but useful.  */
+      while (isspace (*line))
+	++line;
+
+      elt = line;
+      while (1)
+	{
+	  if (*line == '\0' || TRAILING_LIST_SEPARATOR_P (*line))
+	    {
+	      /* End of the next entry.  */
+	      if (line > elt)
+		/* We really found some data.  */
+		*p++ = elt;
+
+	      /* Terminate string if necessary.  */
+	      if (*line != '\0')
+		*line++ = '\0';
+	      break;
+	    }
+	  ++line;
+	}
+    }
+  *p = NULL;
+
+  return list;
+}
+
+# endif	/* TRAILING_LIST_MEMBER */
+#endif	/* EXTERN_PARSER */
+
+
+#define LOOKUP_NAME(nameelt, aliaselt)					      \
+{									      \
+  char **ap;								      \
+  if (! strcmp (name, result->nameelt))					      \
+    break;								      \
+  for (ap = result->aliaselt; *ap; ++ap)				      \
+    if (! strcmp (name, *ap))						      \
+      break;								      \
+  if (*ap)								      \
+    break;								      \
+}
+
+#define LOOKUP_NAME_CASE(nameelt, aliaselt)				      \
+{									      \
+  char **ap;								      \
+  if (! __strcasecmp (name, result->nameelt))				      \
+    break;								      \
+  for (ap = result->aliaselt; *ap; ++ap)				      \
+    if (! __strcasecmp (name, *ap))					      \
+      break;								      \
+  if (*ap)								      \
+    break;								      \
+}
+
+
+/* This is defined by db-*.c to include "../nss_db/db-XXX.c" instead.  */
+#ifndef GENERIC
+# define GENERIC "files-XXX.c"
+#endif
diff --git a/glibc-compat/nss_files/files-proto.c b/glibc-compat/nss_files/files-proto.c
new file mode 100644
index 0000000000..6c53cce6a1
--- /dev/null
+++ b/glibc-compat/nss_files/files-proto.c
@@ -0,0 +1,47 @@
+/* Protocols file parser in nss_files module.
+   Copyright (C) 1996, 1997 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include <glibc-compat/include/netdb.h>
+
+
+#define ENTNAME		protoent
+#define DATABASE	"protocols"
+
+struct protoent_data {};
+
+#define TRAILING_LIST_MEMBER		p_aliases
+#define TRAILING_LIST_SEPARATOR_P	isspace
+#include "files-parse.c"
+LINE_PARSER
+("#",
+ STRING_FIELD (result->p_name, isspace, 1);
+ INT_FIELD (result->p_proto, isspace, 1, 10,);
+ )
+
+#include GENERIC
+
+DB_LOOKUP (protobyname, 1 + strlen (name), (".%s", name),
+	   LOOKUP_NAME (p_name, p_aliases),
+	   const char *name)
+
+DB_LOOKUP (protobynumber, 20, ("=%d", proto),
+	   {
+	     if (result->p_proto == proto)
+	       break;
+	   }, int proto)
diff --git a/glibc-compat/nss_files/files-pwd.c b/glibc-compat/nss_files/files-pwd.c
new file mode 100644
index 0000000000..621d70e065
--- /dev/null
+++ b/glibc-compat/nss_files/files-pwd.c
@@ -0,0 +1,45 @@
+/* User file parser in nss_files module.
+   Copyright (C) 1996, 1997 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include <glibc-compat/include/pwd.h>
+
+#define STRUCTURE	passwd
+#define ENTNAME		pwent
+#define DATABASE	"passwd"
+struct pwent_data {};
+
+/* Our parser function is already defined in fgetpwent_r.c, so use that
+   to parse lines from the database file.  */
+#define EXTERN_PARSER
+#include "files-parse.c"
+#include GENERIC
+
+DB_LOOKUP (pwnam, 1 + strlen (name), (".%s", name),
+	   {
+	     if (name[0] != '+' && name[0] != '-'
+		 && ! strcmp (name, result->pw_name))
+	       break;
+	   }, const char *name)
+
+DB_LOOKUP (pwuid, 20, ("=%lu", (unsigned long int) uid),
+	   {
+	     if (result->pw_uid == uid && result->pw_name[0] != '+'
+		 && result->pw_name[0] != '-')
+	       break;
+	   }, uid_t uid)
diff --git a/glibc-compat/nss_files/files-rpc.c b/glibc-compat/nss_files/files-rpc.c
new file mode 100644
index 0000000000..4e73e0e06b
--- /dev/null
+++ b/glibc-compat/nss_files/files-rpc.c
@@ -0,0 +1,47 @@
+/* SunRPC program number file parser in nss_files module.
+   Copyright (C) 1996, 1997 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include <glibc-compat/include/rpc/netdb.h>
+
+
+#define ENTNAME		rpcent
+#define DATABASE	"rpc"
+
+struct rpcent_data {};
+
+#define TRAILING_LIST_MEMBER		r_aliases
+#define TRAILING_LIST_SEPARATOR_P	isspace
+#include "files-parse.c"
+LINE_PARSER
+("#",
+ STRING_FIELD (result->r_name, isspace, 1);
+ INT_FIELD (result->r_number, isspace, 1, 10,);
+ )
+
+#include GENERIC
+
+DB_LOOKUP (rpcbyname, 1 + strlen (name), (".%s", name),
+	   LOOKUP_NAME (r_name, r_aliases),
+	   const char *name)
+
+DB_LOOKUP (rpcbynumber, 20, ("=%d", number),
+	   {
+	     if (result->r_number == number)
+	       break;
+	   }, int number)
diff --git a/glibc-compat/nss_files/files-service.c b/glibc-compat/nss_files/files-service.c
new file mode 100644
index 0000000000..96255dd223
--- /dev/null
+++ b/glibc-compat/nss_files/files-service.c
@@ -0,0 +1,60 @@
+/* Services file parser in nss_files module.
+   Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include <netinet/in.h>
+#include <glibc-compat/include/netdb.h>
+
+
+#define ENTNAME		servent
+#define DATABASE	"services"
+
+struct servent_data {};
+
+#define TRAILING_LIST_MEMBER		s_aliases
+#define TRAILING_LIST_SEPARATOR_P	isspace
+#include "files-parse.c"
+#define ISSLASH(c) ((c) == '/')
+LINE_PARSER
+("#",
+ STRING_FIELD (result->s_name, isspace, 1);
+ INT_FIELD (result->s_port, ISSLASH, 10, 0, htons);
+ STRING_FIELD (result->s_proto, isspace, 1);
+ )
+
+#include GENERIC
+
+DB_LOOKUP (servbyname, 2 + strlen (name) + (proto ? strlen (proto) : 0),
+	   (".%s/%s", name, proto ?: ""),
+	   {
+	     /* Must match both protocol (if specified) and name.  */
+	     if (proto != NULL && strcmp (result->s_proto, proto))
+	       continue;
+	     LOOKUP_NAME (s_name, s_aliases)
+	   },
+	   const char *name, const char *proto)
+
+DB_LOOKUP (servbyport, 21 + (proto ? strlen (proto) : 0),
+	   ("=%d/%s", ntohs (port), proto ?: ""),
+	   {
+	     /* Must match both port and protocol.  */
+	     if (result->s_port == port
+		 && (proto == NULL
+		     || strcmp (result->s_proto, proto) == 0))
+	       break;
+	   }, int port, const char *proto)
diff --git a/glibc-compat/nss_files/files-spwd.c b/glibc-compat/nss_files/files-spwd.c
new file mode 100644
index 0000000000..f7f25fd304
--- /dev/null
+++ b/glibc-compat/nss_files/files-spwd.c
@@ -0,0 +1,38 @@
+/* User file parser in nss_files module.
+   Copyright (C) 1996, 1997 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include <glibc-compat/include/shadow.h>
+
+#define STRUCTURE	spwd
+#define ENTNAME		spent
+#define DATABASE	"shadow"
+struct spent_data {};
+
+/* Our parser function is already defined in sgetspent_r.c, so use that
+   to parse lines from the database file.  */
+#define EXTERN_PARSER
+#include "files-parse.c"
+#include GENERIC
+
+DB_LOOKUP (spnam, 1 + strlen (name), (".%s", name),
+	   {
+	     if (name[0] != '+' && name[0] != '-'
+		 && ! strcmp (name, result->sp_namp))
+	       break;
+	   }, const char *name)
diff --git a/glibc-compat/nss_nis/nis-alias.c b/glibc-compat/nss_nis/nis-alias.c
new file mode 100644
index 0000000000..14149699d3
--- /dev/null
+++ b/glibc-compat/nss_nis/nis-alias.c
@@ -0,0 +1,278 @@
+/* Copyright (C) 1996, 1998 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1996.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include <nss.h>
+#include <ctype.h>
+#include <errno.h>
+#include <string.h>
+#include <glibc-compat/include/aliases.h>
+#include <bits/libc-lock.h>
+#include <rpcsvc/yp.h>
+#include <rpcsvc/ypclnt.h>
+
+#include "nss-nis.h"
+
+__libc_lock_define_initialized (static, lock)
+
+static bool_t new_start = 1;
+static char *oldkey = NULL;
+static int oldkeylen = 0;
+
+static int
+_nss_nis_parse_aliasent (const char *key, char *alias, struct aliasent *result,
+			 char *buffer, size_t buflen)
+{
+  char *first_unused = buffer + strlen (alias) + 1;
+  size_t room_left =
+    buflen - (buflen % __alignof__ (char *)) - strlen (alias) - 2;
+  char *line;
+  char *cp;
+
+  result->alias_members_len = 0;
+  *first_unused = '\0';
+  first_unused++;
+  strcpy (first_unused, key);
+
+  if (first_unused[room_left - 1] != '\0')
+    {
+      /* The line is too long for our buffer.  */
+    no_more_room:
+      __set_errno (ERANGE);
+      return -1;
+    }
+
+  result->alias_name = first_unused;
+
+  /* Terminate the line for any case.  */
+  cp = strpbrk (alias, "#\n");
+  if (cp != NULL)
+    *cp = '\0';
+
+  first_unused += strlen (result->alias_name) + 1;
+  /* Adjust the pointer so it is aligned for
+     storing pointers.  */
+  first_unused += __alignof__ (char *) - 1;
+  first_unused -= ((first_unused - (char *) 0) % __alignof__ (char *));
+  result->alias_members = (char **) first_unused;
+
+  line = alias;
+
+  while (*line != '\0')
+    {
+      /* Skip leading blanks.  */
+      while (isspace (*line))
+	line++;
+
+      if (*line == '\0')
+	break;
+
+      if (room_left < sizeof (char *))
+	  goto no_more_room;
+      room_left -= sizeof (char *);
+      result->alias_members[result->alias_members_len] = line;
+
+      while (*line != '\0' && *line != ',')
+	line++;
+
+      if (line != result->alias_members[result->alias_members_len])
+	{
+	  *line = '\0';
+	  line++;
+	  result->alias_members_len++;
+	}
+    }
+  return result->alias_members_len == 0 ? 0 : 1;
+}
+
+enum nss_status
+_nss_nis_setaliasent (void)
+{
+  __libc_lock_lock (lock);
+
+  new_start = 1;
+  if (oldkey != NULL)
+    {
+      free (oldkey);
+      oldkey = NULL;
+      oldkeylen = 0;
+    }
+
+  __libc_lock_unlock (lock);
+
+  return NSS_STATUS_SUCCESS;
+}
+
+enum nss_status
+_nss_nis_endaliasent (void)
+{
+  __libc_lock_lock (lock);
+
+  new_start = 1;
+  if (oldkey != NULL)
+    {
+      free (oldkey);
+      oldkey = NULL;
+      oldkeylen = 0;
+    }
+
+  __libc_lock_unlock (lock);
+
+  return NSS_STATUS_SUCCESS;
+}
+
+static enum nss_status
+internal_nis_getaliasent_r (struct aliasent *alias, char *buffer,
+			    size_t buflen)
+{
+  char *domain;
+  char *result;
+  int len;
+  char *outkey;
+  int keylen;
+  char *p;
+  int parse_res;
+
+  if (yp_get_default_domain (&domain))
+    return NSS_STATUS_UNAVAIL;
+
+  alias->alias_local = 0;
+
+  /* Get the next entry until we found a correct one. */
+  do
+    {
+      enum nss_status retval;
+
+      if (new_start)
+        retval = yperr2nss (yp_first (domain, "mail.aliases",
+				      &outkey, &keylen, &result, &len));
+      else
+        retval = yperr2nss ( yp_next (domain, "mail.aliases", oldkey,
+				      oldkeylen, &outkey, &keylen,
+				      &result, &len));
+      if (retval != NSS_STATUS_SUCCESS)
+	{
+	  if (retval == NSS_STATUS_TRYAGAIN)
+            __set_errno (EAGAIN);
+          return retval;
+        }
+
+      if ((size_t) (len + 1) > buflen)
+        {
+	  free (result);
+          __set_errno (ERANGE);
+          return NSS_STATUS_TRYAGAIN;
+        }
+      p = strncpy (buffer, result, len);
+      buffer[len] = '\0';
+      while (isspace (*p))
+        ++p;
+      free (result);
+
+      parse_res = _nss_nis_parse_aliasent (outkey, p, alias, buffer, buflen);
+      if (parse_res == -1)
+	{
+	  __set_errno (ERANGE);
+	  return NSS_STATUS_TRYAGAIN;
+	}
+
+      free (oldkey);
+      oldkey = outkey;
+      oldkeylen = keylen;
+      new_start = 0;
+    }
+  while (!parse_res);
+
+  return NSS_STATUS_SUCCESS;
+}
+
+enum nss_status
+_nss_nis_getaliasent_r (struct aliasent *alias, char *buffer, size_t buflen)
+{
+  enum nss_status status;
+
+  __libc_lock_lock (lock);
+
+  status = internal_nis_getaliasent_r (alias, buffer, buflen);
+
+  __libc_lock_unlock (lock);
+
+  return status;
+}
+
+enum nss_status
+_nss_nis_getaliasbyname_r (const char *name, struct aliasent *alias,
+			   char *buffer, size_t buflen)
+{
+  enum nss_status retval;
+  int parse_res;
+  char *domain;
+  char *result;
+  int len;
+  char *p;
+  size_t namlen = strlen (name);
+  char name2[namlen + 1];
+  int i;
+
+  if (name == NULL)
+    {
+      __set_errno (EINVAL);
+      return NSS_STATUS_UNAVAIL;
+    }
+
+  if (yp_get_default_domain (&domain))
+    return NSS_STATUS_UNAVAIL;
+
+  /* Convert name to lowercase.  */
+  for (i = 0; i < namlen; ++i)
+    name2[i] = tolower (name[i]);
+  name2[i] = '\0';
+
+  retval = yperr2nss (yp_match (domain, "mail.aliases", name, namlen,
+				&result, &len));
+
+  if (retval != NSS_STATUS_SUCCESS)
+    {
+      if (retval == NSS_STATUS_TRYAGAIN)
+	__set_errno (EAGAIN);
+      return retval;
+    }
+
+  if ((size_t) (len + 1) > buflen)
+    {
+      free (result);
+      __set_errno (ERANGE);
+      return NSS_STATUS_TRYAGAIN;
+    }
+
+  p = strncpy (buffer, result, len);
+  buffer[len] = '\0';
+  while (isspace (*p))
+    ++p;
+  free (result);
+
+  alias->alias_local = 0;
+  parse_res = _nss_nis_parse_aliasent (name, p, alias, buffer, buflen);
+  if (parse_res == -1)
+    return NSS_STATUS_TRYAGAIN;
+  else
+    if (parse_res == 0)
+      return NSS_STATUS_NOTFOUND;
+    else
+      return NSS_STATUS_SUCCESS;
+}
diff --git a/glibc-compat/nss_nis/nis-ethers.c b/glibc-compat/nss_nis/nis-ethers.c
new file mode 100644
index 0000000000..54b99dcba9
--- /dev/null
+++ b/glibc-compat/nss_nis/nis-ethers.c
@@ -0,0 +1,299 @@
+/* Copyright (C) 1996, 1997 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1996.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include <nss.h>
+#include <ctype.h>
+#include <errno.h>
+#include <string.h>
+#include <bits/libc-lock.h>
+#include <rpcsvc/yp.h>
+#include <rpcsvc/ypclnt.h>
+#include <netinet/if_ether.h>
+
+#include "nss-nis.h"
+
+/* Protect global state against multiple changers */
+__libc_lock_define_initialized (static, lock)
+
+struct ether
+{
+  const char *e_name;
+  struct ether_addr e_addr;
+};
+
+/* Get the declaration of the parser function.  */
+#define ENTNAME etherent
+#define STRUCTURE ether
+#define EXTERN_PARSER
+#include "../nss_files/files-parse.c"
+
+struct response
+{
+  char *val;
+  struct response *next;
+};
+
+static struct response *start = NULL;
+static struct response *next = NULL;
+
+static int
+saveit (int instatus, char *inkey, int inkeylen, char *inval,
+	int invallen, char *indata)
+{
+  if (instatus != YP_TRUE)
+    return instatus;
+
+  if (inkey && inkeylen > 0 && inval && invallen > 0)
+    {
+      if (start == NULL)
+	{
+	  start = malloc (sizeof (struct response));
+	  next = start;
+	}
+      else
+	{
+	  next->next = malloc (sizeof (struct response));
+	  next = next->next;
+	}
+      next->next = NULL;
+      next->val = malloc (invallen + 1);
+      strncpy (next->val, inval, invallen);
+      next->val[invallen] = '\0';
+    }
+
+  return 0;
+}
+
+enum nss_status
+internal_nis_setetherent (void)
+{
+  char *domainname;
+  struct ypall_callback ypcb;
+  enum nss_status status;
+
+  yp_get_default_domain (&domainname);
+
+  while (start != NULL)
+    {
+      if (start->val != NULL)
+	free (start->val);
+      next = start;
+      start = start->next;
+      free (next);
+    }
+  start = NULL;
+
+  ypcb.foreach = saveit;
+  ypcb.data = NULL;
+  status = yperr2nss (yp_all (domainname, "ethers.byname", &ypcb));
+  next = start;
+
+  return status;
+}
+
+enum nss_status
+_nss_nis_setetherent (void)
+{
+  enum nss_status result;
+
+  __libc_lock_lock (lock);
+
+  result = internal_nis_setetherent ();
+
+  __libc_lock_unlock (lock);
+
+  return result;
+}
+
+enum nss_status
+_nss_nis_endetherent (void)
+{
+  __libc_lock_lock (lock);
+
+  while (start != NULL)
+    {
+      if (start->val != NULL)
+	free (start->val);
+      next = start;
+      start = start->next;
+      free (next);
+    }
+  start = NULL;
+  next = NULL;
+
+  __libc_lock_unlock (lock);
+
+  return NSS_STATUS_SUCCESS;
+}
+
+static enum nss_status
+internal_nis_getetherent_r (struct ether *eth, char *buffer, size_t buflen)
+{
+  struct parser_data *data = (void *) buffer;
+  int parse_res;
+
+  if (start == NULL)
+    internal_nis_setetherent ();
+
+  /* Get the next entry until we found a correct one. */
+  do
+    {
+      char *p;
+
+      if (next == NULL)
+	return NSS_STATUS_NOTFOUND;
+      p = strncpy (buffer, next->val, buflen);
+      next = next->next;
+
+      while (isspace (*p))
+        ++p;
+
+      parse_res = _nss_files_parse_etherent (p, eth, data, buflen);
+      if (parse_res == -1 && errno == ERANGE)
+        return NSS_STATUS_TRYAGAIN;
+    }
+  while (!parse_res);
+
+  return NSS_STATUS_SUCCESS;
+}
+
+enum nss_status
+_nss_nis_getetherent_r (struct ether *result, char *buffer, size_t buflen)
+{
+  int status;
+
+  __libc_lock_lock (lock);
+
+  status = internal_nis_getetherent_r (result, buffer, buflen);
+
+  __libc_lock_unlock (lock);
+
+  return status;
+}
+
+enum nss_status
+_nss_nis_gethostton_r (const char *name, struct ether *eth,
+		       char *buffer, size_t buflen)
+{
+  struct parser_data *data = (void *) buffer;
+  enum nss_status retval;
+  char *domain, *result, *p;
+  int len, parse_res;
+
+  if (name == NULL)
+    {
+      __set_errno (EINVAL);
+      return NSS_STATUS_UNAVAIL;
+    }
+
+  if (yp_get_default_domain (&domain))
+    return NSS_STATUS_UNAVAIL;
+
+  retval = yperr2nss (yp_match (domain, "ethers.byname", name,
+				strlen (name), &result, &len));
+
+  if (retval != NSS_STATUS_SUCCESS)
+    {
+      if (retval == NSS_STATUS_TRYAGAIN)
+        __set_errno (EAGAIN);
+      return retval;
+    }
+
+  if ((size_t) (len + 1) > buflen)
+    {
+      free (result);
+      __set_errno (ERANGE);
+      return NSS_STATUS_TRYAGAIN;
+    }
+
+  p = strncpy (buffer, result, len);
+  buffer[len] = '\0';
+  while (isspace (*p))
+    ++p;
+  free (result);
+
+  parse_res = _nss_files_parse_etherent (p, eth, data, buflen);
+
+  if (parse_res == -1 && errno == ERANGE)
+    return NSS_STATUS_TRYAGAIN;
+  else if (parse_res == 0)
+    return NSS_STATUS_NOTFOUND;
+
+  return NSS_STATUS_SUCCESS;
+}
+
+enum nss_status
+_nss_nis_getntohost_r (struct ether_addr *addr, struct ether *eth,
+		       char *buffer, size_t buflen)
+{
+  struct parser_data *data = (void *) buffer;
+  enum nss_status retval;
+  char *domain, *result, *p;
+  int len, nlen, parse_res;
+  char buf[33];
+
+  if (addr == NULL)
+    {
+      __set_errno (EINVAL);
+      return NSS_STATUS_UNAVAIL;
+    }
+
+  if (yp_get_default_domain (&domain))
+    return NSS_STATUS_UNAVAIL;
+
+  nlen = sprintf (buf, "%x:%x:%x:%x:%x:%x",
+		  (int) addr->ether_addr_octet[0],
+		  (int) addr->ether_addr_octet[1],
+		  (int) addr->ether_addr_octet[2],
+		  (int) addr->ether_addr_octet[3],
+		  (int) addr->ether_addr_octet[4],
+		  (int) addr->ether_addr_octet[5]);
+
+  retval = yperr2nss (yp_match (domain, "ethers.byaddr", buf,
+				nlen, &result, &len));
+
+  if (retval != NSS_STATUS_SUCCESS)
+    {
+      if (retval == NSS_STATUS_TRYAGAIN)
+        __set_errno (EAGAIN);
+      return retval;
+    }
+
+  if ((size_t) (len + 1) > buflen)
+    {
+      free (result);
+      __set_errno (ERANGE);
+      return NSS_STATUS_TRYAGAIN;
+    }
+
+  p = strncpy (buffer, result, len);
+  buffer[len] = '\0';
+  while (isspace (*p))
+    ++p;
+  free (result);
+
+  parse_res = _nss_files_parse_etherent (p, eth, data, buflen);
+
+  if (parse_res == -1 && errno == ERANGE)
+    return NSS_STATUS_TRYAGAIN;
+  else if (parse_res == 0)
+    return NSS_STATUS_NOTFOUND;
+
+  return NSS_STATUS_SUCCESS;
+}
diff --git a/glibc-compat/nss_nis/nis-grp.c b/glibc-compat/nss_nis/nis-grp.c
new file mode 100644
index 0000000000..5b8e838bdc
--- /dev/null
+++ b/glibc-compat/nss_nis/nis-grp.c
@@ -0,0 +1,249 @@
+/* Copyright (C) 1996, 1997 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1996.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include <nss.h>
+#include <glibc-compat/include/grp.h>
+#include <ctype.h>
+#include <errno.h>
+#include <string.h>
+#include <bits/libc-lock.h>
+#include <rpcsvc/yp.h>
+#include <rpcsvc/ypclnt.h>
+
+#include "nss-nis.h"
+
+/* Get the declaration of the parser function.  */
+#define ENTNAME grent
+#define STRUCTURE group
+#define EXTERN_PARSER
+#include "../nss_files/files-parse.c"
+
+/* Protect global state against multiple changers */
+__libc_lock_define_initialized (static, lock)
+
+static bool_t new_start = 1;
+static char *oldkey = NULL;
+static int oldkeylen = 0;
+
+enum nss_status
+_nss_nis_setgrent (void)
+{
+  __libc_lock_lock (lock);
+
+  new_start = 1;
+  if (oldkey != NULL)
+    {
+      free (oldkey);
+      oldkey = NULL;
+      oldkeylen = 0;
+    }
+
+  __libc_lock_unlock (lock);
+
+  return NSS_STATUS_SUCCESS;
+}
+
+enum nss_status
+_nss_nis_endgrent (void)
+{
+  __libc_lock_lock (lock);
+
+  new_start = 1;
+  if (oldkey != NULL)
+    {
+      free (oldkey);
+      oldkey = NULL;
+      oldkeylen = 0;
+    }
+
+  __libc_lock_unlock (lock);
+
+  return NSS_STATUS_SUCCESS;
+}
+
+static enum nss_status
+internal_nis_getgrent_r (struct group *grp, char *buffer, size_t buflen)
+{
+  struct parser_data *data = (void *) buffer;
+  char *domain, *result, *outkey;
+  int len, keylen, parse_res;
+
+  if (yp_get_default_domain (&domain))
+    return NSS_STATUS_UNAVAIL;
+
+  /* Get the next entry until we found a correct one. */
+  do
+    {
+      enum nss_status retval;
+      char *p;
+
+      if (new_start)
+        retval = yperr2nss (yp_first (domain, "group.byname",
+                                      &outkey, &keylen, &result, &len));
+      else
+        retval = yperr2nss ( yp_next (domain, "group.byname",
+                                      oldkey, oldkeylen,
+                                      &outkey, &keylen, &result, &len));
+
+      if (retval != NSS_STATUS_SUCCESS)
+        {
+          if (retval == NSS_STATUS_TRYAGAIN)
+            __set_errno (EAGAIN);
+          return retval;
+        }
+
+      if ((size_t) (len + 1) > buflen)
+        {
+          free (result);
+          __set_errno (ERANGE);
+          return NSS_STATUS_TRYAGAIN;
+        }
+
+      p = strncpy (buffer, result, len);
+      buffer[len] = '\0';
+      while (isspace (*p))
+        ++p;
+      free (result);
+
+      parse_res = _nss_files_parse_grent (p, grp, data, buflen);
+      if (parse_res == -1 && errno == ERANGE)
+        return NSS_STATUS_TRYAGAIN;
+
+      free (oldkey);
+      oldkey = outkey;
+      oldkeylen = keylen;
+      new_start = 0;
+    }
+  while (!parse_res);
+
+  return NSS_STATUS_SUCCESS;
+}
+
+enum nss_status
+_nss_nis_getgrent_r (struct group *result, char *buffer, size_t buflen)
+{
+  int status;
+
+  __libc_lock_lock (lock);
+
+  status = internal_nis_getgrent_r (result, buffer, buflen);
+
+  __libc_lock_unlock (lock);
+
+  return status;
+}
+
+enum nss_status
+_nss_nis_getgrnam_r (const char *name, struct group *grp,
+		     char *buffer, size_t buflen)
+{
+  struct parser_data *data = (void *) buffer;
+  enum nss_status retval;
+  char *domain, *result, *p;
+  int len, parse_res;
+
+  if (name == NULL)
+    {
+      __set_errno (EINVAL);
+      return NSS_STATUS_UNAVAIL;
+    }
+
+  if (yp_get_default_domain (&domain))
+    return NSS_STATUS_UNAVAIL;
+
+  retval = yperr2nss (yp_match (domain, "group.byname", name,
+				strlen (name), &result, &len));
+
+  if (retval != NSS_STATUS_SUCCESS)
+    {
+      if (retval == NSS_STATUS_TRYAGAIN)
+        __set_errno (EAGAIN);
+      return retval;
+    }
+
+  if ((size_t) (len + 1) > buflen)
+    {
+      free (result);
+      __set_errno (ERANGE);
+      return NSS_STATUS_TRYAGAIN;
+    }
+
+  p = strncpy (buffer, result, len);
+  buffer[len] = '\0';
+  while (isspace (*p))
+    ++p;
+  free (result);
+
+  parse_res = _nss_files_parse_grent (p, grp, data, buflen);
+
+  if (parse_res == -1 && errno == ERANGE)
+    return NSS_STATUS_TRYAGAIN;
+  else if (parse_res == 0)
+    return NSS_STATUS_NOTFOUND;
+
+  return NSS_STATUS_SUCCESS;
+}
+
+enum nss_status
+_nss_nis_getgrgid_r (gid_t gid, struct group *grp,
+		     char *buffer, size_t buflen)
+{
+  struct parser_data *data = (void *) buffer;
+  enum nss_status retval;
+  char *domain, *result, *p;
+  int len, nlen, parse_res;
+  char buf[32];
+
+  if (yp_get_default_domain (&domain))
+    return NSS_STATUS_UNAVAIL;
+
+  nlen = sprintf (buf, "%d", gid);
+
+  retval = yperr2nss (yp_match (domain, "group.bygid", buf,
+				nlen, &result, &len));
+
+  if (retval != NSS_STATUS_SUCCESS)
+    {
+      if (retval == NSS_STATUS_TRYAGAIN)
+        __set_errno (EAGAIN);
+      return retval;
+    }
+
+  if ((size_t) (len + 1) > buflen)
+    {
+      free (result);
+      __set_errno (ERANGE);
+      return NSS_STATUS_TRYAGAIN;
+    }
+
+  p = strncpy (buffer, result, len);
+  buffer[len] = '\0';
+  while (isspace (*p))
+    ++p;
+  free (result);
+
+  parse_res = _nss_files_parse_grent (p, grp, data, buflen);
+
+  if (parse_res == -1 && errno == ERANGE)
+    return NSS_STATUS_TRYAGAIN;
+  else if (parse_res == 0)
+    return NSS_STATUS_NOTFOUND;
+
+  return NSS_STATUS_SUCCESS;
+}
diff --git a/glibc-compat/nss_nis/nis-hosts.c b/glibc-compat/nss_nis/nis-hosts.c
new file mode 100644
index 0000000000..c6c413c55d
--- /dev/null
+++ b/glibc-compat/nss_nis/nis-hosts.c
@@ -0,0 +1,417 @@
+/* Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1996.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include <nss.h>
+#include <ctype.h>
+#include <glibc-compat/include/netdb.h>
+#include <string.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <resolv.h>
+#include <bits/libc-lock.h>
+#include <rpcsvc/yp.h>
+#include <rpcsvc/ypclnt.h>
+
+#include "nss-nis.h"
+
+/* Get implementation for some internal functions. */
+#include "../../resolv/mapv4v6addr.h"
+#include "../../resolv/mapv4v6hostent.h"
+
+#define ENTNAME         hostent
+#define DATABASE        "hosts"
+#define NEED_H_ERRNO
+
+#define ENTDATA hostent_data
+struct hostent_data
+  {
+    unsigned char host_addr[16];	/* IPv4 or IPv6 address.  */
+    char *h_addr_ptrs[2];	/* Points to that and null terminator.  */
+  };
+
+#define TRAILING_LIST_MEMBER            h_aliases
+#define TRAILING_LIST_SEPARATOR_P       isspace
+#include "../nss_files/files-parse.c"
+LINE_PARSER
+("#",
+ {
+   char *addr;
+
+   STRING_FIELD (addr, isspace, 1);
+
+   /* Parse address.  */
+   if ((_res.options & RES_USE_INET6)
+       && inet_pton (AF_INET6, addr, entdata->host_addr) > 0)
+     {
+       result->h_addrtype = AF_INET6;
+       result->h_length = IN6ADDRSZ;
+     }
+   else
+     if (inet_pton (AF_INET, addr, entdata->host_addr) > 0)
+       {
+	 if (_res.options & RES_USE_INET6)
+	   {
+	     map_v4v6_address ((char *) entdata->host_addr,
+			       (char *) entdata->host_addr);
+	     result->h_addrtype = AF_INET6;
+	     result->h_length = IN6ADDRSZ;
+	   }
+	 else
+	   {
+	     result->h_addrtype = AF_INET;
+	     result->h_length = INADDRSZ;
+	   }
+       }
+     else
+       /* Illegal address: ignore line.  */
+       return 0;
+
+   /* Store a pointer to the address in the expected form.  */
+   entdata->h_addr_ptrs[0] = entdata->host_addr;
+   entdata->h_addr_ptrs[1] = NULL;
+   result->h_addr_list = entdata->h_addr_ptrs;
+
+   /* If we need the host entry in IPv6 form change it now.  */
+   if (_res.options & RES_USE_INET6)
+     {
+       char *bufptr = data->linebuffer;
+       size_t buflen = (char *) data + datalen - bufptr;
+       int ibuflen = buflen;	/* Use this for machines with size_t > int.  */
+       map_v4v6_hostent (result, &bufptr, &ibuflen);
+       buflen = ibuflen;
+     }
+
+   STRING_FIELD (result->h_name, isspace, 1);
+ }
+)
+
+__libc_lock_define_initialized (static, lock)
+
+static bool_t new_start = 1;
+static char *oldkey = NULL;
+static int oldkeylen = 0;
+
+enum nss_status
+_nss_nis_sethostent (void)
+{
+  __libc_lock_lock (lock);
+
+  new_start = 1;
+  if (oldkey != NULL)
+    {
+      free (oldkey);
+      oldkey = NULL;
+      oldkeylen = 0;
+    }
+
+  __libc_lock_unlock (lock);
+
+  return NSS_STATUS_SUCCESS;
+}
+
+enum nss_status
+_nss_nis_endhostent (void)
+{
+  __libc_lock_lock (lock);
+
+  new_start = 1;
+  if (oldkey != NULL)
+    {
+      free (oldkey);
+      oldkey = NULL;
+      oldkeylen = 0;
+    }
+
+  __libc_lock_unlock (lock);
+
+  return NSS_STATUS_SUCCESS;
+}
+
+static enum nss_status
+internal_nis_gethostent_r (struct hostent *host, char *buffer,
+			   size_t buflen, int *h_errnop)
+{
+  char *domain;
+  char *result;
+  int len, parse_res;
+  char *outkey;
+  int keylen;
+  struct parser_data *data = (void *) buffer;
+  size_t linebuflen = buffer + buflen - data->linebuffer;
+
+  if (yp_get_default_domain (&domain))
+    return NSS_STATUS_UNAVAIL;
+
+  if (buflen < sizeof *data + 1)
+    {
+      __set_errno (ERANGE);
+      *h_errnop = NETDB_INTERNAL;
+      return NSS_STATUS_TRYAGAIN;
+    }
+
+  /* Get the next entry until we found a correct one. */
+  do
+    {
+      enum nss_status retval;
+      char *p;
+
+      if (new_start)
+        retval = yperr2nss (yp_first (domain, "hosts.byname",
+                                      &outkey, &keylen, &result, &len));
+      else
+        retval = yperr2nss ( yp_next (domain, "hosts.byname",
+                                      oldkey, oldkeylen,
+                                      &outkey, &keylen, &result, &len));
+
+      if (retval != NSS_STATUS_SUCCESS)
+        {
+	  switch (retval)
+	    {
+	    case NSS_STATUS_TRYAGAIN:
+	      __set_errno (EAGAIN);
+	      *h_errnop = TRY_AGAIN;
+	      break;
+	    case NSS_STATUS_NOTFOUND:
+	      *h_errnop = HOST_NOT_FOUND;
+	      break;
+	    default:
+	      *h_errnop = NO_RECOVERY;
+	      break;
+	    }
+	  return retval;
+	}
+
+      if ((size_t) (len + 1) > linebuflen)
+        {
+          free (result);
+	  *h_errnop = NETDB_INTERNAL;
+          __set_errno (ERANGE);
+          return NSS_STATUS_TRYAGAIN;
+        }
+
+      p = strncpy (data->linebuffer, result, len);
+      data->linebuffer[len] = '\0';
+      while (isspace (*p))
+	++p;
+      free (result);
+
+      parse_res = parse_line (p, host, data, buflen);
+      if (parse_res == -1 && errno == ERANGE)
+	{
+	  *h_errnop = NETDB_INTERNAL;;
+	  return NSS_STATUS_TRYAGAIN;
+	}
+      free (oldkey);
+      oldkey = outkey;
+      oldkeylen = keylen;
+      new_start = 0;
+    }
+  while (!parse_res);
+
+  *h_errnop = NETDB_SUCCESS;
+  return NSS_STATUS_SUCCESS;
+}
+
+int
+_nss_nis_gethostent_r (struct hostent *host, char *buffer, size_t buflen,
+		       int *h_errnop)
+{
+  int status;
+
+  __libc_lock_lock (lock);
+
+  status = internal_nis_gethostent_r (host, buffer, buflen, h_errnop);
+
+  __libc_lock_unlock (lock);
+
+  return status;
+}
+
+enum nss_status
+_nss_nis_gethostbyname2_r (const char *name, int af, struct hostent *host,
+			  char *buffer, size_t buflen, int *h_errnop)
+{
+  enum nss_status retval;
+  char *domain, *result, *p;
+  int len, parse_res;
+  struct parser_data *data = (void *) buffer;
+  size_t linebuflen = buffer + buflen - data->linebuffer;
+
+  if (name == NULL)
+    {
+      __set_errno (EINVAL);
+      return NSS_STATUS_UNAVAIL;
+    }
+
+  if (yp_get_default_domain (&domain))
+    return NSS_STATUS_UNAVAIL;
+
+  if (buflen < sizeof *data + 1)
+    {
+      *h_errnop = NETDB_INTERNAL;
+      __set_errno (ERANGE);
+      return NSS_STATUS_TRYAGAIN;
+    }
+  else
+    {
+      /* Convert name to lowercase.  */
+      size_t namelen = strlen (name);
+      char name2[namelen + 1];
+      int i;
+
+      for (i = 0; i < namelen; ++i)
+	name2[i] = tolower (name[i]);
+      name2[i] = '\0';
+
+      retval = yperr2nss (yp_match (domain, "hosts.byname", name2,
+				    namelen, &result, &len));
+
+    }
+
+  if (retval != NSS_STATUS_SUCCESS)
+    {
+      if (retval == NSS_STATUS_TRYAGAIN)
+	{
+	  *h_errnop = TRY_AGAIN;
+	  __set_errno (EAGAIN);
+	}
+      if (retval == NSS_STATUS_NOTFOUND)
+	*h_errnop = HOST_NOT_FOUND;
+      return retval;
+    }
+
+  if ((size_t) (len + 1) > linebuflen)
+    {
+      free (result);
+      *h_errnop = NETDB_INTERNAL;
+      __set_errno (ERANGE);
+      return NSS_STATUS_TRYAGAIN;
+    }
+
+  p = strncpy (data->linebuffer, result, len);
+  data->linebuffer[len] = '\0';
+  while (isspace (*p))
+    ++p;
+  free (result);
+
+  parse_res = parse_line (p, host, data, buflen);
+
+  if (parse_res == -1 && errno == ERANGE)
+    {
+      *h_errnop = NETDB_INTERNAL;
+      return NSS_STATUS_TRYAGAIN;
+    }
+
+  if (parse_res == 0 || host->h_addrtype != af)
+    {
+      *h_errnop = HOST_NOT_FOUND;
+      return NSS_STATUS_NOTFOUND;
+    }
+
+  *h_errnop = NETDB_SUCCESS;
+  return NSS_STATUS_SUCCESS;
+}
+
+enum nss_status
+_nss_nis_gethostbyname_r (const char *name, struct hostent *host,
+			  char *buffer, size_t buflen, int *h_errnop)
+{
+  if (_res.options & RES_USE_INET6)
+    {
+      enum nss_status status;
+
+      status = _nss_nis_gethostbyname2_r (name, AF_INET6, host, buffer, buflen,
+					  h_errnop);
+      if (status == NSS_STATUS_SUCCESS)
+	return status;
+    }
+
+  return _nss_nis_gethostbyname2_r (name, AF_INET, host, buffer, buflen,
+				    h_errnop);
+}
+
+enum nss_status
+_nss_nis_gethostbyaddr_r (char *addr, int addrlen, int type,
+			  struct hostent *host, char *buffer, size_t buflen,
+			  int *h_errnop)
+{
+  enum nss_status retval;
+  char *domain, *result, *p;
+  int len, parse_res;
+  char *buf;
+  struct parser_data *data = (void *) buffer;
+  size_t linebuflen = buffer + buflen - data->linebuffer;
+
+  if (yp_get_default_domain (&domain))
+    return NSS_STATUS_UNAVAIL;
+
+  if (buflen < sizeof *data + 1)
+    {
+      __set_errno (ERANGE);
+      *h_errnop = NETDB_INTERNAL;
+      return NSS_STATUS_TRYAGAIN;
+    }
+
+  buf = inet_ntoa (*(struct in_addr *) addr);
+
+  retval = yperr2nss (yp_match (domain, "hosts.byaddr", buf,
+                                strlen (buf), &result, &len));
+
+  if (retval != NSS_STATUS_SUCCESS)
+    {
+      if (retval == NSS_STATUS_TRYAGAIN)
+	{
+	  *h_errnop = TRY_AGAIN;
+	  __set_errno (EAGAIN);
+	}
+      if (retval == NSS_STATUS_NOTFOUND)
+	*h_errnop = HOST_NOT_FOUND;
+      return retval;
+    }
+
+  if ((size_t) (len + 1) > linebuflen)
+    {
+      free (result);
+      __set_errno (ERANGE);
+      *h_errnop = NETDB_INTERNAL;
+      return NSS_STATUS_TRYAGAIN;
+    }
+
+  p = strncpy (data->linebuffer, result, len);
+  data->linebuffer[len] = '\0';
+  while (isspace (*p))
+    ++p;
+  free (result);
+
+  parse_res = parse_line (p, host, data, buflen);
+
+  if (parse_res == -1 && errno == ERANGE)
+    {
+      *h_errnop = NETDB_INTERNAL;
+      return NSS_STATUS_TRYAGAIN;
+    }
+  else if (parse_res == 0)
+    {
+      *h_errnop = HOST_NOT_FOUND;
+      return NSS_STATUS_NOTFOUND;
+    }
+
+  *h_errnop = NETDB_SUCCESS;
+  return NSS_STATUS_SUCCESS;
+}
diff --git a/glibc-compat/nss_nis/nis-netgrp.c b/glibc-compat/nss_nis/nis-netgrp.c
new file mode 100644
index 0000000000..da87f1a605
--- /dev/null
+++ b/glibc-compat/nss_nis/nis-netgrp.c
@@ -0,0 +1,128 @@
+/* Copyright (C) 1996 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1996.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include <nss.h>
+#include <ctype.h>
+#include <errno.h>
+#include <bits/libc-lock.h>
+#include <glibc-compat/include/netdb.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <netgroup.h>
+#include <rpcsvc/yp.h>
+#include <rpcsvc/ypclnt.h>
+
+#include "nss-nis.h"
+
+/* Locks the static variables in this file.  */
+__libc_lock_define_initialized (static, lock)
+
+static char *data = NULL;
+static size_t data_size = 0;
+static char *cursor = NULL;;
+
+extern enum nss_status
+_nss_netgroup_parseline (char **cursor, struct __netgrent *result,
+			 char *buffer, size_t buflen);
+
+enum nss_status
+_nss_nis_setnetgrent (char *group)
+{
+  char *domain;
+  char *result;
+  int len, group_len;
+  enum nss_status status;
+
+  status = NSS_STATUS_SUCCESS;
+
+  if (group[0] == '\0')
+    return NSS_STATUS_UNAVAIL;
+
+  if (yp_get_default_domain (&domain))
+    return NSS_STATUS_UNAVAIL;
+
+  __libc_lock_lock (lock);
+
+  if (data != NULL)
+    {
+      free (data);
+      data = NULL;
+      data_size = 0;
+      cursor = NULL;
+    }
+
+  group_len = strlen (group);
+
+  status = yperr2nss (yp_match (domain, "netgroup", group, group_len,
+				&result, &len));
+  if (status == NSS_STATUS_SUCCESS)
+    {
+      if (len > 0)
+	{
+	  data = malloc (len + 1);
+	  data_size = len;
+	  cursor = strncpy (data, result, len + 1);
+	  data[len] = '\0';
+	  free (result);
+	}
+      else
+	status = NSS_STATUS_NOTFOUND;
+    }
+
+  __libc_lock_unlock (lock);
+
+  return status;
+}
+
+
+enum nss_status
+_nss_nis_endnetgrent (void)
+{
+  __libc_lock_lock (lock);
+
+  if (data != NULL)
+    {
+      free (data);
+      data = NULL;
+      data_size = 0;
+      cursor = NULL;
+    }
+
+  __libc_lock_unlock (lock);
+
+  return NSS_STATUS_SUCCESS;
+}
+
+enum nss_status
+_nss_nis_getnetgrent_r (struct __netgrent *result, char *buffer, size_t buflen)
+{
+  enum nss_status status;
+
+  if (cursor == NULL)
+    return NSS_STATUS_NOTFOUND;
+
+  __libc_lock_lock (lock);
+
+  status = _nss_netgroup_parseline (&cursor, result, buffer, buflen);
+
+  __libc_lock_unlock (lock);
+
+  return status;
+}
diff --git a/glibc-compat/nss_nis/nis-network.c b/glibc-compat/nss_nis/nis-network.c
new file mode 100644
index 0000000000..3accc2be41
--- /dev/null
+++ b/glibc-compat/nss_nis/nis-network.c
@@ -0,0 +1,318 @@
+/* Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1996.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include <nss.h>
+#include <glibc-compat/include/netdb.h>
+#include <ctype.h>
+#include <errno.h>
+#include <string.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <bits/libc-lock.h>
+#include <rpcsvc/yp.h>
+#include <rpcsvc/ypclnt.h>
+
+#include "nss-nis.h"
+
+/* Get the declaration of the parser function.  */
+#define ENTNAME netent
+#define EXTERN_PARSER
+#include "../nss_files/files-parse.c"
+
+__libc_lock_define_initialized (static, lock)
+
+static bool_t new_start = 1;
+static char *oldkey = NULL;
+static int oldkeylen = 0;
+
+enum nss_status
+_nss_nis_setnetent (void)
+{
+  __libc_lock_lock (lock);
+
+  new_start = 1;
+  if (oldkey != NULL)
+    {
+      free (oldkey);
+      oldkey = NULL;
+      oldkeylen = 0;
+    }
+
+  __libc_lock_unlock (lock);
+
+  return NSS_STATUS_SUCCESS;
+}
+
+enum nss_status
+_nss_nis_endnetent (void)
+{
+  __libc_lock_lock (lock);
+
+  new_start = 1;
+  if (oldkey != NULL)
+    {
+      free (oldkey);
+      oldkey = NULL;
+      oldkeylen = 0;
+    }
+
+  __libc_lock_unlock (lock);
+
+  return NSS_STATUS_SUCCESS;
+}
+
+static enum nss_status
+internal_nis_getnetent_r (struct netent *net, char *buffer, size_t buflen,
+			  int *herrnop)
+{
+  struct parser_data *data = (void *) buffer;
+  char *domain, *result, *outkey;
+  int len, keylen, parse_res;
+
+  if (yp_get_default_domain (&domain))
+    return NSS_STATUS_UNAVAIL;
+
+  /* Get the next entry until we found a correct one. */
+  do
+    {
+      enum nss_status retval;
+      char *p;
+
+      if (new_start)
+        retval = yperr2nss (yp_first (domain, "networks.byname",
+                                      &outkey, &keylen, &result, &len));
+      else
+        retval = yperr2nss ( yp_next (domain, "networks.byname",
+                                      oldkey, oldkeylen,
+                                      &outkey, &keylen, &result, &len));
+
+      if (retval != NSS_STATUS_SUCCESS)
+        {
+          if (retval == NSS_STATUS_TRYAGAIN)
+	    {
+	      *herrnop = NETDB_INTERNAL;
+	      __set_errno (EAGAIN);
+	    }
+          return retval;
+        }
+
+      if ((size_t) (len + 1) > buflen)
+        {
+          free (result);
+          __set_errno (ERANGE);
+	  *herrnop = NETDB_INTERNAL;
+          return NSS_STATUS_TRYAGAIN;
+        }
+
+      p = strncpy (buffer, result, len);
+      buffer[len] = '\0';
+      while (isspace (*p))
+        ++p;
+      free (result);
+
+      parse_res = _nss_files_parse_netent (p, net, data, buflen);
+      if (parse_res == -1 && errno == ERANGE)
+	{
+	  *herrnop = NETDB_INTERNAL;
+	  return NSS_STATUS_TRYAGAIN;
+	}
+
+      free (oldkey);
+      oldkey = outkey;
+      oldkeylen = keylen;
+      new_start = 0;
+    }
+  while (!parse_res);
+
+  return NSS_STATUS_SUCCESS;
+}
+
+enum nss_status
+_nss_nis_getnetent_r (struct netent *net, char *buffer, size_t buflen,
+		      int *herrnop)
+{
+  enum nss_status status;
+
+  __libc_lock_lock (lock);
+
+  status = internal_nis_getnetent_r (net, buffer, buflen, herrnop);
+
+  __libc_lock_unlock (lock);
+
+  return status;
+}
+
+enum nss_status
+_nss_nis_getnetbyname_r (const char *name, struct netent *net,
+			 char *buffer, size_t buflen, int *herrnop)
+{
+  enum nss_status retval;
+  struct parser_data *data = (void *) buffer;
+  char *domain, *result, *p;
+  int len, parse_res;
+
+  if (name == NULL)
+    {
+      __set_errno (EINVAL);
+      *herrnop = NETDB_INTERNAL;
+      return NSS_STATUS_UNAVAIL;
+    }
+
+  if (yp_get_default_domain (&domain))
+    return NSS_STATUS_UNAVAIL;
+
+  if (buflen < sizeof *data + 1)
+    {
+      *herrnop = NETDB_INTERNAL;
+      __set_errno(ERANGE);
+      return NSS_STATUS_TRYAGAIN;
+    }
+  else
+    {
+      /* Convert name to lowercase.  */
+      size_t namlen = strlen (name);
+      char name2[namlen + 1];
+      int i;
+
+      for (i = 0; i < namlen; ++i)
+	name2[i] = tolower (name[i]);
+      name2[i] = '\0';
+
+      retval = yperr2nss (yp_match (domain, "networks.byname", name2,
+				    namlen, &result, &len));
+    }
+
+  if (retval != NSS_STATUS_SUCCESS)
+    {
+      if (retval == NSS_STATUS_TRYAGAIN)
+	{
+	  __set_errno (EAGAIN);
+	  *herrnop = NETDB_INTERNAL;
+	}
+      return retval;
+    }
+
+  if ((size_t) (len + 1) > buflen)
+    {
+      free (result);
+      __set_errno (ERANGE);
+      *herrnop = NETDB_INTERNAL;
+      return NSS_STATUS_TRYAGAIN;
+    }
+
+  p = strncpy (buffer, result, len);
+  buffer[len] = '\0';
+  while (isspace (*p))
+    ++p;
+  free (result);
+
+  parse_res = _nss_files_parse_netent (p, net, data, buflen);
+
+  if (parse_res <= 0)
+    {
+      *herrnop = NETDB_INTERNAL;
+      if (parse_res == -1 && errno == ERANGE)
+	return NSS_STATUS_TRYAGAIN;
+      else
+        return NSS_STATUS_NOTFOUND;
+    }
+  else
+    return NSS_STATUS_SUCCESS;
+}
+
+enum nss_status
+_nss_nis_getnetbyaddr_r (unsigned long addr, int type, struct netent *net,
+			 char *buffer, size_t buflen, int *herrnop)
+{
+  struct parser_data *data = (void *) buffer;
+  char *domain;
+  char *result;
+  int len;
+  char buf[256];
+  int blen;
+  struct in_addr in;
+  char *p;
+
+  if (yp_get_default_domain (&domain))
+    return NSS_STATUS_UNAVAIL;
+
+  in = inet_makeaddr (addr, 0);
+  strcpy (buf, inet_ntoa (in));
+  blen = strlen (buf);
+
+  while (1)
+    {
+      enum nss_status retval;
+      int parse_res;
+
+      retval = yperr2nss (yp_match (domain, "networks.byaddr", buf,
+				    strlen (buf), &result, &len));
+
+	if (retval != NSS_STATUS_SUCCESS)
+	  {
+	    if (retval == NSS_STATUS_NOTFOUND)
+	      {
+		if (buf[blen - 2] == '.' && buf[blen - 1] == '0')
+		  {
+		    /* Try again, but with trailing dot(s)
+		       removed (one by one) */
+		    buf[blen - 2] = '\0';
+		    blen -= 2;
+		    continue;
+		  }
+		else
+		  return NSS_STATUS_NOTFOUND;
+	      }
+	    else
+	      {
+		if (retval == NSS_STATUS_TRYAGAIN)
+		  __set_errno (EAGAIN);
+		return retval;
+	      }
+	  }
+
+      if ((size_t) (len + 1) > buflen)
+	{
+	  free (result);
+	  __set_errno (ERANGE);
+	  *herrnop = NETDB_INTERNAL;
+	  return NSS_STATUS_TRYAGAIN;
+	}
+
+        p = strncpy (buffer, result, len);
+	buffer[len] = '\0';
+	while (isspace (*p))
+	  ++p;
+	free (result);
+
+	parse_res = _nss_files_parse_netent (p, net, data, buflen);
+
+
+	if (parse_res <= 0)
+	  {
+	    *herrnop = NETDB_INTERNAL;
+	    if (parse_res == -1 && errno == ERANGE)
+	      return NSS_STATUS_TRYAGAIN;
+	    else
+	      return NSS_STATUS_NOTFOUND;
+	  }
+	else
+	  return NSS_STATUS_SUCCESS;
+    }
+}
diff --git a/glibc-compat/nss_nis/nis-proto.c b/glibc-compat/nss_nis/nis-proto.c
new file mode 100644
index 0000000000..8dff7d3687
--- /dev/null
+++ b/glibc-compat/nss_nis/nis-proto.c
@@ -0,0 +1,280 @@
+/* Copyright (C) 1996, 1997 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1996.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include <nss.h>
+#include <glibc-compat/include/netdb.h>
+#include <ctype.h>
+#include <errno.h>
+#include <string.h>
+#include <bits/libc-lock.h>
+#include <rpcsvc/yp.h>
+#include <rpcsvc/ypclnt.h>
+
+#include "nss-nis.h"
+
+/* Get the declaration of the parser function.  */
+#define ENTNAME protoent
+#define EXTERN_PARSER
+#include "../nss_files/files-parse.c"
+
+__libc_lock_define_initialized (static, lock)
+
+struct response
+{
+  char *val;
+  struct response *next;
+};
+
+static struct response *start = NULL;
+static struct response *next = NULL;
+
+static int
+saveit (int instatus, char *inkey, int inkeylen, char *inval,
+        int invallen, char *indata)
+{
+  if (instatus != YP_TRUE)
+    return instatus;
+
+  if (inkey && inkeylen > 0 && inval && invallen > 0)
+    {
+      if (start == NULL)
+        {
+          start = malloc (sizeof (struct response));
+          next = start;
+        }
+      else
+        {
+          next->next = malloc (sizeof (struct response));
+          next = next->next;
+        }
+      next->next = NULL;
+      next->val = malloc (invallen + 1);
+      strncpy (next->val, inval, invallen);
+      next->val[invallen] = '\0';
+    }
+
+  return 0;
+}
+
+enum nss_status
+internal_nis_setprotoent (void)
+{
+  char *domainname;
+  struct ypall_callback ypcb;
+  enum nss_status status;
+
+  yp_get_default_domain (&domainname);
+
+  while (start != NULL)
+    {
+      if (start->val != NULL)
+        free (start->val);
+      next = start;
+      start = start->next;
+      free (next);
+    }
+  start = NULL;
+
+  ypcb.foreach = saveit;
+  ypcb.data = NULL;
+  status = yperr2nss (yp_all (domainname, "protocols.bynumber", &ypcb));
+  next = start;
+
+  return status;
+}
+
+enum nss_status
+_nss_nis_setprotoent (void)
+{
+  enum nss_status status;
+
+  __libc_lock_lock (lock);
+
+  status = internal_nis_setprotoent ();
+
+  __libc_lock_unlock (lock);
+
+  return status;
+}
+
+enum nss_status
+_nss_nis_endprotoent (void)
+{
+  __libc_lock_lock (lock);
+
+  while (start != NULL)
+    {
+      if (start->val != NULL)
+        free (start->val);
+      next = start;
+      start = start->next;
+      free (next);
+    }
+  start = NULL;
+  next = NULL;
+
+  __libc_lock_unlock (lock);
+
+  return NSS_STATUS_SUCCESS;
+}
+
+static enum nss_status
+internal_nis_getprotoent_r (struct protoent *proto,
+			    char *buffer, size_t buflen)
+{
+  struct parser_data *data = (void *) buffer;
+  int parse_res;
+
+  if (start == NULL)
+    internal_nis_setprotoent ();
+
+  /* Get the next entry until we found a correct one. */
+  do
+    {
+      char *p;
+
+      if (next == NULL)
+        return NSS_STATUS_NOTFOUND;
+      p = strncpy (buffer, next->val, buflen);
+      next = next->next;
+
+      while (isspace (*p))
+        ++p;
+
+      parse_res = _nss_files_parse_protoent (p, proto, data, buflen);
+      if (parse_res == -1 && errno == ERANGE)
+        return NSS_STATUS_TRYAGAIN;
+    }
+  while (!parse_res);
+
+  return NSS_STATUS_SUCCESS;
+}
+
+enum nss_status
+_nss_nis_getprotoent_r (struct protoent *proto, char *buffer, size_t buflen)
+{
+  enum nss_status status;
+
+  __libc_lock_lock (lock);
+
+  status = internal_nis_getprotoent_r (proto, buffer, buflen);
+
+  __libc_lock_unlock (lock);
+
+  return status;
+}
+
+enum nss_status
+_nss_nis_getprotobyname_r (const char *name, struct protoent *proto,
+			   char *buffer, size_t buflen)
+{
+  struct parser_data *data = (void *) buffer;
+  enum nss_status retval;
+  char *domain, *result, *p;
+  int len, parse_res;
+
+  if (name == NULL)
+    {
+      __set_errno (EINVAL);
+      return NSS_STATUS_UNAVAIL;
+    }
+
+  if (yp_get_default_domain (&domain))
+    return NSS_STATUS_UNAVAIL;
+
+  retval = yperr2nss (yp_match (domain, "protocols.byname", name,
+                                strlen (name), &result, &len));
+
+  if (retval != NSS_STATUS_SUCCESS)
+    {
+      if (retval == NSS_STATUS_TRYAGAIN)
+        __set_errno (EAGAIN);
+      return retval;
+    }
+
+  if ((size_t) (len + 1) > buflen)
+    {
+      free (result);
+      __set_errno (ERANGE);
+      return NSS_STATUS_TRYAGAIN;
+    }
+
+  p = strncpy (buffer, result, len);
+  buffer[len] = '\0';
+  while (isspace (*p))
+    ++p;
+  free (result);
+
+  parse_res = _nss_files_parse_protoent (p, proto, data, buflen);
+
+  if (parse_res == -1 && errno == ERANGE)
+    return NSS_STATUS_TRYAGAIN;
+  else if (parse_res == 0)
+    return NSS_STATUS_NOTFOUND;
+
+  return NSS_STATUS_SUCCESS;
+}
+
+enum nss_status
+_nss_nis_getprotobynumber_r (int number, struct protoent *proto,
+			     char *buffer, size_t buflen)
+{
+  struct parser_data *data = (void *) buffer;
+  enum nss_status retval;
+  char *domain, *result, *p;
+  int len, nlen, parse_res;
+  char buf[32];
+
+  if (yp_get_default_domain (&domain))
+    return NSS_STATUS_UNAVAIL;
+
+  nlen = sprintf (buf, "%d", number);
+
+  retval = yperr2nss (yp_match (domain, "protocols.bynumber", buf,
+                                nlen, &result, &len));
+
+  if (retval != NSS_STATUS_SUCCESS)
+    {
+      if (retval == NSS_STATUS_TRYAGAIN)
+        __set_errno (EAGAIN);
+      return retval;
+    }
+
+  if ((size_t) (len + 1) > buflen)
+    {
+      free (result);
+      __set_errno (ERANGE);
+      return NSS_STATUS_TRYAGAIN;
+    }
+
+  p = strncpy (buffer, result, len);
+  buffer[len] = '\0';
+  while (isspace (*p))
+    ++p;
+  free (result);
+
+  parse_res = _nss_files_parse_protoent (p, proto, data, buflen);
+
+  if (parse_res == -1 && errno == ERANGE)
+    return NSS_STATUS_TRYAGAIN;
+  else if (parse_res == 0)
+    return NSS_STATUS_NOTFOUND;
+
+  return NSS_STATUS_SUCCESS;
+}
diff --git a/glibc-compat/nss_nis/nis-pwd.c b/glibc-compat/nss_nis/nis-pwd.c
new file mode 100644
index 0000000000..e18c80d8ac
--- /dev/null
+++ b/glibc-compat/nss_nis/nis-pwd.c
@@ -0,0 +1,407 @@
+/* Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1996.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include <nss.h>
+#include <glibc-compat/include/pwd.h>
+#include <ctype.h>
+#include <errno.h>
+#include <string.h>
+#include <bits/libc-lock.h>
+#include <rpcsvc/yp.h>
+#include <rpcsvc/ypclnt.h>
+
+#include "nss-nis.h"
+
+/* Get the declaration of the parser function.  */
+#define ENTNAME pwent
+#define STRUCTURE passwd
+#define EXTERN_PARSER
+#include "../nss_files/files-parse.c"
+
+/* Protect global state against multiple changers */
+__libc_lock_define_initialized (static, lock)
+
+static bool_t new_start = 1;
+static char *oldkey = NULL;
+static int oldkeylen = 0;
+
+enum nss_status
+_nss_nis_setpwent (void)
+{
+  __libc_lock_lock (lock);
+
+  new_start = 1;
+  if (oldkey != NULL)
+    {
+      free (oldkey);
+      oldkey = NULL;
+      oldkeylen = 0;
+    }
+
+  __libc_lock_unlock (lock);
+
+  return NSS_STATUS_SUCCESS;
+}
+
+enum nss_status
+_nss_nis_endpwent (void)
+{
+  __libc_lock_lock (lock);
+
+  new_start = 1;
+  if (oldkey != NULL)
+    {
+      free (oldkey);
+      oldkey = NULL;
+      oldkeylen = 0;
+    }
+
+  __libc_lock_unlock (lock);
+
+  return NSS_STATUS_SUCCESS;
+}
+
+static enum nss_status
+internal_nis_getpwent_r (struct passwd *pwd, char *buffer, size_t buflen)
+{
+  struct parser_data *data = (void *) buffer;
+  char *domain;
+  int parse_res;
+
+  if (yp_get_default_domain (&domain))
+    return NSS_STATUS_UNAVAIL;
+
+  /* Get the next entry until we found a correct one. */
+  do
+    {
+      enum nss_status retval;
+      char *result, *outkey, *result2, *p;
+      int len, keylen, len2;
+      size_t namelen;
+
+      if (new_start)
+        retval = yperr2nss (yp_first (domain, "passwd.byname",
+                                      &outkey, &keylen, &result, &len));
+      else
+        retval = yperr2nss ( yp_next (domain, "passwd.byname",
+                                      oldkey, oldkeylen,
+                                      &outkey, &keylen, &result, &len));
+
+      if (retval != NSS_STATUS_SUCCESS)
+        {
+          if (retval == NSS_STATUS_TRYAGAIN)
+            __set_errno (EAGAIN);
+          return retval;
+        }
+
+      /* Check for adjunct style secret passwords.  They can be
+	 recognized by a password starting with "##".  */
+      p = strchr (result, ':');
+      if (p != NULL	/* This better should be true in all cases.  */
+	  && p[1] == '#' && p[2] == '#'
+	  && (namelen = p - result,
+	      yp_match (domain, "passwd.adjunct.byname", result, namelen,
+			&result2, &len2)) == YPERR_SUCCESS)
+	{
+	  /* We found a passwd.adjunct entry.  Merge encrypted
+	     password therein into original result.  */
+	  char *encrypted = strchr (result2, ':');
+	  char *endp, *tmp;
+	  size_t restlen;
+
+	  if (encrypted == NULL
+	      || (endp = strchr (++encrypted, ':')) == NULL
+	      || (p = strchr (p + 1, ':')) == NULL)
+	    {
+	      /* Invalid format of the entry.  This never should happen
+		 unless the data from which the NIS table is generated is
+		 wrong.  We simply ignore it.  */
+	      free (result2);
+	      goto non_adjunct;
+	    }
+
+	  restlen = len - (p - result);
+	  if ((size_t) (namelen + (endp - encrypted) + restlen + 2) > buflen)
+	    {
+	      free (result2);
+	      free (result);
+	      __set_errno (ERANGE);
+	      return NSS_STATUS_TRYAGAIN;
+	    }
+
+	  memcpy (buffer, result, namelen);
+	  tmp = buffer + namelen;
+	  *tmp++ = ':';
+	  memcpy (tmp, encrypted, endp - encrypted);
+	  tmp += endp - encrypted;
+	  memcpy (tmp, p, restlen + 1);
+	  p = buffer;
+
+	  free (result2);
+	}
+      else
+	{
+	non_adjunct:
+	  if ((size_t) (len + 1) > buflen)
+	    {
+	      free (result);
+	      __set_errno (ERANGE);
+	      return NSS_STATUS_TRYAGAIN;
+	    }
+
+	  p = strncpy (buffer, result, len);
+	  buffer[len] = '\0';
+	}
+
+      p = strncpy (buffer, result, len);
+      buffer[len] = '\0';
+      while (isspace (*p))
+        ++p;
+      free (result);
+
+      parse_res = _nss_files_parse_pwent (p, pwd, data, buflen);
+      if (parse_res == -1 && errno == ERANGE)
+        return NSS_STATUS_TRYAGAIN;
+
+      free (oldkey);
+      oldkey = outkey;
+      oldkeylen = keylen;
+      new_start = 0;
+    }
+  while (!parse_res);
+
+  return NSS_STATUS_SUCCESS;
+}
+
+enum nss_status
+_nss_nis_getpwent_r (struct passwd *result, char *buffer, size_t buflen)
+{
+  int status;
+
+  __libc_lock_lock (lock);
+
+  status = internal_nis_getpwent_r (result, buffer, buflen);
+
+  __libc_lock_unlock (lock);
+
+  return status;
+}
+
+enum nss_status
+_nss_nis_getpwnam_r (const char *name, struct passwd *pwd,
+		     char *buffer, size_t buflen)
+{
+  struct parser_data *data = (void *) buffer;
+  enum nss_status retval;
+  char *domain, *result, *result2, *p;
+  int len, len2, parse_res;
+  size_t namelen;
+
+  if (name == NULL)
+    {
+      __set_errno (EINVAL);
+      return NSS_STATUS_UNAVAIL;
+    }
+
+  if (yp_get_default_domain (&domain))
+    return NSS_STATUS_UNAVAIL;
+
+  namelen = strlen (name);
+
+  retval = yperr2nss (yp_match (domain, "passwd.byname", name,
+				namelen, &result, &len));
+
+  if (retval != NSS_STATUS_SUCCESS)
+    {
+      if (retval == NSS_STATUS_TRYAGAIN)
+        __set_errno (EAGAIN);
+      return retval;
+    }
+
+  /* Check for adjunct style secret passwords.  They can be recognized
+     by a password starting with "##".  */
+  p = strchr (result, ':');
+  if (p != NULL	/* This better should be true in all cases.  */
+      && p[1] == '#' && p[2] == '#'
+      && (namelen = p - result,
+	  yp_match (domain, "passwd.adjunct.byname", name, namelen,
+		    &result2, &len2)) == YPERR_SUCCESS)
+    {
+      /* We found a passwd.adjunct entry.  Merge encrypted password
+	 therein into original result.  */
+      char *encrypted = strchr (result2, ':');
+      char *endp, *tmp;
+      size_t restlen;
+
+      if (encrypted == NULL
+	  || (endp = strchr (++encrypted, ':')) == NULL
+	  || (p = strchr (p + 1, ':')) == NULL)
+	{
+	  /* Invalid format of the entry.  This never should happen
+	     unless the data from which the NIS table is generated is
+	     wrong.  We simply ignore it.  */
+	  free (result2);
+	  goto non_adjunct;
+	}
+
+      restlen = len - (p - result);
+      if ((size_t) (namelen + (endp - encrypted) + restlen + 2) > buflen)
+	{
+	  free (result2);
+	  free (result);
+	  __set_errno (ERANGE);
+	  return NSS_STATUS_TRYAGAIN;
+	}
+
+      memcpy (buffer, name, namelen);
+      tmp = buffer + namelen;
+      *tmp++ = ':';
+      memcpy (tmp, encrypted, endp - encrypted);
+      tmp += endp - encrypted;
+      memcpy (tmp, p, restlen + 1);
+      p = buffer;
+
+      free (result2);
+    }
+  else
+    {
+    non_adjunct:
+      if ((size_t) (len + 1) > buflen)
+	{
+	  free (result);
+	  __set_errno (ERANGE);
+	  return NSS_STATUS_TRYAGAIN;
+	}
+
+      p = strncpy (buffer, result, len);
+      buffer[len] = '\0';
+    }
+
+  while (isspace (*p))
+    ++p;
+  free (result);
+
+  parse_res = _nss_files_parse_pwent (p, pwd, data, buflen);
+
+  if (parse_res == -1 && errno == ERANGE)
+    return NSS_STATUS_TRYAGAIN;
+  else if (parse_res == 0)
+    return NSS_STATUS_NOTFOUND;
+
+  return NSS_STATUS_SUCCESS;
+}
+
+enum nss_status
+_nss_nis_getpwuid_r (uid_t uid, struct passwd *pwd,
+		     char *buffer, size_t buflen)
+{
+  struct parser_data *data = (void *) buffer;
+  enum nss_status retval;
+  char *domain, *result, *p, *result2;
+  int len, nlen, parse_res, len2;
+  char buf[32];
+  size_t namelen;
+
+  if (yp_get_default_domain (&domain))
+    return NSS_STATUS_UNAVAIL;
+
+  nlen = sprintf (buf, "%d", uid);
+
+  retval = yperr2nss (yp_match (domain, "passwd.byuid", buf,
+				nlen, &result, &len));
+
+  if (retval != NSS_STATUS_SUCCESS)
+    {
+      if (retval == NSS_STATUS_TRYAGAIN)
+        __set_errno (EAGAIN);
+      return retval;
+    }
+
+  /* Check for adjunct style secret passwords.  They can be recognized
+     by a password starting with "##".  */
+  p = strchr (result, ':');
+  if (p != NULL	/* This better should be true in all cases.  */
+      && p[1] == '#' && p[2] == '#'
+      && (namelen = p - result,
+	  yp_match (domain, "passwd.adjunct.byname", result, namelen,
+		    &result2, &len2)) == YPERR_SUCCESS)
+    {
+      /* We found a passwd.adjunct entry.  Merge encrypted password
+	 therein into original result.  */
+      char *encrypted = strchr (result2, ':');
+      char *endp, *tmp;
+      size_t restlen;
+
+      if (encrypted == NULL
+	  || (endp = strchr (++encrypted, ':')) == NULL
+	  || (p = strchr (p + 1, ':')) == NULL)
+	{
+	  /* Invalid format of the entry.  This never should happen
+	     unless the data from which the NIS table is generated is
+	     wrong.  We simply ignore it.  */
+	  free (result2);
+	  goto non_adjunct;
+	}
+
+      restlen = len - (p - result);
+      if ((size_t) (namelen + (endp - encrypted) + restlen + 2) > buflen)
+	{
+	  free (result2);
+	  free (result);
+	  __set_errno (ERANGE);
+	  return NSS_STATUS_TRYAGAIN;
+	}
+
+      memcpy (buffer, result, namelen);
+      tmp = buffer + namelen;
+      *tmp++ = ':';
+      memcpy (tmp, encrypted, endp - encrypted);
+      tmp += endp - encrypted;
+      memcpy (tmp, p, restlen + 1);
+      p = buffer;
+
+      free (result2);
+    }
+  else
+    {
+    non_adjunct:
+      if ((size_t) (len + 1) > buflen)
+	{
+	  free (result);
+	  __set_errno (ERANGE);
+	  return NSS_STATUS_TRYAGAIN;
+	}
+
+      p = strncpy (buffer, result, len);
+      buffer[len] = '\0';
+    }
+
+  while (isspace (*p))
+    ++p;
+  free (result);
+
+  parse_res = _nss_files_parse_pwent (p, pwd, data, buflen);
+
+  if (parse_res == -1 && errno == ERANGE)
+    return NSS_STATUS_TRYAGAIN;
+  else if (parse_res == 0)
+    return NSS_STATUS_NOTFOUND;
+
+  return NSS_STATUS_SUCCESS;
+}
diff --git a/glibc-compat/nss_nis/nis-rpc.c b/glibc-compat/nss_nis/nis-rpc.c
new file mode 100644
index 0000000000..b265fcdecb
--- /dev/null
+++ b/glibc-compat/nss_nis/nis-rpc.c
@@ -0,0 +1,295 @@
+/* Copyright (C) 1996, 1997 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1996.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include <nss.h>
+#include <glibc-compat/include/netdb.h>
+#include <ctype.h>
+#include <errno.h>
+#include <string.h>
+#include <bits/libc-lock.h>
+#include <rpcsvc/yp.h>
+#include <rpcsvc/ypclnt.h>
+
+#include "nss-nis.h"
+
+/* Get the declaration of the parser function.  */
+#define ENTNAME rpcent
+#define EXTERN_PARSER
+#include "../nss_files/files-parse.c"
+
+__libc_lock_define_initialized (static, lock)
+
+struct response_t
+{
+  char *val;
+  struct response_t *next;
+};
+
+struct intern_t
+{
+  struct response_t *start;
+  struct response_t *next;
+};
+typedef struct intern_t intern_t;
+
+static intern_t intern = {NULL, NULL};
+
+static int
+saveit (int instatus, char *inkey, int inkeylen, char *inval,
+        int invallen, char *indata)
+{
+  intern_t *intern = (intern_t *)indata;
+
+  if (instatus != YP_TRUE)
+    return instatus;
+
+  if (inkey && inkeylen > 0 && inval && invallen > 0)
+    {
+      if (intern->start == NULL)
+        {
+          intern->start = malloc (sizeof (struct response_t));
+          intern->next = intern->start;
+        }
+      else
+        {
+          intern->next->next = malloc (sizeof (struct response_t));
+          intern->next = intern->next->next;
+        }
+      intern->next->next = NULL;
+      intern->next->val = malloc (invallen + 1);
+      strncpy (intern->next->val, inval, invallen);
+      intern->next->val[invallen] = '\0';
+    }
+
+  return 0;
+}
+
+static enum nss_status
+internal_nis_setrpcent (intern_t *intern)
+{
+  char *domainname;
+  struct ypall_callback ypcb;
+  enum nss_status status;
+
+  if (yp_get_default_domain (&domainname))
+    return NSS_STATUS_UNAVAIL;
+
+  while (intern->start != NULL)
+    {
+      if (intern->start->val != NULL)
+        free (intern->start->val);
+      intern->next = intern->start;
+      intern->start = intern->start->next;
+      free (intern->next);
+    }
+  intern->start = NULL;
+
+  ypcb.foreach = saveit;
+  ypcb.data = (char *)intern;
+  status = yperr2nss (yp_all(domainname, "rpc.bynumber", &ypcb));
+  intern->next = intern->start;
+
+  return status;
+}
+
+enum nss_status
+_nss_nis_setrpcent (void)
+{
+  enum nss_status status;
+
+  __libc_lock_lock (lock);
+
+  status = internal_nis_setrpcent (&intern);
+
+  __libc_lock_unlock (lock);
+
+  return status;
+}
+
+static enum nss_status
+internal_nis_endrpcent (intern_t *intern)
+{
+  while (intern->start != NULL)
+    {
+      if (intern->start->val != NULL)
+        free (intern->start->val);
+      intern->next = intern->start;
+      intern->start = intern->start->next;
+      free (intern->next);
+    }
+  intern->start = NULL;
+
+  return NSS_STATUS_SUCCESS;
+}
+
+enum nss_status
+_nss_nis_endrpcent (void)
+{
+  enum nss_status status;
+
+  __libc_lock_lock (lock);
+
+  status = internal_nis_endrpcent (&intern);
+
+  __libc_lock_unlock (lock);
+
+  return status;
+}
+
+static enum nss_status
+internal_nis_getrpcent_r (struct rpcent *rpc, char *buffer, size_t buflen,
+			  intern_t *data)
+{
+  struct parser_data *pdata = (void *) buffer;
+  int parse_res;
+  char *p;
+
+  if (data->start == NULL)
+    internal_nis_setrpcent (data);
+
+  /* Get the next entry until we found a correct one. */
+  do
+    {
+      if (data->next == NULL)
+        return NSS_STATUS_NOTFOUND;
+      p = strncpy (buffer, data->next->val, buflen);
+      data->next = data->next->next;
+      while (isspace (*p))
+        ++p;
+
+      parse_res = _nss_files_parse_rpcent (p, rpc, pdata, buflen);
+      if (parse_res == -1 && errno == ERANGE)
+	return NSS_STATUS_TRYAGAIN;
+    }
+  while (!parse_res);
+
+  return NSS_STATUS_SUCCESS;
+}
+
+enum nss_status
+_nss_nis_getrpcent_r (struct rpcent *rpc, char *buffer, size_t buflen)
+{
+  enum nss_status status;
+
+  __libc_lock_lock (lock);
+
+  status = internal_nis_getrpcent_r (rpc, buffer, buflen, &intern);
+
+  __libc_lock_unlock (lock);
+
+  return status;
+}
+
+enum nss_status
+_nss_nis_getrpcbyname_r (const char *name, struct rpcent *rpc,
+			 char *buffer, size_t buflen)
+{
+  intern_t data = {NULL, NULL};
+  enum nss_status status;
+  int found;
+
+  if (name == NULL)
+    {
+      __set_errno (EINVAL);
+      return NSS_STATUS_UNAVAIL;
+    }
+
+  status = internal_nis_setrpcent (&data);
+  if (status != NSS_STATUS_SUCCESS)
+    return status;
+
+  found = 0;
+  while (!found &&
+         ((status = internal_nis_getrpcent_r (rpc, buffer, buflen, &data))
+          == NSS_STATUS_SUCCESS))
+    {
+      if (strcmp (rpc->r_name, name) == 0)
+	found = 1;
+      else
+	{
+	  int i = 0;
+
+	  while (rpc->r_aliases[i] != NULL)
+	    {
+	      if (strcmp (rpc->r_aliases[i], name) == 0)
+		{
+		  found = 1;
+		  break;
+		}
+	      else
+		++i;
+	    }
+	}
+    }
+
+  internal_nis_endrpcent (&data);
+
+  if (!found && status == NSS_STATUS_SUCCESS)
+    return NSS_STATUS_NOTFOUND;
+  else
+    return status;
+}
+
+enum nss_status
+_nss_nis_getrpcbynumber_r (int number, struct rpcent *rpc,
+			   char *buffer, size_t buflen)
+{
+  struct parser_data *data = (void *) buffer;
+  enum nss_status retval;
+  char *domain, *result, *p;
+  int len, nlen, parse_res;
+  char buf[32];
+
+  if (yp_get_default_domain (&domain))
+    return NSS_STATUS_UNAVAIL;
+
+  nlen = sprintf (buf, "%d", number);
+
+  retval = yperr2nss (yp_match (domain, "rpc.bynumber", buf,
+				 nlen, &result, &len));
+
+  if (retval != NSS_STATUS_SUCCESS)
+    {
+      if (retval == NSS_STATUS_TRYAGAIN)
+	__set_errno (EAGAIN);
+      return retval;
+    }
+
+  if ((size_t) (len + 1) > buflen)
+    {
+      free (result);
+      __set_errno (ERANGE);
+      return NSS_STATUS_TRYAGAIN;
+    }
+
+  p = strncpy (buffer, result, len);
+  buffer[len] = '\0';
+  while (isspace (*p))
+    ++p;
+  free (result);
+
+  parse_res = _nss_files_parse_rpcent (p, rpc, data, buflen);
+
+  if (parse_res == -1 && errno == ERANGE)
+    return NSS_STATUS_TRYAGAIN;
+  else if (parse_res == 0)
+    return NSS_STATUS_NOTFOUND;
+
+  return NSS_STATUS_SUCCESS;
+}
diff --git a/glibc-compat/nss_nis/nis-service.c b/glibc-compat/nss_nis/nis-service.c
new file mode 100644
index 0000000000..75b871e440
--- /dev/null
+++ b/glibc-compat/nss_nis/nis-service.c
@@ -0,0 +1,280 @@
+/* Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1996.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include <nss.h>
+#include <glibc-compat/include/netdb.h>
+#include <ctype.h>
+#include <errno.h>
+#include <string.h>
+#include <bits/libc-lock.h>
+#include <rpcsvc/yp.h>
+#include <rpcsvc/ypclnt.h>
+
+#include "nss-nis.h"
+
+/* Get the declaration of the parser function.  */
+#define ENTNAME servent
+#define EXTERN_PARSER
+#include "../nss_files/files-parse.c"
+
+__libc_lock_define_initialized (static, lock)
+
+struct response_t
+{
+  char *val;
+  struct response_t *next;
+};
+
+struct intern_t
+{
+  struct response_t *start;
+  struct response_t *next;
+};
+typedef struct intern_t intern_t;
+
+static intern_t intern = { NULL, NULL };
+
+static int
+saveit (int instatus, char *inkey, int inkeylen, char *inval,
+        int invallen, char *indata)
+{
+  intern_t *intern = (intern_t *) indata;
+
+  if (instatus != YP_TRUE)
+    return instatus;
+
+  if (inkey && inkeylen > 0 && inval && invallen > 0)
+    {
+      if (intern->start == NULL)
+        {
+          intern->start = malloc (sizeof (struct response_t));
+          intern->next = intern->start;
+        }
+      else
+        {
+          intern->next->next = malloc (sizeof (struct response_t));
+          intern->next = intern->next->next;
+        }
+      intern->next->next = NULL;
+      intern->next->val = malloc (invallen + 1);
+      strncpy (intern->next->val, inval, invallen);
+      intern->next->val[invallen] = '\0';
+    }
+
+  return 0;
+}
+
+static enum nss_status
+internal_nis_setservent (intern_t *intern)
+{
+  char *domainname;
+  struct ypall_callback ypcb;
+  enum nss_status status;
+
+  if (yp_get_default_domain (&domainname))
+    return NSS_STATUS_UNAVAIL;
+
+  while (intern->start != NULL)
+    {
+      if (intern->start->val != NULL)
+        free (intern->start->val);
+      intern->next = intern->start;
+      intern->start = intern->start->next;
+      free (intern->next);
+    }
+  intern->start = NULL;
+
+  ypcb.foreach = saveit;
+  ypcb.data = (char *) intern;
+  status = yperr2nss (yp_all (domainname, "services.byname", &ypcb));
+  intern->next = intern->start;
+
+  return status;
+}
+enum nss_status
+_nss_nis_setservent (void)
+{
+  enum nss_status status;
+
+  __libc_lock_lock (lock);
+
+  status = internal_nis_setservent (&intern);
+
+  __libc_lock_unlock (lock);
+
+  return status;
+}
+
+static enum nss_status
+internal_nis_endservent (intern_t * intern)
+{
+  while (intern->start != NULL)
+    {
+      if (intern->start->val != NULL)
+        free (intern->start->val);
+      intern->next = intern->start;
+      intern->start = intern->start->next;
+      free (intern->next);
+    }
+  intern->start = NULL;
+
+  return NSS_STATUS_SUCCESS;
+}
+
+enum nss_status
+_nss_nis_endservent (void)
+{
+  enum nss_status status;
+
+  __libc_lock_lock (lock);
+
+  status = internal_nis_endservent (&intern);
+
+  __libc_lock_unlock (lock);
+
+  return status;
+}
+
+static enum nss_status
+internal_nis_getservent_r (struct servent *serv, char *buffer,
+			   size_t buflen, intern_t *data)
+{
+  struct parser_data *pdata = (void *) buffer;
+  int parse_res;
+  char *p;
+
+  if (data->start == NULL)
+    internal_nis_setservent (data);
+
+  /* Get the next entry until we found a correct one. */
+  do
+    {
+      if (data->next == NULL)
+	return NSS_STATUS_NOTFOUND;
+      p = strncpy (buffer, data->next->val, buflen);
+      data->next = data->next->next;
+      while (isspace (*p))
+        ++p;
+
+      parse_res = _nss_files_parse_servent (p, serv, pdata, buflen);
+      if (parse_res == -1 && errno == ERANGE)
+        return NSS_STATUS_TRYAGAIN;
+    }
+  while (!parse_res);
+
+  return NSS_STATUS_SUCCESS;
+}
+
+enum nss_status
+_nss_nis_getservent_r (struct servent *serv, char *buffer, size_t buflen)
+{
+  enum nss_status status;
+
+  __libc_lock_lock (lock);
+
+  status = internal_nis_getservent_r (serv, buffer, buflen, &intern);
+
+  __libc_lock_unlock (lock);
+
+  return status;
+}
+
+enum nss_status
+_nss_nis_getservbyname_r (const char *name, char *protocol,
+			  struct servent *serv, char *buffer, size_t buflen)
+{
+  intern_t data = { NULL, NULL };
+  enum nss_status status;
+  int found;
+
+  if (name == NULL)
+    {
+      __set_errno (EINVAL);
+      return NSS_STATUS_UNAVAIL;
+    }
+
+  status = internal_nis_setservent (&data);
+  if (status != NSS_STATUS_SUCCESS)
+    return status;
+
+  found = 0;
+  while (!found &&
+         ((status = internal_nis_getservent_r (serv, buffer, buflen, &data))
+          == NSS_STATUS_SUCCESS))
+    {
+      if (protocol == NULL || strcmp (serv->s_proto, protocol) == 0)
+	{
+	  char **cp;
+
+	  if (strcmp (serv->s_name, name) == 0)
+	    found = 1;
+	  else
+	    for (cp = serv->s_aliases; *cp; cp++)
+	      if (strcmp (name, *cp) == 0)
+		found = 1;
+	}
+    }
+
+  internal_nis_endservent (&data);
+
+  if (!found && status == NSS_STATUS_SUCCESS)
+    return NSS_STATUS_NOTFOUND;
+  else
+    return status;
+}
+
+enum nss_status
+_nss_nis_getservbyport_r (int port, char *protocol, struct servent *serv,
+			  char *buffer, size_t buflen)
+{
+  intern_t data = { NULL, NULL };
+  enum nss_status status;
+  int found;
+
+  if (protocol == NULL)
+    {
+      __set_errno (EINVAL);
+      return NSS_STATUS_UNAVAIL;
+    }
+
+  status = internal_nis_setservent (&data);
+  if (status != NSS_STATUS_SUCCESS)
+    return status;
+
+  found = 0;
+  while (!found &&
+         ((status = internal_nis_getservent_r (serv, buffer, buflen, &data))
+          == NSS_STATUS_SUCCESS))
+    {
+      if (htons (serv->s_port) == port)
+        {
+          if  (strcmp (serv->s_proto, protocol) == 0)
+            {
+              found = 1;
+            }
+        }
+    }
+
+  internal_nis_endservent (&data);
+
+  if (!found && status == NSS_STATUS_SUCCESS)
+    return NSS_STATUS_NOTFOUND;
+  else
+    return status;
+}
diff --git a/glibc-compat/nss_nis/nis-spwd.c b/glibc-compat/nss_nis/nis-spwd.c
new file mode 100644
index 0000000000..d7857b2c88
--- /dev/null
+++ b/glibc-compat/nss_nis/nis-spwd.c
@@ -0,0 +1,201 @@
+/* Copyright (C) 1996, 1997 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1996.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include <nss.h>
+#include <ctype.h>
+#include <errno.h>
+#include <string.h>
+#include <glibc-compat/include/shadow.h>
+#include <bits/libc-lock.h>
+#include <rpcsvc/yp.h>
+#include <rpcsvc/ypclnt.h>
+
+#include "nss-nis.h"
+
+/* Get the declaration of the parser function.  */
+#define ENTNAME spent
+#define STRUCTURE spwd
+#define EXTERN_PARSER
+#include "../nss_files/files-parse.c"
+
+/* Protect global state against multiple changers */
+__libc_lock_define_initialized (static, lock)
+
+static bool_t new_start = 1;
+static char *oldkey = NULL;
+static int oldkeylen = 0;
+
+enum nss_status
+_nss_nis_setspent (void)
+{
+  __libc_lock_lock (lock);
+
+  new_start = 1;
+  if (oldkey != NULL)
+    {
+      free (oldkey);
+      oldkey = NULL;
+      oldkeylen = 0;
+    }
+
+  __libc_lock_unlock (lock);
+
+  return NSS_STATUS_SUCCESS;
+}
+
+enum nss_status
+_nss_nis_endspent (void)
+{
+  __libc_lock_lock (lock);
+
+  new_start = 1;
+  if (oldkey != NULL)
+    {
+      free (oldkey);
+      oldkey = NULL;
+      oldkeylen = 0;
+    }
+
+  __libc_lock_unlock (lock);
+
+  return NSS_STATUS_SUCCESS;
+}
+
+static enum nss_status
+internal_nis_getspent_r (struct spwd *sp, char *buffer, size_t buflen)
+{
+  struct parser_data *data = (void *) buffer;
+  char *domain, *result, *outkey;
+  int len, keylen, parse_res;
+
+  if (yp_get_default_domain (&domain))
+    return NSS_STATUS_UNAVAIL;
+
+  /* Get the next entry until we found a correct one. */
+  do
+    {
+      enum nss_status retval;
+      char *p;
+
+      if (new_start)
+        retval = yperr2nss (yp_first (domain, "shadow.byname",
+                                      &outkey, &keylen, &result, &len));
+      else
+        retval = yperr2nss ( yp_next (domain, "shadow.byname",
+                                      oldkey, oldkeylen,
+                                      &outkey, &keylen, &result, &len));
+
+      if (retval != NSS_STATUS_SUCCESS)
+        {
+          if (retval == NSS_STATUS_TRYAGAIN)
+            __set_errno (EAGAIN);
+          return retval;
+        }
+
+      if ((size_t) (len + 1) > buflen)
+        {
+          free (result);
+          __set_errno (ERANGE);
+          return NSS_STATUS_TRYAGAIN;
+        }
+
+      p = strncpy (buffer, result, len);
+      buffer[len] = '\0';
+      while (isspace (*p))
+        ++p;
+      free (result);
+
+      parse_res = _nss_files_parse_spent (p, sp, data, buflen);
+      if (parse_res == -1 && errno == ERANGE)
+        return NSS_STATUS_TRYAGAIN;
+
+      free (oldkey);
+      oldkey = outkey;
+      oldkeylen = keylen;
+      new_start = 0;
+    }
+  while (!parse_res);
+
+  return NSS_STATUS_SUCCESS;
+}
+
+enum nss_status
+_nss_nis_getspent_r (struct spwd *result, char *buffer, size_t buflen)
+{
+  int status;
+
+  __libc_lock_lock (lock);
+
+  status = internal_nis_getspent_r (result, buffer, buflen);
+
+  __libc_lock_unlock (lock);
+
+  return status;
+}
+
+enum nss_status
+_nss_nis_getspnam_r (const char *name, struct spwd *sp,
+		     char *buffer, size_t buflen)
+{
+  struct parser_data *data = (void *) buffer;
+  enum nss_status retval;
+  char *domain, *result, *p;
+  int len, parse_res;
+
+  if (name == NULL)
+    {
+      __set_errno (EINVAL);
+      return NSS_STATUS_UNAVAIL;
+    }
+
+  if (yp_get_default_domain (&domain))
+    return NSS_STATUS_UNAVAIL;
+
+  retval = yperr2nss (yp_match (domain, "shadow.byname", name,
+				strlen (name), &result, &len));
+
+  if (retval != NSS_STATUS_SUCCESS)
+    {
+      if (retval == NSS_STATUS_TRYAGAIN)
+        __set_errno (EAGAIN);
+      return retval;
+    }
+
+  if ((size_t) (len + 1) > buflen)
+    {
+      free (result);
+      __set_errno (ERANGE);
+      return NSS_STATUS_TRYAGAIN;
+    }
+
+  p = strncpy (buffer, result, len);
+  buffer[len] = '\0';
+  while (isspace (*p))
+    ++p;
+  free (result);
+
+  parse_res = _nss_files_parse_spent (p, sp, data, buflen);
+
+  if (parse_res == -1 && errno == ERANGE)
+    return NSS_STATUS_TRYAGAIN;
+  else if (parse_res == 0)
+    return NSS_STATUS_NOTFOUND;
+
+  return NSS_STATUS_SUCCESS;
+}
diff --git a/glibc-compat/oldfileops.c b/glibc-compat/oldfileops.c
new file mode 100644
index 0000000000..9e11d65be4
--- /dev/null
+++ b/glibc-compat/oldfileops.c
@@ -0,0 +1,774 @@
+/* Copyright (C) 1993, 1995, 1997, 1998 Free Software Foundation, Inc.
+   This file is part of the GNU IO Library.
+   Written by Per Bothner <bothner@cygnus.com>.
+
+   This library 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 library 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 library; see the file COPYING.  If not, write to
+   the Free Software Foundation, 59 Temple Place - Suite 330, Boston,
+   MA 02111-1307, USA.
+
+   As a special exception, if you link this library with files
+   compiled with a GNU compiler to produce an executable, this does
+   not cause the resulting executable to be covered by the GNU General
+   Public License.  This exception does not however invalidate any
+   other reasons why the executable file might be covered by the GNU
+   General Public License.  */
+
+/* This is a compatibility file.  If we don't build the libc with
+   versioning don't compile this file.  */
+
+#ifndef _POSIX_SOURCE
+# define _POSIX_SOURCE
+#endif
+#define _IO_USE_OLD_IO_FILE
+#include "libioP.h"
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <string.h>
+#include <errno.h>
+#ifndef errno
+extern int errno;
+#endif
+#ifndef __set_errno
+# define __set_errno(Val) errno = (Val)
+#endif
+
+
+#ifdef _LIBC
+# define open(Name, Flags, Prot) __open (Name, Flags, Prot)
+# define close(FD) __close (FD)
+# define lseek(FD, Offset, Whence) __lseek (FD, Offset, Whence)
+# define read(FD, Buf, NBytes) __read (FD, Buf, NBytes)
+# define write(FD, Buf, NBytes) __write (FD, Buf, NBytes)
+#endif
+
+/* An fstream can be in at most one of put mode, get mode, or putback mode.
+   Putback mode is a variant of get mode.
+
+   In a filebuf, there is only one current position, instead of two
+   separate get and put pointers.  In get mode, the current position
+   is that of gptr(); in put mode that of pptr().
+
+   The position in the buffer that corresponds to the position
+   in external file system is normally _IO_read_end, except in putback
+   mode, when it is _IO_save_end.
+   If the field _fb._offset is >= 0, it gives the offset in
+   the file as a whole corresponding to eGptr(). (?)
+
+   PUT MODE:
+   If a filebuf is in put mode, then all of _IO_read_ptr, _IO_read_end,
+   and _IO_read_base are equal to each other.  These are usually equal
+   to _IO_buf_base, though not necessarily if we have switched from
+   get mode to put mode.  (The reason is to maintain the invariant
+   that _IO_read_end corresponds to the external file position.)
+   _IO_write_base is non-NULL and usually equal to _IO_base_base.
+   We also have _IO_write_end == _IO_buf_end, but only in fully buffered mode.
+   The un-flushed character are those between _IO_write_base and _IO_write_ptr.
+
+   GET MODE:
+   If a filebuf is in get or putback mode, eback() != egptr().
+   In get mode, the unread characters are between gptr() and egptr().
+   The OS file position corresponds to that of egptr().
+
+   PUTBACK MODE:
+   Putback mode is used to remember "excess" characters that have
+   been sputbackc'd in a separate putback buffer.
+   In putback mode, the get buffer points to the special putback buffer.
+   The unread characters are the characters between gptr() and egptr()
+   in the putback buffer, as well as the area between save_gptr()
+   and save_egptr(), which point into the original reserve buffer.
+   (The pointers save_gptr() and save_egptr() are the values
+   of gptr() and egptr() at the time putback mode was entered.)
+   The OS position corresponds to that of save_egptr().
+
+   LINE BUFFERED OUTPUT:
+   During line buffered output, _IO_write_base==base() && epptr()==base().
+   However, ptr() may be anywhere between base() and ebuf().
+   This forces a call to filebuf::overflow(int C) on every put.
+   If there is more space in the buffer, and C is not a '\n',
+   then C is inserted, and pptr() incremented.
+
+   UNBUFFERED STREAMS:
+   If a filebuf is unbuffered(), the _shortbuf[1] is used as the buffer.
+*/
+
+#define CLOSED_FILEBUF_FLAGS \
+  (_IO_IS_FILEBUF+_IO_NO_READS+_IO_NO_WRITES+_IO_TIED_PUT_GET)
+
+
+void
+_IO_old_file_init (fp)
+     _IO_FILE *fp;
+{
+  /* POSIX.1 allows another file handle to be used to change the position
+     of our file descriptor.  Hence we actually don't know the actual
+     position before we do the first fseek (and until a following fflush). */
+  fp->_old_offset = _IO_pos_BAD;
+  fp->_IO_file_flags |= CLOSED_FILEBUF_FLAGS;
+
+  _IO_link_in(fp);
+  fp->_vtable_offset = ((int) sizeof (struct _IO_FILE)
+			- (int) sizeof (struct _IO_FILE_complete));
+  fp->_fileno = -1;
+}
+
+int
+_IO_old_file_close_it (fp)
+     _IO_FILE *fp;
+{
+  int write_status, close_status;
+  if (!_IO_file_is_open (fp))
+    return EOF;
+
+  write_status = _IO_old_do_flush (fp);
+
+  _IO_unsave_markers(fp);
+
+  close_status = _IO_SYSCLOSE (fp);
+
+  /* Free buffer. */
+  _IO_setb (fp, NULL, NULL, 0);
+  _IO_setg (fp, NULL, NULL, NULL);
+  _IO_setp (fp, NULL, NULL);
+
+  _IO_un_link (fp);
+  fp->_flags = _IO_MAGIC|CLOSED_FILEBUF_FLAGS;
+  fp->_fileno = EOF;
+  fp->_old_offset = _IO_pos_BAD;
+
+  return close_status ? close_status : write_status;
+}
+
+void
+_IO_old_file_finish (fp, dummy)
+     _IO_FILE *fp;
+     int dummy;
+{
+  if (_IO_file_is_open (fp))
+    {
+      _IO_old_do_flush (fp);
+      if (!(fp->_flags & _IO_DELETE_DONT_CLOSE))
+	_IO_SYSCLOSE (fp);
+    }
+  _IO_default_finish (fp, 0);
+}
+
+_IO_FILE *
+_IO_old_file_fopen (fp, filename, mode)
+     _IO_FILE *fp;
+     const char *filename;
+     const char *mode;
+{
+  int oflags = 0, omode;
+  int read_write, fdesc;
+  int oprot = 0666;
+  if (_IO_file_is_open (fp))
+    return 0;
+  switch (*mode++)
+    {
+    case 'r':
+      omode = O_RDONLY;
+      read_write = _IO_NO_WRITES;
+      break;
+    case 'w':
+      omode = O_WRONLY;
+      oflags = O_CREAT|O_TRUNC;
+      read_write = _IO_NO_READS;
+      break;
+    case 'a':
+      omode = O_WRONLY;
+      oflags = O_CREAT|O_APPEND;
+      read_write = _IO_NO_READS|_IO_IS_APPENDING;
+      break;
+    default:
+      __set_errno (EINVAL);
+      return NULL;
+    }
+  if (mode[0] == '+' || (mode[0] == 'b' && mode[1] == '+'))
+    {
+      omode = O_RDWR;
+      read_write &= _IO_IS_APPENDING;
+    }
+  fdesc = open (filename, omode|oflags, oprot);
+  if (fdesc < 0)
+    return NULL;
+  fp->_fileno = fdesc;
+  _IO_mask_flags (fp, read_write,_IO_NO_READS+_IO_NO_WRITES+_IO_IS_APPENDING);
+  if (read_write & _IO_IS_APPENDING)
+    if (_IO_SEEKOFF (fp, (_IO_off_t)0, _IO_seek_end, _IOS_INPUT|_IOS_OUTPUT)
+	== _IO_pos_BAD && errno != ESPIPE)
+      return NULL;
+  _IO_link_in (fp);
+  return fp;
+}
+
+_IO_FILE *
+_IO_old_file_attach (fp, fd)
+     _IO_FILE *fp;
+     int fd;
+{
+  if (_IO_file_is_open (fp))
+    return NULL;
+  fp->_fileno = fd;
+  fp->_flags &= ~(_IO_NO_READS+_IO_NO_WRITES);
+  fp->_flags |= _IO_DELETE_DONT_CLOSE;
+  /* Get the current position of the file. */
+  /* We have to do that since that may be junk. */
+  fp->_old_offset = _IO_pos_BAD;
+  if (_IO_SEEKOFF (fp, (_IO_off_t)0, _IO_seek_cur, _IOS_INPUT|_IOS_OUTPUT)
+      == _IO_pos_BAD && errno != ESPIPE)
+    return NULL;
+  return fp;
+}
+
+_IO_FILE *
+_IO_old_file_setbuf (fp, p, len)
+     _IO_FILE *fp;
+     char *p;
+     _IO_ssize_t len;
+{
+    if (_IO_default_setbuf (fp, p, len) == NULL)
+      return NULL;
+
+    fp->_IO_write_base = fp->_IO_write_ptr = fp->_IO_write_end
+      = fp->_IO_buf_base;
+    _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base, fp->_IO_buf_base);
+
+    return fp;
+}
+
+static int old_do_write (_IO_FILE *, const char *, _IO_size_t) __THROW;
+
+/* Write TO_DO bytes from DATA to FP.
+   Then mark FP as having empty buffers. */
+
+int
+_IO_old_do_write (fp, data, to_do)
+     _IO_FILE *fp;
+     const char *data;
+     _IO_size_t to_do;
+{
+  return (to_do == 0 || old_do_write (fp, data, to_do) == to_do)
+	 ? 0 : EOF;
+}
+
+static
+int
+old_do_write (fp, data, to_do)
+     _IO_FILE *fp;
+     const char *data;
+     _IO_size_t to_do;
+{
+  _IO_size_t count;
+  if (fp->_flags & _IO_IS_APPENDING)
+    /* On a system without a proper O_APPEND implementation,
+       you would need to sys_seek(0, SEEK_END) here, but is
+       is not needed nor desirable for Unix- or Posix-like systems.
+       Instead, just indicate that offset (before and after) is
+       unpredictable. */
+    fp->_old_offset = _IO_pos_BAD;
+  else if (fp->_IO_read_end != fp->_IO_write_base)
+    {
+      _IO_pos_t new_pos
+	= _IO_SYSSEEK (fp, fp->_IO_write_base - fp->_IO_read_end, 1);
+      if (new_pos == _IO_pos_BAD)
+	return 0;
+      fp->_old_offset = new_pos;
+    }
+  count = _IO_SYSWRITE (fp, data, to_do);
+  if (fp->_cur_column && count)
+    fp->_cur_column = _IO_adjust_column (fp->_cur_column - 1, data, count) + 1;
+  _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base, fp->_IO_buf_base);
+  fp->_IO_write_base = fp->_IO_write_ptr = fp->_IO_buf_base;
+  fp->_IO_write_end = ((fp->_flags & (_IO_LINE_BUF+_IO_UNBUFFERED))
+		       ? fp->_IO_buf_base : fp->_IO_buf_end);
+  return count;
+}
+
+int
+_IO_old_file_underflow (fp)
+     _IO_FILE *fp;
+{
+  _IO_ssize_t count;
+#if 0
+  /* SysV does not make this test; take it out for compatibility */
+  if (fp->_flags & _IO_EOF_SEEN)
+    return (EOF);
+#endif
+
+  if (fp->_flags & _IO_NO_READS)
+    {
+      __set_errno (EBADF);
+      return EOF;
+    }
+  if (fp->_IO_read_ptr < fp->_IO_read_end)
+    return *(unsigned char *) fp->_IO_read_ptr;
+
+  if (fp->_IO_buf_base == NULL)
+    _IO_doallocbuf (fp);
+
+  /* Flush all line buffered files before reading. */
+  /* FIXME This can/should be moved to genops ?? */
+  if (fp->_flags & (_IO_LINE_BUF|_IO_UNBUFFERED))
+    _IO_flush_all_linebuffered ();
+
+  _IO_switch_to_get_mode (fp);
+
+  /* This is very tricky. We have to adjust those
+     pointers before we call _IO_SYSREAD () since
+     we may longjump () out while waiting for
+     input. Those pointers may be screwed up. H.J. */
+  fp->_IO_read_base = fp->_IO_read_ptr = fp->_IO_buf_base;
+  fp->_IO_read_end = fp->_IO_buf_base;
+  fp->_IO_write_base = fp->_IO_write_ptr = fp->_IO_write_end
+    = fp->_IO_buf_base;
+
+  count = _IO_SYSREAD (fp, fp->_IO_buf_base,
+		       fp->_IO_buf_end - fp->_IO_buf_base);
+  if (count <= 0)
+    {
+      if (count == 0)
+	fp->_flags |= _IO_EOF_SEEN;
+      else
+	fp->_flags |= _IO_ERR_SEEN, count = 0;
+  }
+  fp->_IO_read_end += count;
+  if (count == 0)
+    return EOF;
+  if (fp->_old_offset != _IO_pos_BAD)
+    _IO_pos_adjust (fp->_old_offset, count);
+  return *(unsigned char *) fp->_IO_read_ptr;
+}
+
+int
+_IO_old_file_overflow (f, ch)
+      _IO_FILE *f;
+      int ch;
+{
+  if (f->_flags & _IO_NO_WRITES) /* SET ERROR */
+    {
+      f->_flags |= _IO_ERR_SEEN;
+      __set_errno (EBADF);
+      return EOF;
+    }
+  /* If currently reading or no buffer allocated. */
+  if ((f->_flags & _IO_CURRENTLY_PUTTING) == 0)
+    {
+      /* Allocate a buffer if needed. */
+      if (f->_IO_write_base == 0)
+	{
+	  _IO_doallocbuf (f);
+	  _IO_setg (f, f->_IO_buf_base, f->_IO_buf_base, f->_IO_buf_base);
+	}
+      /* Otherwise must be currently reading.
+	 If _IO_read_ptr (and hence also _IO_read_end) is at the buffer end,
+	 logically slide the buffer forwards one block (by setting the
+	 read pointers to all point at the beginning of the block).  This
+	 makes room for subsequent output.
+	 Otherwise, set the read pointers to _IO_read_end (leaving that
+	 alone, so it can continue to correspond to the external position). */
+      if (f->_IO_read_ptr == f->_IO_buf_end)
+	f->_IO_read_end = f->_IO_read_ptr = f->_IO_buf_base;
+      f->_IO_write_ptr = f->_IO_read_ptr;
+      f->_IO_write_base = f->_IO_write_ptr;
+      f->_IO_write_end = f->_IO_buf_end;
+      f->_IO_read_base = f->_IO_read_ptr = f->_IO_read_end;
+
+      if (f->_flags & (_IO_LINE_BUF+_IO_UNBUFFERED))
+	f->_IO_write_end = f->_IO_write_ptr;
+      f->_flags |= _IO_CURRENTLY_PUTTING;
+    }
+  if (ch == EOF)
+    return _IO_old_do_flush (f);
+  if (f->_IO_write_ptr == f->_IO_buf_end ) /* Buffer is really full */
+    if (_IO_old_do_flush (f) == EOF)
+      return EOF;
+  *f->_IO_write_ptr++ = ch;
+  if ((f->_flags & _IO_UNBUFFERED)
+      || ((f->_flags & _IO_LINE_BUF) && ch == '\n'))
+    if (_IO_old_do_flush (f) == EOF)
+      return EOF;
+  return (unsigned char) ch;
+}
+
+int
+_IO_old_file_sync (fp)
+     _IO_FILE *fp;
+{
+  _IO_size_t delta;
+  int retval = 0;
+
+  _IO_cleanup_region_start ((void (*) (void *)) _IO_funlockfile, fp);
+  _IO_flockfile (fp);
+  /*    char* ptr = cur_ptr(); */
+  if (fp->_IO_write_ptr > fp->_IO_write_base)
+    if (_IO_old_do_flush(fp)) return EOF;
+  delta = fp->_IO_read_ptr - fp->_IO_read_end;
+  if (delta != 0)
+    {
+#ifdef TODO
+      if (_IO_in_backup (fp))
+	delta -= eGptr () - Gbase ();
+#endif
+      _IO_off_t new_pos = _IO_SYSSEEK (fp, delta, 1);
+      if (new_pos != (_IO_off_t) EOF)
+	fp->_IO_read_end = fp->_IO_read_ptr;
+#ifdef ESPIPE
+      else if (errno == ESPIPE)
+	; /* Ignore error from unseekable devices. */
+#endif
+      else
+	retval = EOF;
+    }
+  if (retval != EOF)
+    fp->_old_offset = _IO_pos_BAD;
+  /* FIXME: Cleanup - can this be shared? */
+  /*    setg(base(), ptr, ptr); */
+  _IO_funlockfile (fp);
+  _IO_cleanup_region_end (0);
+  return retval;
+}
+
+_IO_fpos64_t
+_IO_old_file_seekoff (fp, offset, dir, mode)
+     _IO_FILE *fp;
+     _IO_off64_t offset;
+     int dir;
+     int mode;
+{
+  _IO_pos_t result;
+  _IO_off64_t delta, new_offset;
+  long count;
+  /* POSIX.1 8.2.3.7 says that after a call the fflush() the file
+     offset of the underlying file must be exact.  */
+  int must_be_exact = (fp->_IO_read_base == fp->_IO_read_end
+		       && fp->_IO_write_base == fp->_IO_write_ptr);
+
+  if (mode == 0)
+    dir = _IO_seek_cur, offset = 0; /* Don't move any pointers. */
+
+  /* Flush unwritten characters.
+     (This may do an unneeded write if we seek within the buffer.
+     But to be able to switch to reading, we would need to set
+     egptr to ptr.  That can't be done in the current design,
+     which assumes file_ptr() is eGptr.  Anyway, since we probably
+     end up flushing when we close(), it doesn't make much difference.)
+     FIXME: simulate mem-papped files. */
+
+  if (fp->_IO_write_ptr > fp->_IO_write_base || _IO_in_put_mode (fp))
+    if (_IO_switch_to_get_mode (fp))
+      return EOF;
+
+  if (fp->_IO_buf_base == NULL)
+    {
+      _IO_doallocbuf (fp);
+      _IO_setp (fp, fp->_IO_buf_base, fp->_IO_buf_base);
+      _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base, fp->_IO_buf_base);
+    }
+
+  switch (dir)
+    {
+    case _IO_seek_cur:
+      /* Adjust for read-ahead (bytes is buffer). */
+      offset -= fp->_IO_read_end - fp->_IO_read_ptr;
+      if (fp->_old_offset == _IO_pos_BAD)
+	goto dumb;
+      /* Make offset absolute, assuming current pointer is file_ptr(). */
+      offset += _IO_pos_as_off (fp->_old_offset);
+
+      dir = _IO_seek_set;
+      break;
+    case _IO_seek_set:
+      break;
+    case _IO_seek_end:
+      {
+	struct _G_stat64 st;
+	if (_IO_SYSSTAT (fp, &st) == 0 && S_ISREG (st.st_mode))
+	  {
+	    offset += st.st_size;
+	    dir = _IO_seek_set;
+	  }
+	else
+	  goto dumb;
+      }
+    }
+  /* At this point, dir==_IO_seek_set. */
+
+  /* If destination is within current buffer, optimize: */
+  if (fp->_old_offset != _IO_pos_BAD && fp->_IO_read_base != NULL
+      && !_IO_in_backup (fp))
+    {
+      /* Offset relative to start of main get area. */
+      _IO_pos_t rel_offset = (offset - fp->_old_offset
+			      + (fp->_IO_read_end - fp->_IO_read_base));
+      if (rel_offset >= 0)
+	{
+#if 0
+	  if (_IO_in_backup (fp))
+	    _IO_switch_to_main_get_area (fp);
+#endif
+	  if (rel_offset <= fp->_IO_read_end - fp->_IO_read_base)
+	    {
+	      _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base + rel_offset,
+			fp->_IO_read_end);
+	      _IO_setp (fp, fp->_IO_buf_base, fp->_IO_buf_base);
+	      goto resync;
+	    }
+#ifdef TODO
+	    /* If we have streammarkers, seek forward by reading ahead. */
+	    if (_IO_have_markers (fp))
+	      {
+		int to_skip = rel_offset
+		  - (fp->_IO_read_ptr - fp->_IO_read_base);
+		if (ignore (to_skip) != to_skip)
+		  goto dumb;
+		goto resync;
+	      }
+#endif
+	}
+#ifdef TODO
+      if (rel_offset < 0 && rel_offset >= Bbase () - Bptr ())
+	{
+	  if (!_IO_in_backup (fp))
+	    _IO_switch_to_backup_area (fp);
+	  gbump (fp->_IO_read_end + rel_offset - fp->_IO_read_ptr);
+	  goto resync;
+	}
+#endif
+    }
+
+#ifdef TODO
+  _IO_unsave_markers (fp);
+#endif
+
+  if (fp->_flags & _IO_NO_READS)
+    goto dumb;
+
+  /* Try to seek to a block boundary, to improve kernel page management. */
+  new_offset = offset & ~(fp->_IO_buf_end - fp->_IO_buf_base - 1);
+  delta = offset - new_offset;
+  if (delta > fp->_IO_buf_end - fp->_IO_buf_base)
+    {
+      new_offset = offset;
+      delta = 0;
+    }
+  result = _IO_SYSSEEK (fp, new_offset, 0);
+  if (result < 0)
+    return EOF;
+  if (delta == 0)
+    count = 0;
+  else
+    {
+      count = _IO_SYSREAD (fp, fp->_IO_buf_base,
+			   (must_be_exact
+			    ? delta : fp->_IO_buf_end - fp->_IO_buf_base));
+      if (count < delta)
+	{
+	  /* We weren't allowed to read, but try to seek the remainder. */
+	  offset = count == EOF ? delta : delta-count;
+	  dir = _IO_seek_cur;
+	  goto dumb;
+	}
+    }
+  _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base + delta,
+	    fp->_IO_buf_base + count);
+  _IO_setp (fp, fp->_IO_buf_base, fp->_IO_buf_base);
+  fp->_old_offset = result + count;
+  _IO_mask_flags (fp, 0, _IO_EOF_SEEN);
+  return offset;
+ dumb:
+
+  _IO_unsave_markers (fp);
+  result = _IO_SYSSEEK (fp, offset, dir);
+  if (result != EOF)
+    {
+      _IO_mask_flags (fp, 0, _IO_EOF_SEEN);
+      fp->_old_offset = result;
+      _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base, fp->_IO_buf_base);
+      _IO_setp (fp, fp->_IO_buf_base, fp->_IO_buf_base);
+    }
+  return result;
+
+resync:
+  /* We need to do it since it is possible that the file offset in
+     the kernel may be changed behind our back. It may happen when
+     we fopen a file and then do a fork. One process may access the
+     the file and the kernel file offset will be changed. */
+  if (fp->_old_offset >= 0)
+    _IO_SYSSEEK (fp, fp->_old_offset, 0);
+
+  return offset;
+}
+
+_IO_ssize_t
+_IO_old_file_write (f, data, n)
+     _IO_FILE *f;
+     const void *data;
+     _IO_ssize_t n;
+{
+  _IO_ssize_t to_do = n;
+  while (to_do > 0)
+    {
+      _IO_ssize_t count = write (f->_fileno, data, to_do);
+      if (count == EOF)
+	{
+	  f->_flags |= _IO_ERR_SEEN;
+	  break;
+        }
+      to_do -= count;
+      data = (void *) ((char *) data + count);
+    }
+  n -= to_do;
+  if (f->_old_offset >= 0)
+    f->_old_offset += n;
+  return n;
+}
+
+_IO_size_t
+_IO_old_file_xsputn (f, data, n)
+     _IO_FILE *f;
+     const void *data;
+     _IO_size_t n;
+{
+  register const char *s = (char *) data;
+  _IO_size_t to_do = n;
+  int must_flush = 0;
+  _IO_size_t count;
+
+  if (n <= 0)
+    return 0;
+  /* This is an optimized implementation.
+     If the amount to be written straddles a block boundary
+     (or the filebuf is unbuffered), use sys_write directly. */
+
+  /* First figure out how much space is available in the buffer. */
+  count = f->_IO_write_end - f->_IO_write_ptr; /* Space available. */
+  if ((f->_flags & _IO_LINE_BUF) && (f->_flags & _IO_CURRENTLY_PUTTING))
+    {
+      count = f->_IO_buf_end - f->_IO_write_ptr;
+      if (count >= n)
+	{
+	  register const char *p;
+	  for (p = s + n; p > s; )
+	    {
+	      if (*--p == '\n')
+		{
+		  count = p - s + 1;
+		  must_flush = 1;
+		  break;
+		}
+	    }
+	}
+    }
+  /* Then fill the buffer. */
+  if (count > 0)
+    {
+      if (count > to_do)
+	count = to_do;
+      if (count > 20)
+	{
+	  memcpy (f->_IO_write_ptr, s, count);
+	  s += count;
+	}
+      else
+	{
+	  register char *p = f->_IO_write_ptr;
+	  register int i = (int) count;
+	  while (--i >= 0)
+	    *p++ = *s++;
+	}
+      f->_IO_write_ptr += count;
+      to_do -= count;
+    }
+  if (to_do + must_flush > 0)
+    {
+      _IO_size_t block_size, do_write;
+      /* Next flush the (full) buffer. */
+      if (__overflow (f, EOF) == EOF)
+	return n - to_do;
+
+      /* Try to maintain alignment: write a whole number of blocks.
+	 dont_write is what gets left over. */
+      block_size = f->_IO_buf_end - f->_IO_buf_base;
+      do_write = to_do - (block_size >= 128 ? to_do % block_size : 0);
+
+      if (do_write)
+        {
+	  count = old_do_write (f, s, do_write);
+	  to_do -= count;
+	  if (count < do_write)
+	    return n - to_do;
+        }
+
+      /* Now write out the remainder.  Normally, this will fit in the
+	 buffer, but it's somewhat messier for line-buffered files,
+	 so we let _IO_default_xsputn handle the general case. */
+      if (to_do)
+	to_do -= _IO_default_xsputn (f, s+do_write, to_do);
+    }
+  return n - to_do;
+}
+
+
+struct _IO_jump_t _IO_old_file_jumps =
+{
+  JUMP_INIT_DUMMY,
+  JUMP_INIT(finish, _IO_old_file_finish),
+  JUMP_INIT(overflow, _IO_old_file_overflow),
+  JUMP_INIT(underflow, _IO_old_file_underflow),
+  JUMP_INIT(uflow, _IO_default_uflow),
+  JUMP_INIT(pbackfail, _IO_default_pbackfail),
+  JUMP_INIT(xsputn, _IO_old_file_xsputn),
+  JUMP_INIT(xsgetn, _IO_default_xsgetn),
+  JUMP_INIT(seekoff, _IO_old_file_seekoff),
+  JUMP_INIT(seekpos, _IO_default_seekpos),
+  JUMP_INIT(setbuf, _IO_old_file_setbuf),
+  JUMP_INIT(sync, _IO_old_file_sync),
+  JUMP_INIT(doallocate, _IO_file_doallocate),
+  JUMP_INIT(read, _IO_file_read),
+  JUMP_INIT(write, _IO_old_file_write),
+  JUMP_INIT(seek, _IO_file_seek),
+  JUMP_INIT(close, _IO_file_close),
+  JUMP_INIT(stat, _IO_file_stat)
+};
+
+#ifdef SHARED
+symbol_version (_IO_old_do_write, _IO_do_write, GLIBC_2.0);
+symbol_version (_IO_old_file_attach, _IO_file_attach, GLIBC_2.0);
+symbol_version (_IO_old_file_close_it, _IO_file_close_it, GLIBC_2.0);
+symbol_version (_IO_old_file_finish, _IO_file_finish, GLIBC_2.0);
+symbol_version (_IO_old_file_fopen, _IO_file_fopen, GLIBC_2.0);
+symbol_version (_IO_old_file_init, _IO_file_init, GLIBC_2.0);
+symbol_version (_IO_old_file_setbuf, _IO_file_setbuf, GLIBC_2.0);
+symbol_version (_IO_old_file_sync, _IO_file_sync, GLIBC_2.0);
+symbol_version (_IO_old_file_overflow, _IO_file_overflow, GLIBC_2.0);
+symbol_version (_IO_old_file_seekoff, _IO_file_seekoff, GLIBC_2.0);
+symbol_version (_IO_old_file_underflow, _IO_file_underflow, GLIBC_2.0);
+symbol_version (_IO_old_file_write, _IO_file_write, GLIBC_2.0);
+symbol_version (_IO_old_file_xsputn, _IO_file_xsputn, GLIBC_2.0);
+#else
+strong_alias (_IO_old_do_write, _IO_do_write);
+strong_alias (_IO_old_file_attach, _IO_file_attach);
+strong_alias (_IO_old_file_close_it, _IO_file_close_it);
+strong_alias (_IO_old_file_finish, _IO_file_finish);
+strong_alias (_IO_old_file_fopen, _IO_file_fopen);
+strong_alias (_IO_old_file_init, _IO_file_init);
+strong_alias (_IO_old_file_setbuf, _IO_file_setbuf);
+strong_alias (_IO_old_file_sync, _IO_file_sync);
+strong_alias (_IO_old_file_overflow, _IO_file_overflow);
+strong_alias (_IO_old_file_seekoff, _IO_file_seekoff);
+strong_alias (_IO_old_file_underflow, _IO_file_underflow);
+strong_alias (_IO_old_file_write, _IO_file_write);
+strong_alias (_IO_old_file_xsputn, _IO_file_xsputn);
+#endif
diff --git a/glibc-compat/oldiofclose.c b/glibc-compat/oldiofclose.c
new file mode 100644
index 0000000000..eadad8adbe
--- /dev/null
+++ b/glibc-compat/oldiofclose.c
@@ -0,0 +1,60 @@
+/* Copyright (C) 1993, 1995, 1997, 1998 Free Software Foundation, Inc.
+   This file is part of the GNU IO Library.
+
+   This library 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 library 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 library; see the file COPYING.  If not, write to
+   the Free Software Foundation, 59 Temple Place - Suite 330, Boston,
+   MA 02111-1307, USA.
+
+   As a special exception, if you link this library with files
+   compiled with a GNU compiler to produce an executable, this does
+   not cause the resulting executable to be covered by the GNU General
+   Public License.  This exception does not however invalidate any
+   other reasons why the executable file might be covered by the GNU
+   General Public License.  */
+
+#define _IO_USE_OLD_IO_FILE
+#include "libioP.h"
+#ifdef __STDC__
+#include <stdlib.h>
+#endif
+
+int
+_IO_old_fclose (fp)
+     _IO_FILE *fp;
+{
+  int status;
+
+  CHECK_FILE(fp, EOF);
+
+  _IO_cleanup_region_start ((void (*) (void *)) _IO_funlockfile, fp);
+  _IO_flockfile (fp);
+  if (fp->_IO_file_flags & _IO_IS_FILEBUF)
+    status = _IO_old_file_close_it (fp);
+  else
+    status = fp->_flags & _IO_ERR_SEEN ? -1 : 0;
+  _IO_FINISH (fp);
+  _IO_funlockfile (fp);
+  _IO_cleanup_region_end (0);
+  if (fp != _IO_stdin && fp != _IO_stdout && fp != _IO_stderr)
+    {
+      fp->_IO_file_flags = 0;
+      free(fp);
+    }
+
+  return status;
+}
+
+strong_alias (_IO_old_fclose, __old_fclose)
+symbol_version (_IO_old_fclose, _IO_fclose, GLIBC_2.0);
+symbol_version (__old_fclose, fclose, GLIBC_2.0);
diff --git a/glibc-compat/oldiofdopen.c b/glibc-compat/oldiofdopen.c
new file mode 100644
index 0000000000..410206412a
--- /dev/null
+++ b/glibc-compat/oldiofdopen.c
@@ -0,0 +1,140 @@
+/* Copyright (C) 1993, 1994, 1997 Free Software Foundation, Inc.
+   This file is part of the GNU IO Library.
+
+   This library 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 library 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 library; see the file COPYING.  If not, write to
+   the Free Software Foundation, 59 Temple Place - Suite 330, Boston,
+   MA 02111-1307, USA.
+
+   As a special exception, if you link this library with files
+   compiled with a GNU compiler to produce an executable, this does
+   not cause the resulting executable to be covered by the GNU General
+   Public License.  This exception does not however invalidate any
+   other reasons why the executable file might be covered by the GNU
+   General Public License.  */
+
+#define _IO_USE_OLD_IO_FILE
+#ifdef __STDC__
+# include <stdlib.h>
+#endif
+#include "libioP.h"
+#include <fcntl.h>
+
+#ifndef _IO_fcntl
+# define _IO_fcntl __fcntl
+#endif
+
+_IO_FILE *
+_IO_old_fdopen (fd, mode)
+     int fd;
+     const char *mode;
+{
+  int read_write;
+  int posix_mode = 0;
+  struct locked_FILE
+  {
+    struct _IO_FILE_plus fp;
+#ifdef _IO_MTSAFE_IO
+    _IO_lock_t lock;
+#endif
+  } *new_f;
+  int fd_flags;
+
+  switch (*mode++)
+    {
+    case 'r':
+      read_write = _IO_NO_WRITES;
+      break;
+    case 'w':
+      read_write = _IO_NO_READS;
+      break;
+    case 'a':
+      posix_mode = O_APPEND;
+      read_write = _IO_NO_READS|_IO_IS_APPENDING;
+      break;
+    default:
+      MAYBE_SET_EINVAL;
+      return NULL;
+  }
+  if (mode[0] == '+' || (mode[0] == 'b' && mode[1] == '+'))
+    read_write &= _IO_IS_APPENDING;
+#ifdef F_GETFL
+  fd_flags = _IO_fcntl (fd, F_GETFL);
+#ifndef O_ACCMODE
+#define O_ACCMODE (O_RDONLY|O_WRONLY|O_RDWR)
+#endif
+  if (fd_flags == -1
+      || ((fd_flags & O_ACCMODE) == O_RDONLY && !(read_write & _IO_NO_WRITES))
+      || ((fd_flags & O_ACCMODE) == O_WRONLY && !(read_write & _IO_NO_READS)))
+    return NULL;
+
+  /* The May 93 draft of P1003.4/D14.1 (redesignated as 1003.1b)
+     [System Application Program Interface (API) Amendment 1:
+     Realtime Extensions], Rationale B.8.3.3
+     Open a Stream on a File Descriptor says:
+
+         Although not explicitly required by POSIX.1, a good
+         implementation of append ("a") mode would cause the
+         O_APPEND flag to be set.
+
+     (Historical implementations [such as Solaris2] do a one-time
+     seek in fdopen.)
+
+     However, we do not turn O_APPEND off if the mode is "w" (even
+     though that would seem consistent) because that would be more
+     likely to break historical programs.
+     */
+  if ((posix_mode & O_APPEND) && !(fd_flags & O_APPEND))
+    {
+#ifdef F_SETFL
+      if (_IO_fcntl (fd, F_SETFL, fd_flags | O_APPEND) == -1)
+#endif
+	return NULL;
+    }
+#endif
+
+  new_f = (struct locked_FILE *) malloc (sizeof (struct locked_FILE));
+  if (new_f == NULL)
+    return NULL;
+#ifdef _IO_MTSAFE_IO
+  new_f->fp.file._lock = &new_f->lock;
+#endif
+  _IO_init (&new_f->fp.file, 0);
+  _IO_JUMPS (&new_f->fp) = &_IO_old_file_jumps;
+  _IO_old_file_init (&new_f->fp.file);
+#if  !_IO_UNIFIED_JUMPTABLES
+  new_f->fp.vtable = NULL;
+#endif
+  if (_IO_old_file_attach (&new_f->fp.file, fd) == NULL)
+    {
+      _IO_un_link (&new_f->fp.file);
+      free (new_f);
+      return NULL;
+    }
+  new_f->fp.file._flags &= ~_IO_DELETE_DONT_CLOSE;
+
+  new_f->fp.file._IO_file_flags =
+    _IO_mask_flags (&new_f->fp.file, read_write,
+		    _IO_NO_READS+_IO_NO_WRITES+_IO_IS_APPENDING);
+
+  return (_IO_FILE *) &new_f->fp;
+}
+
+#ifdef SHARED
+strong_alias (_IO_old_fdopen, __old_fdopen)
+symbol_version (_IO_old_fdopen, _IO_fdopen, GLIBC_2.0);
+symbol_version (__old_fdopen, fdopen, GLIBC_2.0);
+#else
+strong_alias (_IO_old_fdopen, _IO_fdopen);
+strong_alias (__old_fdopen, fdopen);
+#endif
diff --git a/glibc-compat/oldiofopen.c b/glibc-compat/oldiofopen.c
new file mode 100644
index 0000000000..e2d9a826ce
--- /dev/null
+++ b/glibc-compat/oldiofopen.c
@@ -0,0 +1,71 @@
+/* Copyright (C) 1993, 1997 Free Software Foundation, Inc.
+   This file is part of the GNU IO Library.
+
+   This library 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 library 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 library; see the file COPYING.  If not, write to
+   the Free Software Foundation, 59 Temple Place - Suite 330, Boston,
+   MA 02111-1307, USA.
+
+   As a special exception, if you link this library with files
+   compiled with a GNU compiler to produce an executable, this does
+   not cause the resulting executable to be covered by the GNU General
+   Public License.  This exception does not however invalidate any
+   other reasons why the executable file might be covered by the GNU
+   General Public License.  */
+
+#define _IO_USE_OLD_IO_FILE
+#include "libioP.h"
+#ifdef __STDC__
+#include <stdlib.h>
+#endif
+
+
+_IO_FILE *
+_IO_old_fopen (filename, mode)
+     const char *filename;
+     const char *mode;
+{
+  struct locked_FILE
+  {
+    struct _IO_FILE_plus fp;
+#ifdef _IO_MTSAFE_IO
+    _IO_lock_t lock;
+#endif
+  } *new_f = (struct locked_FILE *) malloc (sizeof (struct locked_FILE));
+
+  if (new_f == NULL)
+    return NULL;
+#ifdef _IO_MTSAFE_IO
+  new_f->fp.file._lock = &new_f->lock;
+#endif
+  _IO_init (&new_f->fp.file, 0);
+  _IO_JUMPS (&new_f->fp.file) = &_IO_old_file_jumps;
+  _IO_old_file_init (&new_f->fp.file);
+#if  !_IO_UNIFIED_JUMPTABLES
+  new_f->fp.vtable = NULL;
+#endif
+  if (_IO_old_file_fopen (&new_f->fp.file, filename, mode) != NULL)
+        return (_IO_FILE *) &new_f->fp;
+  _IO_un_link (&new_f->fp.file);
+  free (new_f);
+  return NULL;
+}
+
+#ifdef SHARED
+strong_alias (_IO_old_fopen, __old_fopen)
+symbol_version (_IO_old_fopen, _IO_fopen, GLIBC_2.0);
+symbol_version (__old_fopen, fopen, GLIBC_2.0);
+#else
+strong_alias (_IO_old_fopen, _IO_fopen);
+strong_alias (__old_fopen, fopen);
+#endif
diff --git a/glibc-compat/oldiopopen.c b/glibc-compat/oldiopopen.c
new file mode 100644
index 0000000000..13b5d16c83
--- /dev/null
+++ b/glibc-compat/oldiopopen.c
@@ -0,0 +1,289 @@
+/* Copyright (C) 1998 Free Software Foundation, Inc.
+   This file is part of the GNU IO Library.
+   Written by Per Bothner <bothner@cygnus.com>.
+
+   This library 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 library 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 library; see the file COPYING.  If not, write to
+   the Free Software Foundation, 59 Temple Place - Suite 330, Boston,
+   MA 02111-1307, USA.
+
+   As a special exception, if you link this library with files
+   compiled with a GNU compiler to produce an executable, this does
+   not cause the resulting executable to be covered by the GNU General
+   Public License.  This exception does not however invalidate any
+   other reasons why the executable file might be covered by the GNU
+   General Public License.  */
+
+#define _IO_USE_OLD_IO_FILE
+#ifndef _POSIX_SOURCE
+# define _POSIX_SOURCE
+#endif
+#include "libioP.h"
+#if _IO_HAVE_SYS_WAIT
+#include <signal.h>
+#include <unistd.h>
+#ifdef __STDC__
+#include <stdlib.h>
+#endif
+#ifdef _LIBC
+# include <unistd.h>
+#endif
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#ifndef _IO_fork
+#ifdef _LIBC
+#define _IO_fork __vfork
+#else
+#define _IO_fork vfork /* defined in libiberty, if needed */
+#endif
+extern _IO_pid_t _IO_fork (void);
+#endif
+
+#endif /* _IO_HAVE_SYS_WAIT */
+
+#ifndef _IO_pipe
+#ifdef _LIBC
+#define _IO_pipe __pipe
+#else
+#define _IO_pipe pipe
+#endif
+extern int _IO_pipe (int des[2]);
+#endif
+
+#ifndef _IO_dup2
+#ifdef _LIBC
+#define _IO_dup2 __dup2
+#else
+#define _IO_dup2 dup2
+#endif
+extern int _IO_dup2 (int fd, int fd2);
+#endif
+
+#ifndef _IO_waitpid
+#ifdef _LIBC
+#define _IO_waitpid __waitpid
+#else
+#define _IO_waitpid waitpid
+#endif
+#endif
+
+#ifndef _IO_execl
+#define _IO_execl execl
+#endif
+#ifndef _IO__exit
+#define _IO__exit _exit
+#endif
+
+#ifndef _IO_close
+#ifdef _LIBC
+#define _IO_close __close
+#else
+#define _IO_close close
+#endif
+#endif
+
+struct _IO_proc_file
+{
+  struct _IO_FILE_plus file;
+  /* Following fields must match those in class procbuf (procbuf.h) */
+  _IO_pid_t pid;
+  struct _IO_proc_file *next;
+};
+typedef struct _IO_proc_file _IO_proc_file;
+
+static struct _IO_proc_file *old_proc_file_chain = NULL;
+
+_IO_FILE *
+_IO_old_proc_open (fp, command, mode)
+     _IO_FILE *fp;
+     const char *command;
+     const char *mode;
+{
+#if _IO_HAVE_SYS_WAIT
+  volatile int read_or_write;
+  volatile int parent_end, child_end;
+  int pipe_fds[2];
+  _IO_pid_t child_pid;
+  if (_IO_file_is_open (fp))
+    return NULL;
+  if (_IO_pipe (pipe_fds) < 0)
+    return NULL;
+  if (mode[0] == 'r' && mode[1] == '\0')
+    {
+      parent_end = pipe_fds[0];
+      child_end = pipe_fds[1];
+      read_or_write = _IO_NO_WRITES;
+    }
+  else if (mode[0] == 'w' && mode[1] == '\0')
+    {
+      parent_end = pipe_fds[1];
+      child_end = pipe_fds[0];
+      read_or_write = _IO_NO_READS;
+    }
+  else
+    {
+      __set_errno (EINVAL);
+      return NULL;
+    }
+  ((_IO_proc_file *) fp)->pid = child_pid = _IO_fork ();
+  if (child_pid == 0)
+    {
+      int child_std_end = mode[0] == 'r' ? 1 : 0;
+      _IO_close (parent_end);
+      if (child_end != child_std_end)
+	{
+	  _IO_dup2 (child_end, child_std_end);
+	  _IO_close (child_end);
+	}
+      /* POSIX.2:  "popen() shall ensure that any streams from previous
+         popen() calls that remain open in the parent process are closed
+	 in the new child process." */
+      while (old_proc_file_chain)
+	{
+	  _IO_close (_IO_fileno ((_IO_FILE *) old_proc_file_chain));
+	  old_proc_file_chain = old_proc_file_chain->next;
+	}
+
+      _IO_execl ("/bin/sh", "sh", "-c", command, (char *) 0);
+      _IO__exit (127);
+    }
+  _IO_close (child_end);
+  if (child_pid < 0)
+    {
+      _IO_close (parent_end);
+      return NULL;
+    }
+  _IO_fileno (fp) = parent_end;
+
+  /* Link into old_proc_file_chain. */
+  ((_IO_proc_file *) fp)->next = old_proc_file_chain;
+  old_proc_file_chain = (_IO_proc_file *) fp;
+
+  _IO_mask_flags (fp, read_or_write, _IO_NO_READS|_IO_NO_WRITES);
+  return fp;
+#else /* !_IO_HAVE_SYS_WAIT */
+  return NULL;
+#endif
+}
+
+_IO_FILE *
+_IO_old_popen (command, mode)
+     const char *command;
+     const char *mode;
+{
+  struct locked_FILE
+  {
+    struct _IO_proc_file fpx;
+#ifdef _IO_MTSAFE_IO
+    _IO_lock_t lock;
+#endif
+  } *new_f;
+  _IO_FILE *fp;
+
+  new_f = (struct locked_FILE *) malloc (sizeof (struct locked_FILE));
+  if (new_f == NULL)
+    return NULL;
+#ifdef _IO_MTSAFE_IO
+  new_f->fpx.file.file._lock = &new_f->lock;
+#endif
+  fp = &new_f->fpx.file.file;
+  _IO_init (fp, 0);
+  _IO_JUMPS (fp) = &_IO_old_proc_jumps;
+  _IO_old_file_init (fp);
+#if  !_IO_UNIFIED_JUMPTABLES
+  new_f->fpx.file.vtable = NULL;
+#endif
+  if (_IO_old_proc_open (fp, command, mode) != NULL)
+    return fp;
+  _IO_un_link (fp);
+  free (new_f);
+  return NULL;
+}
+
+int
+_IO_old_proc_close (fp)
+     _IO_FILE *fp;
+{
+  /* This is not name-space clean. FIXME! */
+#if _IO_HAVE_SYS_WAIT
+  int wstatus;
+  _IO_proc_file **ptr = &old_proc_file_chain;
+  _IO_pid_t wait_pid;
+  int status = -1;
+
+  /* Unlink from old_proc_file_chain. */
+  for ( ; *ptr != NULL; ptr = &(*ptr)->next)
+    {
+      if (*ptr == (_IO_proc_file *) fp)
+	{
+	  *ptr = (*ptr)->next;
+	  status = 0;
+	  break;
+	}
+    }
+
+  if (status < 0 || _IO_close (_IO_fileno(fp)) < 0)
+    return -1;
+  /* POSIX.2 Rationale:  "Some historical implementations either block
+     or ignore the signals SIGINT, SIGQUIT, and SIGHUP while waiting
+     for the child process to terminate.  Since this behavior is not
+     described in POSIX.2, such implementations are not conforming." */
+  do
+    {
+      wait_pid = _IO_waitpid (((_IO_proc_file *) fp)->pid, &wstatus, 0);
+    }
+  while (wait_pid == -1 && errno == EINTR);
+  if (wait_pid == -1)
+    return -1;
+  return wstatus;
+#else /* !_IO_HAVE_SYS_WAIT */
+  return -1;
+#endif
+}
+
+struct _IO_jump_t _IO_old_proc_jumps = {
+  JUMP_INIT_DUMMY,
+  JUMP_INIT(finish, _IO_old_file_finish),
+  JUMP_INIT(overflow, _IO_old_file_overflow),
+  JUMP_INIT(underflow, _IO_old_file_underflow),
+  JUMP_INIT(uflow, _IO_default_uflow),
+  JUMP_INIT(pbackfail, _IO_default_pbackfail),
+  JUMP_INIT(xsputn, _IO_old_file_xsputn),
+  JUMP_INIT(xsgetn, _IO_default_xsgetn),
+  JUMP_INIT(seekoff, _IO_old_file_seekoff),
+  JUMP_INIT(seekpos, _IO_default_seekpos),
+  JUMP_INIT(setbuf, _IO_old_file_setbuf),
+  JUMP_INIT(sync, _IO_old_file_sync),
+  JUMP_INIT(doallocate, _IO_file_doallocate),
+  JUMP_INIT(read, _IO_file_read),
+  JUMP_INIT(write, _IO_old_file_write),
+  JUMP_INIT(seek, _IO_file_seek),
+  JUMP_INIT(close, _IO_old_proc_close),
+  JUMP_INIT(stat, _IO_file_stat),
+  JUMP_INIT(showmanyc, _IO_default_showmanyc),
+  JUMP_INIT(imbue, _IO_default_imbue)
+};
+
+#ifdef SHARED
+strong_alias (_IO_old_popen, __old_popen)
+symbol_version (_IO_old_popen, _IO_popen, GLIBC_2.0);
+symbol_version (__old_popen, popen, GLIBC_2.0);
+symbol_version (_IO_old_proc_open, _IO_proc_open, GLIBC_2.0);
+symbol_version (_IO_old_proc_close, _IO_proc_close, GLIBC_2.0);
+#else
+strong_alias (_IO_old_popen, _IO_popen);
+strong_alias (__old_popen, popen);
+strong_alias (_IO_old_proc_open, _IO_proc_open);
+strong_alias (_IO_old_proc_close, _IO_proc_close);
+#endif
diff --git a/glibc-compat/oldpclose.c b/glibc-compat/oldpclose.c
new file mode 100644
index 0000000000..c33e19c431
--- /dev/null
+++ b/glibc-compat/oldpclose.c
@@ -0,0 +1,48 @@
+/* Copyright (C) 1998 Free Software Foundation, Inc.
+   This file is part of the GNU IO Library.
+
+   This library 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 library 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 library; see the file COPYING.  If not, write to
+   the Free Software Foundation, 59 Temple Place - Suite 330, Boston,
+   MA 02111-1307, USA.
+
+   As a special exception, if you link this library with files
+   compiled with a GNU compiler to produce an executable, this does
+   not cause the resulting executable to be covered by the GNU General
+   Public License.  This exception does not however invalidate any
+   other reasons why the executable file might be covered by the GNU
+   General Public License.  */
+
+#define _IO_USE_OLD_IO_FILE
+#include "libioP.h"
+#include "stdio.h"
+#include <errno.h>
+
+int
+__old_pclose (fp)
+     FILE *fp;
+{
+#if 0
+  /* Does not actually test that stream was created by popen(). Instead,
+     it depends on the filebuf::sys_close() virtual to Do The Right Thing. */
+  if (fp is not a proc_file)
+    return -1;
+#endif
+  return _IO_old_fclose (fp);
+}
+
+#ifdef SHARED
+symbol_version (__old_pclose, pclose, GLIBC_2.0);
+#else
+strong_alias (__old_pclose, pclose);
+#endif
diff --git a/glibc-compat/oldstdfiles.c b/glibc-compat/oldstdfiles.c
new file mode 100644
index 0000000000..e9c992b943
--- /dev/null
+++ b/glibc-compat/oldstdfiles.c
@@ -0,0 +1,97 @@
+/* Copyright (C) 1993, 1994, 1996, 1997 Free Software Foundation, Inc.
+   This file is part of the GNU IO Library.
+
+   This library 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 library 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 library; see the file COPYING.  If not, write to
+   the Free Software Foundation, 59 Temple Place - Suite 330, Boston,
+   MA 02111-1307, USA.
+
+   As a special exception, if you link this library with files
+   compiled with a GNU compiler to produce an executable, this does
+   not cause the resulting executable to be covered by the GNU General
+   Public License.  This exception does not however invalidate any
+   other reasons why the executable file might be covered by the GNU
+   General Public License.  */
+
+
+/* This file provides definitions of _IO_stdin, _IO_stdout, and _IO_stderr
+   for C code.  Compare stdstreams.cc.
+   (The difference is that here the vtable field is set to 0,
+   so the objects defined are not valid C++ objects.  On the other
+   hand, we don't need a C++ compiler to build this file.) */
+
+#define _IO_USE_OLD_IO_FILE
+#include "libioP.h"
+
+#ifdef _IO_MTSAFE_IO
+#define DEF_STDFILE(NAME, FD, CHAIN, FLAGS) \
+  static _IO_lock_t _IO_stdfile_##FD##_lock = _IO_lock_initializer; \
+  struct _IO_FILE_plus NAME \
+    = {FILEBUF_LITERAL(CHAIN, FLAGS, FD), &_IO_old_file_jumps};
+#else
+#define DEF_STDFILE(NAME, FD, CHAIN, FLAGS) \
+  struct _IO_FILE_plus NAME \
+    = {FILEBUF_LITERAL(CHAIN, FLAGS, FD), &_IO_old_file_jumps};
+#endif
+
+DEF_STDFILE(_IO_stdin_, 0, 0, _IO_NO_WRITES);
+DEF_STDFILE(_IO_stdout_, 1, &_IO_stdin_.file, _IO_NO_READS);
+DEF_STDFILE(_IO_stderr_, 2, &_IO_stdout_.file,
+	    _IO_NO_READS+_IO_UNBUFFERED);
+
+#if defined __GNUC__ && __GNUC__ >= 2
+
+#include <stdio.h>
+
+extern const int _IO_stdin_used;
+weak_extern (_IO_stdin_used);
+
+#undef stdin
+#undef stdout
+#undef stderr
+
+extern FILE *stdin;
+extern FILE *stdout;
+extern FILE *stderr;
+
+#ifdef SHARED
+extern
+#endif
+FILE *_IO_list_all;
+
+static void _IO_check_libio (void) __attribute__ ((constructor));
+
+/* This function determines which shared C library the application
+   was linked against. We then set up the stdin/stdout/stderr and
+   _IO_list_all accordingly. */
+
+static void
+_IO_check_libio ()
+{
+#ifdef SHARED
+  if (&_IO_stdin_used == NULL)
+#endif
+    {
+      /* We are using the old one. */
+      _IO_stdin = stdin = &_IO_stdin_.file;
+      _IO_stdout = stdout = &_IO_stdout_.file;
+      _IO_stderr = stderr = _IO_list_all = &_IO_stderr_.file;
+      _IO_stdin->_vtable_offset = _IO_stdout->_vtable_offset =
+	_IO_stderr->_vtable_offset = stdin->_vtable_offset =
+	stdout->_vtable_offset = stderr->_vtable_offset =
+	((int) sizeof (struct _IO_FILE)
+	 - (int) sizeof (struct _IO_FILE_complete));
+    }
+}
+
+#endif
diff --git a/glibc-compat/oldtmpfile.c b/glibc-compat/oldtmpfile.c
new file mode 100644
index 0000000000..9607bceefe
--- /dev/null
+++ b/glibc-compat/oldtmpfile.c
@@ -0,0 +1,55 @@
+/* Copyright (C) 1991, 1993, 1996, 1997, 1998 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#define _IO_USE_OLD_IO_FILE
+#include <stdio.h>
+#include <unistd.h>
+#include <iolibio.h>
+
+/* This returns a new stream opened on a temporary file (generated
+   by tmpnam).  The file is opened with mode "w+b" (binary read/write).
+   If we couldn't generate a unique filename or the file couldn't
+   be opened, NULL is returned.  */
+FILE *
+__old_tmpfile (void)
+{
+  char buf[FILENAME_MAX];
+  int fd;
+  FILE *f;
+
+  if (__path_search (buf, FILENAME_MAX, NULL, "tmpf", 0))
+    return NULL;
+  fd = __gen_tempname (buf, 1, 0);
+  if (fd < 0)
+    return NULL;
+
+  /* Note that this relies on the Unix semantics that
+     a file is not really removed until it is closed.  */
+  (void) remove (buf);
+
+  if ((f = _IO_old_fdopen (fd, "w+b")) == NULL)
+    __close (fd);
+
+  return f;
+}
+
+#ifdef SHARED
+symbol_version (__old_tmpfile, tmpfile, GLIBC_2.0);
+#else
+strong_alias (__old_tmpfile, tmpfile);
+#endif
diff --git a/glibc-compat/rpcsvc/yp.h b/glibc-compat/rpcsvc/yp.h
new file mode 100644
index 0000000000..40914c5813
--- /dev/null
+++ b/glibc-compat/rpcsvc/yp.h
@@ -0,0 +1,621 @@
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part.  Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California  94043
+ */
+
+#ifndef __RPCSVC_YP_H__
+#define __RPCSVC_YP_H__
+
+#include <rpc/rpc.h>
+
+#define YPMAXRECORD 1024
+#define YPMAXDOMAIN 64
+#define YPMAXMAP 64
+#define YPMAXPEER 64
+
+enum ypstat {
+	YP_TRUE = 1,
+	YP_NOMORE = 2,
+	YP_FALSE = 0,
+	YP_NOMAP = -1,
+	YP_NODOM = -2,
+	YP_NOKEY = -3,
+	YP_BADOP = -4,
+	YP_BADDB = -5,
+	YP_YPERR = -6,
+	YP_BADARGS = -7,
+	YP_VERS = -8,
+};
+typedef enum ypstat ypstat;
+#ifdef __cplusplus
+extern "C" bool_t xdr_ypstat(XDR *, ypstat*);
+#elif __STDC__
+extern  bool_t xdr_ypstat(XDR *, ypstat*);
+#else /* Old Style C */
+bool_t xdr_ypstat();
+#endif /* Old Style C */
+
+
+enum ypxfrstat {
+	YPXFR_SUCC = 1,
+	YPXFR_AGE = 2,
+	YPXFR_NOMAP = -1,
+	YPXFR_NODOM = -2,
+	YPXFR_RSRC = -3,
+	YPXFR_RPC = -4,
+	YPXFR_MADDR = -5,
+	YPXFR_YPERR = -6,
+	YPXFR_BADARGS = -7,
+	YPXFR_DBM = -8,
+	YPXFR_FILE = -9,
+	YPXFR_SKEW = -10,
+	YPXFR_CLEAR = -11,
+	YPXFR_FORCE = -12,
+	YPXFR_XFRERR = -13,
+	YPXFR_REFUSED = -14,
+};
+typedef enum ypxfrstat ypxfrstat;
+#ifdef __cplusplus
+extern "C" bool_t xdr_ypxfrstat(XDR *, ypxfrstat*);
+#elif __STDC__
+extern  bool_t xdr_ypxfrstat(XDR *, ypxfrstat*);
+#else /* Old Style C */
+bool_t xdr_ypxfrstat();
+#endif /* Old Style C */
+
+
+typedef char *domainname;
+#ifdef __cplusplus
+extern "C" bool_t xdr_domainname(XDR *, domainname*);
+#elif __STDC__
+extern  bool_t xdr_domainname(XDR *, domainname*);
+#else /* Old Style C */
+bool_t xdr_domainname();
+#endif /* Old Style C */
+
+
+typedef char *mapname;
+#ifdef __cplusplus
+extern "C" bool_t xdr_mapname(XDR *, mapname*);
+#elif __STDC__
+extern  bool_t xdr_mapname(XDR *, mapname*);
+#else /* Old Style C */
+bool_t xdr_mapname();
+#endif /* Old Style C */
+
+
+typedef char *peername;
+#ifdef __cplusplus
+extern "C" bool_t xdr_peername(XDR *, peername*);
+#elif __STDC__
+extern  bool_t xdr_peername(XDR *, peername*);
+#else /* Old Style C */
+bool_t xdr_peername();
+#endif /* Old Style C */
+
+
+typedef struct {
+	u_int keydat_len;
+	char *keydat_val;
+} keydat;
+#ifdef __cplusplus
+extern "C" bool_t xdr_keydat(XDR *, keydat*);
+#elif __STDC__
+extern  bool_t xdr_keydat(XDR *, keydat*);
+#else /* Old Style C */
+bool_t xdr_keydat();
+#endif /* Old Style C */
+
+
+typedef struct {
+	u_int valdat_len;
+	char *valdat_val;
+} valdat;
+#ifdef __cplusplus
+extern "C" bool_t xdr_valdat(XDR *, valdat*);
+#elif __STDC__
+extern  bool_t xdr_valdat(XDR *, valdat*);
+#else /* Old Style C */
+bool_t xdr_valdat();
+#endif /* Old Style C */
+
+
+struct ypmap_parms {
+	domainname domain;
+	mapname map;
+	u_int ordernum;
+	peername peer;
+};
+typedef struct ypmap_parms ypmap_parms;
+#ifdef __cplusplus
+extern "C" bool_t xdr_ypmap_parms(XDR *, ypmap_parms*);
+#elif __STDC__
+extern  bool_t xdr_ypmap_parms(XDR *, ypmap_parms*);
+#else /* Old Style C */
+bool_t xdr_ypmap_parms();
+#endif /* Old Style C */
+
+
+struct ypreq_key {
+	domainname domain;
+	mapname map;
+	keydat key;
+};
+typedef struct ypreq_key ypreq_key;
+#ifdef __cplusplus
+extern "C" bool_t xdr_ypreq_key(XDR *, ypreq_key*);
+#elif __STDC__
+extern  bool_t xdr_ypreq_key(XDR *, ypreq_key*);
+#else /* Old Style C */
+bool_t xdr_ypreq_key();
+#endif /* Old Style C */
+
+
+struct ypreq_nokey {
+	domainname domain;
+	mapname map;
+};
+typedef struct ypreq_nokey ypreq_nokey;
+#ifdef __cplusplus
+extern "C" bool_t xdr_ypreq_nokey(XDR *, ypreq_nokey*);
+#elif __STDC__
+extern  bool_t xdr_ypreq_nokey(XDR *, ypreq_nokey*);
+#else /* Old Style C */
+bool_t xdr_ypreq_nokey();
+#endif /* Old Style C */
+
+
+struct ypreq_xfr {
+	ypmap_parms map_parms;
+	u_int transid;
+	u_int prog;
+	u_int port;
+};
+typedef struct ypreq_xfr ypreq_xfr;
+#ifdef __cplusplus
+extern "C" bool_t xdr_ypreq_xfr(XDR *, ypreq_xfr*);
+#elif __STDC__
+extern  bool_t xdr_ypreq_xfr(XDR *, ypreq_xfr*);
+#else /* Old Style C */
+bool_t xdr_ypreq_xfr();
+#endif /* Old Style C */
+
+
+struct ypresp_val {
+	ypstat stat;
+	valdat val;
+};
+typedef struct ypresp_val ypresp_val;
+#ifdef __cplusplus
+extern "C" bool_t xdr_ypresp_val(XDR *, ypresp_val*);
+#elif __STDC__
+extern  bool_t xdr_ypresp_val(XDR *, ypresp_val*);
+#else /* Old Style C */
+bool_t xdr_ypresp_val();
+#endif /* Old Style C */
+
+
+struct ypresp_key_val {
+	ypstat stat;
+#ifdef STUPID_SUN_BUG
+	/* This is the form as distributed by Sun.  But even the Sun NIS
+	   servers expect the values in the other order.  So their
+	   implementation somehow must change the order internally.  We
+	   don't want to follow this bad example since the user should be
+	   able to use rpcgen on this file.  */
+	keydat key;
+	valdat val;
+#else
+	valdat val;
+	keydat key;
+#endif
+};
+typedef struct ypresp_key_val ypresp_key_val;
+#ifdef __cplusplus
+extern "C" bool_t xdr_ypresp_key_val(XDR *, ypresp_key_val*);
+#elif __STDC__
+extern  bool_t xdr_ypresp_key_val(XDR *, ypresp_key_val*);
+#else /* Old Style C */
+bool_t xdr_ypresp_key_val();
+#endif /* Old Style C */
+
+
+struct ypresp_master {
+	ypstat stat;
+	peername peer;
+};
+typedef struct ypresp_master ypresp_master;
+#ifdef __cplusplus
+extern "C" bool_t xdr_ypresp_master(XDR *, ypresp_master*);
+#elif __STDC__
+extern  bool_t xdr_ypresp_master(XDR *, ypresp_master*);
+#else /* Old Style C */
+bool_t xdr_ypresp_master();
+#endif /* Old Style C */
+
+
+struct ypresp_order {
+	ypstat stat;
+	u_int ordernum;
+};
+typedef struct ypresp_order ypresp_order;
+#ifdef __cplusplus
+extern "C" bool_t xdr_ypresp_order(XDR *, ypresp_order*);
+#elif __STDC__
+extern  bool_t xdr_ypresp_order(XDR *, ypresp_order*);
+#else /* Old Style C */
+bool_t xdr_ypresp_order();
+#endif /* Old Style C */
+
+
+struct ypresp_all {
+	bool_t more;
+	union {
+		ypresp_key_val val;
+	} ypresp_all_u;
+};
+typedef struct ypresp_all ypresp_all;
+#ifdef __cplusplus
+extern "C" bool_t xdr_ypresp_all(XDR *, ypresp_all*);
+#elif __STDC__
+extern  bool_t xdr_ypresp_all(XDR *, ypresp_all*);
+#else /* Old Style C */
+bool_t xdr_ypresp_all();
+#endif /* Old Style C */
+
+
+struct ypresp_xfr {
+	u_int transid;
+	ypxfrstat xfrstat;
+};
+typedef struct ypresp_xfr ypresp_xfr;
+#ifdef __cplusplus
+extern "C" bool_t xdr_ypresp_xfr(XDR *, ypresp_xfr*);
+#elif __STDC__
+extern  bool_t xdr_ypresp_xfr(XDR *, ypresp_xfr*);
+#else /* Old Style C */
+bool_t xdr_ypresp_xfr();
+#endif /* Old Style C */
+
+
+struct ypmaplist {
+	mapname map;
+	struct ypmaplist *next;
+};
+typedef struct ypmaplist ypmaplist;
+#ifdef __cplusplus
+extern "C" bool_t xdr_ypmaplist(XDR *, ypmaplist*);
+#elif __STDC__
+extern  bool_t xdr_ypmaplist(XDR *, ypmaplist*);
+#else /* Old Style C */
+bool_t xdr_ypmaplist();
+#endif /* Old Style C */
+
+
+struct ypresp_maplist {
+	ypstat stat;
+	ypmaplist *maps;
+};
+typedef struct ypresp_maplist ypresp_maplist;
+#ifdef __cplusplus
+extern "C" bool_t xdr_ypresp_maplist(XDR *, ypresp_maplist*);
+#elif __STDC__
+extern  bool_t xdr_ypresp_maplist(XDR *, ypresp_maplist*);
+#else /* Old Style C */
+bool_t xdr_ypresp_maplist();
+#endif /* Old Style C */
+
+
+enum yppush_status {
+	YPPUSH_SUCC = 1,
+	YPPUSH_AGE = 2,
+	YPPUSH_NOMAP = -1,
+	YPPUSH_NODOM = -2,
+	YPPUSH_RSRC = -3,
+	YPPUSH_RPC = -4,
+	YPPUSH_MADDR = -5,
+	YPPUSH_YPERR = -6,
+	YPPUSH_BADARGS = -7,
+	YPPUSH_DBM = -8,
+	YPPUSH_FILE = -9,
+	YPPUSH_SKEW = -10,
+	YPPUSH_CLEAR = -11,
+	YPPUSH_FORCE = -12,
+	YPPUSH_XFRERR = -13,
+	YPPUSH_REFUSED = -14,
+};
+typedef enum yppush_status yppush_status;
+#ifdef __cplusplus
+extern "C" bool_t xdr_yppush_status(XDR *, yppush_status*);
+#elif __STDC__
+extern  bool_t xdr_yppush_status(XDR *, yppush_status*);
+#else /* Old Style C */
+bool_t xdr_yppush_status();
+#endif /* Old Style C */
+
+
+struct yppushresp_xfr {
+	u_int transid;
+	yppush_status status;
+};
+typedef struct yppushresp_xfr yppushresp_xfr;
+#ifdef __cplusplus
+extern "C" bool_t xdr_yppushresp_xfr(XDR *, yppushresp_xfr*);
+#elif __STDC__
+extern  bool_t xdr_yppushresp_xfr(XDR *, yppushresp_xfr*);
+#else /* Old Style C */
+bool_t xdr_yppushresp_xfr();
+#endif /* Old Style C */
+
+
+enum ypbind_resptype {
+	YPBIND_SUCC_VAL = 1,
+	YPBIND_FAIL_VAL = 2,
+};
+typedef enum ypbind_resptype ypbind_resptype;
+#ifdef __cplusplus
+extern "C" bool_t xdr_ypbind_resptype(XDR *, ypbind_resptype*);
+#elif __STDC__
+extern  bool_t xdr_ypbind_resptype(XDR *, ypbind_resptype*);
+#else /* Old Style C */
+bool_t xdr_ypbind_resptype();
+#endif /* Old Style C */
+
+
+struct ypbind_binding {
+	char ypbind_binding_addr[4];
+	char ypbind_binding_port[2];
+};
+typedef struct ypbind_binding ypbind_binding;
+#ifdef __cplusplus
+extern "C" bool_t xdr_ypbind_binding(XDR *, ypbind_binding*);
+#elif __STDC__
+extern  bool_t xdr_ypbind_binding(XDR *, ypbind_binding*);
+#else /* Old Style C */
+bool_t xdr_ypbind_binding();
+#endif /* Old Style C */
+
+
+struct ypbind_resp {
+	ypbind_resptype ypbind_status;
+	union {
+		u_int ypbind_error;
+		ypbind_binding ypbind_bindinfo;
+	} ypbind_resp_u;
+};
+typedef struct ypbind_resp ypbind_resp;
+#ifdef __cplusplus
+extern "C" bool_t xdr_ypbind_resp(XDR *, ypbind_resp*);
+#elif __STDC__
+extern  bool_t xdr_ypbind_resp(XDR *, ypbind_resp*);
+#else /* Old Style C */
+bool_t xdr_ypbind_resp();
+#endif /* Old Style C */
+
+#define YPBIND_ERR_ERR 1
+#define YPBIND_ERR_NOSERV 2
+#define YPBIND_ERR_RESC 3
+
+struct ypbind_setdom {
+	domainname ypsetdom_domain;
+	ypbind_binding ypsetdom_binding;
+	u_int ypsetdom_vers;
+};
+typedef struct ypbind_setdom ypbind_setdom;
+#ifdef __cplusplus
+extern "C" bool_t xdr_ypbind_setdom(XDR *, ypbind_setdom*);
+#elif __STDC__
+extern  bool_t xdr_ypbind_setdom(XDR *, ypbind_setdom*);
+#else /* Old Style C */
+bool_t xdr_ypbind_setdom();
+#endif /* Old Style C */
+
+
+#define YPPROG ((u_long)100004)
+#define YPVERS ((u_long)2)
+
+#ifdef __cplusplus
+#define YPPROC_NULL ((u_long)0)
+extern "C" void * ypproc_null_2(void *, CLIENT *);
+extern "C" void * ypproc_null_2_svc(void *, struct svc_req *);
+#define YPPROC_DOMAIN ((u_long)1)
+extern "C" bool_t * ypproc_domain_2(domainname *, CLIENT *);
+extern "C" bool_t * ypproc_domain_2_svc(domainname *, struct svc_req *);
+#define YPPROC_DOMAIN_NONACK ((u_long)2)
+extern "C" bool_t * ypproc_domain_nonack_2(domainname *, CLIENT *);
+extern "C" bool_t * ypproc_domain_nonack_2_svc(domainname *, struct svc_req *);
+#define YPPROC_MATCH ((u_long)3)
+extern "C" ypresp_val * ypproc_match_2(ypreq_key *, CLIENT *);
+extern "C" ypresp_val * ypproc_match_2_svc(ypreq_key *, struct svc_req *);
+#define YPPROC_FIRST ((u_long)4)
+extern "C" ypresp_key_val * ypproc_first_2(ypreq_key *, CLIENT *);
+extern "C" ypresp_key_val * ypproc_first_2_svc(ypreq_key *, struct svc_req *);
+#define YPPROC_NEXT ((u_long)5)
+extern "C" ypresp_key_val * ypproc_next_2(ypreq_key *, CLIENT *);
+extern "C" ypresp_key_val * ypproc_next_2_svc(ypreq_key *, struct svc_req *);
+#define YPPROC_XFR ((u_long)6)
+extern "C" ypresp_xfr * ypproc_xfr_2(ypreq_xfr *, CLIENT *);
+extern "C" ypresp_xfr * ypproc_xfr_2_svc(ypreq_xfr *, struct svc_req *);
+#define YPPROC_CLEAR ((u_long)7)
+extern "C" void * ypproc_clear_2(void *, CLIENT *);
+extern "C" void * ypproc_clear_2_svc(void *, struct svc_req *);
+#define YPPROC_ALL ((u_long)8)
+extern "C" ypresp_all * ypproc_all_2(ypreq_nokey *, CLIENT *);
+extern "C" ypresp_all * ypproc_all_2_svc(ypreq_nokey *, struct svc_req *);
+#define YPPROC_MASTER ((u_long)9)
+extern "C" ypresp_master * ypproc_master_2(ypreq_nokey *, CLIENT *);
+extern "C" ypresp_master * ypproc_master_2_svc(ypreq_nokey *, struct svc_req *);
+#define YPPROC_ORDER ((u_long)10)
+extern "C" ypresp_order * ypproc_order_2(ypreq_nokey *, CLIENT *);
+extern "C" ypresp_order * ypproc_order_2_svc(ypreq_nokey *, struct svc_req *);
+#define YPPROC_MAPLIST ((u_long)11)
+extern "C" ypresp_maplist * ypproc_maplist_2(domainname *, CLIENT *);
+extern "C" ypresp_maplist * ypproc_maplist_2_svc(domainname *, struct svc_req *);
+
+#elif __STDC__
+#define YPPROC_NULL ((u_long)0)
+extern  void * ypproc_null_2(void *, CLIENT *);
+extern  void * ypproc_null_2_svc(void *, struct svc_req *);
+#define YPPROC_DOMAIN ((u_long)1)
+extern  bool_t * ypproc_domain_2(domainname *, CLIENT *);
+extern  bool_t * ypproc_domain_2_svc(domainname *, struct svc_req *);
+#define YPPROC_DOMAIN_NONACK ((u_long)2)
+extern  bool_t * ypproc_domain_nonack_2(domainname *, CLIENT *);
+extern  bool_t * ypproc_domain_nonack_2_svc(domainname *, struct svc_req *);
+#define YPPROC_MATCH ((u_long)3)
+extern  ypresp_val * ypproc_match_2(ypreq_key *, CLIENT *);
+extern  ypresp_val * ypproc_match_2_svc(ypreq_key *, struct svc_req *);
+#define YPPROC_FIRST ((u_long)4)
+extern  ypresp_key_val * ypproc_first_2(ypreq_key *, CLIENT *);
+extern  ypresp_key_val * ypproc_first_2_svc(ypreq_key *, struct svc_req *);
+#define YPPROC_NEXT ((u_long)5)
+extern  ypresp_key_val * ypproc_next_2(ypreq_key *, CLIENT *);
+extern  ypresp_key_val * ypproc_next_2_svc(ypreq_key *, struct svc_req *);
+#define YPPROC_XFR ((u_long)6)
+extern  ypresp_xfr * ypproc_xfr_2(ypreq_xfr *, CLIENT *);
+extern  ypresp_xfr * ypproc_xfr_2_svc(ypreq_xfr *, struct svc_req *);
+#define YPPROC_CLEAR ((u_long)7)
+extern  void * ypproc_clear_2(void *, CLIENT *);
+extern  void * ypproc_clear_2_svc(void *, struct svc_req *);
+#define YPPROC_ALL ((u_long)8)
+extern  ypresp_all * ypproc_all_2(ypreq_nokey *, CLIENT *);
+extern  ypresp_all * ypproc_all_2_svc(ypreq_nokey *, struct svc_req *);
+#define YPPROC_MASTER ((u_long)9)
+extern  ypresp_master * ypproc_master_2(ypreq_nokey *, CLIENT *);
+extern  ypresp_master * ypproc_master_2_svc(ypreq_nokey *, struct svc_req *);
+#define YPPROC_ORDER ((u_long)10)
+extern  ypresp_order * ypproc_order_2(ypreq_nokey *, CLIENT *);
+extern  ypresp_order * ypproc_order_2_svc(ypreq_nokey *, struct svc_req *);
+#define YPPROC_MAPLIST ((u_long)11)
+extern  ypresp_maplist * ypproc_maplist_2(domainname *, CLIENT *);
+extern  ypresp_maplist * ypproc_maplist_2_svc(domainname *, struct svc_req *);
+
+#else /* Old Style C */
+#define YPPROC_NULL ((u_long)0)
+extern  void * ypproc_null_2();
+extern  void * ypproc_null_2_svc();
+#define YPPROC_DOMAIN ((u_long)1)
+extern  bool_t * ypproc_domain_2();
+extern  bool_t * ypproc_domain_2_svc();
+#define YPPROC_DOMAIN_NONACK ((u_long)2)
+extern  bool_t * ypproc_domain_nonack_2();
+extern  bool_t * ypproc_domain_nonack_2_svc();
+#define YPPROC_MATCH ((u_long)3)
+extern  ypresp_val * ypproc_match_2();
+extern  ypresp_val * ypproc_match_2_svc();
+#define YPPROC_FIRST ((u_long)4)
+extern  ypresp_key_val * ypproc_first_2();
+extern  ypresp_key_val * ypproc_first_2_svc();
+#define YPPROC_NEXT ((u_long)5)
+extern  ypresp_key_val * ypproc_next_2();
+extern  ypresp_key_val * ypproc_next_2_svc();
+#define YPPROC_XFR ((u_long)6)
+extern  ypresp_xfr * ypproc_xfr_2();
+extern  ypresp_xfr * ypproc_xfr_2_svc();
+#define YPPROC_CLEAR ((u_long)7)
+extern  void * ypproc_clear_2();
+extern  void * ypproc_clear_2_svc();
+#define YPPROC_ALL ((u_long)8)
+extern  ypresp_all * ypproc_all_2();
+extern  ypresp_all * ypproc_all_2_svc();
+#define YPPROC_MASTER ((u_long)9)
+extern  ypresp_master * ypproc_master_2();
+extern  ypresp_master * ypproc_master_2_svc();
+#define YPPROC_ORDER ((u_long)10)
+extern  ypresp_order * ypproc_order_2();
+extern  ypresp_order * ypproc_order_2_svc();
+#define YPPROC_MAPLIST ((u_long)11)
+extern  ypresp_maplist * ypproc_maplist_2();
+extern  ypresp_maplist * ypproc_maplist_2_svc();
+#endif /* Old Style C */
+
+#define YPPUSH_XFRRESPPROG ((u_long)0x40000000)
+#define YPPUSH_XFRRESPVERS ((u_long)1)
+
+#ifdef __cplusplus
+#define YPPUSHPROC_NULL ((u_long)0)
+extern "C" void * yppushproc_null_1(void *, CLIENT *);
+extern "C" void * yppushproc_null_1_svc(void *, struct svc_req *);
+#define YPPUSHPROC_XFRRESP ((u_long)1)
+extern "C" void * yppushproc_xfrresp_1(yppushresp_xfr *, CLIENT *);
+extern "C" void * yppushproc_xfrresp_1_svc(yppushresp_xfr *, struct svc_req *);
+
+#elif __STDC__
+#define YPPUSHPROC_NULL ((u_long)0)
+extern  void * yppushproc_null_1(void *, CLIENT *);
+extern  void * yppushproc_null_1_svc(void *, struct svc_req *);
+#define YPPUSHPROC_XFRRESP ((u_long)1)
+extern  void * yppushproc_xfrresp_1(yppushresp_xfr *, CLIENT *);
+extern  void * yppushproc_xfrresp_1_svc(yppushresp_xfr *, struct svc_req *);
+
+#else /* Old Style C */
+#define YPPUSHPROC_NULL ((u_long)0)
+extern  void * yppushproc_null_1();
+extern  void * yppushproc_null_1_svc();
+#define YPPUSHPROC_XFRRESP ((u_long)1)
+extern  void * yppushproc_xfrresp_1();
+extern  void * yppushproc_xfrresp_1_svc();
+#endif /* Old Style C */
+
+#define YPBINDPROG ((u_long)100007)
+#define YPBINDVERS ((u_long)2)
+
+#ifdef __cplusplus
+#define YPBINDPROC_NULL ((u_long)0)
+extern "C" void * ypbindproc_null_2(void *, CLIENT *);
+extern "C" void * ypbindproc_null_2_svc(void *, struct svc_req *);
+#define YPBINDPROC_DOMAIN ((u_long)1)
+extern "C" ypbind_resp * ypbindproc_domain_2(domainname *, CLIENT *);
+extern "C" ypbind_resp * ypbindproc_domain_2_svc(domainname *, struct svc_req *);
+#define YPBINDPROC_SETDOM ((u_long)2)
+extern "C" void * ypbindproc_setdom_2(ypbind_setdom *, CLIENT *);
+extern "C" void * ypbindproc_setdom_2_svc(ypbind_setdom *, struct svc_req *);
+
+#elif __STDC__
+#define YPBINDPROC_NULL ((u_long)0)
+extern  void * ypbindproc_null_2(void *, CLIENT *);
+extern  void * ypbindproc_null_2_svc(void *, struct svc_req *);
+#define YPBINDPROC_DOMAIN ((u_long)1)
+extern  ypbind_resp * ypbindproc_domain_2(domainname *, CLIENT *);
+extern  ypbind_resp * ypbindproc_domain_2_svc(domainname *, struct svc_req *);
+#define YPBINDPROC_SETDOM ((u_long)2)
+extern  void * ypbindproc_setdom_2(ypbind_setdom *, CLIENT *);
+extern  void * ypbindproc_setdom_2_svc(ypbind_setdom *, struct svc_req *);
+
+#else /* Old Style C */
+#define YPBINDPROC_NULL ((u_long)0)
+extern  void * ypbindproc_null_2();
+extern  void * ypbindproc_null_2_svc();
+#define YPBINDPROC_DOMAIN ((u_long)1)
+extern  ypbind_resp * ypbindproc_domain_2();
+extern  ypbind_resp * ypbindproc_domain_2_svc();
+#define YPBINDPROC_SETDOM ((u_long)2)
+extern  void * ypbindproc_setdom_2();
+extern  void * ypbindproc_setdom_2_svc();
+#endif /* Old Style C */
+
+#endif /* !__RPCSVC_YP_H__ */
diff --git a/glibc-compat/rpcsvc/ypclnt.h b/glibc-compat/rpcsvc/ypclnt.h
new file mode 100644
index 0000000000..5c1ac389b5
--- /dev/null
+++ b/glibc-compat/rpcsvc/ypclnt.h
@@ -0,0 +1,90 @@
+/*
+** Copyright (c) 1996 Thorsten Kukuk, Germany
+**
+** This library is free software; you can redistribute it and/or
+** modify it under the terms of the GNU Library General Public
+** License as published by the Free Software Foundation; either
+** version 2 of the License, or (at your option) any later version.
+**
+** This library 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
+** Library General Public License for more details.
+**
+** You should have received a copy of the GNU Library General Public
+** License along with this library; if not, write to the Free
+** Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+**
+** Author: Thorsten Kukuk <kukuk@vt.uni-paderborn.de>
+**
+*/
+
+#ifndef	__RPCSVC_YPCLNT_H__
+#define	__RPCSVC_YPCLNT_H__
+
+#include <features.h>
+
+/* some defines */
+#define YPERR_SUCCESS 0                 /* There is no error */
+#define	YPERR_BADARGS 1			/* Args to function are bad */
+#define	YPERR_RPC 2			/* RPC failure */
+#define	YPERR_DOMAIN 3			/* Can't bind to a server with this domain */
+#define	YPERR_MAP 4			/* No such map in server's domain */
+#define	YPERR_KEY 5			/* No such key in map */
+#define	YPERR_YPERR 6			/* Internal yp server or client error */
+#define	YPERR_RESRC 7			/* Local resource allocation failure */
+#define	YPERR_NOMORE 8			/* No more records in map database */
+#define	YPERR_PMAP 9			/* Can't communicate with portmapper */
+#define	YPERR_YPBIND 10			/* Can't communicate with ypbind */
+#define	YPERR_YPSERV 11			/* Can't communicate with ypserv */
+#define	YPERR_NODOM 12			/* Local domain name not set */
+#define	YPERR_BADDB 13			/* yp data base is bad */
+#define	YPERR_VERS 14			/* YP version mismatch */
+#define	YPERR_ACCESS 15			/* Access violation */
+#define	YPERR_BUSY 16			/* Database is busy */
+
+/* Types of update operations */
+#define	YPOP_CHANGE 1			/* change, do not add */
+#define	YPOP_INSERT 2			/* add, do not change */
+#define	YPOP_DELETE 3			/* delete this entry */
+#define	YPOP_STORE  4			/* add, or change */
+
+__BEGIN_DECLS
+
+/* struct ypall_callback * is the arg which must be passed to yp_all */
+struct ypall_callback
+  {
+    int (*foreach) (int __status, char *__key, int __keylen,
+		    char *__val, int __vallen, char *__data);
+    char *data;
+  };
+
+/* External NIS client function references. */
+extern int yp_bind (__const char *) __THROW;
+extern void yp_unbind (__const char *) __THROW;
+extern int yp_get_default_domain (char **) __THROW;
+extern int yp_match (__const char *, __const char *, __const char *,
+		     __const int, char **, int *) __THROW;
+extern int yp_first (__const char *, __const char *, char **,
+		     int *, char **, int *) __THROW;
+extern int yp_next (__const char *, __const char *, __const char *,
+		    __const int, char **, int *, char **, int *) __THROW;
+extern int yp_master (__const char *, __const char *, char **) __THROW;
+extern int yp_order (__const char *, __const char *, unsigned int *) __THROW;
+extern int yp_all (__const char *, __const char *,
+		   __const struct ypall_callback *) __THROW;
+extern __const char *yperr_string (__const int) __THROW;
+extern __const char *ypbinderr_string (__const int) __THROW;
+extern int ypprot_err (__const int) __THROW;
+extern int yp_update (char *, char *, unsigned,  char *,
+		      int, char *, int) __THROW;
+#if 0
+extern int yp_maplist (__const char *, struct ypmaplist **) __THROW;
+#endif
+
+/* Exist only under BSD and Linux systems */
+extern int __yp_check (char **) __THROW;
+
+__END_DECLS
+
+#endif	/* __RPCSVC_YPCLNT_H__ */
diff --git a/glibc-compat/shlib-versions b/glibc-compat/shlib-versions
new file mode 100644
index 0000000000..8b0e2e06e2
--- /dev/null
+++ b/glibc-compat/shlib-versions
@@ -0,0 +1,19 @@
+# Interface revision of the compat nss_* modules.
+#
+# This must match NSS_SHLIB_REVISION in nss/nsswitch.h, 
+# which determines the library names used for service
+# names given in /etc/nsswitch.conf.
+alpha.*-.*-linux.*	libnss1_files=1.1
+alpha.*-.*-linux.*	libnss1_dns=1.1
+alpha.*-.*-linux.*	libnss1_db=1.1
+alpha.*-.*-linux.*	libnss1_compat=1.1
+alpha.*-.*-linux.*	libnss1_nis=1.1
+.*-.*-.*		libnss1_files=1
+.*-.*-.*		libnss1_db=1
+.*-.*-.*		libnss1_dns=1
+.*-.*-.*		libnss1_compat=1
+.*-.*-.*		libnss1_nis=1
+
+# The libNoVersion revision number
+.*-.*-.*		libNoVersion=1
+
diff --git a/glibc-compat/stubs.c b/glibc-compat/stubs.c
new file mode 100644
index 0000000000..6c796d1c78
--- /dev/null
+++ b/glibc-compat/stubs.c
@@ -0,0 +1,57 @@
+/*
+ * STAT stuff that breaks Applix
+ */
+
+#include <sys/stat.h>
+
+/* 1 of 3: _xstat */
+int
+_xstat (int vers, const char *name, struct stat *buf)
+{
+    return __xstat (vers, name, buf);
+}
+
+/* 2 of 3: _fxstat */
+int
+_fxstat (int vers, int fd, struct stat *buf)
+{
+    return __fxstat (vers, fd, buf);
+}
+
+/* 3 of 3: _lxstat */
+int
+_lxstat (int vers, const char *name, struct stat *buf)
+{
+    return __lxstat (vers, name, buf);
+}
+
+
+/*
+ * __setjmp stuff that breaks again Applix
+ */
+#include <setjmp.h>
+
+int __setjmp(jmp_buf env)
+{
+    return _setjmp(env);
+}
+
+
+/*
+ * __setfpucw break several math packages that ahve not heard of
+ * the standard _FPU_SETCW() way of setting the control word for the FPU
+ */
+#include <fpu_control.h>
+void __setfpucw(fpu_control_t cw)
+{
+    _FPU_SETCW(cw);
+}
+
+
+/* Register FUNC to be executed by `exit'.  */
+int
+atexit (void (*func) (void))
+{
+  int __cxa_atexit (void (*func) (void *), void *arg, void *d);
+  return __cxa_atexit ((void (*) (void *)) func, 0, 0);
+}