Changes and additions migrated from cvs.devel.redhat.com:/cvs/devel/glibc to fedora...
authorroland <roland>
Wed, 22 Sep 2004 21:20:45 +0000 (21:20 +0000)
committerroland <roland>
Wed, 22 Sep 2004 21:20:45 +0000 (21:20 +0000)
238 files changed:
ChangeLog
ChangeLog.11
ChangeLog.12
c_stubs/Banner [new file with mode: 0644]
c_stubs/COPYING.LIB [new file with mode: 0644]
c_stubs/ChangeLog [new file with mode: 0644]
c_stubs/Makefile [new file with mode: 0644]
c_stubs/README [new file with mode: 0644]
c_stubs/configure [new file with mode: 0755]
c_stubs/gconv_stubs.c [new file with mode: 0644]
c_stubs/test-stdio.c [new file with mode: 0644]
csu/elf-init.c
elf/dl-support.c
elf/ldconfig.c
elf/rtld.c
elf/tst-tls10.h
glibc-compat/.cvsignore [new file with mode: 0644]
glibc-compat/Banner [new file with mode: 0644]
glibc-compat/ChangeLog [new file with mode: 0644]
glibc-compat/Depend [new file with mode: 0644]
glibc-compat/Makefile [new file with mode: 0644]
glibc-compat/Versions [new file with mode: 0644]
glibc-compat/Versions.def [new file with mode: 0644]
glibc-compat/configure [new file with mode: 0755]
glibc-compat/include/aliases.h [new file with mode: 0644]
glibc-compat/include/grp.h [new file with mode: 0644]
glibc-compat/include/netdb.h [new file with mode: 0644]
glibc-compat/include/pwd.h [new file with mode: 0644]
glibc-compat/include/rpc/netdb.h [new file with mode: 0644]
glibc-compat/include/shadow.h [new file with mode: 0644]
glibc-compat/nss-nis.h [new file with mode: 0644]
glibc-compat/nss_compat/compat-grp.c [new file with mode: 0644]
glibc-compat/nss_compat/compat-pwd.c [new file with mode: 0644]
glibc-compat/nss_compat/compat-spwd.c [new file with mode: 0644]
glibc-compat/nss_db/db-XXX.c [new file with mode: 0644]
glibc-compat/nss_db/db-alias.c [new file with mode: 0644]
glibc-compat/nss_db/db-netgrp.c [new file with mode: 0644]
glibc-compat/nss_db/db-open.c [new file with mode: 0644]
glibc-compat/nss_db/dummy-db.h [new file with mode: 0644]
glibc-compat/nss_db/nss_db.h [new file with mode: 0644]
glibc-compat/nss_dns/dns-host.c [new file with mode: 0644]
glibc-compat/nss_dns/dns-network.c [new file with mode: 0644]
glibc-compat/nss_files/files-XXX.c [new file with mode: 0644]
glibc-compat/nss_files/files-alias.c [new file with mode: 0644]
glibc-compat/nss_files/files-ethers.c [new file with mode: 0644]
glibc-compat/nss_files/files-grp.c [new file with mode: 0644]
glibc-compat/nss_files/files-hosts.c [new file with mode: 0644]
glibc-compat/nss_files/files-netgrp.c [new file with mode: 0644]
glibc-compat/nss_files/files-network.c [new file with mode: 0644]
glibc-compat/nss_files/files-parse.c [new file with mode: 0644]
glibc-compat/nss_files/files-proto.c [new file with mode: 0644]
glibc-compat/nss_files/files-pwd.c [new file with mode: 0644]
glibc-compat/nss_files/files-rpc.c [new file with mode: 0644]
glibc-compat/nss_files/files-service.c [new file with mode: 0644]
glibc-compat/nss_files/files-spwd.c [new file with mode: 0644]
glibc-compat/nss_nis/nis-alias.c [new file with mode: 0644]
glibc-compat/nss_nis/nis-ethers.c [new file with mode: 0644]
glibc-compat/nss_nis/nis-grp.c [new file with mode: 0644]
glibc-compat/nss_nis/nis-hosts.c [new file with mode: 0644]
glibc-compat/nss_nis/nis-netgrp.c [new file with mode: 0644]
glibc-compat/nss_nis/nis-network.c [new file with mode: 0644]
glibc-compat/nss_nis/nis-proto.c [new file with mode: 0644]
glibc-compat/nss_nis/nis-pwd.c [new file with mode: 0644]
glibc-compat/nss_nis/nis-rpc.c [new file with mode: 0644]
glibc-compat/nss_nis/nis-service.c [new file with mode: 0644]
glibc-compat/nss_nis/nis-spwd.c [new file with mode: 0644]
glibc-compat/oldfileops.c [new file with mode: 0644]
glibc-compat/oldiofclose.c [new file with mode: 0644]
glibc-compat/oldiofdopen.c [new file with mode: 0644]
glibc-compat/oldiofopen.c [new file with mode: 0644]
glibc-compat/oldiopopen.c [new file with mode: 0644]
glibc-compat/oldpclose.c [new file with mode: 0644]
glibc-compat/oldstdfiles.c [new file with mode: 0644]
glibc-compat/oldtmpfile.c [new file with mode: 0644]
glibc-compat/rpcsvc/yp.h [new file with mode: 0644]
glibc-compat/rpcsvc/ypclnt.h [new file with mode: 0644]
glibc-compat/shlib-versions [new file with mode: 0644]
glibc-compat/stubs.c [new file with mode: 0644]
iconv/iconvconfig.c
iconvdata/gb18030.c
include/features.h
intl/locale.alias
libio/stdio.h
linuxthreads/ChangeLog
linuxthreads/Makefile
linuxthreads/cancel.c
linuxthreads/lockfile.c
linuxthreads/semaphore.h
linuxthreads/sysdeps/alpha/tls.h
linuxthreads/sysdeps/i386/tls.h
linuxthreads/sysdeps/ia64/tls.h
linuxthreads/sysdeps/powerpc/tls.h
linuxthreads/sysdeps/pthread/Makefile
linuxthreads/sysdeps/pthread/nptl-struct-pthread.sym [new file with mode: 0644]
linuxthreads/sysdeps/s390/tls.h
linuxthreads/sysdeps/sh/tls.h
linuxthreads/sysdeps/sparc/tls.h
linuxthreads/sysdeps/x86_64/tls.h
linuxthreads/tst-tls1.h
locale/iso-4217.def
locale/programs/3level.h
localedata/Makefile
localedata/SUPPORTED
localedata/charmaps/GB18030
localedata/locales/cy_GB
localedata/locales/en_GB
localedata/locales/en_US
localedata/locales/no_NO [new file with mode: 0644]
localedata/locales/zh_TW
nptl/ChangeLog
nptl/Makefile
nptl/alloca_cutoff.c
nptl/descr.h
nptl/pthread_cond_destroy.c
nptl/sysdeps/pthread/allocalim.h
nptl/sysdeps/pthread/bits/libc-lock.h
nptl/sysdeps/pthread/bits/sigthread.h
nptl/sysdeps/pthread/pt-initfini.c
nptl/sysdeps/unix/sysv/linux/bits/local_lim.h
nptl/sysdeps/unix/sysv/linux/bits/posix_opt.h
nptl/sysdeps/unix/sysv/linux/i386/bits/posix_opt.h
nptl/sysdeps/unix/sysv/linux/kernel-features.h [new file with mode: 0644]
nptl/tst-unload.c
nscd/Makefile
nscd/connections.c
nscd/nscd.c
nscd/nscd.conf
nscd/nscd_conf.c
rtkaio/Banner [new file with mode: 0644]
rtkaio/ChangeLog [new file with mode: 0644]
rtkaio/Depend [new file with mode: 0644]
rtkaio/Makefile [new file with mode: 0644]
rtkaio/Versions [new file with mode: 0644]
rtkaio/Versions.def [new file with mode: 0644]
rtkaio/aio.h [new file with mode: 0644]
rtkaio/configure [new file with mode: 0644]
rtkaio/kaio_clock_getcpuclockid.c [new file with mode: 0644]
rtkaio/kaio_clock_getres.c [new file with mode: 0644]
rtkaio/kaio_clock_gettime.c [new file with mode: 0644]
rtkaio/kaio_clock_nanosleep.c [new file with mode: 0644]
rtkaio/kaio_clock_settime.c [new file with mode: 0644]
rtkaio/kaio_get_clockfreq.c [new file with mode: 0644]
rtkaio/kaio_shm_open.c [new file with mode: 0644]
rtkaio/kaio_shm_unlink.c [new file with mode: 0644]
rtkaio/kaio_timer_create.c [new file with mode: 0644]
rtkaio/kaio_timer_delete.c [new file with mode: 0644]
rtkaio/kaio_timer_getoverr.c [new file with mode: 0644]
rtkaio/kaio_timer_gettime.c [new file with mode: 0644]
rtkaio/kaio_timer_settime.c [new file with mode: 0644]
rtkaio/shlib-versions [new file with mode: 0644]
rtkaio/sysdeps/pthread/Makefile [new file with mode: 0644]
rtkaio/sysdeps/pthread/kaio_timer_routines.c [new file with mode: 0644]
rtkaio/sysdeps/pthread/librtkaio-cancellation.c [new file with mode: 0644]
rtkaio/sysdeps/pthread/rtkaio-unwind-resume.c [new file with mode: 0644]
rtkaio/sysdeps/pthread/tst-cancel17.c [new file with mode: 0644]
rtkaio/sysdeps/pthread/tst-cancelx17.c [new file with mode: 0644]
rtkaio/sysdeps/pthread/tst-timer.c [new file with mode: 0644]
rtkaio/sysdeps/rtkaio/kaio_cancel.c [new file with mode: 0644]
rtkaio/sysdeps/rtkaio/kaio_error.c [new file with mode: 0644]
rtkaio/sysdeps/rtkaio/kaio_fsync.c [new file with mode: 0644]
rtkaio/sysdeps/rtkaio/kaio_misc.c [new file with mode: 0644]
rtkaio/sysdeps/rtkaio/kaio_notify.c [new file with mode: 0644]
rtkaio/sysdeps/rtkaio/kaio_read.c [new file with mode: 0644]
rtkaio/sysdeps/rtkaio/kaio_read64.c [new file with mode: 0644]
rtkaio/sysdeps/rtkaio/kaio_return.c [new file with mode: 0644]
rtkaio/sysdeps/rtkaio/kaio_sigqueue.c [new file with mode: 0644]
rtkaio/sysdeps/rtkaio/kaio_suspend.c [new file with mode: 0644]
rtkaio/sysdeps/rtkaio/kaio_write.c [new file with mode: 0644]
rtkaio/sysdeps/rtkaio/kaio_write64.c [new file with mode: 0644]
rtkaio/sysdeps/rtkaio/klio_listio.c [new file with mode: 0644]
rtkaio/sysdeps/rtkaio/klio_listio64.c [new file with mode: 0644]
rtkaio/sysdeps/unix/sysv/linux/Implies [new file with mode: 0644]
rtkaio/sysdeps/unix/sysv/linux/alpha/Versions [new file with mode: 0644]
rtkaio/sysdeps/unix/sysv/linux/alpha/kaio_cancel.c [new file with mode: 0644]
rtkaio/sysdeps/unix/sysv/linux/hppa/Versions [new file with mode: 0644]
rtkaio/sysdeps/unix/sysv/linux/hppa/kaio_cancel.c [new file with mode: 0644]
rtkaio/sysdeps/unix/sysv/linux/ia64/Versions [new file with mode: 0644]
rtkaio/sysdeps/unix/sysv/linux/kaio_cancel.c [new file with mode: 0644]
rtkaio/sysdeps/unix/sysv/linux/kaio_error.c [new file with mode: 0644]
rtkaio/sysdeps/unix/sysv/linux/kaio_fsync.c [new file with mode: 0644]
rtkaio/sysdeps/unix/sysv/linux/kaio_misc.c [new file with mode: 0644]
rtkaio/sysdeps/unix/sysv/linux/kaio_misc.h [new file with mode: 0644]
rtkaio/sysdeps/unix/sysv/linux/kaio_notify.c [new file with mode: 0644]
rtkaio/sysdeps/unix/sysv/linux/kaio_read.c [new file with mode: 0644]
rtkaio/sysdeps/unix/sysv/linux/kaio_read64.c [new file with mode: 0644]
rtkaio/sysdeps/unix/sysv/linux/kaio_return.c [new file with mode: 0644]
rtkaio/sysdeps/unix/sysv/linux/kaio_sigqueue.c [new file with mode: 0644]
rtkaio/sysdeps/unix/sysv/linux/kaio_suspend.c [new file with mode: 0644]
rtkaio/sysdeps/unix/sysv/linux/kaio_write.c [new file with mode: 0644]
rtkaio/sysdeps/unix/sysv/linux/kaio_write64.c [new file with mode: 0644]
rtkaio/sysdeps/unix/sysv/linux/klio_listio.c [new file with mode: 0644]
rtkaio/sysdeps/unix/sysv/linux/klio_listio64.c [new file with mode: 0644]
rtkaio/sysdeps/unix/sysv/linux/powerpc/powerpc64/Versions [new file with mode: 0644]
rtkaio/sysdeps/unix/sysv/linux/s390/s390-64/Versions [new file with mode: 0644]
rtkaio/sysdeps/unix/sysv/linux/sparc/Versions [new file with mode: 0644]
rtkaio/sysdeps/unix/sysv/linux/sparc/kaio_cancel.c [new file with mode: 0644]
rtkaio/sysdeps/unix/sysv/linux/x86_64/Versions [new file with mode: 0644]
rtkaio/tst-aio.c [new file with mode: 0644]
rtkaio/tst-aio2.c [new file with mode: 0644]
rtkaio/tst-aio3.c [new file with mode: 0644]
rtkaio/tst-aio4.c [new file with mode: 0644]
rtkaio/tst-aio5.c [new file with mode: 0644]
rtkaio/tst-aio6.c [new file with mode: 0644]
rtkaio/tst-aio64.c [new file with mode: 0644]
rtkaio/tst-aio7.c [new file with mode: 0644]
rtkaio/tst-clock.c [new file with mode: 0644]
rtkaio/tst-clock_nanosleep.c [new file with mode: 0644]
rtkaio/tst-mqueue.h [new file with mode: 0644]
rtkaio/tst-mqueue1.c [new file with mode: 0644]
rtkaio/tst-mqueue2.c [new file with mode: 0644]
rtkaio/tst-mqueue3.c [new file with mode: 0644]
rtkaio/tst-mqueue4.c [new file with mode: 0644]
rtkaio/tst-mqueue5.c [new file with mode: 0644]
rtkaio/tst-mqueue6.c [new file with mode: 0644]
rtkaio/tst-mqueue7.c [new file with mode: 0644]
rtkaio/tst-shm.c [new file with mode: 0644]
rtkaio/tst-timer2.c [new file with mode: 0644]
rtkaio/tst-timer3.c [new file with mode: 0644]
rtkaio/tst-timer4.c [new file with mode: 0644]
sysdeps/generic/dl-cache.h
sysdeps/i386/bits/atomic.h [new file with mode: 0644]
sysdeps/ia64/Makefile
sysdeps/ia64/ia64libgcc.S
sysdeps/ia64/libgcc-compat.c [new file with mode: 0644]
sysdeps/unix/alpha/sysdep.h
sysdeps/unix/nice.c
sysdeps/unix/sysv/linux/i386/dl-cache.h [new file with mode: 0644]
sysdeps/unix/sysv/linux/ia64/dl-cache.h
sysdeps/unix/sysv/linux/ia64/dl-procinfo.c [new file with mode: 0644]
sysdeps/unix/sysv/linux/ia64/dl-procinfo.h [new file with mode: 0644]
sysdeps/unix/sysv/linux/ia64/ldd-rewrite.sed
sysdeps/unix/sysv/linux/paths.h
sysdeps/unix/sysv/linux/s390/s390-32/sysdep.h
sysdeps/unix/sysv/linux/s390/s390-64/sysdep.h
sysdeps/unix/sysv/linux/sparc/sparc32/setresgid.c [deleted file]
sysdeps/unix/sysv/linux/sparc/sparc32/setresuid.c [deleted file]
sysdeps/unix/sysv/linux/sparc/sysdep.h
sysdeps/unix/sysv/linux/tcsetattr.c

