Update.
authorUlrich Drepper <drepper@redhat.com>
Sun, 15 Aug 2004 20:23:40 +0000 (20:23 +0000)
committerUlrich Drepper <drepper@redhat.com>
Sun, 15 Aug 2004 20:23:40 +0000 (20:23 +0000)
* sysdeps/posix/getaddrinfo.c (gaih_addrtuple): Change type of
addr to avoid casts.
(gethosts): Removed.
(gethosts2): Renamed to gethosts.  Make it usable for family !=
AF_UNSPEC.  Fix AI_V4MAPPED.
(gaih_inet): Remove use of old gethosts.  Always use what used to be
gethosts2.  If entry is found, try to use the same NSS module's
getcanonname_r function.  Use gethostbyaddr for AI_CANONNAME only
if getcanonname_r was not available.  Fix filtering of AI_V4MAPPED
addresses.  Numerous cleanups.
* resolv/nss_dns/dns-canon.c: New file.
* resolv/Makefile (libnss_dns-routines): Add dns-canon.
* resolv/Versions (libnss_dns): Add _nss_dns_getcanonname_r.

* elf/Makefile: Add rules to build and run tst-dlopenrpath.
* elf/tst-dlopenrpath.c: New file.
* elf/tst-dlopenrpathmod.c: New file.

* intl/tst-gettext.sh: Adjust for change of de.po file to UTF-8.

ChangeLog
elf/Makefile
elf/tst-dlopenrpath.c [new file with mode: 0644]
elf/tst-dlopenrpathmod.c [new file with mode: 0644]
resolv/Makefile
resolv/Versions
resolv/nss_dns/dns-canon.c [new file with mode: 0644]
sysdeps/posix/getaddrinfo.c

index 9bf99bd..ef90c57 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,6 +1,24 @@
 2004-08-15  Ulrich Drepper  <drepper@redhat.com>
 
-       * intl/tst-gettext.sh: Adjust for change for de.po file to UTF-8.
+       * sysdeps/posix/getaddrinfo.c (gaih_addrtuple): Change type of
+       addr to avoid casts.
+       (gethosts): Removed.
+       (gethosts2): Renamed to gethosts.  Make it usable for family !=
+       AF_UNSPEC.  Fix AI_V4MAPPED.
+       (gaih_inet): Remove use of old gethosts.  Always use what used to be
+       gethosts2.  If entry is found, try to use the same NSS module's
+       getcanonname_r function.  Use gethostbyaddr for AI_CANONNAME only
+       if getcanonname_r was not available.  Fix filtering of AI_V4MAPPED
+       addresses.  Numerous cleanups.
+       * resolv/nss_dns/dns-canon.c: New file.
+       * resolv/Makefile (libnss_dns-routines): Add dns-canon.
+       * resolv/Versions (libnss_dns): Add _nss_dns_getcanonname_r.
+
+       * elf/Makefile: Add rules to build and run tst-dlopenrpath.
+       * elf/tst-dlopenrpath.c: New file.
+       * elf/tst-dlopenrpathmod.c: New file.
+
+       * intl/tst-gettext.sh: Adjust for change of de.po file to UTF-8.
        * intl/tst-gettext.c: Likewise.
 
        * nss/getent.c (ahosts_keys_int): Correctly print IPv6 addresses.
index 9bbc304..ac8319b 100644 (file)
@@ -82,7 +82,7 @@ distribute    := rtld-Rules \
                   tst-array1.exp tst-array2.exp tst-array4.exp \
                   tst-array2dep.c tst-piemod1.c \
                   tst-execstack-mod.c tst-dlmodcount.c \
-                  check-textrel.c dl-sysdep.h
+                  check-textrel.c dl-sysdep.h test-dlopenrpathmod.c
 
 CFLAGS-dl-runtime.c = -fexceptions -fasynchronous-unwind-tables
 CFLAGS-dl-lookup.c = -fexceptions -fasynchronous-unwind-tables
@@ -152,7 +152,7 @@ tests += loadtest restest1 preloadtest loadfail multiload origtest resolvfail \
         restest2 next dblload dblunload reldep5 reldep6 reldep7 reldep8 \
         circleload1 tst-tls3 tst-tls4 tst-tls5 tst-tls6 tst-tls7 tst-tls8 \
         tst-tls10 tst-tls11 tst-tls12 tst-tls13 tst-tls14 tst-align \
