Blob Blame History Raw
Provide GLIBC_PRIVATE symbols no longer used by the current library
version to increase backwards compatibility during glibc updates.
This will help to avoid some of the issues that surface while a
glibc update is performed with concurrent application updates,
and it also allows old nscd to trigger cache invalidation in a
running nscd daemon.

While at this, also add interfaces for supporting old nss_dns modules.

This patch is not needed upstream because upstream does not provide
backwards compatibility for GLIBC_PRIVATE symbols.

diff --git a/inet/herrno.c b/inet/herrno.c
index 0cd84445190728b3..4d26e9b254181422 100644
--- a/inet/herrno.c
+++ b/inet/herrno.c
@@ -28,3 +28,9 @@ __thread int __h_errno;
 extern __thread int __libc_h_errno __attribute__ ((alias ("__h_errno")))
   attribute_hidden;
 #define h_errno __libc_h_errno
+
+#ifdef SHARED
+/* Provide an alias for use by the old libpthread.so.0 during
+   updates.  */
+asm (".symver __h_errno, h_errno@GLIBC_PRIVATE");
+#endif
diff --git a/resolv/res_libc.c b/resolv/res_libc.c
index 9f2d3c3bd442bb38..5ab02c79c72eb1ac 100644
--- a/resolv/res_libc.c
+++ b/resolv/res_libc.c
@@ -41,6 +41,7 @@
 #include <resolv.h>
 #include <libc-lock.h>
 #include <resolv-internal.h>
+#include <resolv_context.h>
 
 int
 res_init (void)
@@ -80,7 +81,34 @@ res_init (void)
 
   return __res_vinit (&_res, 1);
 }
-
+
+#ifdef SHARED
+
+/* An old nscd binary may bind to __res_maybe_init during a glibc
+   update.  Emulate it using the new functions.  Ignore PREINIT
+   because almost all existing __res_maybe_init callers used zero
+   PREINIT, and the difference for RESP == &_res is very minor (a
+   potential override of application configuration).  */
+attribute_compat_text_section
+int
+__res_maybe_init (res_state resp, int preinit)
+{
+  if (resp == &_res)
+    {
+      /* This performs an implicit initialization of _res.  */
+      struct resolv_context *ctx = __resolv_context_get ();
+      if (ctx == NULL)
+        return -1;
+      __resolv_context_put (ctx);
+      return 0;
+    }
+  else
+    return __res_vinit (resp, 0);
+}
+asm (".symver __res_maybe_init, __res_maybe_init@GLIBC_PRIVATE");
+
+#endif /* SHARED */
+
 /* This needs to be after the use of _res in res_init, above.  */
 #undef _res
 
diff --git a/resolv/res_query.c b/resolv/res_query.c
index ebbe5a6a4ed86abe..24fefb561e7f1f5e 100644
--- a/resolv/res_query.c
+++ b/resolv/res_query.c
@@ -705,6 +705,96 @@ hostalias (const char *name)
     (__resolv_context_get (), name, abuf, sizeof (abuf));
 }
 
+#ifdef SHARED
+/* Compatibiliaty functions to support old nss_dns modules.  */
+
+typedef int (*compat_query_function) (struct resolv_context *,
+				      const char *name,
+				      int class, int type,
+				      u_char *answer,
+				      int anslen,
+				      u_char **answerp,
+				      u_char **answerp2,
+				      int *nanswerp2,
+				      int *resplen2,
+				      int *answerp2_malloced);
+
+attribute_compat_text_section
+static int
+wrap_compat_call (compat_query_function qf,
+		  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 buffer */
+		  u_char **answerp,	/* if buffer needs to be enlarged */
+		  u_char **answerp2,
+		  int *nanswerp2,
+		  int *resplen2,
+		  int *answerp2_malloced)
+{
+  if (statp == &_res)
+    {
+      struct resolv_context *ctx = __resolv_context_get ();
+      if (ctx == NULL)
+	{
+	  __set_h_errno (NO_RECOVERY);
+	  return -1;
+	}
+      int ret = qf (ctx, name, class, type,
+		    answer, anslen, answerp, answerp2,
+		    nanswerp2, resplen2, answerp2_malloced);
+      __resolv_context_put (ctx);
+      return ret;
+    }
+  else
+    {
+      __set_h_errno (NO_RECOVERY);
+      __set_errno (ENOTSUP);
+      return -1;
+    }
+}
+
+attribute_compat_text_section
+int
+__libc_res_nquery(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 buffer */
+		  u_char **answerp,	/* if buffer needs to be enlarged */
+		  u_char **answerp2,
+		  int *nanswerp2,
+		  int *resplen2,
+		  int *answerp2_malloced)
+{
+  return wrap_compat_call (__res_context_query, statp, name, class, type,
+			   answer, anslen, answerp, answerp2,
+			   nanswerp2, resplen2, answerp2_malloced);
+}
+asm (".symver __libc_res_nquery, __libc_res_nquery@GLIBC_PRIVATE");
+
+attribute_compat_text_section
+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,
+		   u_char **answerp2,
+		   int *nanswerp2,
+		   int *resplen2,
+		   int *answerp2_malloced)
+{
+  return wrap_compat_call (__res_context_search, statp, name, class, type,
+			   answer, anslen, answerp, answerp2,
+			   nanswerp2, resplen2, answerp2_malloced);
+}
+asm (".symver __libc_res_nsearch, __libc_res_nsearch@GLIBC_PRIVATE");
+
+#endif /* SHARED */
+
 #if SHLIB_COMPAT (libresolv, GLIBC_2_0, GLIBC_2_2)
 # undef res_query
 # undef res_querydomain