index 027a8c5..8113142 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,7 +1,18 @@
-2004-09-22  Ulrich Drepper  <drepper@redhat.com>
+2004-09-20  Jakub Jelinek  <jakub@redhat.com>
 
-       * string/string.h: Add __nonnull annotations.
-       * stdlib/stdlib.h: Likewise.
+       * sysdeps/unix/alpha/sysdep.h (inline_syscall[0-6]): Change name
+       argument to numbers from syscall names.
+       (INLINE_SYSCALL1): Pass __NR_##name to inline_syscall##nr.
+       (INTERNAL_SYSCALL_NCS): Renamed from...
+       (INTERNAL_SYSCALL_1): ... this.  Use INTERNAL_SYSCALL_NCS.
+       * sysdeps/unix/sysv/linux/s390/s390-32/sysdep.h
+       (INTERNAL_SYSCALL_NCS): Define.
+       * sysdeps/unix/sysv/linux/s390/s390-64/sysdep.h
+       (INTERNAL_SYSCALL_NCS): Likewise.
+       * sysdeps/unix/sysv/linux/sparc/sysdep.h (inline_syscall[0-6]):
+       Change name argument to numbers from syscall names.
+       (INLINE_SYSCALL, INTERNAL_SYSCALL): Adjust.
+       (INTERNAL_SYSCALL_NCS): Define.
 
 2004-09-20  H.J. Lu  <hongjiu.lu@intel.com>
 
        before return type.
        * locale/localename.c (__current_locale_name): Likewise.
 