-        $(tests-execstack-$(have-z-execstack)) tst-dlmodcount
+        $(tests-execstack-$(have-z-execstack)) tst-dlmodcount tst-dlopenrpath
 #       reldep9
 test-srcs = tst-pathopt
 tests-vis-yes = vismain
@@ -184,7 +184,8 @@ modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \
                circlemod3 circlemod3a \
                reldep8mod1 reldep8mod2 reldep8mod3 \
                reldep9mod1 reldep9mod2 reldep9mod3 \
-               tst-alignmod $(modules-execstack-$(have-z-execstack))
+               tst-alignmod $(modules-execstack-$(have-z-execstack)) \
+               tst-dlopenrpathmod
 ifeq (yes,$(have-initfini-array))
 modules-names += tst-array2dep
 endif
@@ -747,3 +748,9 @@ $(objpfx)tst-dlmodcount: $(libdl)
 $(objpfx)tst-dlmodcount.out: $(test-modules)
 
 endif
+
+$(objpfx)tst-dlopenrpathmod.so: $(libdl)
+$(objpfx)tst-dlopenrpath: $(objpfx)tst-dlopenrpathmod.so $(libdl)
+CFLAGS-tst-dlopenrpath.c += -DPFX=\"$(objpfx)\"
+LDFLAGS-tst-dlopenrpathmod.so += -Wl,-rpath,\$$ORIGIN/test-subdir
+$(objpfx)tst-dlopenrpath.out: $(objpfx)firstobj.so
diff --git a/elf/tst-dlopenrpath.c b/elf/tst-dlopenrpath.c
new file mode 100644 (file)
index 0000000..964f103
--- /dev/null
@@ -0,0 +1,74 @@
+/* Copyright (C) 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2004.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <dlfcn.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/stat.h>
+
+
+extern int foo (void);
+
+static const char testsubdir[] = PFX "test-subdir";
+
+
+static int
+do_test (void)
+{
+  struct stat64 st;
+  int result = 1;
+
+  if (mkdir (testsubdir, 0777) != 0
+      && (errno != EEXIST
+         || stat64 (testsubdir, &st) != 0
+         || !S_ISDIR (st.st_mode)))
+    {
+      printf ("cannot create directory %s\n", testsubdir);
+      return 1;
+    }
+
+  if (system ("cp " PFX "firstobj.so " PFX "test-subdir/in-subdir.so") != 0)
+    {
+      puts ("cannot copy DSO");
+      return 1;
+    }
+
+  void *p = dlopen ("in-subdir.so", RTLD_LAZY|RTLD_LOCAL);
+  if (p != NULL)
+    {
+      puts ("succeeded in opening in-subdir.so from do_test");
+      dlclose (p);
+      goto out;
+    }
+
+  result = foo ();
+
+ out:
+#if 0
+  unlink (PFX "test-subdir/in-subdir.so");
+  rmdir (testsubdir);
+#endif
+
+  return result;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/elf/tst-dlopenrpathmod.c b/elf/tst-dlopenrpathmod.c
new file mode 100644 (file)
index 0000000..8fe7873
--- /dev/null
@@ -0,0 +1,36 @@
+/* Copyright (C) 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2004.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <dlfcn.h>
+#include <stdio.h>
+
+
+int
+foo (void)
+{
+  void *p = dlopen ("in-subdir.so", RTLD_LAZY|RTLD_LOCAL);
+  if (p != NULL)
+    {
+      dlclose (p);
+      return 0;
+    }
+
+  puts ("couldn't open in-subdir.so from foo");
+  return 1;
+}
index a91e8a6..f6230da 100644 (file)
@@ -57,7 +57,7 @@ libanl-routines := gai_cancel gai_error gai_misc gai_notify gai_suspend \
 subdir-dirs = nss_dns
 vpath %.c nss_dns
 
-libnss_dns-routines    := dns-host dns-network
+libnss_dns-routines    := dns-host dns-network dns-canon
 ifneq ($(build-static-nss),yes)
 libnss_dns-inhibit-o   = $(filter-out .os,$(object-suffixes))
 endif
index a809508..0e4fea5 100644 (file)
@@ -86,7 +86,7 @@ libnss_dns {
   GLIBC_PRIVATE {
     _nss_dns_gethostbyaddr_r; _nss_dns_gethostbyname2_r;
     _nss_dns_gethostbyname_r; _nss_dns_getnetbyaddr_r;
-    _nss_dns_getnetbyname_r;
+    _nss_dns_getnetbyname_r; _nss_dns_getcanonname_r;
   }
 }
 
diff --git a/resolv/nss_dns/dns-canon.c b/resolv/nss_dns/dns-canon.c
new file mode 100644 (file)
index 0000000..e5b38f5
--- /dev/null
@@ -0,0 +1,137 @@
+/* Copyright (C) 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2004.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <netdb.h>
+#include <resolv.h>
+#include <stdlib.h>
+#include <arpa/nameser.h>
+#include <nsswitch.h>
+
+
+#if PACKETSZ > 65536
+# define MAXPACKET     PACKETSZ
+#else
+# define MAXPACKET     65536
+#endif
+
+
+/* We need this time later.  */
+typedef union querybuf
+{
+  HEADER hdr;
+  unsigned char buf[MAXPACKET];
+} querybuf;
+
+
+enum nss_status
+_nss_dns_getcanonname_r (const char *name, char *buffer, size_t buflen,
+                        char **result,int *errnop, int *h_errnop)
+{
+  /* Just an alibi buffer, res_nquery will allocate a real buffer for
+     us.  */
+  unsigned char buf[20];
+  union
+  {
+    querybuf *buf;
+    unsigned char *ptr;
+  } ansp = { .ptr = buf };
+  enum nss_status status;
+
+  int r = __libc_res_nquery (&_res, name, ns_c_in, ns_t_cname,
+                            buf, sizeof (buf), &ansp.ptr);
+  if (r > 0)
+    {
+      /* We need to decode the response.  Just one question record.
+        And if we got no answers we bail out, too.  */
+      if (ansp.buf->hdr.qdcount != htons (1)
+         || ansp.buf->hdr.ancount == 0)
+       goto unavail;
+
+      /* Beginning and end of the buffer with query, answer, and the
+        rest.  */
+      unsigned char *ptr = &ansp.buf->buf[sizeof (HEADER)];
+      unsigned char *endptr = ansp.ptr + r;
+
+      /* Skip over the query.  This is the name, type, and class.  */
+      int s = __dn_skipname (ptr, endptr);
+      if (s < 0)
+       goto unavail;
+
+      /* Skip over the name and the two 16-bit values containing type
+        and class.  */
+      ptr += s + 2 * sizeof (uint16_t);
+
+      /* Now the reply.  First again the name from the query, then
+        type, class, TTL, and the length of the RDATA.  */
+      s = __dn_skipname (ptr, endptr);
+      if (s < 0)
+       goto unavail;
+
+      ptr += s;
+
+      /* Check whether type and class match.  */
+      if (*(uint16_t *) ptr != htons (ns_t_cname))
+       goto unavail;
+
+      ptr += sizeof (uint16_t);
+      if (*(uint16_t *) ptr != htons (ns_c_in))
+       goto unavail;
+
+      /* Also skip over the TTL and rdata length.  */
+      ptr += sizeof (uint16_t) + sizeof (uint32_t) + sizeof (int16_t);
+
+      /* Now the name we are looking for.  */
+      s = __dn_expand (ansp.buf->buf, endptr, ptr, buffer, buflen);
+      if (s < 0)
+       {
+         if (errno != EMSGSIZE)
+           goto unavail;
+
+         /* The buffer is too small.  */
+         *errnop = ERANGE;
+         status = NSS_STATUS_TRYAGAIN;
+         h_errno = NETDB_INTERNAL;
+       }
+      else
+       {
+         /* Success.  */
+         *result = buffer;
+         status = NSS_STATUS_SUCCESS;
+       }
+    }
+  else if (h_errno == TRY_AGAIN)
+    {
+    again:
+      status = NSS_STATUS_TRYAGAIN;
+      *errnop = errno;
+    }
+  else
+    {
+    unavail:
+      status = NSS_STATUS_UNAVAIL;
+      *errnop = errno;
+    }
+  *h_errnop = h_errno;
+
+  if (ansp.ptr != buf)
+    free (ansp.ptr);
+
+  return status;
+}
index bdfdcfb..23b7429 100644 (file)
@@ -89,7 +89,7 @@ struct gaih_addrtuple
   {
     struct gaih_addrtuple *next;
     int family;
-    char addr[16];
+    uint32_t addr[4];
     uint32_t scopeid;
   };
 
