aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog5
-rw-r--r--nss/nss_files/files-hosts.c200
-rw-r--r--resolv/Versions2
3 files changed, 194 insertions, 13 deletions
diff --git a/ChangeLog b/ChangeLog
index be7ced0..ad3c6d2 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+2000-07-23 Ulrich Drepper <drepper@redhat.com>
+
+ * nss/nss_files/files-hosts.c: Implement multi handling.
+ * resolv/Versions: Export _res_hconf for GLIBC_2.2 from libc.
+
2000-07-22 Ulrich Drepper <drepper@redhat.com>
* nss/nss_files/files-parse.c: Don't pollute namespace by using
diff --git a/nss/nss_files/files-hosts.c b/nss/nss_files/files-hosts.c
index e73fee0..c96a39c 100644
--- a/nss/nss_files/files-hosts.c
+++ b/nss/nss_files/files-hosts.c
@@ -17,6 +17,7 @@
write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
+#include <assert.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <arpa/nameser.h>
@@ -26,6 +27,7 @@
/* Get implementation for some internal functions. */
#include "../resolv/mapv4v6addr.h"
+#include "../resolv/res_hconf.h"
#define ENTNAME hostent
@@ -74,25 +76,199 @@ LINE_PARSER
STRING_FIELD (result->h_name, isspace, 1);
})
+
+
+#define HOST_DB_LOOKUP(name, keysize, keypattern, break_if_match, proto...) \
+enum nss_status \
+_nss_files_get##name##_r (proto, \
+ struct STRUCTURE *result, char *buffer, \
+ size_t buflen, int *errnop H_ERRNO_PROTO) \
+{ \
+ enum nss_status status; \
+ \
+ __libc_lock_lock (lock); \
+ \
+ /* Reset file pointer to beginning or open file. */ \
+ status = internal_setent (keep_stream); \
+ \
+ if (status == NSS_STATUS_SUCCESS) \
+ { \
+ /* Tell getent function that we have repositioned the file pointer. */ \
+ last_use = getby; \
+ \
+ while ((status = internal_getent (result, buffer, buflen, errnop \
+ H_ERRNO_ARG EXTRA_ARGS_VALUE)) \
+ == NSS_STATUS_SUCCESS) \
+ { break_if_match } \
+ \
+ if (status == NSS_STATUS_SUCCESS \
+ && _res_hconf.flags & HCONF_FLAG_MULTI) \
+ { \
+ /* We have to get all host entries from the file. */ \
+ const size_t tmp_buflen = MIN (buflen, 4096); \
+ char tmp_buffer[tmp_buflen]; \
+ struct hostent tmp_result_buf; \
+ int naddrs = 1; \
+ int naliases = 0; \
+ char *bufferend; \
+ \
+ while (result->h_aliases[naliases] != NULL) \
+ ++naliases; \
+ \
+ bufferend = (char *) &result->h_aliases[naliases + 1]; \
+ \
+ while ((status = internal_getent (&tmp_result_buf, tmp_buffer, \
+ tmp_buflen, errnop H_ERRNO_ARG \
+ EXTRA_ARGS_VALUE)) \
+ == NSS_STATUS_SUCCESS) \
+ { \
+ int matches = 1; \
+ struct hostent *old_result = result; \
+ result = &tmp_result_buf; \
+ /* The following piece is a bit clumsy but we want to use the \
+ `break_if_match' value. The optimizer should do its \
+ job. */ \
+ do \
+ { \
+ break_if_match \
+ result = old_result; \
+ } \
+ while ((matches = 0)); \
+ \
+ if (matches) \
+ { \
+ /* We could be very clever and try to recycle a few bytes \
+ in the buffer instead of generating new arrays. But \
+ we are not doing this here since it's more work than \
+ it's worth. Simply let the user provide a bit bigger \
+ buffer. */ \
+ char **new_h_addr_list; \
+ char **new_h_aliases; \
+ int newaliases = 0; \
+ size_t newstrlen = 0; \
+ int cnt; \
+ \
+ /* Count the new aliases and the length of the strings. */ \
+ while (tmp_result_buf.h_aliases[newaliases] != NULL) \
+ { \
+ char *cp = tmp_result_buf.h_aliases[newaliases]; \
+ ++newaliases; \
+ newstrlen += strlen (cp) + 1; \
+ } \
+ /* If the real name is different add it also to the \
+ aliases. This means that there is a duplication \
+ in the alias list but this is really the users \
+ problem. */ \
+ if (strcmp (old_result->h_name, \
+ tmp_result_buf.h_name) != 0) \
+ { \
+ ++newaliases; \
+ newstrlen += strlen (tmp_result_buf.h_name) + 1; \
+ } \
+ \
+ /* Now we can check whether the buffer is large enough. */ \
+ if (bufferend + 16 + (naddrs + 2) * sizeof (char *) \
+ + roundup (newstrlen, sizeof (char *)) \
+ + (naliases + newaliases + 1) * sizeof (char *) \
+ >= buffer + buflen) \
+ { \
+ *errnop = ERANGE; \
+ status = NSS_STATUS_TRYAGAIN; \
+ break; \
+ } \
+ \
+ new_h_addr_list = \
+ (char **) (bufferend \
+ + roundup (newstrlen, sizeof (char *)) \
+ + 16); \
+ new_h_aliases = \
+ (char **) ((char *) new_h_addr_list \
+ + (naddrs + 2) * sizeof (char *)); \
+ \
+ /* Copy the old data in the new arrays. */ \
+ for (cnt = 0; cnt < naddrs; ++cnt) \
+ new_h_addr_list[cnt] = old_result->h_addr_list[cnt]; \
+ \
+ for (cnt = 0; cnt < naliases; ++cnt) \
+ new_h_aliases[cnt] = old_result->h_aliases[cnt]; \
+ \
+ /* Store the new strings. */ \
+ cnt = 0; \
+ while (tmp_result_buf.h_aliases[cnt] != NULL) \
+ { \
+ new_h_aliases[naliases++] = bufferend; \
+ bufferend = (__stpcpy (bufferend, \
+ tmp_result_buf.h_aliases[cnt]) \
+ + 1); \
+ } \
+ \
+ if (cnt < newaliases) \
+ { \
+ new_h_aliases[naliases++] = bufferend; \
+ bufferend = __stpcpy (bufferend, \
+ tmp_result_buf.h_name) + 1; \
+ } \
+ \
+ /* Final NULL pointer. */ \
+ new_h_aliases[naliases] = NULL; \
+ \
+ /* Round up the buffer end address. */ \
+ bufferend += (sizeof (char *) \
+ - ((bufferend - (char *) 0) \
+ % sizeof (char *))); \
+ \
+ /* Now the new address. */ \
+ new_h_addr_list[naddrs++] = \
+ memcpy (bufferend, tmp_result_buf.h_addr, \
+ tmp_result_buf.h_length); \
+ \
+ /* Also here a final NULL pointer. */ \
+ new_h_addr_list[naddrs] = NULL; \
+ \
+ /* Store the new array pointers. */ \
+ old_result->h_aliases = new_h_aliases; \
+ old_result->h_addr_list = new_h_addr_list; \
+ \
+ /* Compute the new buffer end. */ \
+ bufferend = (char *) &new_h_aliases[naliases + 1]; \
+ assert (bufferend <= buffer + buflen); \
+ } \
+ } \
+ \
+ if (status != NSS_STATUS_TRYAGAIN) \
+ status = NSS_STATUS_SUCCESS; \
+ } \
+ \
+ \
+ if (! keep_stream) \
+ internal_endent (); \
+ } \
+ \
+ __libc_lock_unlock (lock); \
+ \
+ return status; \
+}
+
+
#define EXTRA_ARGS_VALUE \
, ((_res.options & RES_USE_INET6) ? AF_INET6 : AF_INET), \
((_res.options & RES_USE_INET6) ? AI_V4MAPPED : 0)
#include "files-XXX.c"
+HOST_DB_LOOKUP (hostbyname, ,,
+ {
+ LOOKUP_NAME_CASE (h_name, h_aliases)
+ }, const char *name)
-DB_LOOKUP (hostbyname, ,,
- {
- 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 \
, af, ((_res.options & RES_USE_INET6) ? AI_V4MAPPED : 0)
-DB_LOOKUP (hostbyname2, ,,
- {
- LOOKUP_NAME_CASE (h_name, h_aliases)
- }, const char *name, int af)
+HOST_DB_LOOKUP (hostbyname2, ,,
+ {
+ LOOKUP_NAME_CASE (h_name, h_aliases)
+ }, const char *name, int af)
DB_LOOKUP (hostbyaddr, ,,
{
@@ -104,7 +280,7 @@ DB_LOOKUP (hostbyaddr, ,,
#undef EXTRA_ARGS_VALUE
#define EXTRA_ARGS_VALUE \
, af, flags
-DB_LOOKUP (ipnodebyname, ,,
- {
- LOOKUP_NAME_CASE (h_name, h_aliases)
- }, const char *name, int af, int flags)
+HOST_DB_LOOKUP (ipnodebyname, ,,
+ {
+ LOOKUP_NAME_CASE (h_name, h_aliases)
+ }, const char *name, int af, int flags)
diff --git a/resolv/Versions b/resolv/Versions
index 0f9255d..9868524 100644
--- a/resolv/Versions
+++ b/resolv/Versions
@@ -20,7 +20,7 @@ libc {
}
GLIBC_2.2 {
# r*
- __res_state; __res_init; __res_nclose; __res_ninit;
+ __res_state; __res_init; __res_nclose; __res_ninit; _res_hconf;
}
}