summaryrefslogtreecommitdiff
path: root/glibc-compat
diff options
context:
space:
mode:
authorRoland McGrath <roland@gnu.org>2004-09-22 21:21:10 +0000
committerRoland McGrath <roland@gnu.org>2004-09-22 21:21:10 +0000
commitb5707b44d25d7af61b0338c2a2206c036eaf7337 (patch)
treed8b9e865cbc78d64835a63959370865a2a043223 /glibc-compat
parent4ff389feb39f2eb649530b843d478c80c27ab4cf (diff)
Changes and additions migrated from cvs.devel.redhat.com:/cvs/devel/glibc to fedora-branch
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);
+}