@@ -290,92 +290,6 @@ gaih_inet_serv (const char *servicename, const struct gaih_typeproto *tp,
   no_data = 0;                                                               \
   do {                                                                       \
     tmpbuf = extend_alloca (tmpbuf, tmpbuflen, 2 * tmpbuflen);               \
-    rc = __gethostbyname2_r (name, _family, &th, tmpbuf,                     \
-         tmpbuflen, &h, &herrno);                                            \
-  } while (rc == ERANGE && herrno == NETDB_INTERNAL);                        \
-  if (rc != 0)                                                               \
-    {                                                                        \
-      if (herrno == NETDB_INTERNAL)                                          \
-       {                                                                     \
-         __set_h_errno (herrno);                                             \
-         return -EAI_SYSTEM;                                                 \
-       }                                                                     \
-      if (herrno == TRY_AGAIN)                                               \
-       no_data = EAI_AGAIN;                                                  \
-      else                                                                   \
-       no_data = herrno == NO_DATA;                                          \
-    }                                                                        \
-  else if (h != NULL)                                                        \
-    {                                                                        \
-      for (i = 0; h->h_addr_list[i]; i++)                                    \
-       {                                                                     \
-         if (*pat == NULL) {                                                 \
-           *pat = __alloca (sizeof (struct gaih_addrtuple));                 \
-           (*pat)->scopeid = 0;                                              \
-         }                                                                   \
-         (*pat)->next = NULL;                                                \
-         (*pat)->family = _family;                                           \
-         memcpy ((*pat)->addr, h->h_addr_list[i],                            \
-                sizeof(_type));                                              \
-         pat = &((*pat)->next);                                              \
-       }                                                                     \
-      if (_family == AF_INET6)                                               \
-       got_ipv6 = true;                                                      \
-    }                                                                        \
-  else if (_family == AF_INET6 && (req->ai_flags & AI_V4MAPPED))             \
-    {                                                                        \
-      /* We have to add V4 mapped addresses.  Maybe we discard them          \
-         later again but we get them anyhow for now.  */                     \
-      while ((rc = __gethostbyname2_r (name, AF_INET6, &th, tmpbuf,          \
-                                      tmpbuflen, &h, &herrno)) == ERANGE     \
-            && herrno == NETDB_INTERNAL)                                     \
-       tmpbuf = extend_alloca (tmpbuf, tmpbuflen, 2 * tmpbuflen);            \
-                                                                             \
-      if (rc != 0)                                                           \
-       {                                                                     \
-         if (herrno == NETDB_INTERNAL)                                       \
-           {                                                                 \
-             __set_h_errno (herrno);                                         \
-             return -EAI_SYSTEM;                                             \
-           }                                                                 \
-         if (herrno == TRY_AGAIN)                                            \
-           no_data = EAI_AGAIN;                                              \
-         else                                                                \
-           no_data = herrno == NO_DATA;                                      \
-       }                                                                     \
-      else if (h != NULL)                                                    \
-       {                                                                     \
-         for (i = 0; h->h_addr_list[i]; ++i)                                 \
-           {                                                                 \
-             if (*pat == NULL)                                               \
-               {                                                             \
-                 *pat = __alloca (sizeof (struct gaih_addrtuple));           \
-                 (*pat)->scopeid = 0;                                        \
-               }                                                             \
-             uint32_t *addr = (uint32_t *) (*pat)->addr;                     \
-             (*pat)->next = NULL;                                            \
-             (*pat)->family = _family;                                       \
-             addr[3] = *(uint32_t *) h->h_addr_list[i];                      \
-             addr[2] = htonl (0xffff);                                       \
-             addr[1] = 0;                                                    \
-             addr[0] = 0;                                                    \
-             pat = &((*pat)->next);                                          \
-           }                                                                 \
-       }                                                                     \
-    }                                                                        \
- }
-
-
-#define gethosts2(_family, _type) \
- {                                                                           \
-  int i, herrno;                                                             \
-  size_t tmpbuflen;                                                          \
-  struct hostent th;                                                         \
-  char *tmpbuf = NULL;                                                       \
-  tmpbuflen = 512;                                                           \
-  no_data = 0;                                                               \
-  do {                                                                       \
-    tmpbuf = extend_alloca (tmpbuf, tmpbuflen, 2 * tmpbuflen);               \
     rc = 0;                                                                  \
     status = DL_CALL_FCT (fct, (name, _family, &th, tmpbuf,                  \
            tmpbuflen, &rc, &herrno));                                        \
@@ -400,23 +314,42 @@ gaih_inet_serv (const char *servicename, const struct gaih_typeproto *tp,
     {                                                                        \
       for (i = 0; h->h_addr_list[i]; i++)                                    \
        {                                                                     \
-         if (*pat == NULL) {                                                 \
-           *pat = __alloca (sizeof (struct gaih_addrtuple));                 \
-           (*pat)->scopeid = 0;                                              \
-         }                                                                   \
+         if (*pat == NULL)                                                   \
+           {                                                                 \
+             *pat = __alloca (sizeof (struct gaih_addrtuple));               \
+             (*pat)->scopeid = 0;                                            \
+           }                                                                 \
+         uint32_t *addr = (*pat)->addr;                                      \
          (*pat)->next = NULL;                                                \
-         (*pat)->family = _family;                                           \
-         memcpy ((*pat)->addr, h->h_addr_list[i],                            \
-                sizeof(_type));                                              \
+         if (_family == AF_INET && req->ai_family == AF_INET6)               \
+           {                                                                 \
+             (*pat)->family = AF_INET6;                                      \
+             addr[3] = *(uint32_t *) h->h_addr_list[i];                      \
+             addr[2] = htonl (0xffff);                                       \
+             addr[1] = 0;                                                    \
+             addr[0] = 0;                                                    \
+           }                                                                 \
+         else                                                                \
+           {                                                                 \
+             (*pat)->family = _family;                                       \
+             memcpy (addr, h->h_addr_list[i], sizeof(_type));                \
+           }                                                                 \
          pat = &((*pat)->next);                                              \
        }                                                                     \
+                                                                             \
+      if (_family == AF_INET6 && i > 0)                                              \
+       got_ipv6 = true;                                                      \
     }                                                                        \
  }
 
+
 typedef enum nss_status (*nss_gethostbyname2_r)
   (const char *name, int af, struct hostent *host,
    char *buffer, size_t buflen, int *errnop,
    int *h_errnop);
+typedef enum nss_status (*nss_getcanonname_r)
+  (const char *name, char *buffer, size_t buflen, char **result,
+   int *errnop, int *h_errnop);
 extern service_user *__nss_hosts_database attribute_hidden;
 
 static int
@@ -428,6 +361,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
   struct gaih_addrtuple *at = NULL;
   int rc;
   bool got_ipv6 = false;
+  const char *canon = NULL;
 
   if (req->ai_protocol || req->ai_socktype)
     {
@@ -581,10 +515,10 @@ gaih_inet (const char *name, const struct gaih_service *service,
            at->family = AF_INET;
          else if (req->ai_family == AF_INET6 && req->ai_flags & AI_V4MAPPED)
            {
-             ((uint32_t *) at->addr)[3] = *(uint32_t *) at->addr;
-             ((uint32_t *) at->addr)[2] = htonl (0xffff);
-             ((uint32_t *) at->addr)[1] = 0;
-             ((uint32_t *) at->addr)[0] = 0;
+             at->addr[3] = at->addr[0];
+             at->addr[2] = htonl (0xffff);
+             at->addr[1] = 0;
+             at->addr[0] = 0;
              at->family = AF_INET6;
            }
          else
@@ -607,7 +541,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
              else if (req->ai_family == AF_INET
                       && IN6_IS_ADDR_V4MAPPED (at->addr))
                {
-                 *(uint32_t *) at->addr = ((uint32_t *) at->addr)[3];
+                 at->addr[0] = at->addr[3];
                  at->family = AF_INET;
                }
              else
@@ -645,82 +579,110 @@ gaih_inet (const char *name, const struct gaih_service *service,
          struct gaih_addrtuple **pat = &at;
          int no_data = 0;
          int no_inet6_data = 0;
+         service_user *nip = NULL;
+         enum nss_status inet6_status = NSS_STATUS_UNAVAIL;
+         enum nss_status status = NSS_STATUS_UNAVAIL;
+         int no_more;
+         nss_gethostbyname2_r fct;
+         int old_res_options;
+
+         if (__nss_hosts_database != NULL)
+           {
+             no_more = 0;
+             nip = __nss_hosts_database;
+           }
+         else
+           no_more = __nss_database_lookup ("hosts", NULL,
+                                            "dns [!UNAVAIL=return] files",
+                                            &nip);
+
+         if (__res_maybe_init (&_res, 0) == -1)
+           no_more = 1;
+
          /* If we are looking for both IPv4 and IPv6 address we don't
             want the lookup functions to automatically promote IPv4
             addresses to IPv6 addresses.  Currently this is decided
             by setting the RES_USE_INET6 bit in _res.options.  */
-         if (req->ai_family == AF_UNSPEC)
-           {
-             service_user *nip = NULL;
-             enum nss_status inet6_status, status = NSS_STATUS_UNAVAIL;
-             int no_more;
-             nss_gethostbyname2_r fct;
-             int old_res_options;
-
-             if (__nss_hosts_database != NULL)
-               {
-                 no_more = 0;
-                 nip = __nss_hosts_database;
-               }
-             else
-               no_more = __nss_database_lookup ("hosts", NULL,
-                                                "dns [!UNAVAIL=return] files",
-                                                &nip);
+         old_res_options = _res.options;
+         _res.options &= ~RES_USE_INET6;
 
-             if (__res_maybe_init (&_res, 0) == -1)
-               no_more = 1;
-             old_res_options = _res.options;
-             _res.options &= ~RES_USE_INET6;
+         while (!no_more)
+           {
+             fct = __nss_lookup_function (nip, "gethostbyname2_r");
 
-             while (!no_more)
+             if (fct != NULL)
                {
-                 fct = __nss_lookup_function (nip, "gethostbyname2_r");
-
-                 if (fct != NULL)
+                 if (req->ai_family == AF_INET6
+                     || req->ai_family == AF_UNSPEC)
                    {
-                     gethosts2 (AF_INET6, struct in6_addr);
+                     gethosts (AF_INET6, struct in6_addr);
                      no_inet6_data = no_data;
                      inet6_status = status;
-                     gethosts2 (AF_INET, struct in_addr);
-
-                     /* If we found one address for AF_INET or AF_INET6,
-                        don't continue the search.  */
-                     if (inet6_status == NSS_STATUS_SUCCESS ||
-                         status == NSS_STATUS_SUCCESS)
-                       break;
-
-                     /* We can have different states for AF_INET
-                        and AF_INET6. Try to find a usefull one for
-                        both.  */
-                     if (inet6_status == NSS_STATUS_TRYAGAIN)
-                       status = NSS_STATUS_TRYAGAIN;
-                     else if (status == NSS_STATUS_UNAVAIL &&
-                              inet6_status != NSS_STATUS_UNAVAIL)
-                       status = inet6_status;
                    }
+                 if (req->ai_family == AF_INET
+                     || req->ai_family == AF_UNSPEC
+                     || (req->ai_family == AF_INET6
+                         && (req->ai_flags & AI_V4MAPPED)))
+                   {
+                     gethosts (AF_INET, struct in_addr);
 
-                 if (nss_next_action (nip, status) == NSS_ACTION_RETURN)
-                   break;
+                     if (req->ai_family == AF_INET)
+                       {
+                         no_inet6_data = no_data;
+                         inet6_status = status;
+                       }
+                   }
 
-                 if (nip->next == NULL)
-                   no_more = -1;
-                 else
-                   nip = nip->next;
+                 /* If we found one address for AF_INET or AF_INET6,
+                    don't continue the search.  */
+                 if (inet6_status == NSS_STATUS_SUCCESS
+                     || status == NSS_STATUS_SUCCESS)
+                   {
+                     /* If we need the canonical name, get it from the same
+                        service as the result.  */
+                     nss_getcanonname_r cfct;
+                     int herrno;
+
+                     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;
+
+                         if (DL_CALL_FCT (cfct, (name, buf, max_fqdn_len,
+                                                 &s, &rc, &herrno))
+                             == NSS_STATUS_SUCCESS)
+                           canon = s;
+                         else
+                           /* Set to name now to avoid using
+                              gethostbyaddr.  */
+                           canon = name;
+                       }
+
+                     break;
+                   }
+
+                 /* We can have different states for AF_INET and
+                    AF_INET6.  Try to find a useful one for both.  */
+                 if (inet6_status == NSS_STATUS_TRYAGAIN)
+                   status = NSS_STATUS_TRYAGAIN;
+                 else if (status == NSS_STATUS_UNAVAIL &&
+                          inet6_status != NSS_STATUS_UNAVAIL)
+                   status = inet6_status;
                }
 
-             _res.options = old_res_options;
-           }
-         else if (req->ai_family == AF_INET6)
-           {
-             gethosts (AF_INET6, struct in6_addr);
-             no_inet6_data = no_data;
-           }
-         else if (req->ai_family == AF_INET)
-           {
-             gethosts (AF_INET, struct in_addr);
-             no_inet6_data = no_data;
+             if (nss_next_action (nip, status) == NSS_ACTION_RETURN)
+               break;
+
+             if (nip->next == NULL)
+               no_more = -1;
+             else
+               nip = nip->next;
            }
 
+         _res.options = old_res_options;
+
          if (no_data != 0 && no_inet6_data != 0)
            {
              /* If both requests timed out report this.  */
@@ -742,13 +704,13 @@ gaih_inet (const char *name, const struct gaih_service *service,
       atr = at = __alloca (sizeof (struct gaih_addrtuple));
       memset (at, '\0', sizeof (struct gaih_addrtuple));
 
-      if (req->ai_family == 0)
+      if (req->ai_family == AF_UNSPEC)
        {
          at->next = __alloca (sizeof (struct gaih_addrtuple));
          memset (at->next, '\0', sizeof (struct gaih_addrtuple));
        }
 
-      if (req->ai_family == 0 || req->ai_family == AF_INET6)
+      if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET6)
        {
          at->family = AF_INET6;
          if ((req->ai_flags & AI_PASSIVE) == 0)
@@ -756,11 +718,11 @@ gaih_inet (const char *name, const struct gaih_service *service,
          atr = at->next;
        }
 
-      if (req->ai_family == 0 || req->ai_family == AF_INET)
+      if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET)
        {
          atr->family = AF_INET;
          if ((req->ai_flags & AI_PASSIVE) == 0)
-           *(uint32_t *) atr->addr = htonl (INADDR_LOOPBACK);
+           atr->addr[0] = htonl (INADDR_LOOPBACK);
        }
     }
 
@@ -770,7 +732,8 @@ gaih_inet (const char *name, const struct gaih_service *service,
   {
     struct gaih_servtuple *st2;
     struct gaih_addrtuple *at2 = at;
-    size_t socklen, namelen;
+    size_t socklen;
+    size_t canonlen;
     sa_family_t family;
 
     /*
@@ -778,77 +741,46 @@ gaih_inet (const char *name, const struct gaih_service *service,
      */
     while (at2 != NULL)
       {
-       const char *c = NULL;
-
        /* Only the first entry gets the canonical name.  */
        if (at2 == at && (req->ai_flags & AI_CANONNAME) != 0)
          {
-           struct hostent *h = NULL;
-
-           int herrno;
-           struct hostent th;
-           size_t tmpbuflen = 512;
-           char *tmpbuf = NULL;
-
-           do
+           if (canon == NULL)
              {
-               tmpbuf = extend_alloca (tmpbuf, tmpbuflen, tmpbuflen * 2);
-               rc = __gethostbyaddr_r (at2->addr,
-                                       ((at2->family == AF_INET6)
-                                        ? sizeof(struct in6_addr)
-                                        : sizeof(struct in_addr)),
-                                       at2->family, &th, tmpbuf, tmpbuflen,
-                                       &h, &herrno);
+               struct hostent *h = NULL;
+               int herrno;
+               struct hostent th;
+               size_t tmpbuflen = 512;
+               char *tmpbuf = NULL;
 
-             }
-           while (rc == ERANGE && herrno == NETDB_INTERNAL);
-
-           if (rc != 0 && herrno == NETDB_INTERNAL)
-             {
-               __set_h_errno (herrno);
-               return -EAI_SYSTEM;
-             }
+               do
+                 {
+                   tmpbuf = extend_alloca (tmpbuf, tmpbuflen, tmpbuflen * 2);
+                   rc = __gethostbyaddr_r (at2->addr,
+                                           ((at2->family == AF_INET6)
+                                            ? sizeof (struct in6_addr)
+                                            : sizeof (struct in_addr)),
+                                           at2->family, &th, tmpbuf,
+                                           tmpbuflen, &h, &herrno);
+                 }
+               while (rc == ERANGE && herrno == NETDB_INTERNAL);
 
-           if (h != NULL)
-             c = h->h_name;
-           else
-             {
-               /* We have to try to get the canonical in some other
-                  way.  If we are looking for either AF_INET or
-                  AF_INET6 try the other line.  */
-               if (req->ai_family == AF_UNSPEC)
+               if (rc != 0 && herrno == NETDB_INTERNAL)
                  {
-                   struct addrinfo *p = NULL;
-                   struct addrinfo **end = &p;
-                   struct addrinfo localreq = *req;
-                   struct addrinfo *runp;
-
-                   localreq.ai_family = AF_INET + AF_INET6 - at2->family;
-                   (void) gaih_inet (name, service, &localreq, end);
-
-                   runp = p;
-                   while (runp != NULL)
-                     {
-                       if (p->ai_canonname != name)
-                         {
-                           c = strdupa (p->ai_canonname);
-                           break;
-                         }
-                       runp = runp->ai_next;
-                     }
-
-                   freeaddrinfo (p);
+                   __set_h_errno (herrno);
+                   return -EAI_SYSTEM;
                  }
 
-               /* If this code is used the missing canonical name is
-                  substituted with the name passed in by the user.  */
-               if (c == NULL)
-                 c = name;
+               if (h != NULL)
+                 canon = h->h_name;
+               else
+                 {
+                   assert (name != NULL);
+                   /* If the canonical name cannot be determined, use
+                      the passed in string.  */
+                   canon = name;
+                 }
              }
 
-           if (c == NULL)
-             return GAIH_OKIFUNSPEC | -EAI_NONAME;
-
 #ifdef HAVE_LIBIDN
            if (req->ai_flags & AI_CANONIDN)
              {
@@ -859,7 +791,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
                  idn_flags |= IDNA_USE_STD3_ASCII_RULES;
 
                char *out;
-               int rc = __idna_to_unicode_lzlz (c, &out, idn_flags);
+               int rc = __idna_to_unicode_lzlz (canon, &out, idn_flags);
                if (rc != IDNA_SUCCESS)
                  {
                    if (rc == IDNA_MALLOC_ERROR)
@@ -870,18 +802,18 @@ gaih_inet (const char *name, const struct gaih_service *service,
                  }
                /* In case the output string is the same as the input
                   string no new string has been allocated.  */
-               if (out != c)
+               if (out != canon)
                  {
-                   c = strdupa (out);
+                   canon = strdupa (out);
                    free (out);
                  }
              }
 #endif
 
-           namelen = strlen (c) + 1;
+           canonlen = strlen (canon) + 1;
          }
        else
-         namelen = 0;
+         canonlen = 0;
 
        if (at2->family == AF_INET6)
          {
@@ -891,7 +823,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
            /* If we looked up IPv4 mapped address discard them here if
               the caller isn't interested in all address and we have
               found at least one IPv6 address.  */
-           if (got_ipv6
+           if (got_ipv6
                && (req->ai_flags & (AI_V4MAPPED|AI_ALL)) == AI_V4MAPPED
                && IN6_IS_ADDR_V4MAPPED (at2->addr))
              goto ignore;
@@ -904,7 +836,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
 
        for (st2 = st; st2 != NULL; st2 = st2->next)
          {
-           *pai = malloc (sizeof (struct addrinfo) + socklen + namelen);
+           *pai = malloc (sizeof (struct addrinfo) + socklen + canonlen);
            if (*pai == NULL)
              return -EAI_MEMORY;
 
@@ -913,7 +845,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
            (*pai)->ai_socktype = st2->socktype;
            (*pai)->ai_protocol = st2->protocol;
            (*pai)->ai_addrlen = socklen;
-           (*pai)->ai_addr = (void *) (*pai) + sizeof (struct addrinfo);
+           (*pai)->ai_addr = (void *) (*pai + 1);
 #if SALEN
            (*pai)->ai_addr->sa_len = socklen;
 #endif /* SALEN */
@@ -924,30 +856,30 @@ gaih_inet (const char *name, const struct gaih_service *service,
                struct sockaddr_in6 *sin6p =
                  (struct sockaddr_in6 *) (*pai)->ai_addr;
 
+               sin6p->sin6_port = st2->port;
                sin6p->sin6_flowinfo = 0;
                memcpy (&sin6p->sin6_addr,
                        at2->addr, sizeof (struct in6_addr));
-               sin6p->sin6_port = st2->port;
                sin6p->sin6_scope_id = at2->scopeid;
              }
            else
              {
                struct sockaddr_in *sinp =
                  (struct sockaddr_in *) (*pai)->ai_addr;
+               sinp->sin_port = st2->port;
                memcpy (&sinp->sin_addr,
                        at2->addr, sizeof (struct in_addr));
-               sinp->sin_port = st2->port;
                memset (sinp->sin_zero, '\0', sizeof (sinp->sin_zero));
              }
 
-           if (namelen != 0)
+           if (canonlen != 0)
              {
                (*pai)->ai_canonname = ((void *) (*pai) +
                                        sizeof (struct addrinfo) + socklen);
-               strcpy ((*pai)->ai_canonname, c);
+               strcpy ((*pai)->ai_canonname, canon);
 
                /* We do not need to allocate the canonical name anymore.  */
-               namelen = 0;
+               canonlen = 0;
              }
            else
              (*pai)->ai_canonname = NULL;