+2004-08-31  Jakub Jelinek  <jakub@redhat.com>
+
+       * elf/ldconfig.c (parse_conf): Add prefix argument, prepend it
+       before arguments to add_dir and pass to parse_conf_include.
+       (parse_conf_include): Add prefix argument, pass it down to
+       parse_conf.
+       (main): Call arch_startup.  Adjust parse_conf caller.
+       Call add_arch_dirs.
+       * sysdeps/generic/dl-cache.h (arch_startup, add_arch_dirs): Define.
+       * sysdeps/unix/sysv/linux/i386/dl-cache.h: New file.
+       * sysdeps/unix/sysv/linux/ia64/dl-cache.h (EMUL_HACK, arch_startup,
+       add_arch_dirs): Define.
+       * sysdeps/unix/sysv/linux/ia64/ldd-rewrite.sed: Prepend
+       /emul/ia32-linux before the 32-bit ld.so pathname.
+       * sysdeps/unix/sysv/linux/ia64/dl-procinfo.c: New file.
+       * sysdeps/unix/sysv/linux/ia64/dl-procinfo.h: New file.
+
 2004-08-30  Roland McGrath  <roland@frob.com>
 
        * scripts/extract-abilist.awk: If `lastversion' variable defined, omit
        * resolv/nss_dns/dns-canon.c (_nss_dns_getcanonname_r): Initialize
        status to NSS_STATUS_UNAVAIL.
 
+2004-08-19  Jakub Jelinek  <jakub@redhat.com>
+
+       * sysdeps/powerpc/powerpc64/configure.in: New file.
+       * sysdeps/powerpc/powerpc64/configure: Rebuilt.
+       * config.h.in (USE_PPC64_OVERLAPPING_OPD): Add.
+       * configure.in (HAVE_ASM_GLOBAL_DOT_NAME): Remove.
+       * configure: Rebuilt.
+       * sysdeps/powerpc/powerpc64/sysdep.h: Formatting.
+       (OPD_ENT, BODY_LABEL, ENTRY_1, ENTRY_2, END_2, DOT_PREFIX,
+       BODY_PREFIX): Define.
+       (ENTRY, DOT_LABEL, END, TRACEBACK, END_GEN_TB, EALIGN): Support
+       HAVE_ASM_GLOBAL_DOT_NAME or no dot symbols,
+       USE_PPC64_OVERLAPPING_OPD or never overlapping .opd entries.
+       * sysdeps/powerpc/powerpc64/dl-machine.h: Include sysdep.h.
+       (TRAMPOLINE_TEMPLATE, RTLD_START): Use the new sysdep.h macros.
+
 2004-08-19  Ulrich Drepper  <drepper@redhat.com>
 
        * sysdeps/posix/getaddrinfo.c (gaih_inet): Use h->h_name in the
 
        * iconvdata/testdata/ISO-2022-JP-3: Regenerated.
 
+2004-07-23  Jakub Jelinek  <jakub@redhat.com>
+
+       [BZ #284]
+       * include/features.h (_POSIX_SOURCE, _POSIX_C_SOURCE): Define
+       if _XOPEN_SOURCE >= 500 even if __STRICT_ANSI__ is defined.
+
 2004-08-10  Alfred M. Szmidt  <ams@kemisten.nu>
 
        * sysdeps/generic/bits/in.h (struct ip_mreq): Remove definition.
index d9b0364..f2f274f 100644 (file)
        * sysdeps/unix/sysv/linux/mips/sys/tas.h: Add missing .mips0 at the
        end of inline assembler code.
 
+2000-10-02  Jakub Jelinek  <jakub@redhat.com>
+
+       * sunrpc/svc_udp.c (svcudp_recv): Set msg_controllen to all
+       remaining xp_pad space.
+
 2000-10-02  Ulrich Drepper  <drepper@redhat.com>
 
        * include/features.h [__USE_FILE_OFFSET && !__REDIRECT]: Define
        syscall.
        * sysdeps/unix/sysv/linux/mips/truncate64.c: Likewise.
 
+2000-05-30  Jakub Jelinek  <jakub@redhat.com>
+
+       * resolv/res_query.c (res_nsearch): Remove unused variable
+       root_on_list. If dots >= statp->ndots and as is querydomain
+       fails, keep searching.
+
 2000-05-30  Ulrich Drepper  <drepper@redhat.com>
 
        * sysdeps/unix/sysv/linux/alpha/oldglob.c (__old_glob): Loose __P.
        * sysdeps/i386/fpu/bits/mathinline.h: Define expm1 inline only if
        __FAST_MATH__ is defined.
 
+2000-05-22  Jakub Jelinek  <jakub@redhat.com>
+
+       * sysdeps/i386/fpu/bits/mathinline.h (__expm1_code): Avoid using ?:
+       with omitted middle operand.
+
 2000-05-22  Andreas Jaeger  <aj@suse.de>
 
        * math/Makefile: Add -D__FAST_MATH__ to CFLAGS-test-ifloat.c,
 
 2000-05-17  Jakub Jelinek  <jakub@redhat.com>
 
+       * inet/rcmd.c (rcmd_af): If *ahost cannot be resolved, include
+       unresolved hostname in the message.
+
+2000-05-17  Jakub Jelinek  <jakub@redhat.com>
+
        * sysdeps/arm/bits/huge_val.h (HUGE_VAL, HUGE_VALF): Add
        __extension__ to hexadecimal floating constant notation.
        * sysdeps/i386/bits/huge_val.h (HUGE_VAL, HUGE_VALF, HUGE_VALL):
index 2a4620e..9f1981e 100644 (file)
 
        * Versions.def [ld]: Add GLIBC_2.2.1.
 
+2001-01-10  Jakub Jelinek  <jakub@redhat.com>
+
+       * malloc/memusage.c (me): If not SUID/SGID, allow creating new
+       $MEMUSAGE_OUTPUT file.
+       * sysdeps/generic/segfault.c (segfault.c): If not SUID/SGID, allow
+       creating new $SEGFAULT_OUTPUT_NAME file.
+
 2001-01-10  H.J. Lu  <hjl@gnu.org>
 
        * elf/dl-libc.c (do_dlopen): Call DL_STATIC_INIT for static binaries.
        * sysdeps/powerpc/soft-fp/Versions: Likewise.
        * sysdeps/sparc/sparc64/soft-fp/Versions: Likewise.
 
+2001-01-02  Jakub Jelinek  <jakub@redhat.com>
+
+       * locale/setlocale.c (setlocale): Don't allocate/free category name
+       unnecessarily.
+
 2001-01-02  Franz Sirl <Franz.Sirl-kernel@lauterbach.com>
 
        * sysdeps/powerpc/dl-machine.c (__process_machine_rela): Fix typo.
diff --git a/c_stubs/Banner b/c_stubs/Banner
new file mode 100644 (file)
index 0000000..0e1b60a
--- /dev/null
@@ -0,0 +1 @@
+The C stubs add-on version 2.1.2.
diff --git a/c_stubs/COPYING.LIB b/c_stubs/COPYING.LIB
new file mode 100644 (file)
index 0000000..161a3d1
--- /dev/null
@@ -0,0 +1,482 @@
+                 GNU LIBRARY GENERAL PUBLIC LICENSE
+                      Version 2, June 1991
+
+ Copyright (C) 1991 Free Software Foundation, Inc.
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the library GPL.  It is
+ numbered 2 because it goes with version 2 of the ordinary GPL.]
+
+                           Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+  This license, the Library General Public License, applies to some
+specially designated Free Software Foundation software, and to any
+other libraries whose authors decide to use it.  You can use it for
+your libraries, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if
+you distribute copies of the library, or if you modify it.
+
+  For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you.  You must make sure that they, too, receive or can get the source
+code.  If you link a program with the library, you must provide
+complete object files to the recipients so that they can relink them
+with the library, after making changes to the library and recompiling
+it.  And you must show them these terms so they know their rights.
+
+  Our method of protecting your rights has two steps: (1) copyright
+the library, and (2) offer you this license which gives you legal
+permission to copy, distribute and/or modify the library.
+
+  Also, for each distributor's protection, we want to make certain
+that everyone understands that there is no warranty for this free
+library.  If the library is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original
+version, so that any problems introduced by others will not reflect on
+the original authors' reputations.
+\f
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that companies distributing free
+software will individually obtain patent licenses, thus in effect
+transforming the program into proprietary software.  To prevent this,
+we have made it clear that any patent must be licensed for everyone's
+free use or not licensed at all.
+
+  Most GNU software, including some libraries, is covered by the ordinary
+GNU General Public License, which was designed for utility programs.  This
+license, the GNU Library General Public License, applies to certain
+designated libraries.  This license is quite different from the ordinary
+one; be sure to read it in full, and don't assume that anything in it is
+the same as in the ordinary license.
+
+  The reason we have a separate public license for some libraries is that
+they blur the distinction we usually make between modifying or adding to a
+program and simply using it.  Linking a program with a library, without
+changing the library, is in some sense simply using the library, and is
+analogous to running a utility program or application program.  However, in
+a textual and legal sense, the linked executable is a combined work, a
+derivative of the original library, and the ordinary General Public License
+treats it as such.
+
+  Because of this blurred distinction, using the ordinary General
+Public License for libraries did not effectively promote software
+sharing, because most developers did not use the libraries.  We
+concluded that weaker conditions might promote sharing better.
+
+  However, unrestricted linking of non-free programs would deprive the
+users of those programs of all benefit from the free status of the
+libraries themselves.  This Library General Public License is intended to
+permit developers of non-free programs to use free libraries, while
+preserving your freedom as a user of such programs to change the free
+libraries that are incorporated in them.  (We have not seen how to achieve
+this as regards changes in header files, but we have achieved it as regards
+changes in the actual functions of the Library.)  The hope is that this
+will lead to faster development of free libraries.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.  Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library".  The
+former contains code derived from the library, while the latter only
+works together with the library.
+
+  Note that it is possible for a library to be covered by the ordinary
+General Public License rather than by this special one.
+\f
+                 GNU LIBRARY GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any software library which
+contains a notice placed by the copyright holder or other authorized
+party saying it may be distributed under the terms of this Library
+General Public License (also called "this License").  Each licensee is
+addressed as "you".
+
+  A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+  The "Library", below, refers to any such software library or work
+which has been distributed under these terms.  A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language.  (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+  "Source code" for a work means the preferred form of the work for
+making modifications to it.  For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+  Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it).  Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+  
+  1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+  You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+\f
+  2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) The modified work must itself be a software library.
+
+    b) You must cause the files modified to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    c) You must cause the whole of the work to be licensed at no
+    charge to all third parties under the terms of this License.
+
+    d) If a facility in the modified Library refers to a function or a
+    table of data to be supplied by an application program that uses
+    the facility, other than as an argument passed when the facility
+    is invoked, then you must make a good faith effort to ensure that,
+    in the event an application does not supply such function or
+    table, the facility still operates, and performs whatever part of
+    its purpose remains meaningful.
+
+    (For example, a function in a library to compute square roots has
+    a purpose that is entirely well-defined independent of the
+    application.  Therefore, Subsection 2d requires that any
+    application-supplied function or table used by this function must
+    be optional: if the application does not supply it, the square
+    root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library.  To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License.  (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.)  Do not make any other change in
+these notices.
+\f
+  Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+  This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+  4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+  If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library".  Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+  However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library".  The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+  When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library.  The
+threshold for this to be true is not precisely defined by law.
+
+  If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work.  (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+  Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+\f
+  6. As an exception to the Sections above, you may also compile or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+  You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License.  You must supply a copy of this License.  If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License.  Also, you must do one
+of these things:
+
+    a) Accompany the work with the complete corresponding
+    machine-readable source code for the Library including whatever
+    changes were used in the work (which must be distributed under
+    Sections 1 and 2 above); and, if the work is an executable linked
+    with the Library, with the complete machine-readable "work that
+    uses the Library", as object code and/or source code, so that the
+    user can modify the Library and then relink to produce a modified
+    executable containing the modified Library.  (It is understood
+    that the user who changes the contents of definitions files in the
+    Library will not necessarily be able to recompile the application
+    to use the modified definitions.)
+
+    b) Accompany the work with a written offer, valid for at
+    least three years, to give the same user the materials
+    specified in Subsection 6a, above, for a charge no more
+    than the cost of performing this distribution.
+
+    c) If distribution of the work is made by offering access to copy
+    from a designated place, offer equivalent access to copy the above
+    specified materials from the same place.
+
+    d) Verify that the user has already received a copy of these
+    materials or that you have already sent this user a copy.
+
+  For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it.  However, as a special exception,
+the source code distributed need not include anything that is normally
+distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+  It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system.  Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+\f
+  7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+    a) Accompany the combined library with a copy of the same work
+    based on the Library, uncombined with any other library
+    facilities.  This must be distributed under the terms of the
+    Sections above.
+
+    b) Give prominent notice with the combined library of the fact
+    that part of it is a work based on the Library, and explaining
+    where to find the accompanying uncombined form of the same work.
+
+  8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License.  Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License.  However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+  9. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Library or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+  10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+\f
+  11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded.  In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+  13. The Free Software Foundation may publish revised and/or new
+versions of the Library General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation.  If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+\f
+  14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission.  For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this.  Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+                           NO WARRANTY
+
+  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+                    END OF TERMS AND CONDITIONS
+\f
+     Appendix: How to Apply These Terms to Your New Libraries
+
+  If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change.  You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+  To apply these terms, attach the following notices to the library.  It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the library's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    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., 59 Temple Place - Suite 330, Boston,
+    MA 02111-1307, USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
+  library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+  <signature of Ty Coon>, 1 April 1990
+  Ty Coon, President of Vice
+
+That's all there is to it!
diff --git a/c_stubs/ChangeLog b/c_stubs/ChangeLog
new file mode 100644 (file)
index 0000000..b4fda90
--- /dev/null
@@ -0,0 +1,42 @@
+2001-08-07  Jakub Jelinek  <jakub@redhat.com>
+
+       * gconv_stubs.c (__gconv_lookup_alias): Remove.
+       (__gconv_NOOP, __gconv_compare_alias, __gconv_release_cache,
+       __gconv_release_step): New.
+
+2001-06-07  Jakub Jelinek  <jakub@redhat.com>
+
+       * gconv_stubs.c (__gconv_lookup_alias): New.
+
+2000-02-27  Cristian Gafton  <gafton@redhat.com>
+
+       * gconv_stubs.c: Return __gconv_OK for:
+       __gconv_transform_ascii_internal
+       __gconv_transform_ucs2little_internal
+       __gconv_transform_utf16_internal
+       __gconv_transform_utf8_internal
+       __gconv_transform_ucs2_internal
+
+2000-02-25  Cristian Gafton  <gafton@redhat.com>
+
+       * gconv_stubs.c: add __c_stubs_is_compiled_in so we can detect when
+       the library is linked in.
+
+Wed Dec  8 13:47:25 1999  Ivan Brunello <ivan.brunello@tiscalinet.it>
+
+       * Makefile (extra-objs): Changed stubs.o to gconv_stubs.o.
+
+Sun Dec  5 11:32:17 1999  H.J. Lu  <hjl@gnu.org>
+
+       * gconv_stubs.c: Renamed from stubs.c.
+       Support glibc 2.1.x.
+
+Mon Aug 23 16:42:05 1999  H.J. Lu  <hjl@gnu.org>
+
+       * Banner: New.
+       * COPYING.LIB: Likewise.
+       * Makefile: Likewise.
+       * README: Likewise.
+       * configure: Likewise.
+       * stubs.c: Likewise.
+       * test-stdio.c: Likewise.
diff --git a/c_stubs/Makefile b/c_stubs/Makefile
new file mode 100644 (file)
index 0000000..0b8da7c
--- /dev/null
@@ -0,0 +1,46 @@
+# Copyright (C) 1999 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.
+
+#
+#      Sub-makefile for the C stub add-on library.
+#
+subdir := c_stubs
+
+tests-static := test-stdio
+tests := $(tests-static)
+
+libc_stubs-objs := gconv_stubs.o
+
+install-lib := libc_stubs.a
+non-lib.a := libc_stubs.a
+
+extra-objs := gconv_stubs.o libc_stubs.a
+
+include ../Makeconfig
+
+CPPFLAGS += -I../iconv
+
+include ../Rules
+
+$(objpfx)libc_stubs.a: $(addprefix $(objpfx), $(libc_stubs-objs))
+       -rm -f $@
+       $(CC) -nostdlib -nostartfiles -r -o $@ $^
+
+lib: $(objpfx)libc_stubs.a
+
+$(objpfx)test-stdio: $(objpfx)libc_stubs.a
diff --git a/c_stubs/README b/c_stubs/README
new file mode 100644 (file)
index 0000000..9567ff8
--- /dev/null
@@ -0,0 +1,8 @@
+This is a stub add-on library for the GNU C library version 2.1.2 and
+above. It is used to create the smaller static binaries by stubbing
+out the gconv related functions. The resulting binaries may not have
+all the functionalities.
+
+H.J. Lu
+hjl@gnu.org
+12/05/1999
diff --git a/c_stubs/configure b/c_stubs/configure
new file mode 100755 (executable)
index 0000000..53d0dcd
--- /dev/null
@@ -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/c_stubs/gconv_stubs.c b/c_stubs/gconv_stubs.c
new file mode 100644 (file)
index 0000000..f4c0b66
--- /dev/null
@@ -0,0 +1,126 @@
+/* Provide gconv stub functions for the minimum static binaries.
+   Copyright (C) 1999, 2001, 2003, 2004 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 <features.h>
+#include <string.h>
+#include <wchar.h>
+#include <bits/libc-lock.h>
+#if __GNUC_PREREQ(3, 3)
+# include <gconv_int.h>
+#else
+# include <gconv.h>
+#endif
+
+__libc_lock_define_initialized (, __gconv_lock)
+
+/* hack for self identification */
+int __c_stubs_is_compiled_in;
+
+/* Don't drag in the dynamic linker. */
+void *__libc_stack_end;
+
+int attribute_hidden
+__gconv_OK (void)
+{
+#if __GLIBC__ > 2 || __GLIBC_MINOR__ > 1
+  return __GCONV_OK;
+#else
+  return GCONV_OK;
+#endif
+}
+
+int attribute_hidden
+__gconv_NOCONV (void)
+{
+#if __GLIBC__ > 2 || __GLIBC_MINOR__ > 1
+  return __GCONV_NOCONV;
+#else
+  return GCONV_NOCONV;
+#endif
+}
+
+void attribute_hidden
+__gconv_NOOP (void)
+{
+}
+
+int
+internal_function
+__gconv_compare_alias (const char *name1, const char *name2)
+{
+  return strcmp (name1, name2);
+}
+
+wint_t
+__gconv_btwoc_ascii (struct __gconv_step *step, unsigned char c)
+{
+  if (c < 0x80)
+    return c;
+  else
+    return WEOF;
+}
+
+
+#if __GNUC_PREREQ(3, 3)
+# undef strong_alias
+# define strong_alias(impl, name) \
+  __typeof (name) name __attribute__ ((alias (#impl)))
+#endif
+
+strong_alias (__gconv_OK,
+             __gconv_close_transform);
+strong_alias (__gconv_OK,
+             __gconv_close);
+
+strong_alias (__gconv_NOCONV,
+             __gconv);
+strong_alias (__gconv_NOCONV,
+             __gconv_find_transform);
+strong_alias (__gconv_NOCONV,
+             __gconv_open);
+
+/* These transformations should not fail in normal conditions */
+strong_alias (__gconv_OK,
+             __gconv_transform_ascii_internal);
+strong_alias (__gconv_OK,
+             __gconv_transform_utf16_internal);
+strong_alias (__gconv_OK,
+             __gconv_transform_utf8_internal);
+strong_alias (__gconv_OK,
+             __gconv_transform_ucs2_internal);
+
+/* We can assume no conversion for these ones */
+strong_alias (__gconv_NOCONV,
+             __gconv_transform_internal_ascii);
+strong_alias (__gconv_NOCONV,
+             __gconv_transform_internal_ucs2);
+strong_alias (__gconv_NOCONV,
+             __gconv_transform_internal_ucs4);
+strong_alias (__gconv_NOCONV,
+             __gconv_transform_internal_utf16);
+strong_alias (__gconv_NOCONV,
+             __gconv_transform_internal_utf8);
+
+strong_alias (__gconv_NOCONV,
+             __gconv_transliterate);
+
+strong_alias (__gconv_NOOP,
+             __gconv_release_cache);
+strong_alias (__gconv_NOOP,
+             __gconv_release_step);
diff --git a/c_stubs/test-stdio.c b/c_stubs/test-stdio.c
new file mode 100644 (file)
index 0000000..8f4ea6d
--- /dev/null
@@ -0,0 +1,8 @@
+#include <stdio.h>
+
+int
+main (void)
+{
+  printf ("Hello world\n");
+  return 0;
+}
index d4e0b3f..c538627 100644 (file)
@@ -44,6 +44,24 @@ extern void (*__init_array_start []) (void) attribute_hidden;
 extern void (*__init_array_end []) (void) attribute_hidden;
 extern void (*__fini_array_start []) (void) attribute_hidden;
 extern void (*__fini_array_end []) (void) attribute_hidden;
+
+# if defined HAVE_VISIBILITY_ATTRIBUTE \
+     && (defined SHARED || defined LIBC_NONSHARED)
+#  define hidden_undef_2(x) #x
+#  define hidden_undef_1(x) hidden_undef_2 (x)
+#  define hidden_undef(x) \
+  __asm (hidden_undef_1 (ASM_GLOBAL_DIRECTIVE) " " #x); \
+  __asm (".hidden " #x);
+# else
+#  define hidden_undef(x)
+# endif
+
+hidden_undef (__preinit_array_start)
+hidden_undef (__preinit_array_end)
+hidden_undef (__init_array_start)
+hidden_undef (__init_array_end)
+hidden_undef (__fini_array_start)
+hidden_undef (__fini_array_end)
 #endif
 
 /* These function symbols are provided for the .init/.fini section entry
index 2b53770..e3df749 100644 (file)
@@ -287,6 +287,11 @@ _dl_non_dynamic_init (void)
   if (_dl_platform != NULL)
     _dl_platformlen = strlen (_dl_platform);
 
+#if defined (__i386__) && !defined (USE_TLS)
+  /* Load libs not using TLS.  */
+  _dl_osversion = 0x20205;
+#endif
+
   /* Scan for a program header telling us the stack is nonexecutable.  */
   if (_dl_phdr != NULL)
     for (uint_fast16_t i = 0; i < _dl_phnum; ++i)
index aab52b7..f8504fb 100644 (file)
@@ -944,17 +944,19 @@ search_dirs (void)
 
 
 static void parse_conf_include (const char *config_file, unsigned int lineno,
-                               bool do_chroot, const char *pattern);
+                               const char *prefix, bool do_chroot,
+                               const char *pattern);
 
 /* Parse configuration file.  */
 static void
-parse_conf (const char *filename, bool do_chroot)
+parse_conf (const char *filename, const char *prefix, bool do_chroot)
 {
   FILE *file = NULL;
   char *line = NULL;
   const char *canon;
   size_t len = 0;
   unsigned int lineno;
+  size_t prefix_len = prefix ? strlen (prefix) : 0;
 
   if (do_chroot && opt_chroot)
     {
@@ -1015,7 +1017,14 @@ parse_conf (const char *filename, bool do_chroot)
          cp += 8;
          while ((dir = strsep (&cp, " \t")) != NULL)
            if (dir[0] != '\0')
-             parse_conf_include (filename, lineno, do_chroot, dir);
+             parse_conf_include (filename, lineno, prefix, do_chroot, dir);
+       }
+      else if (prefix != NULL)
+       {
+         size_t cp_len = strlen (cp);
+         char new_cp [prefix_len + cp_len + 1];
+         memcpy (mempcpy (new_cp, prefix, prefix_len), cp, cp_len + 1);
+         add_dir (new_cp);
        }
       else
        add_dir (cp);
@@ -1031,7 +1040,7 @@ parse_conf (const char *filename, bool do_chroot)
    config files to read.  */
 static void
 parse_conf_include (const char *config_file, unsigned int lineno,
-                   bool do_chroot, const char *pattern)
+                   const char *prefix, bool do_chroot, const char *pattern)
 {
   if (opt_chroot && pattern[0] != '/')
     error (EXIT_FAILURE, 0,
@@ -1061,7 +1070,7 @@ parse_conf_include (const char *config_file, unsigned int lineno,
     {
     case 0:
       for (size_t i = 0; i < gl.gl_pathc; ++i)
-       parse_conf (gl.gl_pathv[i], false);
+       parse_conf (gl.gl_pathv[i], prefix, false);
       globfree64 (&gl);
       break;
 
@@ -1101,6 +1110,8 @@ main (int argc, char **argv)
 {
   int remaining;
 
+  arch_startup (argc, argv);
+
   /* Parse and process arguments.  */
   argp_parse (&argp, argc, argv, 0, &remaining, NULL);
 
@@ -1209,12 +1220,14 @@ main (int argc, char **argv)
 
   if (!opt_only_cline)
     {
-      parse_conf (config_file, true);
+      parse_conf (config_file, NULL, true);
 
       /* Always add the standard search paths.  */
       add_system_dir (SLIBDIR);
       if (strcmp (SLIBDIR, LIBDIR))
        add_system_dir (LIBDIR);
+
+      add_arch_dirs (config_file);
     }
 
   search_dirs ();
index 2daf05a..b912124 100644 (file)
@@ -1077,6 +1077,49 @@ of this helper program; chances are you did not intend to run this program.\n\
   ++GL(dl_nloaded);
   ++GL(dl_load_adds);
 
+#if defined(__i386__)
+  /* Force non-TLS libraries for glibc 2.0 binaries
+     or if a buggy binary references non-TLS errno or h_errno.  */
+  if (__builtin_expect (GL(dl_loaded)->l_info[DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGIDX (DT_VERNEED)] == NULL, 0)
+      && GL(dl_loaded)->l_info[DT_DEBUG])
+    GLRO(dl_osversion) = 0x20205;
+  else if ((__builtin_expect (mode, normal) != normal
+           || GL(dl_loaded)->l_info [ADDRIDX (DT_GNU_LIBLIST)] == NULL)
+             /* Only binaries have DT_DEBUG dynamic tags...  */
+          && GL(dl_loaded)->l_info[DT_DEBUG])
+    {
+      /* Workaround for buggy binaries.  This doesn't handle buggy
+        libraries.  */
+      bool buggy = false;
+      const ElfW(Sym) *symtab = (const void *) D_PTR (GL(dl_loaded), l_info[DT_SYMTAB]);
+      const char *strtab = (const void *) D_PTR (GL(dl_loaded), l_info[DT_STRTAB]);
+      Elf_Symndx symidx;
+      for (symidx = GL(dl_loaded)->l_buckets[0x6c994f % GL(dl_loaded)->l_nbuckets];
+          symidx != STN_UNDEF;
+          symidx = GL(dl_loaded)->l_chain[symidx])
+       {
+         if (__builtin_expect (strcmp (strtab + symtab[symidx].st_name,
+                                       "errno") == 0, 0)
+             && ELFW(ST_TYPE) (symtab[symidx].st_info) != STT_TLS)
+           buggy = true;
+       }
+      for (symidx = GL(dl_loaded)->l_buckets[0xe5c992f % GL(dl_loaded)->l_nbuckets];
+          symidx != STN_UNDEF;
+          symidx = GL(dl_loaded)->l_chain[symidx])
+       {
+         if (__builtin_expect (strcmp (strtab + symtab[symidx].st_name,
+                                       "h_errno") == 0, 0)
+             && ELFW(ST_TYPE) (symtab[symidx].st_info) != STT_TLS)
+           buggy = true;
+       }
+      if (__builtin_expect (buggy, false) && GLRO(dl_osversion) > 0x20401)
+       {
+         GLRO(dl_osversion) = 0x20401;
+         _dl_error_printf ("Incorrectly built binary which accesses errno or h_errno directly. Needs to be fixed.\n");
+       }
+    }
+#endif
+
   /* If LD_USE_LOAD_BIAS env variable has not been seen, default
      to not using bias for non-prelinked PIEs and libraries
      and using it for executables or prelinked PIEs or libraries.  */
@@ -1247,6 +1290,64 @@ ERROR: ld.so: object '%s' from %s cannot be preloaded: ignored.\n",
        }
     }
 
+
+#if defined(__i386__) || defined(__alpha__) || (defined(__sparc__) && !defined(__arch64__))
+  /*
+   * Modifications by Red Hat Software
+   *
+   * Deal with the broken binaries from the non-versioned ages of glibc.
+   * If a binary does not have version information enabled, we assume that
+   * it is a glibc 2.0 binary and we load a compatibility library to try to
+   * overcome binary incompatibilities.
+   *                   Blame: gafton@redhat.com
+   */
+#define LIB_NOVERSION "/lib/libNoVersion.so.1"
+
+  if (__builtin_expect (GL(dl_loaded)->l_info[DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGIDX (DT_VERNEED)] == NULL, 0)
+      && (GL(dl_loaded)->l_info[DT_DEBUG] || !(GLRO(dl_debug_mask) & DL_DEBUG_PRELINK)))
+    {
+      struct stat test_st;
+      int test_fd;
+      int can_load;
+      
+      HP_TIMING_NOW (start);
+          
+/*       _dl_sysdep_message("Loading compatibility library... ", NULL); */
+
+      can_load = 1;
+      test_fd = __open (LIB_NOVERSION, O_RDONLY);
+      if (test_fd < 0) {
+         can_load = 0;
+/*       _dl_sysdep_message(" Can't find " LIB_NOVERSION "\n",  NULL); */
+      } else {
+         if (__fxstat (_STAT_VER, test_fd, &test_st) < 0 || test_st.st_size == 0) {
+             can_load = 0;
+/*           _dl_sysdep_message(" Can't stat " LIB_NOVERSION "\n",  NULL); */
+         }
+      }
+      
+      if (test_fd >= 0) /* open did no fail.. */
+         __close(test_fd); /* avoid fd leaks */
+
+      if (can_load != 0) {
+         struct link_map *new_map;
+         new_map = _dl_map_object (GL(dl_loaded), LIB_NOVERSION,
+                                   1, lt_library, 0, 0);
+         if (++new_map->l_opencount == 1) {
+             /* It is no duplicate.  */
+             ++npreloads;
+/*           _dl_sysdep_message(" DONE\n", NULL); */
+         } else {
+/*           _dl_sysdep_message(" FAILED\n", NULL); */
+         }
+      }
+         
+      HP_TIMING_NOW (stop);
+      HP_TIMING_DIFF (diff, start, stop);
+      HP_TIMING_ACCUM_NT (load_time, diff);
+    }
+#endif
+
   if (__builtin_expect (npreloads, 0) != 0)
     {
       /* Set up PRELOADS with a vector of the preloaded libraries.  */
index 1be6adc..6133209 100644 (file)
@@ -1,8 +1,8 @@
 #include <tls.h>
 #include <stdlib.h>
 
-#if defined USE_TLS && defined HAVE___THREAD \
-    && defined HAVE_TLS_MODEL_ATTRIBUTE
+#if defined USE_TLS \
+    && (0 || (defined HAVE___THREAD && defined HAVE_TLS_MODEL_ATTRIBUTE))
 # define USE_TLS__THREAD
 
 struct A
diff --git a/glibc-compat/.cvsignore b/glibc-compat/.cvsignore
new file mode 100644 (file)
index 0000000..6eaa1d3
--- /dev/null
@@ -0,0 +1 @@
+glibc-compat*.tar.gz
diff --git a/glibc-compat/Banner b/glibc-compat/Banner
new file mode 100644 (file)
index 0000000..7d4bde6
--- /dev/null
@@ -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 (file)
index 0000000..e61c488
--- /dev/null
@@ -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 (file)
index 0000000..89d8e5b
--- /dev/null
@@ -0,0 +1,3 @@
+resolv
+nss
+nis
diff --git a/glibc-compat/Makefile b/glibc-compat/Makefile
new file mode 100644 (file)
index 0000000..8c60483
--- /dev/null
@@ -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 (file)
index 0000000..354d5b6
--- /dev/null
@@ -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 (file)
index 0000000..742eda0
--- /dev/null
@@ -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 (executable)
index 0000000..53d0dcd
--- /dev/null
@@ -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 (file)
index 0000000..3932e52
--- /dev/null
@@ -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 (file)
index 0000000..aba77c6
--- /dev/null
@@ -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 (file)
index 0000000..85ab234
--- /dev/null
@@ -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 (file)
index 0000000..a0e94e6
--- /dev/null
@@ -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 (file)
index 0000000..54a4b70
--- /dev/null
@@ -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 (file)
index 0000000..e9429d7
--- /dev/null
@@ -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 (file)
index 0000000..13ba62e
--- /dev/null
@@ -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 (file)
index 0000000..d0780c4
--- /dev/null
@@ -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 (file)
index 0000000..5857bf9
--- /dev/null
@@ -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 (file)
index 0000000..2c33d80
--- /dev/null
@@ -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 (file)
index 0000000..8c05829
--- /dev/null
@@ -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)
+\f
+/* 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;
+}
+\f
+/* 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)
+\f
+
+
+
+/* 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 (file)
index 0000000..b9b9489
--- /dev/null
@@ -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)
+\f
+/* 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;
+}
+\f
+/* 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;
+}
+\f
+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 (file)
index 0000000..7330907
--- /dev/null
@@ -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)
+\f
+/* 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 (file)
index 0000000..99ff303
--- /dev/null
@@ -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 (file)
index 0000000..aed8462
--- /dev/null
@@ -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 (file)
index 0000000..0bd98b5
--- /dev/null
@@ -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 (file)
index 0000000..5db030c
--- /dev/null
@@ -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 (file)
index 0000000..b6c7a4f
--- /dev/null
@@ -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 (file)
index 0000000..fde75a8
--- /dev/null
@@ -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)
+\f
+/* 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;
+}
+\f
+/* 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;
+}
+\f
+/* 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 (file)
index 0000000..d9e5549
--- /dev/null
@@ -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)
+\f
+/* 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;
+}
+\f
+/* 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 (file)
index 0000000..290d931
--- /dev/null
@@ -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 (file)
index 0000000..ac9b632
--- /dev/null
@@ -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 (file)
index 0000000..1b96f74
--- /dev/null
@@ -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 (file)
index 0000000..8820e6a
--- /dev/null
@@ -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 (file)
index 0000000..45ded2f
--- /dev/null
@@ -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 (file)
index 0000000..49c0815
--- /dev/null
@@ -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';