[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[commits] r6155 - in /trunk/libc: ./ elf/ include/ include/arpa/ io/ misc/ nis/ nis/nss_nis/ nis/nss_nisplus/ nptl/ nptl/sysdeps/unix/...



Author: joseph
Date: Mon May 12 08:38:35 2008
New Revision: 6155

Log:
Merge changes between r6123 and r6154 from /fsf/trunk.

Modified:
    trunk/libc/ChangeLog
    trunk/libc/NEWS
    trunk/libc/elf/dl-tls.c
    trunk/libc/include/arpa/nameser_compat.h
    trunk/libc/include/resolv.h
    trunk/libc/io/openat.c
    trunk/libc/io/openat64.c
    trunk/libc/misc/truncate64.c
    trunk/libc/nis/Versions
    trunk/libc/nis/nss_nis/nis-hosts.c
    trunk/libc/nis/nss_nisplus/nisplus-hosts.c
    trunk/libc/nptl/ChangeLog
    trunk/libc/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_rdlock.S
    trunk/libc/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_timedrdlock.S
    trunk/libc/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_timedwrlock.S
    trunk/libc/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_unlock.S
    trunk/libc/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_wrlock.S
    trunk/libc/nscd/aicache.c
    trunk/libc/nscd/cache.c
    trunk/libc/nscd/grpcache.c
    trunk/libc/nscd/hstcache.c
    trunk/libc/nscd/initgrcache.c
    trunk/libc/nscd/pwdcache.c
    trunk/libc/nscd/servicescache.c
    trunk/libc/nss/Versions
    trunk/libc/nss/nss.h
    trunk/libc/nss/nss_files/files-hosts.c
    trunk/libc/resolv/Versions
    trunk/libc/resolv/gethnamaddr.c
    trunk/libc/resolv/nss_dns/dns-canon.c
    trunk/libc/resolv/nss_dns/dns-host.c
    trunk/libc/resolv/nss_dns/dns-network.c
    trunk/libc/resolv/res_query.c
    trunk/libc/resolv/res_send.c
    trunk/libc/string/tester.c
    trunk/libc/sysdeps/ieee754/ldbl-128/e_j0l.c
    trunk/libc/sysdeps/ieee754/ldbl-128/e_j1l.c
    trunk/libc/sysdeps/ieee754/ldbl-128/s_expm1l.c
    trunk/libc/sysdeps/ieee754/ldbl-128/s_log1pl.c
    trunk/libc/sysdeps/posix/getaddrinfo.c
    trunk/libc/sysdeps/unix/sysv/linux/sys/user.h

Modified: trunk/libc/ChangeLog
==============================================================================
--- trunk/libc/ChangeLog (original)
+++ trunk/libc/ChangeLog Mon May 12 08:38:35 2008
@@ -1,3 +1,99 @@
+2008-05-11  Ulrich Drepper  <drepper@xxxxxxxxxx>
+
+	* elf/dl-tls.c (__tls_get_addr): Optimize by moving slow path in
+	its own function.  This reduces the frame setup costs and more.
+
+2008-02-11  Joseph Myers  <joseph@xxxxxxxxxxxxxxxx>
+
+	[BZ #3406]
+	* sysdeps/ieee754/flt-32/w_expf.c (o_threshold): Correct value.
+	* math/libm-test.inc (exp_test): Test 88.72269439697265625.
+
+2008-05-11  Ulrich Drepper  <drepper@xxxxxxxxxx>
+
+	* io/openat.c (__openat_2): Also pass fd to __openat.
+	* io/openat64.c (__openat64_2): Also pass fd to __openat64.
+	Patch by Kristian Van Der Vliet <vanders@xxxxxxxxxx>.
+
+	* string/tester.c (test_memcmp): Add a few more tests.
+	Patch by Mats Erik Andersson <ynglingatal@xxxxxxxxx>.
+
+2008-05-10  Ulrich Drepper  <drepper@xxxxxxxxxx>
+
+	* nscd/cache.c (cache_add): Before returning with failure and this
+	is the first use of the record, mark it as unusable.
+	* nscd/aicache.c: Don't touch the dataset after cache_add returns
+	reporting a failure.
+	* nscd/grpcache.c: Likewise
+	* nscd/hstcache.c: Likewise.
+	* nscd/initgrcache.c: Likewise.
+	* nscd/pwdcache.c: Likewise.
+	* nscd/servicecache.c: Likewise.
+
+2008-05-10  Roland McGrath  <roland@xxxxxxxxxx>
+
+	[BZ #6505]
+	* sysdeps/unix/sysv/linux/sys/user.h: Replace with #error stub.
+
+2008-05-08  David S. Miller  <davem@xxxxxxxxxxxxx>
+
+	* misc/truncate64.c (truncate64): Use __truncate not truncate.
+
+	* sysdeps/ieee754/ldbl-128/e_j0l.c (__ieee751_j0l): Use __finitel.
+	(__ieee754_y0l): Likewise.
+	* sysdeps/ieee754/ldbl-128/e_j1l.c (__ieee754_j1l): Likewise.
+	(__ieee754_y1l): Likewise.
+	* sysdeps/ieee754/ldbl-128/s_expm1l.c (__expm1l): Use __ldexpl.
+	* sysdeps/ieee754/ldbl-128/s_log1pl.c: Kill bogus prototypes for
+	frexpl and ldexpl.  math_private.h provides them and the latter
+	is not even used.
+	(__log1pl): Use __frexpl.
+
+2008-05-10  Ulrich Drepper  <drepper@xxxxxxxxxx>
+
+	* include/resolv.h: Adjust __libc_res_nquery and __libc_res_nsend
+	prototypes.
+	* include/arpa/nameser_compat.h: Define T_UNSPEC.
+	* nis/Versions (libnss_nis): Export _nss_nis_gethostbyname4_r.
+	(libnss_nisplus): Export _nss_nisplus_gethostbyname4_r.
+	* nis/nss_nis/nis-hosts.c (LINE_PARSER): Change to also handle
+	af==AF_UNSPEC.
+	(_nss_nis_gethostbyname4_r): New function.
+	* nis/nss_nisplus/nisplus-hosts.c (_nss_nisplus_parse_hostent):
+	Change to also handle af==AF_UNSPEC.
+	(get_tablename): New function.  Use it to avoid duplication.
+	(_nss_nisplus_gethostbyname4_r): New function.
+	* nscd/aicache.c (addhstaiX): Use gethostbyname4_r function is
+	available.
+	* nss/Versions (libnss_files): Export _nss_files_gethostbyname4_r.
+	* nss/nss.h: Define struct gaih_addrtuple.
+	* nss/nss_files/files-hosts.c (LINE_PARSER): Change to also handle
+	af==AF_UNSPEC.
+	(_nss_files_gethostbyname4_r): New function.
+	* resolv/Versions (libnss_dns): Export _nss_dns_gethostbyname4_r.
+	* resolv/gethnmaddr.c: Adjust __libc_res_nsearch and __libc_res_nquery
+	calls.
+	* resolv/res_query.c (__libc_res_nquery): Take two additional
+	parameters for second answer buffer.  Handle type=T_UNSPEC to mean
+	look up IPv4 and IPv6.
+	Change all callers.
+	* resolv/res_send.c (__libc_res_nsend): Take five aditional parameters
+	for an additional query and answer buffer.  Pass to send_vc and
+	send_dg.
+	(send_vc): Send possibly two requests and receive two answers.
+	(send_dg): Likewise.
+	* resolv/nss_dns/dns-host.c: Adjust calls to __libc_res_nsearch and
+	__libc_res_nquery.
+	(_nss_dns_gethostbyname4_r): New function.
+	(gaih_getanswer_slice): Likewise.
+	(gaih_getanswer): Likewise.
+	* resolv/nss_dns/dns-canon.c (_nss_dns_getcanonname_r): Adjust
+	__libc_res_nquery call.
+	* resolv/nss_dns/dns-network.c (_nss_dns_getnetbyaddr_r): Likewise.
+	(_nss_dns_getnetbyname_r): Adjust __libc_res_nsearch call.
+	* sysdeps/posix/getaddrinfo.c: Use gethostbyname4_r function is
+	available.
+
 2008-05-05  David S. Miller  <davem@xxxxxxxxxxxxx>
 
 	* sysdeps/sparc/sparc32/Makefile: Use -mcpu=v7 for initfini.s build.

Modified: trunk/libc/NEWS
==============================================================================
--- trunk/libc/NEWS (original)
+++ trunk/libc/NEWS Mon May 12 08:38:35 2008
@@ -1,9 +1,14 @@
-GNU C Library NEWS -- history of user-visible changes.  2008-4-9
+GNU C Library NEWS -- history of user-visible changes.  2008-5-10
 Copyright (C) 1992-2007, 2008 Free Software Foundation, Inc.
 See the end for copying conditions.
 
 Please send GNU C library bug reports via <http://sources.redhat.com/bugzilla/>
 using `glibc' in the "product" field.
+
+Version 2.9
+
+* Unified lookup for getaddrinfo: IPv4 and IPv6 addresses are now looked
+  up at the same time.
 
 Version 2.8
 

Modified: trunk/libc/elf/dl-tls.c
==============================================================================
--- trunk/libc/elf/dl-tls.c (original)
+++ trunk/libc/elf/dl-tls.c Mon May 12 08:38:35 2008
@@ -691,6 +691,61 @@
 }
 
 
+static void *
+__attribute_noinline__
+tls_get_addr_tail (dtv_t *dtv, struct link_map *the_map, size_t module)
+{
+  /* The allocation was deferred.  Do it now.  */
+  if (the_map == NULL)
+    {
+      /* Find the link map for this module.  */
+      size_t idx = module;
+      struct dtv_slotinfo_list *listp = GL(dl_tls_dtv_slotinfo_list);
+
+      while (idx >= listp->len)
+	{
+	  idx -= listp->len;
+	  listp = listp->next;
+	}
+
+      the_map = listp->slotinfo[idx].map;
+    }
+
+ again:
+  /* Make sure that, if a dlopen running in parallel forces the
+     variable into static storage, we'll wait until the address in the
+     static TLS block is set up, and use that.  If we're undecided
+     yet, make sure we make the decision holding the lock as well.  */
+  if (__builtin_expect (the_map->l_tls_offset
+			!= FORCED_DYNAMIC_TLS_OFFSET, 0))
+    {
+      __rtld_lock_lock_recursive (GL(dl_load_lock));
+      if (__builtin_expect (the_map->l_tls_offset == NO_TLS_OFFSET, 1))
+	{
+	  the_map->l_tls_offset = FORCED_DYNAMIC_TLS_OFFSET;
+	  __rtld_lock_unlock_recursive (GL(dl_load_lock));
+	}
+      else
+	{
+	  __rtld_lock_unlock_recursive (GL(dl_load_lock));
+	  if (__builtin_expect (the_map->l_tls_offset
+				!= FORCED_DYNAMIC_TLS_OFFSET, 1))
+	    {
+	      void *p = dtv[module].pointer.val;
+	      if (__builtin_expect (p == TLS_DTV_UNALLOCATED, 0))
+		goto again;
+
+	      return p;
+	    }
+	}
+    }
+  void *p = dtv[module].pointer.val = allocate_and_init (the_map);
+  dtv[module].pointer.is_static = false;
+
+  return p;
+}
+
+
 /* The generic dynamic and local dynamic model cannot be used in
    statically linked applications.  */
 void *
@@ -703,52 +758,10 @@
   if (__builtin_expect (dtv[0].counter != GL(dl_tls_generation), 0))
     the_map = _dl_update_slotinfo (GET_ADDR_MODULE);
 
- retry:
   p = dtv[GET_ADDR_MODULE].pointer.val;
 
   if (__builtin_expect (p == TLS_DTV_UNALLOCATED, 0))
-    {
-      /* The allocation was deferred.  Do it now.  */
-      if (the_map == NULL)
-	{
-	  /* Find the link map for this module.  */
-	  size_t idx = GET_ADDR_MODULE;
-	  struct dtv_slotinfo_list *listp = GL(dl_tls_dtv_slotinfo_list);
-
-	  while (idx >= listp->len)
-	    {
-	      idx -= listp->len;
-	      listp = listp->next;
-	    }
-
-	  the_map = listp->slotinfo[idx].map;
-	}
-
-      /* Make sure that, if a dlopen running in parallel forces the
-	 variable into static storage, we'll wait until the address in
-	 the static TLS block is set up, and use that.  If we're
-	 undecided yet, make sure we make the decision holding the
-	 lock as well.  */
-      if (__builtin_expect (the_map->l_tls_offset
-			    != FORCED_DYNAMIC_TLS_OFFSET, 0))
-	{
-	  __rtld_lock_lock_recursive (GL(dl_load_lock));
-	  if (__builtin_expect (the_map->l_tls_offset == NO_TLS_OFFSET, 1))
-	    {
-	      the_map->l_tls_offset = FORCED_DYNAMIC_TLS_OFFSET;
-	      __rtld_lock_unlock_recursive (GL(dl_load_lock));
-	    }
-	  else
-	    {
-	      __rtld_lock_unlock_recursive (GL(dl_load_lock));
-	      if (__builtin_expect (the_map->l_tls_offset
-				    != FORCED_DYNAMIC_TLS_OFFSET, 1))
-		goto retry;
-	    }
-	}
-      p = dtv[GET_ADDR_MODULE].pointer.val = allocate_and_init (the_map);
-      dtv[GET_ADDR_MODULE].pointer.is_static = false;
-    }
+    p = tls_get_addr_tail (dtv, the_map, GET_ADDR_MODULE);
 
   return (char *) p + GET_ADDR_OFFSET;
 }

Modified: trunk/libc/include/arpa/nameser_compat.h
==============================================================================
--- trunk/libc/include/arpa/nameser_compat.h (original)
+++ trunk/libc/include/arpa/nameser_compat.h Mon May 12 08:38:35 2008
@@ -1,1 +1,8 @@
+#ifndef _ARPA_NAMESER_COMPAT_
 #include <resolv/arpa/nameser_compat.h>
+
+/* Picksome unused number to represent lookups of IPv4 and IPv6 (i.e.,
+   T_A and T_AAAA).  */
+#define T_UNSPEC 62321
+
+#endif

Modified: trunk/libc/include/resolv.h
==============================================================================
--- trunk/libc/include/resolv.h (original)
+++ trunk/libc/include/resolv.h Mon May 12 08:38:35 2008
@@ -58,11 +58,11 @@
 libc_hidden_proto (__res_state)
 
 int __libc_res_nquery (res_state, const char *, int, int, u_char *, int,
-		       u_char **);
+		       u_char **, u_char **, int *);
 int __libc_res_nsearch (res_state, const char *, int, int, u_char *, int,
-			u_char **);
-int __libc_res_nsend (res_state, const u_char *, int, u_char *, int,
-		      u_char **)
+			u_char **, u_char **, int *);
+int __libc_res_nsend (res_state, const u_char *, int, const u_char *, int,
+		      u_char *, int, u_char **, u_char **, int *)
   attribute_hidden;
 
 libresolv_hidden_proto (_sethtent)

Modified: trunk/libc/io/openat.c
==============================================================================
--- trunk/libc/io/openat.c (original)
+++ trunk/libc/io/openat.c Mon May 12 08:38:35 2008
@@ -79,7 +79,7 @@
   if (oflag & O_CREAT)
     __fortify_fail ("invalid openat call: O_CREAT without mode");
 
-  return __openat (file, oflag);
+  return __openat (fd, file, oflag);
 }
 stub_warning (__openat_2)
 

Modified: trunk/libc/io/openat64.c
==============================================================================
--- trunk/libc/io/openat64.c (original)
+++ trunk/libc/io/openat64.c Mon May 12 08:38:35 2008
@@ -79,7 +79,7 @@
   if (oflag & O_CREAT)
     __fortify_fail ("invalid openat64 call: O_CREAT without mode");
 
-  return __openat64 (file, oflag);
+  return __openat64 (fd, file, oflag);
 }
 stub_warning (__openat_2)
 

Modified: trunk/libc/misc/truncate64.c
==============================================================================
--- trunk/libc/misc/truncate64.c (original)
+++ trunk/libc/misc/truncate64.c Mon May 12 08:38:35 2008
@@ -31,5 +31,5 @@
       __set_errno (EINVAL);
       return -1;
     }
-  return truncate (path, (off_t) length);
+  return __truncate (path, (off_t) length);
 }

Modified: trunk/libc/nis/Versions
==============================================================================
--- trunk/libc/nis/Versions (original)
+++ trunk/libc/nis/Versions Mon May 12 08:38:35 2008
@@ -95,7 +95,7 @@
     _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;
-    _nss_nis_initgroups_dyn;
+    _nss_nis_initgroups_dyn; _nss_nis_gethostbyname4_r;
   }
 }
 
@@ -126,5 +126,6 @@
     _nss_nisplus_setnetent; _nss_nisplus_setnetgrent; _nss_nisplus_setprotoent;
     _nss_nisplus_setpwent; _nss_nisplus_setrpcent; _nss_nisplus_setservent;
     _nss_nisplus_setspent; _nss_nisplus_initgroups_dyn;
+    _nss_nisplus_gethostbyname4_r;
   }
 }

Modified: trunk/libc/nis/nss_nis/nis-hosts.c
==============================================================================
--- trunk/libc/nis/nss_nis/nis-hosts.c (original)
+++ trunk/libc/nis/nss_nis/nis-hosts.c Mon May 12 08:38:35 2008
@@ -1,4 +1,5 @@
-/* Copyright (C) 1996-2000, 2002, 2003, 2006, 2007 Free Software Foundation, Inc.
+/* Copyright (C) 1996-2000, 2002, 2003, 2006, 2007, 2008
+   Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Thorsten Kukuk <kukuk@xxxxxxx>, 1996.
 
@@ -17,6 +18,7 @@
    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
    02111-1307 USA.  */
 
+#include <assert.h>
 #include <nss.h>
 #include <ctype.h>
 /* The following is an ugly trick to avoid a prototype declaration for
@@ -61,9 +63,12 @@
 
    STRING_FIELD (addr, isspace, 1);
 
+   assert (af == AF_INET || af == AF_INET6 || af == AF_UNSPEC);
+
    /* Parse address.  */
-   if (af == AF_INET && inet_pton (AF_INET, addr, entdata->host_addr) > 0)
+   if (af != AF_INET6 && inet_pton (AF_INET, addr, entdata->host_addr) > 0)
      {
+       assert ((flags & AI_V4MAPPED) == 0 || af != AF_UNSPEC);
        if (flags & AI_V4MAPPED)
          {
            map_v4v6_address ((char *) entdata->host_addr,
@@ -77,7 +82,7 @@
            result->h_length = INADDRSZ;
          }
      }
-   else if (af == AF_INET6
+   else if (af != AF_INET
             && inet_pton (AF_INET6, addr, entdata->host_addr) > 0)
      {
        result->h_addrtype = AF_INET6;
@@ -102,6 +107,7 @@
 static char *oldkey = NULL;
 static int oldkeylen = 0;
 
+
 enum nss_status
 _nss_nis_sethostent (int stayopen)
 {
@@ -123,6 +129,7 @@
    even though the prototypes don't match.  The argument of sethostent
    is used so this makes no difference.  */
 strong_alias (_nss_nis_sethostent, _nss_nis_endhostent)
+
 
 /* The calling function always need to get a lock first. */
 static enum nss_status
@@ -216,6 +223,7 @@
   return NSS_STATUS_SUCCESS;
 }
 
+
 enum nss_status
 _nss_nis_gethostent_r (struct hostent *host, char *buffer, size_t buflen,
 		       int *errnop, int *h_errnop)
@@ -232,6 +240,7 @@
 
   return status;
 }
+
 
 static enum nss_status
 internal_gethostbyname2_r (const char *name, int af, struct hostent *host,
@@ -323,15 +332,23 @@
   return NSS_STATUS_SUCCESS;
 }
 
+
 enum nss_status
 _nss_nis_gethostbyname2_r (const char *name, int af, struct hostent *host,
 			   char *buffer, size_t buflen, int *errnop,
 			   int *h_errnop)
 {
+  if (af != AF_INET && af != AF_INET6)
+    {
+      *h_errnop = HOST_NOT_FOUND;
+      return NSS_STATUS_NOTFOUND;
+    }
+
   return internal_gethostbyname2_r (name, af, host, buffer, buflen, errnop,
 				    h_errnop,
 		        ((_res.options & RES_USE_INET6) ? AI_V4MAPPED : 0));
 }
+
 
 enum nss_status
 _nss_nis_gethostbyname_r (const char *name, struct hostent *host, char *buffer,
@@ -350,6 +367,7 @@
   return internal_gethostbyname2_r (name, AF_INET, host, buffer, buflen,
 				    errnop, h_errnop, 0);
 }
+
 
 enum nss_status
 _nss_nis_gethostbyaddr_r (const void *addr, socklen_t addrlen, int af,
@@ -430,13 +448,93 @@
   return NSS_STATUS_SUCCESS;
 }
 
-#if 0
+
 enum nss_status
-_nss_nis_getipnodebyname_r (const char *name, int af, int flags,
-			    struct hostent *result, char *buffer,
-			    size_t buflen, int *errnop, int *herrnop)
-{
-  return internal_gethostbyname2_r (name, af, result, buffer, buflen,
-				    errnop, herrnop, flags);
-}
-#endif
+_nss_nis_gethostbyname4_r (const char *name, struct gaih_addrtuple **pat,
+			   char *buffer, size_t buflen, int *errnop,
+			   int *herrnop, int32_t *ttlp)
+{
+  char *domain;
+  if (yp_get_default_domain (&domain))
+    return NSS_STATUS_UNAVAIL;
+
+  /* Convert name to lowercase.  */
+  size_t namlen = strlen (name);
+  char name2[namlen + 1];
+  size_t i;
+
+  for (i = 0; i < namlen; ++i)
+    name2[i] = tolower (name[i]);
+  name2[i] = '\0';
+
+  char *result;
+  int len;
+  int yperr = yp_match (domain, "hosts.byname", name2, namlen, &result, &len);
+
+  if (__builtin_expect (yperr != YPERR_SUCCESS, 0))
+    {
+      enum nss_status retval = yperr2nss (yperr);
+
+      if (retval == NSS_STATUS_TRYAGAIN)
+	{
+	  *herrnop = TRY_AGAIN;
+	  *errnop = errno;
+	}
+      if (retval == NSS_STATUS_NOTFOUND)
+	*herrnop = HOST_NOT_FOUND;
+      return retval;
+    }
+
+  struct parser_data data;
+  struct hostent host;
+  int parse_res = parse_line (result, &host, &data, buflen, errnop, AF_UNSPEC,
+			      0);
+  if (__builtin_expect (parse_res < 1, 0))
+    {
+      if (parse_res == -1)
+	{
+	  *herrnop = NETDB_INTERNAL;
+	  return NSS_STATUS_TRYAGAIN;
+	}
+      else
+	{
+	  *herrnop = HOST_NOT_FOUND;
+	  return NSS_STATUS_NOTFOUND;
+	}
+    }
+
+  if (*pat == NULL)
+    {
+      uintptr_t pad = (-(uintptr_t) buffer
+		       % __alignof__ (struct gaih_addrtuple));
+      buffer += pad;
+      buflen = buflen > pad ? buflen - pad : 0;
+
+      if (__builtin_expect (buflen < sizeof (struct gaih_addrtuple), 0))
+	{
+	erange:
+	  free (result);
+	  *errnop = ERANGE;
+	  *herrnop = NETDB_INTERNAL;
+	  return NSS_STATUS_TRYAGAIN;
+	}
+
+      *pat = (struct gaih_addrtuple *) buffer;
+      buffer += sizeof (struct gaih_addrtuple);
+      buflen -= sizeof (struct gaih_addrtuple);
+    }
+
+  (*pat)->next = NULL;
+  size_t h_name_len = strlen (host.h_name);
+  if (h_name_len >= buflen)
+    goto erange;
+  (*pat)->name = memcpy (buffer, host.h_name, h_name_len + 1);
+  (*pat)->family = host.h_addrtype;
+  memcpy ((*pat)->addr, host.h_addr_list[0], host.h_length);
+  (*pat)->scopeid = 0;
+  assert (host.h_addr_list[1] == NULL);
+
+  free (result);
+
+  return NSS_STATUS_SUCCESS;
+}

Modified: trunk/libc/nis/nss_nisplus/nisplus-hosts.c
==============================================================================
--- trunk/libc/nis/nss_nisplus/nisplus-hosts.c (original)
+++ trunk/libc/nis/nss_nisplus/nisplus-hosts.c Mon May 12 08:38:35 2008
@@ -1,4 +1,4 @@
-/* Copyright (C) 1997-2002, 2003, 2005, 2006 Free Software Foundation, Inc.
+/* Copyright (C) 1997-2003, 2005, 2006, 2008 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Thorsten Kukuk <kukuk@xxxxxxx>, 1997.
 
@@ -17,6 +17,7 @@
    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
    02111-1307 USA.  */
 
+#include <assert.h>
 #include <atomic.h>
 #include <ctype.h>
 #include <errno.h>
@@ -58,15 +59,15 @@
   if (result == NULL)
     return 0;
 
-  if ((result->status != NIS_SUCCESS && result->status != NIS_S_SUCCESS) ||
-      __type_of (NIS_RES_OBJECT (result)) != NIS_ENTRY_OBJ ||
-      strcmp(NIS_RES_OBJECT (result)[0].EN_data.en_type, "hosts_tbl") != 0 ||
-      NIS_RES_OBJECT (result)[0].EN_data.en_cols.en_cols_len < 4)
+  if ((result->status != NIS_SUCCESS && result->status != NIS_S_SUCCESS)
+      || __type_of (NIS_RES_OBJECT (result)) != NIS_ENTRY_OBJ
+      || strcmp (NIS_RES_OBJECT (result)[0].EN_data.en_type, "hosts_tbl") != 0
+      || NIS_RES_OBJECT (result)[0].EN_data.en_cols.en_cols_len < 4)
     return 0;
 
   char *data = first_unused;
 
-  if (room_left < (af == AF_INET6 || (flags & AI_V4MAPPED) != 0
+  if (room_left < (af != AF_INET || (flags & AI_V4MAPPED) != 0
 		   ? IN6ADDRSZ : INADDRSZ))
     {
     no_more_room:
@@ -75,8 +76,10 @@
     }
 
   /* Parse address.  */
-  if (af == AF_INET && inet_pton (af, NISENTRYVAL (0, 2, result), data) > 0)
-    {
+  if (af != AF_INET6
+      && inet_pton (AF_INET, NISENTRYVAL (0, 2, result), data) > 0)
+    {
+      assert ((flags & AI_V4MAPPED) == 0 || af != AF_UNSPEC);
       if (flags & AI_V4MAPPED)
 	{
 	  map_v4v6_address (data, data);
@@ -89,7 +92,7 @@
 	  host->h_length = INADDRSZ;
 	}
     }
-  else if (af == AF_INET6
+  else if (af != AF_INET
 	   && inet_pton (AF_INET6, NISENTRYVAL (0, 2, result), data) > 0)
     {
       host->h_addrtype = AF_INET6;
@@ -109,27 +112,33 @@
   first_unused = __stpncpy (first_unused, NISENTRYVAL (0, 0, result),
 			    NISENTRYLEN (0, 0, result));
   *first_unused++ = '\0';
+
   room_left -= NISENTRYLEN (0, 0, result) + 1;
-
-  /* XXX Rewrite at some point to allocate the array first and then
-     copy the strings.  It wasteful to first concatenate the strings
-     to just split them again later.  */
   char *line = first_unused;
-  for (i = 0; i < NIS_RES_NUMOBJ (result); ++i)
-    {
-      if (strcmp (NISENTRYVAL (i, 1, result), host->h_name) != 0)
-	{
-	  if (NISENTRYLEN (i, 1, result) + 2 > room_left)
-	    goto no_more_room;
-
-	  *first_unused++ = ' ';
-	  first_unused = __stpncpy (first_unused, NISENTRYVAL (i, 1, result),
-				    NISENTRYLEN (i, 1, result));
-	  *first_unused = '\0';
-	  room_left -= NISENTRYLEN (i, 1, result) + 1;
-	}
-    }
-  *first_unused++ = '\0';
+
+  /* When this is a call to gethostbyname4_r we do not need the aliases.  */
+  if (af != AF_UNSPEC)
+    {
+      /* XXX Rewrite at some point to allocate the array first and then
+	 copy the strings.  It is wasteful to first concatenate the strings
+	 to just split them again later.  */
+      for (i = 0; i < NIS_RES_NUMOBJ (result); ++i)
+	{
+	  if (strcmp (NISENTRYVAL (i, 1, result), host->h_name) != 0)
+	    {
+	      if (NISENTRYLEN (i, 1, result) + 2 > room_left)
+		goto no_more_room;
+
+	      *first_unused++ = ' ';
+	      first_unused = __stpncpy (first_unused,
+					NISENTRYVAL (i, 1, result),
+					NISENTRYLEN (i, 1, result));
+	      *first_unused = '\0';
+	      room_left -= NISENTRYLEN (i, 1, result) + 1;
+	    }
+	}
+      *first_unused++ = '\0';
+    }
 
   /* Adjust the pointer so it is aligned for
      storing pointers.  */
@@ -147,30 +156,34 @@
   host->h_addr_list[1] = NULL;
   host->h_aliases = &host->h_addr_list[2];
 
-  i = 0;
-  while (*line != '\0')
-    {
-      /* Skip leading blanks.  */
-      while (isspace (*line))
-	++line;
-
-      if (*line == '\0')
-	break;
-
-      if (room_left < sizeof (char *))
-	goto no_more_room;
-
-      room_left -= sizeof (char *);
-      host->h_aliases[i++] = line;
-
-      while (*line != '\0' && *line != ' ')
-	++line;
-
-      if (*line == ' ')
-	*line++ = '\0';
-    }
-
-  host->h_aliases[i] = NULL;
+  /* When this is a call to gethostbyname4_r we do not need the aliases.  */
+  if (af != AF_UNSPEC)
+    {
+      i = 0;
+      while (*line != '\0')
+	{
+	  /* Skip leading blanks.  */
+	  while (isspace (*line))
+	    ++line;
+
+	  if (*line == '\0')
+	    break;
+
+	  if (room_left < sizeof (char *))
+	    goto no_more_room;
+
+	  room_left -= sizeof (char *);
+	  host->h_aliases[i++] = line;
+
+	  while (*line != '\0' && *line != ' ')
+	    ++line;
+
+	  if (*line == ' ')
+	    *line++ = '\0';
+	}
+
+      host->h_aliases[i] = NULL;
+    }
 
   return 1;
 }
@@ -204,6 +217,7 @@
   return NSS_STATUS_SUCCESS;
 }
 
+
 enum nss_status
 _nss_nisplus_sethostent (int stayopen)
 {
@@ -226,6 +240,7 @@
   return status;
 }
 
+
 enum nss_status
 _nss_nisplus_endhostent (void)
 {
@@ -241,6 +256,7 @@
 
   return NSS_STATUS_SUCCESS;
 }
+
 
 static enum nss_status
 internal_nisplus_gethostent_r (struct hostent *host, char *buffer,
@@ -329,6 +345,7 @@
   return NSS_STATUS_SUCCESS;
 }
 
+
 enum nss_status
 _nss_nisplus_gethostent_r (struct hostent *result, char *buffer,
 			   size_t buflen, int *errnop, int *herrnop)
@@ -344,27 +361,34 @@
 
   return status;
 }
+
+
+static enum nss_status
+get_tablename (int *herrnop)
+{
+  __libc_lock_lock (lock);
+
+  enum nss_status status = _nss_create_tablename (herrnop);
+
+  __libc_lock_unlock (lock);
+
+  if (status != NSS_STATUS_SUCCESS)
+    *herrnop = NETDB_INTERNAL;
+
+  return status;
+}
+
 
 static enum nss_status
 internal_gethostbyname2_r (const char *name, int af, struct hostent *host,
 			   char *buffer, size_t buflen, int *errnop,
 			   int *herrnop, int flags)
 {
-  int parse_res, retval;
-
   if (tablename_val == NULL)
     {
-      __libc_lock_lock (lock);
-
-      enum nss_status status = _nss_create_tablename (errnop);
-
-      __libc_lock_unlock (lock);
-
+      enum nss_status status = get_tablename (herrnop);
       if (status != NSS_STATUS_SUCCESS)
-	{
-	  *herrnop = NETDB_INTERNAL;
-	  return NSS_STATUS_UNAVAIL;
-	}
+	return status;
     }
 
   if (name == NULL)
@@ -374,38 +398,35 @@
       return NSS_STATUS_NOTFOUND;
     }
 
-  nis_result *result;
   char buf[strlen (name) + 10 + tablename_len];
   int olderr = errno;
 
   /* Search at first in the alias list, and use the correct name
      for the next search.  */
   snprintf (buf, sizeof (buf), "[name=%s],%s", name, tablename_val);
-  result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL);
+  nis_result *result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL);
 
   if (result != NULL)
     {
-      char *bufptr = buf;
-
       /* If we did not find it, try it as original name. But if the
 	 database is correct, we should find it in the first case, too.  */
-      if ((result->status != NIS_SUCCESS
-	   && result->status != NIS_S_SUCCESS)
-	  || __type_of (result->objects.objects_val) != NIS_ENTRY_OBJ
-	  || strcmp (result->objects.objects_val->EN_data.en_type,
-		     "hosts_tbl") != 0
-	  || result->objects.objects_val->EN_data.en_cols.en_cols_len < 3)
-	snprintf (buf, sizeof (buf), "[cname=%s],%s", name, tablename_val);
-      else
+      char *bufptr = buf;
+      size_t buflen = sizeof (buf);
+
+      if ((result->status == NIS_SUCCESS || result->status == NIS_S_SUCCESS)
+	  && __type_of (result->objects.objects_val) == NIS_ENTRY_OBJ
+	  && strcmp (result->objects.objects_val->EN_data.en_type,
+		     "hosts_tbl") == 0
+	  && result->objects.objects_val->EN_data.en_cols.en_cols_len >= 3)
 	{
 	  /* We need to allocate a new buffer since there is no
-	     guarantee the returned name has a length limit.  */
-	  const char *entryval = NISENTRYVAL(0, 0, result);
-	  size_t buflen = strlen (entryval) + 10 + tablename_len;
+	     guarantee the returned alias name has a length limit.  */
+	  name = NISENTRYVAL(0, 0, result);
+	  size_t buflen = strlen (name) + 10 + tablename_len;
 	  bufptr = alloca (buflen);
-	  snprintf (bufptr, buflen, "[cname=%s],%s",
-		    entryval, tablename_val);
-	}
+	}
+
+      snprintf (bufptr, buflen, "[cname=%s],%s", name, tablename_val);
 
       nis_freeresult (result);
       result = nis_list (bufptr, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL);
@@ -417,7 +438,7 @@
       return NSS_STATUS_TRYAGAIN;
     }
 
-  retval = niserr2nss (result->status);
+  int retval = niserr2nss (result->status);
   if (__builtin_expect (retval != NSS_STATUS_SUCCESS, 0))
     {
       if (retval == NSS_STATUS_TRYAGAIN)
@@ -431,8 +452,8 @@
       return retval;
     }
 
-  parse_res = _nss_nisplus_parse_hostent (result, af, host, buffer,
-					  buflen, errnop, flags);
+  int parse_res = _nss_nisplus_parse_hostent (result, af, host, buffer,
+					      buflen, errnop, flags);
 
   nis_freeresult (result);
 
@@ -449,16 +470,24 @@
   __set_errno (olderr);
   return NSS_STATUS_NOTFOUND;
 }
+
 
 enum nss_status
 _nss_nisplus_gethostbyname2_r (const char *name, int af, struct hostent *host,
 			       char *buffer, size_t buflen, int *errnop,
 			       int *herrnop)
 {
+  if (af != AF_INET && af != AF_INET6)
+    {
+      *herrnop = HOST_NOT_FOUND;
+      return NSS_STATUS_NOTFOUND;
+    }
+
   return internal_gethostbyname2_r (name, af, host, buffer, buflen, errnop,
 				    herrnop,
 			 ((_res.options & RES_USE_INET6) ? AI_V4MAPPED : 0));
 }
+
 
 enum nss_status
 _nss_nisplus_gethostbyname_r (const char *name, struct hostent *host,
@@ -480,6 +509,7 @@
 				   buflen, errnop, h_errnop, 0);
 }
 
+
 enum nss_status
 _nss_nisplus_gethostbyaddr_r (const void *addr, socklen_t addrlen, int af,
 			      struct hostent *host, char *buffer,
@@ -487,12 +517,7 @@
 {
   if (tablename_val == NULL)
     {
-      __libc_lock_lock (lock);
-
-      enum nss_status status = _nss_create_tablename (errnop);
-
-      __libc_lock_unlock (lock);
-
+      enum nss_status status = get_tablename (herrnop);
       if (status != NSS_STATUS_SUCCESS)
 	return status;
     }
@@ -547,3 +572,44 @@
   __set_errno (olderr);
   return NSS_STATUS_NOTFOUND;
 }
+
+
+enum nss_status
+_nss_nisplus_gethostbyname4_r (const char *name, struct gaih_addrtuple **pat,
+			       char *buffer, size_t buflen, int *errnop,
+			       int *herrnop, int32_t *ttlp)
+{
+  struct hostent host;
+
+  enum nss_status status = internal_gethostbyname2_r (name, AF_UNSPEC, &host,
+						      buffer, buflen,
+						      errnop, herrnop, 0);
+  if (__builtin_expect (status == NSS_STATUS_SUCCESS, 1))
+    {
+      if (*pat == NULL)
+	{
+	  uintptr_t pad = (-(uintptr_t) buffer
+			   % __alignof__ (struct gaih_addrtuple));
+	  buffer += pad;
+	  buflen = buflen > pad ? buflen - pad : 0;
+
+	  if (__builtin_expect (buflen < sizeof (struct gaih_addrtuple), 0))
+	    {
+	      free (result);
+	      *errnop = ERANGE;
+	      *herrnop = NETDB_INTERNAL;
+	      return NSS_STATUS_TRYAGAIN;
+	    }
+	}
+
+      (*pat)->next = NULL;
+      (*pat)->name = host.h_name;
+      (*pat)->family = host.h_addrtype;
+
+      memcpy ((*pat)->addr, host.h_addr_list[0], host.h_length);
+      (*pat)->scopeid = 0;
+      assert (host.h_addr_list[1] == NULL);
+    }
+
+  return status;
+}

Modified: trunk/libc/nptl/ChangeLog
==============================================================================
--- trunk/libc/nptl/ChangeLog (original)
+++ trunk/libc/nptl/ChangeLog Mon May 12 08:38:35 2008
@@ -1,3 +1,17 @@
+2008-05-10  Ulrich Drepper  <drepper@xxxxxxxxxx>
+
+	* sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_rdlock.S: Access
+	__pshared correctly.
+	* sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_timedrdlock.S:
+	Likewise.
+	* sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_timedwrlock.S:
+	Likewise.
+	* sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_unlock.S:
+	Likewise.
+	* sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_wrlock.S:
+	Likewise.
+	Reported by Clemens Kolbitsch <clemens.kol@xxxxxx>.
+
 2008-04-14  David S. Miller  <davem@xxxxxxxxxxxxx>
 
 	* sysdeps/unix/sysv/linux/sparc/sparc32/sem_wait.c

Modified: trunk/libc/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_rdlock.S
==============================================================================
--- trunk/libc/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_rdlock.S (original)
+++ trunk/libc/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_rdlock.S Mon May 12 08:38:35 2008
@@ -122,7 +122,7 @@
 #else
 	leal	MUTEX(%ebx), %edx
 #endif
-	movl	PSHARED(%ebx), %ecx
+	movzbl	PSHARED(%ebx), %ecx
 	call	__lll_lock_wait
 	jmp	2b
 
@@ -138,7 +138,7 @@
 #else
 	leal	MUTEX(%ebx), %eax
 #endif
-	movl	PSHARED(%ebx), %ecx
+	movzbl	PSHARED(%ebx), %ecx
 	call	__lll_unlock_wake
 	jmp	7b
 
@@ -158,7 +158,7 @@
 #else
 	leal	MUTEX(%ebx), %eax
 #endif
-	movl	PSHARED(%ebx), %ecx
+	movzbl	PSHARED(%ebx), %ecx
 	call	__lll_unlock_wake
 	jmp	11b
 
@@ -168,7 +168,7 @@
 #else
 	leal	MUTEX(%ebx), %edx
 #endif
-	movl	PSHARED(%ebx), %ecx
+	movzbl	PSHARED(%ebx), %ecx
 	call	__lll_lock_wait
 	jmp	13b
 	.size	__pthread_rwlock_rdlock,.-__pthread_rwlock_rdlock

Modified: trunk/libc/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_timedrdlock.S
==============================================================================
--- trunk/libc/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_timedrdlock.S (original)
+++ trunk/libc/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_timedrdlock.S Mon May 12 08:38:35 2008
@@ -162,7 +162,7 @@
 #else
 	leal	MUTEX(%ebp), %edx
 #endif
-	movl	PSHARED(%ebp), %ecx
+	movzbl	PSHARED(%ebp), %ecx
 	call	__lll_lock_wait
 	jmp	2b
 
@@ -177,7 +177,7 @@
 #else
 	leal	MUTEX(%ebp), %eax
 #endif
-	movl	PSHARED(%ebp), %ecx
+	movzbl	PSHARED(%ebp), %ecx
 	call	__lll_unlock_wake
 	jmp	7b
 
@@ -197,7 +197,7 @@
 #else
 	leal	MUTEX(%ebp), %eax
 #endif
-	movl	PSHARED(%ebp), %ecx
+	movzbl	PSHARED(%ebp), %ecx
 	call	__lll_unlock_wake
 	jmp	11b
 
@@ -207,7 +207,7 @@
 #else
 	leal	MUTEX(%ebp), %edx
 #endif
-	movl	PSHARED(%ebp), %ecx
+	movzbl	PSHARED(%ebp), %ecx
 	call	__lll_lock_wait
 	jmp	13b
 

Modified: trunk/libc/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_timedwrlock.S
==============================================================================
--- trunk/libc/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_timedwrlock.S (original)
+++ trunk/libc/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_timedwrlock.S Mon May 12 08:38:35 2008
@@ -160,7 +160,7 @@
 #else
 	leal	MUTEX(%ebp), %edx
 #endif
-	movl	PSHARED(%ebp), %ecx
+	movzbl	PSHARED(%ebp), %ecx
 	call	__lll_lock_wait
 	jmp	2b
 
@@ -175,7 +175,7 @@
 #else
 	leal	MUTEX(%ebp), %eax
 #endif
-	movl	PSHARED(%ebp), %ecx
+	movzbl	PSHARED(%ebp), %ecx
 	call	__lll_unlock_wake
 	jmp	7b
 
@@ -190,7 +190,7 @@
 #else
 	leal	MUTEX(%ebp), %eax
 #endif
-	movl	PSHARED(%ebp), %ecx
+	movzbl	PSHARED(%ebp), %ecx
 	call	__lll_unlock_wake
 	jmp	11b
 
@@ -200,7 +200,7 @@
 #else
 	leal	MUTEX(%ebp), %edx
 #endif
-	movl	PSHARED(%ebp), %ecx
+	movzbl	PSHARED(%ebp), %ecx
 	call	__lll_lock_wait
 	jmp	13b
 

Modified: trunk/libc/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_unlock.S
==============================================================================
--- trunk/libc/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_unlock.S (original)
+++ trunk/libc/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_unlock.S Mon May 12 08:38:35 2008
@@ -110,7 +110,7 @@
 #else
 	leal	MUTEX(%edi), %edx
 #endif
-	movl	PSHARED(%edi), %ecx
+	movzbl	PSHARED(%edi), %ecx
 	call	__lll_lock_wait
 	jmp	2b
 
@@ -120,7 +120,7 @@
 #else
 	leal	MUTEX(%edi), %eax
 #endif
-	movl	PSHARED(%edi), %ecx
+	movzbl	PSHARED(%edi), %ecx
 	call	__lll_unlock_wake
 	jmp	4b
 
@@ -130,7 +130,7 @@
 #else
 	leal	MUTEX(%edi), %eax
 #endif
-	movl	PSHARED(%edi), %ecx
+	movzbl	PSHARED(%edi), %ecx
 	call	__lll_unlock_wake
 	jmp	8b
 

Modified: trunk/libc/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_wrlock.S
==============================================================================
--- trunk/libc/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_wrlock.S (original)
+++ trunk/libc/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_wrlock.S Mon May 12 08:38:35 2008
@@ -120,7 +120,7 @@
 #else
 	leal	MUTEX(%ebx), %edx
 #endif
-	movl	PSHARED(%ebx), %ecx
+	movzbl	PSHARED(%ebx), %ecx
 	call	__lll_lock_wait
 	jmp	2b
 
@@ -135,7 +135,7 @@
 #else
 	leal	MUTEX(%ebx), %eax
 #endif
-	movl	PSHARED(%ebx), %ecx
+	movzbl	PSHARED(%ebx), %ecx
 	call	__lll_unlock_wake
 	jmp	7b
 
@@ -149,7 +149,7 @@
 #else
 	leal	MUTEX(%ebx), %eax
 #endif
-	movl	PSHARED(%ebx), %ecx
+	movzbl	PSHARED(%ebx), %ecx
 	call	__lll_unlock_wake
 	jmp	11b
 
@@ -159,7 +159,7 @@
 #else
 	leal	MUTEX(%ebx), %edx
 #endif
-	movl	PSHARED(%ebx), %ecx
+	movzbl	PSHARED(%ebx), %ecx
 	call	__lll_lock_wait
 	jmp	13b
 	.size	__pthread_rwlock_wrlock,.-__pthread_rwlock_wrlock

Modified: trunk/libc/nscd/aicache.c
==============================================================================
--- trunk/libc/nscd/aicache.c (original)
+++ trunk/libc/nscd/aicache.c Mon May 12 08:38:35 2008
@@ -21,6 +21,7 @@
 #include <errno.h>
 #include <libintl.h>
 #include <netdb.h>
+#include <nss.h>
 #include <string.h>
 #include <time.h>
 #include <unistd.h>
@@ -33,6 +34,10 @@
 #endif
 
 
+typedef enum nss_status (*nss_gethostbyname4_r)
+  (const char *name, struct gaih_addrtuple **pat,
+   char *buffer, size_t buflen, int *errnop,
+   int *h_errnop, int32_t *ttlp);
 typedef enum nss_status (*nss_gethostbyname3_r)
   (const char *name, int af, struct hostent *host,
    char *buffer, size_t buflen, int *errnop,
@@ -117,16 +122,104 @@
 
   while (!no_more)
     {
+      void *cp;
       int status[2] = { NSS_STATUS_UNAVAIL, NSS_STATUS_UNAVAIL };
-
-      /* Prefer the function which also returns the TTL and canonical name.  */
-      nss_gethostbyname3_r fct = __nss_lookup_function (nip,
-							"gethostbyname3_r");
-      if (fct == NULL)
-	fct = __nss_lookup_function (nip, "gethostbyname2_r");
-
-      if (fct != NULL)
+      int naddrs = 0;
+      size_t addrslen = 0;
+      size_t canonlen;
+
+      nss_gethostbyname4_r fct4 = __nss_lookup_function (nip,
+							 "gethostbyname4_r");
+      if (fct4 != NULL)
 	{
+	  struct gaih_addrtuple *at = NULL;
+	  while (1)
+	    {
+	      rc6 = 0;
+	      status[0] = DL_CALL_FCT (fct4, (key, &at, tmpbuf6, tmpbuf6len,
+					      &rc6, &herrno, &ttl));
+	      if (rc6 != ERANGE || herrno != NETDB_INTERNAL)
+		break;
+	      tmpbuf6 = extend_alloca (tmpbuf6, tmpbuf6len, 2 * tmpbuf6len);
+	    }
+
+	  if (rc6 != 0 && herrno == NETDB_INTERNAL)
+	    goto out;
+
+	  if (status[0] != NSS_STATUS_SUCCESS)
+	    goto next_nip;
+
+	  /* We found the data.  Count the addresses and the size.  */
+	  for (struct gaih_addrtuple *at2 = at; at2 != NULL; at2 = at2->next)
+	    {
+	      ++naddrs;
+	      /* We handle unknown types here the best we can: assume
+		 the maximum size for the address.  */
+	      if (at2->family == AF_INET)
+		addrslen += INADDRSZ;
+	      else if (at2->family == AF_INET6
+		       && IN6ADDRSZ != sizeof (at2->addr))
+		addrslen += IN6ADDRSZ;
+	      else
+		addrslen += sizeof (at2->addr);
+	    }
+	  canon = at->name;
+	  canonlen = strlen (canon) + 1;
+
+	  total = sizeof (*dataset) + naddrs + addrslen + canonlen;
+
+	  /* Now we can allocate the data structure.  If the TTL of the
+	     entry is reported as zero do not cache the entry at all.  */
+	  if (ttl != 0 && he == NULL)
+	    {
+	      dataset = (struct dataset *) mempool_alloc (db, total
+							  + req->key_len,
+							  IDX_result_data);
+	      if (dataset == NULL)
+		++db->head->addfailed;
+	    }
+
+	  if (dataset == NULL)
+	    {
+	      /* We cannot permanently add the result in the moment.  But
+		 we can provide the result as is.  Store the data in some
+		 temporary memory.  */
+	      dataset = (struct dataset *) alloca (total + req->key_len);
+
+	      /* We cannot add this record to the permanent database.  */
+	      alloca_used = true;
+	    }
+
+	  /* Fill in the address and address families.  */
+	  char *addrs = (char *) (&dataset->resp + 1);
+	  uint8_t *family = (uint8_t *) (addrs + addrslen);
+
+	  for (struct gaih_addrtuple *at2 = at; at2 != NULL; at2 = at2->next)
+	    {
+	      *family++ = at2->family;
+	      if (at2->family == AF_INET)
+		addrs = mempcpy (addrs, at2->addr, INADDRSZ);
+	      else if (at2->family == AF_INET6
+		       && IN6ADDRSZ != sizeof (at2->addr))
+		addrs = mempcpy (addrs, at2->addr, IN6ADDRSZ);
+	      else
+		addrs = mempcpy (addrs, at2->addr, sizeof (at2->addr));
+	    }
+
+	  cp = family;
+	}
+      else
+	{
+	  /* Prefer the function which also returns the TTL and
+	     canonical name.  */
+	  nss_gethostbyname3_r fct = __nss_lookup_function (nip,
+							    "gethostbyname3_r");
+	  if (fct == NULL)
+	    fct = __nss_lookup_function (nip, "gethostbyname2_r");
+
+	  if (fct == NULL)
+	    goto next_nip;
+
 	  struct hostent th[2];
 
 	  /* Collect IPv6 information first.  */
@@ -134,8 +227,8 @@
 	    {
 	      rc6 = 0;
 	      status[0] = DL_CALL_FCT (fct, (key, AF_INET6, &th[0], tmpbuf6,
-					     tmpbuf6len, &rc6, &herrno,
-					     &ttl, &canon));
+					     tmpbuf6len, &rc6, &herrno, &ttl,
+					     &canon));
 	      if (rc6 != ERANGE || herrno != NETDB_INTERNAL)
 		break;
 	      tmpbuf6 = extend_alloca (tmpbuf6, tmpbuf6len, 2 * tmpbuf6len);
@@ -173,231 +266,226 @@
 	  if (rc4 != 0 && herrno == NETDB_INTERNAL)
 	    goto out;
 
-	  if (status[0] == NSS_STATUS_SUCCESS
-	      || status[1] == NSS_STATUS_SUCCESS)
-	    {
-	      /* We found the data.  Count the addresses and the size.  */
-	      int naddrs = 0;
-	      size_t addrslen = 0;
-	      for (int j = 0; j < 2; ++j)
-		if (status[j] == NSS_STATUS_SUCCESS)
-		  for (int i = 0; th[j].h_addr_list[i] != NULL; ++i)
+	  if (status[0] != NSS_STATUS_SUCCESS
+	      && status[1] != NSS_STATUS_SUCCESS)
+	    goto next_nip;
+
+	  /* We found the data.  Count the addresses and the size.  */
+	  for (int j = 0; j < 2; ++j)
+	    if (status[j] == NSS_STATUS_SUCCESS)
+	      for (int i = 0; th[j].h_addr_list[i] != NULL; ++i)
+		{
+		  ++naddrs;
+		  addrslen += th[j].h_length;
+		}
+
+	  if (canon == NULL)
+	    {
+	      /* Determine the canonical name.  */
+	      nss_getcanonname_r cfct;
+	      cfct = __nss_lookup_function (nip, "getcanonname_r");
+	      if (cfct != NULL)
+		{
+		  const size_t max_fqdn_len = 256;
+		  char *buf = alloca (max_fqdn_len);
+		  char *s;
+		  int rc;
+
+		  if (DL_CALL_FCT (cfct, (key, buf, max_fqdn_len, &s,
+					  &rc, &herrno))
+		      == NSS_STATUS_SUCCESS)
+		    canon = s;
+		  else
+		    /* Set to name now to avoid using gethostbyaddr.  */
+		    canon = key;
+		}
+	      else
+		{
+		  struct hostent *he = NULL;
+		  int herrno;
+		  struct hostent he_mem;
+		  void *addr;
+		  size_t addrlen;
+		  int addrfamily;
+
+		  if (status[1] == NSS_STATUS_SUCCESS)
 		    {
-		      ++naddrs;
-		      addrslen += th[j].h_length;
-		    }
-
-	      if (canon == NULL)
-		{
-		  /* Determine the canonical name.  */
-		  nss_getcanonname_r cfct;
-		  cfct = __nss_lookup_function (nip, "getcanonname_r");
-		  if (cfct != NULL)
-		    {
-		      const size_t max_fqdn_len = 256;
-		      char *buf = alloca (max_fqdn_len);
-		      char *s;
-		      int rc;
-
-		      if (DL_CALL_FCT (cfct, (key, buf, max_fqdn_len, &s, &rc,
-					      &herrno)) == NSS_STATUS_SUCCESS)
-			canon = s;
-		      else
-			/* Set to name now to avoid using gethostbyaddr.  */
-			canon = key;
+		      addr = th[1].h_addr_list[0];
+		      addrlen = sizeof (struct in_addr);
+		      addrfamily = AF_INET;
 		    }
 		  else
 		    {
-		      struct hostent *he = NULL;
-		      int herrno;
-		      struct hostent he_mem;
-		      void *addr;
-		      size_t addrlen;
-		      int addrfamily;
-
-		      if (status[1] == NSS_STATUS_SUCCESS)
-			{
-			  addr = th[1].h_addr_list[0];
-			  addrlen = sizeof (struct in_addr);
-			  addrfamily = AF_INET;
-			}
+		      addr = th[0].h_addr_list[0];
+		      addrlen = sizeof (struct in6_addr);
+		      addrfamily = AF_INET6;
+		    }
+
+		  size_t tmpbuflen = 512;
+		  char *tmpbuf = alloca (tmpbuflen);
+		  int rc;
+		  while (1)
+		    {
+		      rc = __gethostbyaddr2_r (addr, addrlen, addrfamily,
+					       &he_mem, tmpbuf, tmpbuflen,
+					       &he, &herrno, NULL);
+		      if (rc != ERANGE || herrno != NETDB_INTERNAL)
+			break;
+		      tmpbuf = extend_alloca (tmpbuf, tmpbuflen,
+					      tmpbuflen * 2);
+		    }
+
+		  if (rc == 0)
+		    {
+		      if (he != NULL)
+			canon = he->h_name;
 		      else
-			{
-			  addr = th[0].h_addr_list[0];
-			  addrlen = sizeof (struct in6_addr);
-			  addrfamily = AF_INET6;
-			}
-
-		      size_t tmpbuflen = 512;
-		      char *tmpbuf = alloca (tmpbuflen);
-		      int rc;
-		      while (1)
-			{
-			  rc = __gethostbyaddr2_r (addr, addrlen, addrfamily,
-						   &he_mem, tmpbuf, tmpbuflen,
-						   &he, &herrno, NULL);
-			  if (rc != ERANGE || herrno != NETDB_INTERNAL)
-			    break;
-			  tmpbuf = extend_alloca (tmpbuf, tmpbuflen,
-						  tmpbuflen * 2);
-			}
-
-		      if (rc == 0)
-			{
-			  if (he != NULL)
-			    canon = he->h_name;
-			  else
-			    canon = key;
-			}
+			canon = key;
 		    }
 		}
-	      size_t canonlen = canon == NULL ? 0 : (strlen (canon) + 1);
-
-	      total = sizeof (*dataset) + naddrs + addrslen + canonlen;
-
-	      /* Now we can allocate the data structure.  If the TTL
-		 of the entry is reported as zero do not cache the
-		 entry at all.  */
-	      if (ttl != 0 && he == NULL)
+	    }
+
+	  canonlen = canon == NULL ? 0 : (strlen (canon) + 1);
+
+	  total = sizeof (*dataset) + naddrs + addrslen + canonlen;
+
+
+	  /* Now we can allocate the data structure.  If the TTL of the
+	     entry is reported as zero do not cache the entry at all.  */
+	  if (ttl != 0 && he == NULL)
+	    {
+	      dataset = (struct dataset *) mempool_alloc (db, total
+							  + req->key_len,
+							  IDX_result_data);
+	      if (dataset == NULL)
+		++db->head->addfailed;
+	    }
+
+	  if (dataset == NULL)
+	    {
+	      /* We cannot permanently add the result in the moment.  But
+		 we can provide the result as is.  Store the data in some
+		 temporary memory.  */
+	      dataset = (struct dataset *) alloca (total + req->key_len);
+
+	      /* We cannot add this record to the permanent database.  */
+	      alloca_used = true;
+	    }
+
+	  /* Fill in the address and address families.  */
+	  char *addrs = (char *) (&dataset->resp + 1);
+	  uint8_t *family = (uint8_t *) (addrs + addrslen);
+
+	  for (int j = 0; j < 2; ++j)
+	    if (status[j] == NSS_STATUS_SUCCESS)
+	      for (int i = 0; th[j].h_addr_list[i] != NULL; ++i)
 		{
-		  dataset = (struct dataset *) mempool_alloc (db,
-							      total
-							      + req->key_len,
-							      IDX_result_data);
-		  if (dataset == NULL)
-		    ++db->head->addfailed;
+		  addrs = mempcpy (addrs, th[j].h_addr_list[i],
+				   th[j].h_length);
+		  *family++ = th[j].h_addrtype;
 		}
 
-	      if (dataset == NULL)
+	  cp = family;
+	}
+
+      /* Fill in the rest of the dataset.  */
+      dataset->head.allocsize = total + req->key_len;
+      dataset->head.recsize = total - offsetof (struct dataset, resp);
+      dataset->head.notfound = false;
+      dataset->head.nreloads = he == NULL ? 0 : (dh->nreloads + 1);
+      dataset->head.usable = true;
+
+      /* Compute the timeout time.  */
+      dataset->head.timeout = time (NULL) + (ttl == INT32_MAX
+					     ? db->postimeout : ttl);
+
+      dataset->resp.version = NSCD_VERSION;
+      dataset->resp.found = 1;
+      dataset->resp.naddrs = naddrs;
+      dataset->resp.addrslen = addrslen;
+      dataset->resp.canonlen = canonlen;
+      dataset->resp.error = NETDB_SUCCESS;
+
+      if (canon != NULL)
+	cp = mempcpy (cp, canon, canonlen);
+
+      key_copy = memcpy (cp, key, req->key_len);
+
+      /* Now we can determine whether on refill we have to create a
+	 new record or not.  */
+      if (he != NULL)
+	{
+	  assert (fd == -1);
+
+	  if (total + req->key_len == dh->allocsize
+	      && total - offsetof (struct dataset, resp) == dh->recsize
+	      && memcmp (&dataset->resp, dh->data,
+			 dh->allocsize - offsetof (struct dataset,
+						   resp)) == 0)
+	    {
+	      /* The data has not changed.  We will just bump the
+		 timeout value.  Note that the new record has been
+		 allocated on the stack and need not be freed.  */
+	      dh->timeout = dataset->head.timeout;
+	      ++dh->nreloads;
+	    }
+	  else
+	    {
+	      /* We have to create a new record.  Just allocate
+		 appropriate memory and copy it.  */
+	      struct dataset *newp
+		= (struct dataset *) mempool_alloc (db, total + req->key_len,
+						    IDX_result_data);
+	      if (__builtin_expect (newp != NULL, 1))
 		{
-		  /* We cannot permanently add the result in the moment.  But
-		     we can provide the result as is.  Store the data in some
-		     temporary memory.  */
-		  dataset = (struct dataset *) alloca (total + req->key_len);
-
-		  /* We cannot add this record to the permanent database.  */
-		  alloca_used = true;
-		}
-
-	      dataset->head.allocsize = total + req->key_len;
-	      dataset->head.recsize = total - offsetof (struct dataset, resp);
-	      dataset->head.notfound = false;
-	      dataset->head.nreloads = he == NULL ? 0 : (dh->nreloads + 1);
-	      dataset->head.usable = true;
-
-	      /* Compute the timeout time.  */
-	      dataset->head.timeout = time (NULL) + (ttl == INT32_MAX
-						     ? db->postimeout : ttl);
-
-	      dataset->resp.version = NSCD_VERSION;
-	      dataset->resp.found = 1;
-	      dataset->resp.naddrs = naddrs;
-	      dataset->resp.addrslen = addrslen;
-	      dataset->resp.canonlen = canonlen;
-	      dataset->resp.error = NETDB_SUCCESS;
-
-	      char *addrs = (char *) (&dataset->resp + 1);
-	      uint8_t *family = (uint8_t *) (addrs + addrslen);
-
-	      for (int j = 0; j < 2; ++j)
-		if (status[j] == NSS_STATUS_SUCCESS)
-		  for (int i = 0; th[j].h_addr_list[i] != NULL; ++i)
-		    {
-		      addrs = mempcpy (addrs, th[j].h_addr_list[i],
-				       th[j].h_length);
-		      *family++ = th[j].h_addrtype;
-		    }
-
-	      void *cp = family;
-	      if (canon != NULL)
-		cp = mempcpy (cp, canon, canonlen);
-
-	      key_copy = memcpy (cp, key, req->key_len);
-
-	      /* Now we can determine whether on refill we have to
-		 create a new record or not.  */
-	      if (he != NULL)
-		{
-		  assert (fd == -1);
-
-		  if (total + req->key_len == dh->allocsize
-		      && total - offsetof (struct dataset, resp) == dh->recsize
-		      && memcmp (&dataset->resp, dh->data,
-				 dh->allocsize
-				 - offsetof (struct dataset, resp)) == 0)
-		    {
-		      /* The data has not changed.  We will just bump the
-			 timeout value.  Note that the new record has been
-			 allocated on the stack and need not be freed.  */
-		      dh->timeout = dataset->head.timeout;
-		      ++dh->nreloads;
-		    }
-		  else
-		    {
-		      /* We have to create a new record.  Just allocate
-			 appropriate memory and copy it.  */
-		      struct dataset *newp
-			= (struct dataset *) mempool_alloc (db,
-							    total
-							    + req->key_len,
-							    IDX_result_data);
-		      if (__builtin_expect (newp != NULL, 1))
-			{
-			  /* Adjust pointer into the memory block.  */
-			  key_copy = (char *) newp + (key_copy
-						      - (char *) dataset);
-
-			  dataset = memcpy (newp, dataset,
-					    total + req->key_len);
-			  alloca_used = false;
-			}
-		      else
-			++db->head->addfailed;
-
-		      /* Mark the old record as obsolete.  */
-		      dh->usable = false;
-		    }
+		  /* Adjust pointer into the memory block.  */
+		  key_copy = (char *) newp + (key_copy - (char *) dataset);
+
+		  dataset = memcpy (newp, dataset, total + req->key_len);
+		  alloca_used = false;
 		}
 	      else
-		{
-		  /* We write the dataset before inserting it to the
-		     database since while inserting this thread might
-		     block and so would unnecessarily let the receiver
-		     wait.  */
-		  assert (fd != -1);
+		++db->head->addfailed;
+
+	      /* Mark the old record as obsolete.  */
+	      dh->usable = false;
+	    }
+	}
+      else
+	{
+	  /* We write the dataset before inserting it to the database
+	     since while inserting this thread might block and so
+	     would unnecessarily let the receiver wait.  */
+	  assert (fd != -1);
 
 #ifdef HAVE_SENDFILE
-		  if (__builtin_expect (db->mmap_used, 1) && !alloca_used)
-		    {
-		      assert (db->wr_fd != -1);
-		      assert ((char *) &dataset->resp > (char *) db->data);
-		      assert ((char *) &dataset->resp - (char *) db->head
-			      + total
-			      <= (sizeof (struct database_pers_head)
-				  + db->head->module * sizeof (ref_t)
-				  + db->head->data_size));
-		      ssize_t written;
-		      written = sendfileall (fd, db->wr_fd,
-					     (char *) &dataset->resp
-					     - (char *) db->head, total);
+	  if (__builtin_expect (db->mmap_used, 1) && !alloca_used)
+	    {
+	      assert (db->wr_fd != -1);
+	      assert ((char *) &dataset->resp > (char *) db->data);
+	      assert ((char *) &dataset->resp - (char *) db->head + total
+		      <= (sizeof (struct database_pers_head)
+			  + db->head->module * sizeof (ref_t)
+			  + db->head->data_size));
+	      ssize_t written;
+	      written = sendfileall (fd, db->wr_fd, (char *) &dataset->resp
+				     - (char *) db->head, total);
 # ifndef __ASSUME_SENDFILE
-		      if (written == -1 && errno == ENOSYS)
-			goto use_write;
+	      if (written == -1 && errno == ENOSYS)
+		goto use_write;
 # endif
-		    }
-		  else
+	    }
+	  else
 # ifndef __ASSUME_SENDFILE
-		  use_write:
+	  use_write:
 # endif
 #endif
-		    writeall (fd, &dataset->resp, total);
-		}
-
-	      goto out;
-	    }
-
+	    writeall (fd, &dataset->resp, total);
 	}
 
+      goto out;
+
+next_nip:
       if (nss_next_action (nip, status[1]) == NSS_ACTION_RETURN)
 	break;
 
@@ -468,10 +556,8 @@
       /* Now get the lock to safely insert the records.  */
       pthread_rwlock_rdlock (&db->lock);
 
-      if (cache_add (req->type, key_copy, req->key_len, &dataset->head, true,
-		     db, uid) < 0)
-	/* Ensure the data can be recovered.  */
-	dataset->head.usable = false;
+      (void) cache_add (req->type, key_copy, req->key_len, &dataset->head,
+			true, db, uid);
 
       pthread_rwlock_unlock (&db->lock);
 

Modified: trunk/libc/nscd/cache.c
==============================================================================
--- trunk/libc/nscd/cache.c (original)
+++ trunk/libc/nscd/cache.c Mon May 12 08:38:35 2008
@@ -161,6 +161,11 @@
     {
       ++table->head->addfailed;
 
+      /* If necessary mark the entry as unusable so that lookups will
+	 not use it.  */
+      if (first)
+	packet->usable = false;
+
       /* Mark the in-flight memory as unused.  */
       for (enum in_flight idx = 0; idx < IDX_record_data; ++idx)
 	mem_in_flight.block[idx].dbidx = -1;

Modified: trunk/libc/nscd/grpcache.c
==============================================================================
--- trunk/libc/nscd/grpcache.c (original)
+++ trunk/libc/nscd/grpcache.c Mon May 12 08:38:35 2008
@@ -146,10 +146,8 @@
 	      /* Now get the lock to safely insert the records.  */
 	      pthread_rwlock_rdlock (&db->lock);
 
-	      if (cache_add (req->type, &dataset->strdata, req->key_len,
-			     &dataset->head, true, db, owner) < 0)
-		/* Ensure the data can be recovered.  */
-		dataset->head.usable = false;
+	      (void) cache_add (req->type, &dataset->strdata, req->key_len,
+				&dataset->head, true, db, owner);
 
 	      pthread_rwlock_unlock (&db->lock);
 
@@ -356,12 +354,7 @@
 	    {
 	      if (cache_add (GETGRBYGID, cp, key_offset, &dataset->head, true,
 			     db, owner) < 0)
-		{
-		  /* Could not allocate memory.  Make sure the data gets
-		     discarded.  */
-		  dataset->head.usable = false;
-		  goto out;
-		}
+		goto out;
 
 	      first = false;
 	    }
@@ -370,12 +363,7 @@
 	    {
 	      if (cache_add (GETGRBYNAME, key_copy, key_len + 1,
 			     &dataset->head, true, db, owner) < 0)
-		{
-		  /* Could not allocate memory.  Make sure the data gets
-		     discarded.  */
-		  dataset->head.usable = false;
-		  goto out;
-		}
+		goto out;
 
 	      first = false;
 	    }
@@ -389,12 +377,8 @@
 	    {
 	      if (req->type == GETGRBYNAME && db->propagate)
 		(void) cache_add (GETGRBYGID, cp, key_offset, &dataset->head,
-				  req->type != GETGRBYNAME, db, owner);
-	    }
-	  else if (first)
-	    /* Could not allocate memory.  Make sure the data gets
-	       discarded.  */
-	    dataset->head.usable = false;
+				  false, db, owner);
+	    }
 
 	out:
 	  pthread_rwlock_unlock (&db->lock);

Modified: trunk/libc/nscd/hstcache.c
==============================================================================
--- trunk/libc/nscd/hstcache.c (original)
+++ trunk/libc/nscd/hstcache.c Mon May 12 08:38:35 2008
@@ -155,10 +155,8 @@
 	      /* Now get the lock to safely insert the records.  */
 	      pthread_rwlock_rdlock (&db->lock);
 
-	      if (cache_add (req->type, &dataset->strdata, req->key_len,
-			     &dataset->head, true, db, owner) < 0)
-		/* Ensure the data can be recovered.  */
-		dataset->head.usable = false;
+	      (void) cache_add (req->type, &dataset->strdata, req->key_len,
+				&dataset->head, true, db, owner);
 
 	      pthread_rwlock_unlock (&db->lock);
 
@@ -409,11 +407,8 @@
 		  || req->type == GETHOSTBYADDR
 		  || req->type == GETHOSTBYADDRv6);
 
-	  if (cache_add (req->type, key_copy, req->key_len,
-			 &dataset->head, true, db, owner) < 0)
-	    /* Could not allocate memory.  Make sure the
-	       data gets discarded.  */
-	    dataset->head.usable = false;
+	  (void) cache_add (req->type, key_copy, req->key_len,
+			    &dataset->head, true, db, owner);
 
 	  pthread_rwlock_unlock (&db->lock);
 	}

Modified: trunk/libc/nscd/initgrcache.c
==============================================================================
--- trunk/libc/nscd/initgrcache.c (original)
+++ trunk/libc/nscd/initgrcache.c Mon May 12 08:38:35 2008
@@ -230,10 +230,8 @@
 	      /* Now get the lock to safely insert the records.  */
 	      pthread_rwlock_rdlock (&db->lock);
 
-	      if (cache_add (req->type, key_copy, req->key_len,
-			     &dataset->head, true, db, uid) < 0)
-		/* Ensure the data can be recovered.  */
-		dataset->head.usable = false;
+	      (void) cache_add (req->type, key_copy, req->key_len,
+				&dataset->head, true, db, uid);
 
 	      pthread_rwlock_unlock (&db->lock);
 
@@ -399,11 +397,8 @@
 	  /* Now get the lock to safely insert the records.  */
 	  pthread_rwlock_rdlock (&db->lock);
 
-	  if (cache_add (INITGROUPS, cp, req->key_len, &dataset->head, true,
-			 db, uid) < 0)
-	    /* Could not allocate memory.  Make sure the data gets
-	       discarded.  */
-	    dataset->head.usable = false;
+	  (void) cache_add (INITGROUPS, cp, req->key_len, &dataset->head, true,
+			    db, uid);
 
 	  pthread_rwlock_unlock (&db->lock);
 	}

Modified: trunk/libc/nscd/pwdcache.c
==============================================================================
--- trunk/libc/nscd/pwdcache.c (original)
+++ trunk/libc/nscd/pwdcache.c Mon May 12 08:38:35 2008
@@ -153,11 +153,8 @@
 	      /* Now get the lock to safely insert the records.  */
 	      pthread_rwlock_rdlock (&db->lock);
 
-	      if (cache_add (req->type, key_copy, req->key_len,
-			     &dataset->head, true, db, owner) < 0)
-		/* Ensure the data can be recovered.  */
-		dataset->head.usable = false;
-
+	      (void) cache_add (req->type, key_copy, req->key_len,
+				&dataset->head, true, db, owner);
 
 	      pthread_rwlock_unlock (&db->lock);
 
@@ -352,12 +349,7 @@
 	    {
 	      if (cache_add (GETPWBYUID, cp, key_offset, &dataset->head, true,
 			     db, owner) < 0)
-		{
-		  /* Could not allocate memory.  Make sure the data gets
-		     discarded.  */
-		  dataset->head.usable = false;
-		  goto out;
-		}
+		goto out;
 
 	      first = false;
 	    }
@@ -366,12 +358,7 @@
 	    {
 	      if (cache_add (GETPWBYNAME, key_copy, key_len + 1,
 			     &dataset->head, true, db, owner) < 0)
-		{
-		  /* Could not allocate memory.  Make sure the data gets
-		     discarded.  */
-		  dataset->head.usable = false;
-		  goto out;
-		}
+		goto out;
 
 	      first = false;
 	    }
@@ -384,12 +371,8 @@
 	    {
 	      if (req->type == GETPWBYNAME && db->propagate)
 		(void) cache_add (GETPWBYUID, cp, key_offset, &dataset->head,
-				  req->type != GETPWBYNAME, db, owner);
-	    }
-	  else if (first)
-	    /* Could not allocate memory.  Make sure the data gets
-	       discarded.  */
-	    dataset->head.usable = false;
+				  false, db, owner);
+	    }
 
 	out:
 	  pthread_rwlock_unlock (&db->lock);

Modified: trunk/libc/nscd/servicescache.c
==============================================================================
--- trunk/libc/nscd/servicescache.c (original)
+++ trunk/libc/nscd/servicescache.c Mon May 12 08:38:35 2008
@@ -136,10 +136,8 @@
 	      /* Now get the lock to safely insert the records.  */
 	      pthread_rwlock_rdlock (&db->lock);
 
-	      if (cache_add (req->type, &dataset->strdata, req->key_len,
-			     &dataset->head, true, db, owner) < 0)
-		/* Ensure the data can be recovered.  */
-		dataset->head.usable = false;
+	      (void) cache_add (req->type, &dataset->strdata, req->key_len,
+				&dataset->head, true, db, owner);
 
 	      pthread_rwlock_unlock (&db->lock);
 
@@ -332,11 +330,8 @@
 	  /* Now get the lock to safely insert the records.  */
 	  pthread_rwlock_rdlock (&db->lock);
 
-	  if (cache_add (req->type, key_copy, req->key_len,
-			 &dataset->head, true, db, owner) < 0)
-	    /* Could not allocate memory.  Make sure the
-	       data gets discarded.  */
-	    dataset->head.usable = false;
+	  (void) cache_add (req->type, key_copy, req->key_len,
+			    &dataset->head, true, db, owner);
 
 	  pthread_rwlock_unlock (&db->lock);
 	}

Modified: trunk/libc/nss/Versions
==============================================================================
--- trunk/libc/nss/Versions (original)
+++ trunk/libc/nss/Versions Mon May 12 08:38:35 2008
@@ -38,6 +38,7 @@
     _nss_files_endhostent;
     _nss_files_gethostbyaddr_r;
     _nss_files_gethostbyname2_r;
+    _nss_files_gethostbyname4_r;
     _nss_files_gethostbyname_r;
     _nss_files_gethostent_r;
     _nss_files_gethostton_r;

Modified: trunk/libc/nss/nss.h
==============================================================================
--- trunk/libc/nss/nss.h (original)
+++ trunk/libc/nss/nss.h Mon May 12 08:38:35 2008
@@ -1,4 +1,4 @@
-/* Copyright (C) 1996, 1997, 1999 Free Software Foundation, Inc.
+/* Copyright (C) 1996, 1997, 1999, 2008 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
@@ -23,6 +23,7 @@
 #define _NSS_H	1
 
 #include <features.h>
+#include <stdint.h>
 
 
 __BEGIN_DECLS
@@ -38,6 +39,17 @@
 };
 
 
+/* Data structure used for the 'gethostbyname4_r' function.  */
+struct gaih_addrtuple
+  {
+    struct gaih_addrtuple *next;
+    char *name;
+    int family;
+    uint32_t addr[4];
+    uint32_t scopeid;
+  };
+
+
 /* Overwrite service selection for database DBNAME using specification
    in STRING.
    This function should only be used by system programs which have to

Modified: trunk/libc/nss/nss_files/files-hosts.c
==============================================================================
--- trunk/libc/nss/nss_files/files-hosts.c (original)
+++ trunk/libc/nss/nss_files/files-hosts.c Mon May 12 08:38:35 2008
@@ -1,6 +1,5 @@
 /* Hosts file parser in nss_files module.
-   Copyright (C) 1996-2001, 2003, 2004, 2006, 2007
-   Free Software Foundation, Inc.
+   Copyright (C) 1996-2001, 2003-2007, 2008 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
@@ -56,7 +55,10 @@
    STRING_FIELD (addr, isspace, 1);
 
    /* Parse address.  */
-   if (inet_pton (af, addr, entdata->host_addr) <= 0)
+   if (inet_pton (af == AF_UNSPEC ? AF_INET : af, addr, entdata->host_addr)
+       > 0)
+     af = af == AF_UNSPEC ? AF_INET : af;
+   else
      {
        if (af == AF_INET6 && (flags & AI_V4MAPPED) != 0
 	   && inet_pton (AF_INET, addr, entdata->host_addr) > 0)
@@ -76,6 +78,9 @@
 	     /* Illegal address: ignore line.  */
 	     return 0;
 	 }
+       else if (af == AF_UNSPEC
+		&& inet_pton (AF_INET6, addr, entdata->host_addr) > 0)
+	 af = AF_INET6;
        else
 	 /* Illegal address: ignore line.  */
 	 return 0;
@@ -101,8 +106,6 @@
 			  struct STRUCTURE *result, char *buffer,	      \
 			  size_t buflen, int *errnop H_ERRNO_PROTO)	      \
 {									      \
-  enum nss_status status;						      \
-									      \
   uintptr_t pad = -(uintptr_t) buffer % __alignof__ (struct hostent_data);    \
   buffer += pad;							      \
   buflen = buflen > pad ? buflen - pad : 0;				      \
@@ -110,7 +113,7 @@
   __libc_lock_lock (lock);						      \
 									      \
   /* Reset file pointer to beginning or open file.  */			      \
-  status = internal_setent (keep_stream);				      \
+  enum nss_status status = internal_setent (keep_stream);		      \
 									      \
   if (status == NSS_STATUS_SUCCESS)					      \
     {									      \
@@ -288,9 +291,9 @@
 		{
 		  LOOKUP_NAME_CASE (h_name, h_aliases)
 		}, const char *name)
-
-
 #undef EXTRA_ARGS_VALUE
+
+
 /* XXX Is using _res to determine whether we want to convert IPv4 addresses
    to IPv6 addresses really the right thing to do?  */
 #define EXTRA_ARGS_VALUE \
@@ -299,8 +302,9 @@
 		{
 		  LOOKUP_NAME_CASE (h_name, h_aliases)
 		}, const char *name, int af)
-
 #undef EXTRA_ARGS_VALUE
+
+
 /* We only need to consider IPv4 mapped addresses if the input to the
    gethostbyaddr() function is an IPv6 address.  */
 #define EXTRA_ARGS_VALUE \
@@ -311,3 +315,116 @@
 		 && ! memcmp (addr, result->h_addr_list[0], len))
 	       break;
 	   }, const void *addr, socklen_t len, int af)
+#undef EXTRA_ARGS_VALUE
+
+
+enum nss_status
+_nss_files_gethostbyname4_r (const char *name, struct gaih_addrtuple **pat,
+			     char *buffer, size_t buflen, int *errnop,
+			     int *herrnop, int32_t *ttlp)
+{
+  __libc_lock_lock (lock);
+
+  /* Reset file pointer to beginning or open file.  */
+  enum nss_status status = internal_setent (keep_stream);
+
+  if (status == NSS_STATUS_SUCCESS)
+    {
+      /* Tell getent function that we have repositioned the file pointer.  */
+      last_use = getby;
+
+      bool any = false;
+      bool got_canon = false;
+      while (1)
+	{
+	  /* Align the buffer for the next record.  */
+	  uintptr_t pad = (-(uintptr_t) buffer
+			   % __alignof__ (struct hostent_data));
+	  buffer += pad;
+	  buflen = buflen > pad ? buflen - pad : 0;
+
+	  struct hostent result;
+	  status = internal_getent (&result, buffer, buflen, errnop
+				    H_ERRNO_ARG, AF_UNSPEC, 0);
+	  if (status != NSS_STATUS_SUCCESS)
+	    break;
+
+	  int naliases = 0;
+	  if (__strcasecmp (name, result.h_name) != 0)
+	    {
+	      for (; result.h_aliases[naliases] != NULL; ++naliases)
+		if (! __strcasecmp (name, result.h_aliases[naliases]))
+		  break;
+	      if (result.h_aliases[naliases] == NULL)
+		continue;
+
+	      /* We know this alias exist.  Count it.  */
+	      ++naliases;
+	    }
+
+	  /* Determine how much memory has been used so far.  */
+	  // XXX It is not necessary to preserve the aliases array
+	  while (result.h_aliases[naliases] != NULL)
+	    ++naliases;
+	  char *bufferend = (char *) &result.h_aliases[naliases + 1];
+	  assert (buflen >= bufferend - buffer);
+	  buflen -= bufferend - buffer;
+	  buffer = bufferend;
+
+	  /* We found something.  */
+	  any = true;
+
+	  /* Create the record the caller expects.  There is only one
+	     address.  */
+	  assert (result.h_addr_list[1] == NULL);
+	  if (*pat == NULL)
+	    {
+	      uintptr_t pad = (-(uintptr_t) buffer
+			       % __alignof__ (struct gaih_addrtuple));
+	      buffer += pad;
+	      buflen = buflen > pad ? buflen - pad : 0;
+
+	      if (__builtin_expect (buflen < sizeof (struct gaih_addrtuple),
+				    0))
+		{
+		  *errnop = ERANGE;
+		  *herrnop = NETDB_INTERNAL;
+		  status = NSS_STATUS_TRYAGAIN;
+		  break;
+		}
+
+	      *pat = (struct gaih_addrtuple *) buffer;
+	      buffer += sizeof (struct gaih_addrtuple);
+	      buflen -= sizeof (struct gaih_addrtuple);
+	    }
+
+	  (*pat)->next = NULL;
+	  (*pat)->name = got_canon ? NULL : result.h_name;
+	  got_canon = true;
+	  (*pat)->family = result.h_addrtype;
+	  memcpy ((*pat)->addr, result.h_addr_list[0], result.h_length);
+	  (*pat)->scopeid = 0;
+
+	  pat = &((*pat)->next);
+
+	  /* If we only look for the first matching entry we are done.  */
+	  if ((_res_hconf.flags & HCONF_FLAG_MULTI) == 0)
+	    break;
+	}
+
+      /* If we have to look for multiple records and found one, this
+	 is a success.  */
+      if (status == NSS_STATUS_NOTFOUND && any)
+	{
+	  assert ((_res_hconf.flags & HCONF_FLAG_MULTI) != 0);
+	  status = NSS_STATUS_SUCCESS;
+	}
+
+      if (! keep_stream)
+	internal_endent ();
+    }
+
+  __libc_lock_unlock (lock);
+
+  return status;
+}

Modified: trunk/libc/resolv/Versions
==============================================================================
--- trunk/libc/resolv/Versions (original)
+++ trunk/libc/resolv/Versions Mon May 12 08:38:35 2008
@@ -89,6 +89,7 @@
     _nss_dns_gethostbyname_r; _nss_dns_getnetbyaddr_r;
     _nss_dns_getnetbyname_r; _nss_dns_getcanonname_r;
     _nss_dns_gethostbyaddr2_r;
+    _nss_dns_gethostbyname4_r;
   }
 }
 

Modified: trunk/libc/resolv/gethnamaddr.c
==============================================================================
--- trunk/libc/resolv/gethnamaddr.c (original)
+++ trunk/libc/resolv/gethnamaddr.c Mon May 12 08:38:35 2008
@@ -621,7 +621,7 @@
 	buf.buf = origbuf = (querybuf *) alloca (1024);
 
 	if ((n = __libc_res_nsearch(&_res, name, C_IN, type, buf.buf->buf, 1024,
-				    &buf.ptr)) < 0) {
+				    &buf.ptr, NULL, NULL)) < 0) {
 		if (buf.buf != origbuf)
 			free (buf.buf);
 		Dprintf("res_nsearch failed (%d)\n", n);
@@ -716,12 +716,12 @@
 	buf.buf = orig_buf = (querybuf *) alloca (1024);
 
 	n = __libc_res_nquery(&_res, qbuf, C_IN, T_PTR, buf.buf->buf, 1024,
-			      &buf.ptr);
+			      &buf.ptr, NULL, NULL);
 	if (n < 0 && af == AF_INET6 && (_res.options & RES_NOIP6DOTINT) == 0) {
 		strcpy(qp, "ip6.int");
 		n = __libc_res_nquery(&_res, qbuf, C_IN, T_PTR, buf.buf->buf,
 				      buf.buf != orig_buf ? MAXPACKET : 1024,
-				      &buf.ptr);
+				      &buf.ptr, NULL, NULL);
 	}
 	if (n < 0) {
 		if (buf.buf != orig_buf)

Modified: trunk/libc/resolv/nss_dns/dns-canon.c
==============================================================================
--- trunk/libc/resolv/nss_dns/dns-canon.c (original)
+++ trunk/libc/resolv/nss_dns/dns-canon.c Mon May 12 08:38:35 2008
@@ -1,4 +1,4 @@
-/* Copyright (C) 2004, 2006 Free Software Foundation, Inc.
+/* Copyright (C) 2004, 2006, 2008 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@xxxxxxxxxx>, 2004.
 
@@ -61,7 +61,7 @@
   for (int i = 0; i < nqtypes; ++i)
     {
       int r = __libc_res_nquery (&_res, name, ns_c_in, qtypes[i],
-				 buf, sizeof (buf), &ansp.ptr);
+				 buf, sizeof (buf), &ansp.ptr, NULL, NULL);
       if (r > 0)
 	{
 	  /* We need to decode the response.  Just one question record.

Modified: trunk/libc/resolv/nss_dns/dns-host.c
==============================================================================
--- trunk/libc/resolv/nss_dns/dns-host.c (original)
+++ trunk/libc/resolv/nss_dns/dns-host.c Mon May 12 08:38:35 2008
@@ -71,6 +71,7 @@
  * --Copyright--
  */
 
+#include <assert.h>
 #include <ctype.h>
 #include <errno.h>
 #include <netdb.h>
@@ -126,6 +127,14 @@
 				    struct hostent *result, char *buffer,
 				    size_t buflen, int *errnop, int *h_errnop,
 				    int map, int32_t *ttlp, char **canonp);
+
+static enum nss_status gaih_getanswer (const querybuf *answer1, int anslen1,
+				       const querybuf *answer2, int anslen2,
+				       const char *qname,
+				       struct gaih_addrtuple **pat,
+				       char *buffer, size_t buflen,
+				       int *errnop, int *h_errnop,
+				       int32_t *ttlp);
 
 extern enum nss_status _nss_dns_gethostbyname3_r (const char *name, int af,
 						  struct hostent *result,
@@ -186,11 +195,11 @@
   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);
+			  1024, &host_buffer.ptr, NULL, NULL);
   if (n < 0)
     {
-      enum nss_status status = (errno == ECONNREFUSED
-				? NSS_STATUS_UNAVAIL : NSS_STATUS_NOTFOUND);
+      status = (errno == ECONNREFUSED
+		? NSS_STATUS_UNAVAIL : NSS_STATUS_NOTFOUND);
       *h_errnop = h_errno;
       if (h_errno == TRY_AGAIN)
 	*errnop = EAGAIN;
@@ -203,7 +212,8 @@
       if (af == AF_INET6 && (_res.options & RES_USE_INET6))
 	n = __libc_res_nsearch (&_res, name, C_IN, T_A, host_buffer.buf->buf,
 				host_buffer.buf != orig_host_buffer
-				? MAXPACKET : 1024, &host_buffer.ptr);
+				? MAXPACKET : 1024, &host_buffer.ptr,
+				NULL, NULL);
 
       if (n < 0)
 	{
@@ -250,6 +260,70 @@
   if (status == NSS_STATUS_NOTFOUND)
     status = _nss_dns_gethostbyname3_r (name, AF_INET, result, buffer,
 					buflen, errnop, h_errnop, NULL, NULL);
+
+  return status;
+}
+
+
+enum nss_status
+_nss_dns_gethostbyname4_r (const char *name, struct gaih_addrtuple **pat,
+			   char *buffer, size_t buflen, int *errnop,
+			   int *herrnop, int32_t *ttlp)
+{
+  if (__res_maybe_init (&_res, 0) == -1)
+    return NSS_STATUS_UNAVAIL;
+
+  char tmp[NS_MAXDNAME];
+
+  /*
+   * 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)
+    {
+      const char *cp = res_hostalias (&_res, name, tmp, sizeof (tmp));
+      if (cp != NULL)
+	name = cp;
+    }
+
+  union
+  {
+    querybuf *buf;
+    u_char *ptr;
+  } host_buffer;
+  querybuf *orig_host_buffer;
+  host_buffer.buf = orig_host_buffer = (querybuf *) alloca (2048);
+  u_char *ans2p = NULL;
+  int nans2p = 0;
+
+  int olderr = errno;
+  enum nss_status status;
+  int n = __libc_res_nsearch (&_res, name, C_IN, T_UNSPEC,
+			      host_buffer.buf->buf, 2048, &host_buffer.ptr,
+			      &ans2p, &nans2p);
+  if (n < 0)
+    {
+      status = (errno == ECONNREFUSED
+		? NSS_STATUS_UNAVAIL : NSS_STATUS_NOTFOUND);
+      *herrnop = h_errno;
+      if (h_errno == TRY_AGAIN)
+	*errnop = EAGAIN;
+      else
+	__set_errno (olderr);
+
+      if (host_buffer.buf != orig_host_buffer)
+	free (host_buffer.buf);
+
+      return status;
+    }
+
+  status = gaih_getanswer(host_buffer.buf, n, (const querybuf *) ans2p,
+			  nans2p, name, pat, buffer, buflen,
+			  errnop, herrnop, ttlp);
+
+  if (host_buffer.buf != orig_host_buffer)
+    free (host_buffer.buf);
 
   return status;
 }
@@ -342,7 +416,8 @@
 	    qp += sprintf (qp, "%02hhx", uaddr[n]);
 	  strcpy (qp, "].ip6.arpa");
 	  n = __libc_res_nquery (&_res, qbuf, C_IN, T_PTR,
-				 host_buffer.buf->buf, 1024, &host_buffer.ptr);
+				 host_buffer.buf->buf, 1024, &host_buffer.ptr,
+				 NULL, NULL);
 	  if (n >= 0)
 	    goto got_it_already;
 	}
@@ -363,13 +438,14 @@
     }
 
   n = __libc_res_nquery (&_res, qbuf, C_IN, T_PTR, host_buffer.buf->buf,
-			 1024, &host_buffer.ptr);
+			 1024, &host_buffer.ptr, NULL, NULL);
   if (n < 0 && af == AF_INET6 && (_res.options & RES_NOIP6DOTINT) == 0)
     {
       strcpy (qp, "ip6.int");
       n = __libc_res_nquery (&_res, qbuf, C_IN, T_PTR, host_buffer.buf->buf,
 			     host_buffer.buf != orig_host_buffer
-			     ? MAXPACKET : 1024, &host_buffer.ptr);
+			     ? MAXPACKET : 1024, &host_buffer.ptr,
+			     NULL, NULL);
     }
   if (n < 0)
     {
@@ -555,7 +631,8 @@
   if (n > 0 && bp[0] == '.')
     bp[0] = '\0';
 
-  if (n < 0 || (*name_ok) (bp) == 0)
+  if (__builtin_expect (n < 0 || ((*name_ok) (bp) == 0 && (errno = EBADMSG)),
+			0))
     {
       *errnop = errno;
       *h_errnop = NO_RECOVERY;
@@ -629,7 +706,7 @@
 	  continue;			/* XXX - had_error++ ? */
 	}
 
-      if ((qtype ==T_A || qtype == T_AAAA) && type == T_CNAME)
+      if ((qtype == T_A || qtype == T_AAAA) && type == T_CNAME)
 	{
 	  if (ap >= &host_data->aliases[MAX_NR_ALIASES - 1])
 	    continue;
@@ -857,3 +934,245 @@
   return ((qtype == T_A || qtype == T_AAAA) && ap != host_data->aliases
 	   ? NSS_STATUS_NOTFOUND : NSS_STATUS_TRYAGAIN);
 }
+
+
+static enum nss_status
+gaih_getanswer_slice (const querybuf *answer, int anslen, const char *qname,
+		      struct gaih_addrtuple ***patp,
+		      char **bufferp, size_t *buflenp,
+		      int *errnop, int *h_errnop, int32_t *ttlp, int *firstp)
+{
+  char *buffer = *bufferp;
+  size_t buflen = *buflenp;
+
+  struct gaih_addrtuple **pat = *patp;
+  const HEADER *hp = &answer->hdr;
+  int ancount = ntohs (hp->ancount);
+  int qdcount = ntohs (hp->qdcount);
+  const u_char *cp = answer->buf + HFIXEDSZ;
+  const u_char *end_of_message = answer->buf + anslen;
+  if (__builtin_expect (qdcount != 1, 0))
+    {
+      *h_errnop = NO_RECOVERY;
+      return NSS_STATUS_UNAVAIL;
+    }
+
+   u_char packtmp[NS_MAXCDNAME];
+  int n = __ns_name_unpack (answer->buf, end_of_message, cp,
+			    packtmp, sizeof packtmp);
+  /* We unpack the name to check it for validity.  But we do not need
+     it later.  */
+  if (n != -1 && __ns_name_ntop (packtmp, buffer, buflen) == -1)
+    {
+      if (__builtin_expect (errno, 0) == EMSGSIZE)
+	{
+	too_small:
+	  *errnop = ERANGE;
+	  *h_errnop = NETDB_INTERNAL;
+	  return NSS_STATUS_TRYAGAIN;
+	}
+
+      n = -1;
+    }
+
+  if (__builtin_expect (n < 0 || (res_hnok (buffer) == 0
+				  && (errno = EBADMSG)), 0))
+    {
+      *errnop = errno;
+      *h_errnop = NO_RECOVERY;
+      return NSS_STATUS_UNAVAIL;
+    }
+  cp += n + QFIXEDSZ;
+
+  int haveanswer = 0;
+  int had_error = 0;
+  char *canon = NULL;
+  char *h_name = NULL;
+  int h_namelen = 0;
+
+  while (ancount-- > 0 && cp < end_of_message && had_error == 0)
+    {
+      n = __ns_name_unpack (answer->buf, end_of_message, cp,
+			    packtmp, sizeof packtmp);
+      if (n != -1 &&
+	  (h_namelen = __ns_name_ntop (packtmp, buffer, buflen)) == -1)
+	{
+	  if (__builtin_expect (errno, 0) == EMSGSIZE)
+	    goto too_small;
+
+	  n = -1;
+	}
+      if (n < 0 || res_hnok (buffer) == 0)
+	{
+	  ++had_error;
+	  continue;
+	}
+      if (*firstp)
+	{
+	  h_name = buffer;
+	  buffer += h_namelen;
+	  buflen -= h_namelen;
+	}
+
+      cp += n;				/* name */
+      int type = ns_get16 (cp);
+      cp += INT16SZ;			/* type */
+      int class = ns_get16 (cp);
+      cp += INT16SZ;			/* class */
+      int32_t ttl = ns_get32 (cp);
+      cp += INT32SZ;			/* TTL */
+      n = ns_get16 (cp);
+      cp += INT16SZ;			/* len */
+
+      if (class != C_IN)
+	{
+	  cp += n;
+	  continue;
+	}
+
+      if (type == T_CNAME)
+	{
+	  char tbuf[MAXDNAME];
+	  n = dn_expand (answer->buf, end_of_message, cp, tbuf, sizeof tbuf);
+	  if (n < 0 || res_hnok (tbuf) == 0)
+	    {
+	      ++had_error;
+	      continue;
+	    }
+	  cp += n;
+
+	  if (*firstp)
+	    {
+	      /* Reclaim buffer space.  */
+	      if (h_name + h_namelen == buffer)
+		{
+		  buffer = h_name;
+		  buflen += h_namelen;
+		}
+
+	      n = strlen (tbuf) + 1;
+	      if (__builtin_expect (n > buflen, 0))
+		goto too_small;
+	      if (__builtin_expect (n >= MAXHOSTNAMELEN, 0))
+		{
+		  ++had_error;
+		  continue;
+		}
+
+	      canon = buffer;
+	      buffer = __mempcpy (buffer, tbuf, n);
+	      buflen -= n;
+	      h_namelen = 0;
+	    }
+	  continue;
+	}
+      if (__builtin_expect (type == T_SIG, 0)
+	  || __builtin_expect (type == T_KEY, 0)
+	  || __builtin_expect (type == T_NXT, 0)
+	  || __builtin_expect (type == T_PTR, 0))
+	{
+	  /* We don't support DNSSEC yet.  For now, ignore the record
+	     and send a low priority message to syslog.
+
+	     We also don't expect T_PTR messages.  */
+	  syslog (LOG_DEBUG | LOG_AUTH,
+		  "getaddrinfo*.gaih_getanswer: got type \"%s\"",
+		  p_type (type));
+	  cp += n;
+	  continue;
+	}
+      if (type != T_A && type != T_AAAA)
+	abort ();
+
+      if (*pat == NULL)
+	{
+	  uintptr_t pad = (-(uintptr_t) buffer
+			   % __alignof__ (struct gaih_addrtuple));
+	  buffer += pad;
+	  buflen = buflen > pad ? buflen - pad : 0;
+
+	  if (__builtin_expect (buflen < sizeof (struct gaih_addrtuple),
+				0))
+	    {
+	      *errnop = ERANGE;
+	      *h_errnop = NETDB_INTERNAL;
+	      return NSS_STATUS_TRYAGAIN;
+	    }
+
+	  *pat = (struct gaih_addrtuple *) buffer;
+	  buffer += sizeof (struct gaih_addrtuple);
+	  buflen -= sizeof (struct gaih_addrtuple);
+	}
+
+      (*pat)->name = NULL;
+      (*pat)->next = NULL;
+
+      if (*firstp)
+	{
+	  if (ttl != 0 && ttlp != NULL)
+	    *ttlp = ttl;
+
+	  if (canon != NULL)
+	    {
+	      (*pat)->name = canon;
+
+	      /* Reclaim buffer space.  */
+	      if (h_name + h_namelen == buffer)
+		{
+		  buffer = h_name;
+		  buflen += h_namelen;
+		}
+	    }
+	  else
+	    (*pat)->name = h_name;
+
+	  *firstp = 0;
+	}
+
+      (*pat)->family = type == T_A ? AF_INET : AF_INET6;
+      memcpy ((*pat)->addr, cp, n);
+      cp += n;
+      (*pat)->scopeid = 0;
+
+      pat = &((*pat)->next);
+
+      haveanswer = 1;
+    }
+
+  if (haveanswer)
+    {
+      *patp = pat;
+      *bufferp = buffer;
+      *buflenp = buflen;
+
+      *h_errnop = NETDB_SUCCESS;
+      return NSS_STATUS_SUCCESS;
+    }
+
+  /* Special case here: if the resolver sent a result but it only
+     contains a CNAME while we are looking for a T_A or T_AAAA record,
+     we fail with NOTFOUND instead of TRYAGAIN.  */
+  return canon == NULL ? NSS_STATUS_TRYAGAIN : NSS_STATUS_NOTFOUND;
+}
+
+
+static enum nss_status
+gaih_getanswer (const querybuf *answer1, int anslen1, const querybuf *answer2,
+		int anslen2, const char *qname,
+		struct gaih_addrtuple **pat, char *buffer, size_t buflen,
+		int *errnop, int *h_errnop, int32_t *ttlp)
+{
+  int first = 1;
+
+  enum nss_status status = gaih_getanswer_slice(answer1, anslen1, qname,
+						&pat, &buffer, &buflen,
+						errnop, h_errnop, ttlp,
+						&first);
+  if ((status == NSS_STATUS_SUCCESS || status == NSS_STATUS_NOTFOUND)
+      && answer2 != NULL)
+    status = gaih_getanswer_slice(answer2, anslen2, qname,
+				  &pat, &buffer, &buflen,
+				  errnop, h_errnop, ttlp, &first);
+
+  return status;
+}

Modified: trunk/libc/resolv/nss_dns/dns-network.c
==============================================================================
--- trunk/libc/resolv/nss_dns/dns-network.c (original)
+++ trunk/libc/resolv/nss_dns/dns-network.c Mon May 12 08:38:35 2008
@@ -1,4 +1,4 @@
-/* Copyright (C) 1996, 1997, 1998, 1999, 2002, 2004, 2007
+/* Copyright (C) 1996, 1997, 1998, 1999, 2002, 2004, 2007, 2008
    Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Extended from original form by Ulrich Drepper <drepper@xxxxxxxxxx>, 1996.
@@ -130,7 +130,7 @@
   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);
+			       1024, &net_buffer.ptr, NULL, NULL);
   if (anslen < 0)
     {
       /* Nothing found.  */
@@ -206,7 +206,7 @@
   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);
+			      1024, &net_buffer.ptr, NULL, NULL);
   if (anslen < 0)
     {
       /* Nothing found.  */

Modified: trunk/libc/resolv/res_query.c
==============================================================================
--- trunk/libc/resolv/res_query.c (original)
+++ trunk/libc/resolv/res_query.c Mon May 12 08:38:35 2008
@@ -97,7 +97,7 @@
 static int
 __libc_res_nquerydomain(res_state statp, const char *name, const char *domain,
 			int class, int type, u_char *answer, int anslen,
-			u_char **answerp);
+			u_char **answerp, u_char **answerp2, int *nanswerp2);
 
 /*
  * Formulate a normal query, send, and await answer.
@@ -115,15 +115,20 @@
 		  int class, int type,	/* class and type of query */
 		  u_char *answer,	/* buffer to put answer */
 		  int anslen,		/* size of answer buffer */
-		  u_char **answerp)	/* if buffer needs to be enlarged */
+		  u_char **answerp,	/* if buffer needs to be enlarged */
+		  u_char **answerp2,
+		  int *nanswerp2)
 {
-	u_char *buf;
 	HEADER *hp = (HEADER *) answer;
 	int n, use_malloc = 0;
         u_int oflags = statp->_flags;
 
-	size_t bufsize = QUERYSIZE;
-	buf = alloca (bufsize);
+	size_t bufsize = (type == T_UNSPEC ? 2 : 1) * QUERYSIZE;
+	u_char *buf = alloca (bufsize);
+	u_char *query1 = buf;
+	int nquery1 = -1;
+	u_char *query2 = NULL;
+	int nquery2 = 0;
 
  again:
 	hp->rcode = NOERROR;	/* default */
@@ -133,18 +138,47 @@
 		printf(";; res_query(%s, %d, %d)\n", name, class, type);
 #endif
 
-	n = res_nmkquery(statp, QUERY, name, class, type, NULL, 0, NULL,
-			 buf, bufsize);
-	if (n > 0
-	    && (oflags & RES_F_EDNS0ERR) == 0
-	    && (statp->options & RES_USE_EDNS0) != 0)
-		n = __res_nopt(statp, n, buf, bufsize, anslen);
+	if (type == T_UNSPEC)
+	  {
+	    n = res_nmkquery(statp, QUERY, name, class, T_A, NULL, 0, NULL,
+			     query1, bufsize);
+	    if (n > 0)
+	      {
+		if ((oflags & RES_F_EDNS0ERR) == 0
+		    && (statp->options & RES_USE_EDNS0) != 0)
+		  n = __res_nopt(statp, n, query1, bufsize, anslen / 2);
+
+		nquery1 = n;
+		query2 = buf + nquery1;
+		n = res_nmkquery(statp, QUERY, name, class, T_AAAA, NULL, 0,
+				 NULL, query2, bufsize - n);
+		if (n > 0
+		    && (oflags & RES_F_EDNS0ERR) == 0
+		    && (statp->options & RES_USE_EDNS0) != 0)
+		  n = __res_nopt(statp, n, query2, bufsize - n, anslen / 2);
+		nquery2 = n;
+	      }
+	  }
+	else
+	  {
+	    n = res_nmkquery(statp, QUERY, name, class, type, NULL, 0, NULL,
+			     query1, bufsize);
+
+	    if (n > 0
+		&& (oflags & RES_F_EDNS0ERR) == 0
+		&& (statp->options & RES_USE_EDNS0) != 0)
+	      n = __res_nopt(statp, n, query1, bufsize, anslen);
+
+	    nquery1 = n;
+	  }
+
 	if (__builtin_expect (n <= 0, 0) && !use_malloc) {
 		/* Retry just in case res_nmkquery failed because of too
 		   short buffer.  Shouldn't happen.  */
-		bufsize = MAXPACKET;
+		bufsize = (type == T_UNSPEC ? 2 : 1) * MAXPACKET;
 		buf = malloc (bufsize);
 		if (buf != NULL) {
+			query1 = buf;
 			use_malloc = 1;
 			goto again;
 		}
@@ -168,7 +202,8 @@
 		return (n);
 	}
 	assert (answerp == NULL || (void *) *answerp == (void *) answer);
-	n = __libc_res_nsend(statp, buf, n, answer, anslen, answerp);
+	n = __libc_res_nsend(statp, query1, nquery1, query2, nquery2, answer,
+			     anslen, answerp, answerp2, nanswerp2);
 	if (use_malloc)
 		free (buf);
 	if (n < 0) {
@@ -184,20 +219,37 @@
 	  /* __libc_res_nsend might have reallocated the buffer.  */
 	  hp = (HEADER *) *answerp;
 
-	if (hp->rcode != NOERROR || ntohs(hp->ancount) == 0) {
+	/* We simplify the following tests by assigning HP to HP2.  It
+	   is easy to verify that this is the same as ignoring all
+	   tests of HP2.  */
+	HEADER *hp2 = answerp2 ? (HEADER *) *answerp2 : hp;
+
+	if ((hp->rcode != NOERROR || ntohs(hp->ancount) == 0)
+	    && (hp2->rcode != NOERROR || ntohs(hp2->ancount) == 0)) {
 #ifdef DEBUG
-		if (statp->options & RES_DEBUG)
+		if (statp->options & RES_DEBUG) {
 			printf(";; rcode = %d, ancount=%d\n", hp->rcode,
 			    ntohs(hp->ancount));
-#endif
-		switch (hp->rcode) {
+			if (hp != hp2)
+			  printf(";; rcode2 = %d, ancount2=%d\n", hp2->rcode,
+				 ntohs(hp2->ancount));
+		}
+#endif
+		switch (hp->rcode == NOERROR ? hp2->rcode : hp->rcode) {
 		case NXDOMAIN:
+			if ((hp->rcode == NOERROR && ntohs (hp->ancount) != 0)
+			    || (hp2->rcode == NOERROR
+				&& ntohs (hp2->ancount) != 0))
+				goto success;
 			RES_SET_H_ERRNO(statp, HOST_NOT_FOUND);
 			break;
 		case SERVFAIL:
 			RES_SET_H_ERRNO(statp, TRY_AGAIN);
 			break;
 		case NOERROR:
+			if (ntohs (hp->ancount) != 0
+			    || ntohs (hp2->ancount) != 0)
+				goto success;
 			RES_SET_H_ERRNO(statp, NO_DATA);
 			break;
 		case FORMERR:
@@ -209,6 +261,7 @@
 		}
 		return (-1);
 	}
+ success:
 	return (n);
 }
 libresolv_hidden_def (__libc_res_nquery)
@@ -221,7 +274,7 @@
 	   int anslen)		/* size of answer buffer */
 {
 	return __libc_res_nquery(statp, name, class, type, answer, anslen,
-				 NULL);
+				 NULL, NULL, NULL);
 }
 libresolv_hidden_def (res_nquery)
 
@@ -233,11 +286,13 @@
  */
 int
 __libc_res_nsearch(res_state statp,
-	    const char *name,	/* domain name */
-	    int class, int type,	/* class and type of query */
-	    u_char *answer,	/* buffer to put answer */
-	    int anslen,		/* size of answer */
-	    u_char **answerp)
+		   const char *name,	/* domain name */
+		   int class, int type,	/* class and type of query */
+		   u_char *answer,	/* buffer to put answer */
+		   int anslen,		/* size of answer */
+		   u_char **answerp,
+		   u_char **answerp2,
+		   int *nanswerp2)
 {
 	const char *cp, * const *domain;
 	HEADER *hp = (HEADER *) answer;
@@ -260,7 +315,8 @@
 	/* If there aren't any dots, it could be a user-level alias. */
 	if (!dots && (cp = res_hostalias(statp, name, tmp, sizeof tmp))!= NULL)
 		return (__libc_res_nquery(statp, cp, class, type, answer,
-					  anslen, answerp));
+					  anslen, answerp, answerp2,
+					  nanswerp2));
 
 #ifdef DEBUG
 	if (statp->options & RES_DEBUG)
@@ -276,7 +332,8 @@
 	saved_herrno = -1;
 	if (dots >= statp->ndots || trailing_dot) {
 		ret = __libc_res_nquerydomain(statp, name, NULL, class, type,
-					      answer, anslen, answerp);
+					      answer, anslen, answerp,
+					      answerp2, nanswerp2);
 		if (ret > 0 || trailing_dot)
 			return (ret);
 		saved_herrno = h_errno;
@@ -285,6 +342,12 @@
 			answer = *answerp;
 			anslen = MAXPACKET;
 		}
+		if (answerp2
+		    && (*answerp2 < answer || *answerp2 >= answer + anslen))
+		  {
+		    free (*answerp2);
+		    *answerp2 = NULL;
+		  }
 	}
 
 	/*
@@ -307,7 +370,8 @@
 
 			ret = __libc_res_nquerydomain(statp, name, *domain,
 						      class, type,
-						      answer, anslen, answerp);
+						      answer, anslen, answerp,
+						      answerp2, nanswerp2);
 			if (ret > 0)
 				return (ret);
 
@@ -315,6 +379,13 @@
 				answer = *answerp;
 				anslen = MAXPACKET;
 			}
+			if (answerp2
+			    && (*answerp2 < answer
+				|| *answerp2 >= answer + anslen))
+			  {
+			    free (*answerp2);
+			    *answerp2 = NULL;
+			  }
 
 			/*
 			 * If no server present, give up.
@@ -368,7 +439,8 @@
 	 */
 	if (dots && !(tried_as_is || root_on_list)) {
 		ret = __libc_res_nquerydomain(statp, name, NULL, class, type,
-					      answer, anslen, answerp);
+					      answer, anslen, answerp,
+					      answerp2, nanswerp2);
 		if (ret > 0)
 			return (ret);
 	}
@@ -380,6 +452,11 @@
 	 * else send back meaningless H_ERRNO, that being the one from
 	 * the last DNSRCH we did.
 	 */
+	if (answerp2 && (*answerp2 < answer || *answerp2 >= answer + anslen))
+	  {
+	    free (*answerp2);
+	    *answerp2 = NULL;
+	  }
 	if (saved_herrno != -1)
 		RES_SET_H_ERRNO(statp, saved_herrno);
 	else if (got_nodata)
@@ -398,7 +475,7 @@
 	    int anslen)		/* size of answer */
 {
 	return __libc_res_nsearch(statp, name, class, type, answer,
-				  anslen, NULL);
+				  anslen, NULL, NULL, NULL);
 }
 libresolv_hidden_def (res_nsearch)
 
@@ -408,12 +485,14 @@
  */
 static int
 __libc_res_nquerydomain(res_state statp,
-	    const char *name,
-	    const char *domain,
-	    int class, int type,	/* class and type of query */
-	    u_char *answer,		/* buffer to put answer */
-	    int anslen,			/* size of answer */
-	    u_char **answerp)
+			const char *name,
+			const char *domain,
+			int class, int type,	/* class and type of query */
+			u_char *answer,		/* buffer to put answer */
+			int anslen,			/* size of answer */
+			u_char **answerp,
+			u_char **answerp2,
+			int *nanswerp2)
 {
 	char nbuf[MAXDNAME];
 	const char *longname = nbuf;
@@ -450,7 +529,7 @@
 		sprintf(nbuf, "%s.%s", name, domain);
 	}
 	return (__libc_res_nquery(statp, longname, class, type, answer,
-				  anslen, answerp));
+				  anslen, answerp, answerp2, nanswerp2));
 }
 
 int
@@ -462,7 +541,7 @@
 	    int anslen)		/* size of answer */
 {
 	return __libc_res_nquerydomain(statp, name, domain, class, type,
-				       answer, anslen, NULL);
+				       answer, anslen, NULL, NULL, NULL);
 }
 libresolv_hidden_def (res_nquerydomain)
 

Modified: trunk/libc/resolv/res_send.c
==============================================================================
--- trunk/libc/resolv/res_send.c (original)
+++ trunk/libc/resolv/res_send.c Mon May 12 08:38:35 2008
@@ -176,10 +176,14 @@
 /* Forward. */
 
 static int		send_vc(res_state, const u_char *, int,
-				u_char **, int *, int *, int, u_char **);
+				const u_char *, int,
+				u_char **, int *, int *, int, u_char **,
+				u_char **, int *, int *);
 static int		send_dg(res_state, const u_char *, int,
+				const u_char *, int,
 				u_char **, int *, int *, int,
-				int *, int *, u_char **);
+				int *, int *, u_char **,
+				u_char **, int *, int *);
 #ifdef DEBUG
 static void		Aerror(const res_state, FILE *, const char *, int,
 			       const struct sockaddr *);
@@ -334,33 +338,41 @@
 
 int
 __libc_res_nsend(res_state statp, const u_char *buf, int buflen,
-		 u_char *ans, int anssiz, u_char **ansp)
+		 const u_char *buf2, int buflen2,
+		 u_char *ans, int anssiz, u_char **ansp, u_char **ansp2,
+		 int *nansp2)
 {
-	int gotsomewhere, terrno, try, v_circuit, resplen, ns, n;
+  int gotsomewhere, terrno, try, v_circuit, resplen, resplen2, ns, n;
 
 	if (statp->nscount == 0) {
 		__set_errno (ESRCH);
 		return (-1);
 	}
 
-	if (anssiz < HFIXEDSZ) {
+	if (anssiz < (buf2 == NULL ? 1 : 2) * HFIXEDSZ) {
 		__set_errno (EINVAL);
 		return (-1);
 	}
 
-	if ((statp->qhook || statp->rhook) && anssiz < MAXPACKET && ansp) {
-		u_char *buf = malloc (MAXPACKET);
-		if (buf == NULL)
-			return (-1);
-		memcpy (buf, ans, HFIXEDSZ);
-		*ansp = buf;
-		ans = buf;
-		anssiz = MAXPACKET;
-	}
+#ifdef USE_HOOKS
+	if (__builtin_expect (statp->qhook || statp->rhook, 0)) {
+		if (anssiz < MAXPACKET && ansp) {
+			u_char *buf = malloc (MAXPACKET);
+			if (buf == NULL)
+				return (-1);
+			memcpy (buf, ans, HFIXEDSZ);
+			*ansp = buf;
+			ans = buf;
+			anssiz = MAXPACKET;
+		}
+	}
+#endif
 
 	DprintQ((statp->options & RES_DEBUG) || (statp->pfcode & RES_PRF_QUERY),
 		(stdout, ";; res_send()\n"), buf, buflen);
-	v_circuit = (statp->options & RES_USEVC) || buflen > PACKETSZ;
+	v_circuit = ((statp->options & RES_USEVC)
+		     || buflen > PACKETSZ
+		     || buflen2 > PACKETSZ);
 	gotsomewhere = 0;
 	terrno = ETIMEDOUT;
 
@@ -442,7 +454,7 @@
 	 * Some resolvers want to even out the load on their nameservers.
 	 * Note that RES_BLAST overrides RES_ROTATE.
 	 */
-	if ((statp->options & RES_ROTATE) != 0 &&
+	if (__builtin_expect ((statp->options & RES_ROTATE) != 0, 0) &&
 	    (statp->options & RES_BLAST) == 0) {
 		struct sockaddr_in6 *ina;
 		unsigned int map;
@@ -479,8 +491,9 @@
 
 		if (nsap == NULL)
 			goto next_ns;
- same_ns:
-		if (statp->qhook) {
+	    same_ns:
+#ifdef USE_HOOKS
+		if (__builtin_expect (statp->qhook != NULL, 0)) {
 			int done = 0, loops = 0;
 
 			do {
@@ -512,6 +525,7 @@
 				}
 			} while (!done);
 		}
+#endif
 
 #ifdef DEBUG
 		char tmpbuf[40];
@@ -521,28 +535,33 @@
 			ns + 1, inet_ntop(AF_INET6, &nsap->sin6_addr,
 					  tmpbuf, sizeof (tmpbuf))));
 
-		if (v_circuit) {
+		if (__builtin_expect (v_circuit, 0)) {
 			/* Use VC; at most one attempt per server. */
 			try = statp->retry;
-			n = send_vc(statp, buf, buflen, &ans, &anssiz, &terrno,
-				    ns, ansp);
+			n = send_vc(statp, buf, buflen, buf2, buflen2,
+				    &ans, &anssiz, &terrno,
+				    ns, ansp, ansp2, nansp2, &resplen2);
 			if (n < 0)
 				return (-1);
 			if (n == 0)
 				goto next_ns;
-			resplen = n;
 		} else {
 			/* Use datagrams. */
-			n = send_dg(statp, buf, buflen, &ans, &anssiz, &terrno,
-				    ns, &v_circuit, &gotsomewhere, ansp);
+			n = send_dg(statp, buf, buflen, buf2, buflen2,
+				    &ans, &anssiz, &terrno,
+				    ns, &v_circuit, &gotsomewhere, ansp,
+				    ansp2, nansp2, &resplen2);
 			if (n < 0)
 				return (-1);
 			if (n == 0)
 				goto next_ns;
 			if (v_circuit)
+			  // XXX Check whether both requests failed or
+			  // XXX whether one have been answered successfully
 				goto same_ns;
-			resplen = n;
-		}
+		}
+
+		resplen = n;
 
 		Dprint((statp->options & RES_DEBUG) ||
 		       ((statp->pfcode & RES_PRF_REPLY) &&
@@ -553,6 +572,11 @@
 			(statp->pfcode & RES_PRF_REPLY),
 			(stdout, "%s", ""),
 			ans, (resplen > anssiz) ? anssiz : resplen);
+		if (buf2 != NULL)
+		  DprintQ((statp->options & RES_DEBUG) ||
+			  (statp->pfcode & RES_PRF_REPLY),
+			  (stdout, "%s", ""),
+			  *ansp2, (resplen2 > *nansp2) ? *nansp2 : resplen2);
 
 		/*
 		 * If we have temporarily opened a virtual circuit,
@@ -563,7 +587,8 @@
 		    (statp->options & RES_STAYOPEN) == 0) {
 			__res_iclose(statp, false);
 		}
-		if (statp->rhook) {
+#ifdef USE_HOOKS
+		if (__builtin_expect (statp->rhook, 0)) {
 			int done = 0, loops = 0;
 
 			do {
@@ -593,6 +618,7 @@
 			} while (!done);
 
 		}
+#endif
 		return (resplen);
  next_ns: ;
 	   } /*foreach ns*/
@@ -612,7 +638,8 @@
 res_nsend(res_state statp,
 	  const u_char *buf, int buflen, u_char *ans, int anssiz)
 {
-	return __libc_res_nsend(statp, buf, buflen, ans, anssiz, NULL);
+  return __libc_res_nsend(statp, buf, buflen, NULL, 0, ans, anssiz,
+			  NULL, NULL, NULL);
 }
 libresolv_hidden_def (res_nsend)
 
@@ -620,17 +647,23 @@
 
 static int
 send_vc(res_state statp,
-	const u_char *buf, int buflen, u_char **ansp, int *anssizp,
-	int *terrno, int ns, u_char **anscp)
+	const u_char *buf, int buflen, const u_char *buf2, int buflen2,
+	u_char **ansp, int *anssizp,
+	int *terrno, int ns, u_char **anscp, u_char **ansp2, int *anssizp2,
+	int *resplen2)
 {
 	const HEADER *hp = (HEADER *) buf;
+	const HEADER *hp2 = (HEADER *) buf2;
 	u_char *ans = *ansp;
-	int anssiz = *anssizp;
+	int orig_anssizp = *anssizp;
+	// XXX REMOVE
+	// int anssiz = *anssizp;
 	HEADER *anhp = (HEADER *) ans;
 	struct sockaddr_in6 *nsap = EXT(statp).nsaddrs[ns];
 	int truncating, connreset, resplen, n;
-	struct iovec iov[2];
+	struct iovec iov[4];
 	u_short len;
+	u_short len2;
 	u_char *cp;
 
 	connreset = 0;
@@ -677,11 +710,19 @@
 	/*
 	 * Send length & message
 	 */
-	ns_put16((u_short)buflen, (u_char*)&len);
+	len = htons ((u_short) buflen);
 	evConsIovec(&len, INT16SZ, &iov[0]);
 	evConsIovec((void*)buf, buflen, &iov[1]);
-	if (TEMP_FAILURE_RETRY (writev(statp->_vcsock, iov, 2))
-	    != (INT16SZ + buflen)) {
+	int niov = 2;
+	ssize_t explen = INT16SZ + buflen;
+	if (buf2 != NULL) {
+		len2 = htons ((u_short) buflen2);
+		evConsIovec(&len2, INT16SZ, &iov[2]);
+		evConsIovec((void*)buf2, buflen2, &iov[3]);
+		niov = 4;
+		explen += INT16SZ + buflen2;
+	}
+	if (TEMP_FAILURE_RETRY (writev(statp->_vcsock, iov, niov)) != explen) {
 		*terrno = errno;
 		Perror(statp, stderr, "write failed", errno);
 		__res_iclose(statp, false);
@@ -690,6 +731,8 @@
 	/*
 	 * Receive length & response
 	 */
+	int recvresp1 = 0;
+	int recvresp2 = buf2 == NULL;
  read_len:
 	cp = ans;
 	len = INT16SZ;
@@ -718,30 +761,66 @@
 		}
 		return (0);
 	}
+#ifdef _STRING_ARCH_unaligned
+	resplen = ntohs (*(uint16_t *) ans);
+#else
 	resplen = ns_get16(ans);
-	if (resplen > anssiz) {
+#endif
+
+	int *thisanssizp;
+	u_char **thisansp;
+	int *thisresplenp;
+	if ((recvresp1 | recvresp2) == 0 || buf2 == NULL) {
+		thisanssizp = anssizp;
+		thisansp = anscp ?: ansp;
+		assert (anscp != NULL || ansp2 == NULL);
+		thisresplenp = &resplen;
+	} else {
+		if (*anssizp != MAXPACKET) {
+			/* No buffer allocated for the first
+			   reply.  We can try to use the rest
+			   of the user-provided buffer.  */
+			*anssizp2 = orig_anssizp - resplen;
+			*ansp2 = *ansp + resplen;
+		} else {
+			/* The first reply did not fit into the
+			   user-provided buffer.  Maybe the second
+			   answer will.  */

[... 741 lines stripped ...]