Blame nscd/nscd_helper.c

Packit 6c4009
/* Copyright (C) 1998-2018 Free Software Foundation, Inc.
Packit 6c4009
   This file is part of the GNU C Library.
Packit 6c4009
   Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998.
Packit 6c4009
Packit 6c4009
   The GNU C Library is free software; you can redistribute it and/or
Packit 6c4009
   modify it under the terms of the GNU Lesser General Public
Packit 6c4009
   License as published by the Free Software Foundation; either
Packit 6c4009
   version 2.1 of the License, or (at your option) any later version.
Packit 6c4009
Packit 6c4009
   The GNU C Library is distributed in the hope that it will be useful,
Packit 6c4009
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 6c4009
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 6c4009
   Lesser General Public License for more details.
Packit 6c4009
Packit 6c4009
   You should have received a copy of the GNU Lesser General Public
Packit 6c4009
   License along with the GNU C Library; if not, see
Packit 6c4009
   <http://www.gnu.org/licenses/>.  */
Packit 6c4009
Packit 6c4009
#include <assert.h>
Packit 6c4009
#include <errno.h>
Packit 6c4009
#include <fcntl.h>
Packit 6c4009
#include <stdbool.h>
Packit 6c4009
#include <stddef.h>
Packit 6c4009
#include <stdlib.h>
Packit 6c4009
#include <string.h>
Packit 6c4009
#include <time.h>
Packit 6c4009
#include <unistd.h>
Packit 6c4009
#include <stdint.h>
Packit 6c4009
#include <sys/mman.h>
Packit 6c4009
#include <sys/param.h>
Packit 6c4009
#include <sys/poll.h>
Packit 6c4009
#include <sys/socket.h>
Packit 6c4009
#include <sys/stat.h>
Packit 6c4009
#include <sys/time.h>
Packit 6c4009
#include <sys/uio.h>
Packit 6c4009
#include <sys/un.h>
Packit 6c4009
#include <not-cancel.h>
Packit 6c4009
#include <kernel-features.h>
Packit 6c4009
#include <nss.h>
Packit 6c4009
Packit 6c4009
#include "nscd-client.h"
Packit 6c4009
Packit 6c4009
/* Extra time we wait if the socket is still receiving data.  This
Packit 6c4009
   value is in milliseconds.  Note that the other side is nscd on the
Packit 6c4009
   local machine and it is already transmitting data.  So the wait
Packit 6c4009
   time need not be long.  */
Packit 6c4009
#define EXTRA_RECEIVE_TIME 200
Packit 6c4009
Packit 6c4009
Packit 6c4009
static int
Packit 6c4009
wait_on_socket (int sock, long int usectmo)
Packit 6c4009
{
Packit 6c4009
  struct pollfd fds[1];
Packit 6c4009
  fds[0].fd = sock;
Packit 6c4009
  fds[0].events = POLLIN | POLLERR | POLLHUP;
Packit 6c4009
  int n = __poll (fds, 1, usectmo);
Packit 6c4009
  if (n == -1 && __builtin_expect (errno == EINTR, 0))
Packit 6c4009
    {
Packit 6c4009
      /* Handle the case where the poll() call is interrupted by a
Packit 6c4009
	 signal.  We cannot just use TEMP_FAILURE_RETRY since it might
Packit 6c4009
	 lead to infinite loops.  */
Packit 6c4009
      struct timeval now;
Packit 6c4009
      (void) __gettimeofday (&now, NULL);
Packit 6c4009
      long int end = now.tv_sec * 1000 + usectmo + (now.tv_usec + 500) / 1000;
Packit 6c4009
      long int timeout = usectmo;
Packit 6c4009
      while (1)
Packit 6c4009
	{
Packit 6c4009
	  n = __poll (fds, 1, timeout);
Packit 6c4009
	  if (n != -1 || errno != EINTR)
Packit 6c4009
	    break;
Packit 6c4009
Packit 6c4009
	  /* Recompute the timeout time.  */
Packit 6c4009
	  (void) __gettimeofday (&now, NULL);
Packit 6c4009
	  timeout = end - (now.tv_sec * 1000 + (now.tv_usec + 500) / 1000);
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  return n;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
ssize_t
Packit 6c4009
__readall (int fd, void *buf, size_t len)
Packit 6c4009
{
Packit 6c4009
  size_t n = len;
Packit 6c4009
  ssize_t ret;
Packit 6c4009
  do
Packit 6c4009
    {
Packit 6c4009
    again:
Packit 6c4009
      ret = TEMP_FAILURE_RETRY (__read (fd, buf, n));
Packit 6c4009
      if (ret <= 0)
Packit 6c4009
	{
Packit 6c4009
	  if (__builtin_expect (ret < 0 && errno == EAGAIN, 0)
Packit 6c4009
	      /* The socket is still receiving data.  Wait a bit more.  */
Packit 6c4009
	      && wait_on_socket (fd, EXTRA_RECEIVE_TIME) > 0)
Packit 6c4009
	    goto again;
Packit 6c4009
Packit 6c4009
	  break;
Packit 6c4009
	}
Packit 6c4009
      buf = (char *) buf + ret;
Packit 6c4009
      n -= ret;
Packit 6c4009
    }
Packit 6c4009
  while (n > 0);
Packit 6c4009
  return ret < 0 ? ret : len - n;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
ssize_t
Packit 6c4009
__readvall (int fd, const struct iovec *iov, int iovcnt)
Packit 6c4009
{
Packit 6c4009
  ssize_t ret = TEMP_FAILURE_RETRY (__readv (fd, iov, iovcnt));
Packit 6c4009
  if (ret <= 0)
Packit 6c4009
    {
Packit 6c4009
      if (__glibc_likely (ret == 0 || errno != EAGAIN))
Packit 6c4009
	/* A genuine error or no data to read.  */
Packit 6c4009
	return ret;
Packit 6c4009
Packit 6c4009
      /* The data has not all yet been received.  Do as if we have not
Packit 6c4009
	 read anything yet.  */
Packit 6c4009
      ret = 0;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  size_t total = 0;
Packit 6c4009
  for (int i = 0; i < iovcnt; ++i)
Packit 6c4009
    total += iov[i].iov_len;
Packit 6c4009
Packit 6c4009
  if (ret < total)
Packit 6c4009
    {
Packit 6c4009
      struct iovec iov_buf[iovcnt];
Packit 6c4009
      ssize_t r = ret;
Packit 6c4009
Packit 6c4009
      struct iovec *iovp = memcpy (iov_buf, iov, iovcnt * sizeof (*iov));
Packit 6c4009
      do
Packit 6c4009
	{
Packit 6c4009
	  while (iovp->iov_len <= r)
Packit 6c4009
	    {
Packit 6c4009
	      r -= iovp->iov_len;
Packit 6c4009
	      --iovcnt;
Packit 6c4009
	      ++iovp;
Packit 6c4009
	    }
Packit 6c4009
	  iovp->iov_base = (char *) iovp->iov_base + r;
Packit 6c4009
	  iovp->iov_len -= r;
Packit 6c4009
	again:
Packit 6c4009
	  r = TEMP_FAILURE_RETRY (__readv (fd, iovp, iovcnt));
Packit 6c4009
	  if (r <= 0)
Packit 6c4009
	    {
Packit 6c4009
	      if (__builtin_expect (r < 0 && errno == EAGAIN, 0)
Packit 6c4009
		  /* The socket is still receiving data.  Wait a bit more.  */
Packit 6c4009
		  && wait_on_socket (fd, EXTRA_RECEIVE_TIME) > 0)
Packit 6c4009
		goto again;
Packit 6c4009
Packit 6c4009
	      break;
Packit 6c4009
	    }
Packit 6c4009
	  ret += r;
Packit 6c4009
	}
Packit 6c4009
      while (ret < total);
Packit 6c4009
      if (r < 0)
Packit 6c4009
	ret = r;
Packit 6c4009
    }
Packit 6c4009
  return ret;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
static int
Packit 6c4009
open_socket (request_type type, const char *key, size_t keylen)
Packit 6c4009
{
Packit 6c4009
  int sock;
Packit 6c4009
Packit 6c4009
  sock = __socket (PF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0);
Packit 6c4009
  if (sock < 0)
Packit 6c4009
    return -1;
Packit 6c4009
Packit 6c4009
  size_t real_sizeof_reqdata = sizeof (request_header) + keylen;
Packit 6c4009
  struct
Packit 6c4009
  {
Packit 6c4009
    request_header req;
Packit 6c4009
    char key[];
Packit 6c4009
  } *reqdata = alloca (real_sizeof_reqdata);
Packit 6c4009
Packit 6c4009
  struct sockaddr_un sun;
Packit 6c4009
  sun.sun_family = AF_UNIX;
Packit 6c4009
  strcpy (sun.sun_path, _PATH_NSCDSOCKET);
Packit 6c4009
  if (__connect (sock, (struct sockaddr *) &sun, sizeof (sun)) < 0
Packit 6c4009
      && errno != EINPROGRESS)
Packit 6c4009
    goto out;
Packit 6c4009
Packit 6c4009
  reqdata->req.version = NSCD_VERSION;
Packit 6c4009
  reqdata->req.type = type;
Packit 6c4009
  reqdata->req.key_len = keylen;
Packit 6c4009
Packit 6c4009
  memcpy (reqdata->key, key, keylen);
Packit 6c4009
Packit 6c4009
  bool first_try = true;
Packit 6c4009
  struct timeval tvend;
Packit 6c4009
  /* Fake initializing tvend.  */
Packit 6c4009
  asm ("" : "=m" (tvend));
Packit 6c4009
  while (1)
Packit 6c4009
    {
Packit 6c4009
#ifndef MSG_NOSIGNAL
Packit 6c4009
# define MSG_NOSIGNAL 0
Packit 6c4009
#endif
Packit 6c4009
      ssize_t wres = TEMP_FAILURE_RETRY (__send (sock, reqdata,
Packit 6c4009
						 real_sizeof_reqdata,
Packit 6c4009
						 MSG_NOSIGNAL));
Packit 6c4009
      if (__glibc_likely (wres == (ssize_t) real_sizeof_reqdata))
Packit 6c4009
	/* We managed to send the request.  */
Packit 6c4009
	return sock;
Packit 6c4009
Packit 6c4009
      if (wres != -1 || errno != EAGAIN)
Packit 6c4009
	/* Something is really wrong, no chance to continue.  */
Packit 6c4009
	break;
Packit 6c4009
Packit 6c4009
      /* The daemon is busy wait for it.  */
Packit 6c4009
      int to;
Packit 6c4009
      struct timeval now;
Packit 6c4009
      (void) __gettimeofday (&now, NULL);
Packit 6c4009
      if (first_try)
Packit 6c4009
	{
Packit 6c4009
	  tvend.tv_usec = now.tv_usec;
Packit 6c4009
	  tvend.tv_sec = now.tv_sec + 5;
Packit 6c4009
	  to = 5 * 1000;
Packit 6c4009
	  first_try = false;
Packit 6c4009
	}
Packit 6c4009
      else
Packit 6c4009
	to = ((tvend.tv_sec - now.tv_sec) * 1000
Packit 6c4009
	      + (tvend.tv_usec - now.tv_usec) / 1000);
Packit 6c4009
Packit 6c4009
      struct pollfd fds[1];
Packit 6c4009
      fds[0].fd = sock;
Packit 6c4009
      fds[0].events = POLLOUT | POLLERR | POLLHUP;
Packit 6c4009
      if (__poll (fds, 1, to) <= 0)
Packit 6c4009
	/* The connection timed out or broke down.  */
Packit 6c4009
	break;
Packit 6c4009
Packit 6c4009
      /* We try to write again.  */
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
 out:
Packit 6c4009
  __close_nocancel_nostatus (sock);
Packit 6c4009
Packit 6c4009
  return -1;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
void
Packit 6c4009
__nscd_unmap (struct mapped_database *mapped)
Packit 6c4009
{
Packit 6c4009
  assert (mapped->counter == 0);
Packit 6c4009
  __munmap ((void *) mapped->head, mapped->mapsize);
Packit 6c4009
  free (mapped);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* Try to get a file descriptor for the shared meory segment
Packit 6c4009
   containing the database.  */
Packit 6c4009
struct mapped_database *
Packit 6c4009
__nscd_get_mapping (request_type type, const char *key,
Packit 6c4009
		    struct mapped_database **mappedp)
Packit 6c4009
{
Packit 6c4009
  struct mapped_database *result = NO_MAPPING;
Packit 6c4009
#ifdef SCM_RIGHTS
Packit 6c4009
  const size_t keylen = strlen (key) + 1;
Packit 6c4009
  int saved_errno = errno;
Packit 6c4009
Packit 6c4009
  int mapfd = -1;
Packit 6c4009
  char resdata[keylen];
Packit 6c4009
Packit 6c4009
  /* Open a socket and send the request.  */
Packit 6c4009
  int sock = open_socket (type, key, keylen);
Packit 6c4009
  if (sock < 0)
Packit 6c4009
    goto out;
Packit 6c4009
Packit 6c4009
  /* Room for the data sent along with the file descriptor.  We expect
Packit 6c4009
     the key name back.  */
Packit 6c4009
  uint64_t mapsize;
Packit 6c4009
  struct iovec iov[2];
Packit 6c4009
  iov[0].iov_base = resdata;
Packit 6c4009
  iov[0].iov_len = keylen;
Packit 6c4009
  iov[1].iov_base = &mapsize;
Packit 6c4009
  iov[1].iov_len = sizeof (mapsize);
Packit 6c4009
Packit 6c4009
  union
Packit 6c4009
  {
Packit 6c4009
    struct cmsghdr hdr;
Packit 6c4009
    char bytes[CMSG_SPACE (sizeof (int))];
Packit 6c4009
  } buf;
Packit 6c4009
  struct msghdr msg = { .msg_iov = iov, .msg_iovlen = 2,
Packit 6c4009
			.msg_control = buf.bytes,
Packit 6c4009
			.msg_controllen = sizeof (buf) };
Packit 6c4009
  struct cmsghdr *cmsg = CMSG_FIRSTHDR (&msg;;
Packit 6c4009
Packit 6c4009
  cmsg->cmsg_level = SOL_SOCKET;
Packit 6c4009
  cmsg->cmsg_type = SCM_RIGHTS;
Packit 6c4009
  cmsg->cmsg_len = CMSG_LEN (sizeof (int));
Packit 6c4009
Packit 6c4009
  /* This access is well-aligned since BUF is correctly aligned for an
Packit 6c4009
     int and CMSG_DATA preserves this alignment.  */
Packit 6c4009
  memset (CMSG_DATA (cmsg), '\xff', sizeof (int));
Packit 6c4009
Packit 6c4009
  msg.msg_controllen = cmsg->cmsg_len;
Packit 6c4009
Packit 6c4009
  if (wait_on_socket (sock, 5 * 1000) <= 0)
Packit 6c4009
    goto out_close2;
Packit 6c4009
Packit 6c4009
# ifndef MSG_CMSG_CLOEXEC
Packit 6c4009
#  define MSG_CMSG_CLOEXEC 0
Packit 6c4009
# endif
Packit 6c4009
  ssize_t n = TEMP_FAILURE_RETRY (__recvmsg (sock, &msg, MSG_CMSG_CLOEXEC));
Packit 6c4009
Packit 6c4009
  if (__builtin_expect (CMSG_FIRSTHDR (&msg) == NULL
Packit 6c4009
			|| (CMSG_FIRSTHDR (&msg)->cmsg_len
Packit 6c4009
			    != CMSG_LEN (sizeof (int))), 0))
Packit 6c4009
    goto out_close2;
Packit 6c4009
Packit 6c4009
  int *ip = (void *) CMSG_DATA (cmsg);
Packit 6c4009
  mapfd = *ip;
Packit 6c4009
Packit 6c4009
  if (__glibc_unlikely (n != keylen && n != keylen + sizeof (mapsize)))
Packit 6c4009
    goto out_close;
Packit 6c4009
Packit 6c4009
  if (__glibc_unlikely (strcmp (resdata, key) != 0))
Packit 6c4009
    goto out_close;
Packit 6c4009
Packit 6c4009
  if (__glibc_unlikely (n == keylen))
Packit 6c4009
    {
Packit 6c4009
      struct stat64 st;
Packit 6c4009
      if (__builtin_expect (fstat64 (mapfd, &st) != 0, 0)
Packit 6c4009
	  || __builtin_expect (st.st_size < sizeof (struct database_pers_head),
Packit 6c4009
			       0))
Packit 6c4009
	goto out_close;
Packit 6c4009
Packit 6c4009
      mapsize = st.st_size;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* The file is large enough, map it now.  */
Packit 6c4009
  void *mapping = __mmap (NULL, mapsize, PROT_READ, MAP_SHARED, mapfd, 0);
Packit 6c4009
  if (__glibc_likely (mapping != MAP_FAILED))
Packit 6c4009
    {
Packit 6c4009
      /* Check whether the database is correct and up-to-date.  */
Packit 6c4009
      struct database_pers_head *head = mapping;
Packit 6c4009
Packit 6c4009
      if (__builtin_expect (head->version != DB_VERSION, 0)
Packit 6c4009
	  || __builtin_expect (head->header_size != sizeof (*head), 0)
Packit 6c4009
	  /* Catch some misconfiguration.  The server should catch
Packit 6c4009
	     them now but some older versions did not.  */
Packit 6c4009
	  || __builtin_expect (head->module == 0, 0)
Packit 6c4009
	  /* This really should not happen but who knows, maybe the update
Packit 6c4009
	     thread got stuck.  */
Packit 6c4009
	  || __builtin_expect (! head->nscd_certainly_running
Packit 6c4009
			       && (head->timestamp + MAPPING_TIMEOUT
Packit 6c4009
				   < time (NULL)), 0))
Packit 6c4009
	{
Packit 6c4009
	out_unmap:
Packit 6c4009
	  __munmap (mapping, mapsize);
Packit 6c4009
	  goto out_close;
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      size_t size = (sizeof (*head) + roundup (head->module * sizeof (ref_t),
Packit 6c4009
					       ALIGN)
Packit 6c4009
		     + head->data_size);
Packit 6c4009
Packit 6c4009
      if (__glibc_unlikely (mapsize < size))
Packit 6c4009
	goto out_unmap;
Packit 6c4009
Packit 6c4009
      /* Allocate a record for the mapping.  */
Packit 6c4009
      struct mapped_database *newp = malloc (sizeof (*newp));
Packit 6c4009
      if (newp == NULL)
Packit 6c4009
	/* Ugh, after all we went through the memory allocation failed.  */
Packit 6c4009
	goto out_unmap;
Packit 6c4009
Packit 6c4009
      newp->head = mapping;
Packit 6c4009
      newp->data = ((char *) mapping + head->header_size
Packit 6c4009
		    + roundup (head->module * sizeof (ref_t), ALIGN));
Packit 6c4009
      newp->mapsize = size;
Packit 6c4009
      newp->datasize = head->data_size;
Packit 6c4009
      /* Set counter to 1 to show it is usable.  */
Packit 6c4009
      newp->counter = 1;
Packit 6c4009
Packit 6c4009
      result = newp;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
 out_close:
Packit 6c4009
  __close (mapfd);
Packit 6c4009
 out_close2:
Packit 6c4009
  __close (sock);
Packit 6c4009
 out:
Packit 6c4009
  __set_errno (saved_errno);
Packit 6c4009
#endif	/* SCM_RIGHTS */
Packit 6c4009
Packit 6c4009
  struct mapped_database *oldval = *mappedp;
Packit 6c4009
  *mappedp = result;
Packit 6c4009
Packit 6c4009
  if (oldval != NULL && atomic_decrement_val (&oldval->counter) == 0)
Packit 6c4009
    __nscd_unmap (oldval);
Packit 6c4009
Packit 6c4009
  return result;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
struct mapped_database *
Packit 6c4009
__nscd_get_map_ref (request_type type, const char *name,
Packit 6c4009
		    volatile struct locked_map_ptr *mapptr, int *gc_cyclep)
Packit 6c4009
{
Packit 6c4009
  struct mapped_database *cur = mapptr->mapped;
Packit 6c4009
  if (cur == NO_MAPPING)
Packit 6c4009
    return cur;
Packit 6c4009
Packit 6c4009
  if (!__nscd_acquire_maplock (mapptr))
Packit 6c4009
    return NO_MAPPING;
Packit 6c4009
Packit 6c4009
  cur = mapptr->mapped;
Packit 6c4009
Packit 6c4009
  if (__glibc_likely (cur != NO_MAPPING))
Packit 6c4009
    {
Packit 6c4009
      /* If not mapped or timestamp not updated, request new map.  */
Packit 6c4009
      if (cur == NULL
Packit 6c4009
	  || (cur->head->nscd_certainly_running == 0
Packit 6c4009
	      && cur->head->timestamp + MAPPING_TIMEOUT < time (NULL))
Packit 6c4009
	  || cur->head->data_size > cur->datasize)
Packit 6c4009
	cur = __nscd_get_mapping (type, name,
Packit 6c4009
				  (struct mapped_database **) &mapptr->mapped);
Packit 6c4009
Packit 6c4009
      if (__glibc_likely (cur != NO_MAPPING))
Packit 6c4009
	{
Packit 6c4009
	  if (__builtin_expect (((*gc_cyclep = cur->head->gc_cycle) & 1) != 0,
Packit 6c4009
				0))
Packit 6c4009
	    cur = NO_MAPPING;
Packit 6c4009
	  else
Packit 6c4009
	    atomic_increment (&cur->counter);
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  mapptr->lock = 0;
Packit 6c4009
Packit 6c4009
  return cur;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* Using sizeof (hashentry) is not always correct to determine the size of
Packit 6c4009
   the data structure as found in the nscd cache.  The program could be
Packit 6c4009
   a 64-bit process and nscd could be a 32-bit process.  In this case
Packit 6c4009
   sizeof (hashentry) would overestimate the size.  The following is
Packit 6c4009
   the minimum size of such an entry, good enough for our tests here.  */
Packit 6c4009
#define MINIMUM_HASHENTRY_SIZE \
Packit 6c4009
  (offsetof (struct hashentry, dellist) + sizeof (int32_t))
Packit 6c4009
Packit 6c4009
/* Don't return const struct datahead *, as eventhough the record
Packit 6c4009
   is normally constant, it can change arbitrarily during nscd
Packit 6c4009
   garbage collection.  */
Packit 6c4009
struct datahead *
Packit 6c4009
__nscd_cache_search (request_type type, const char *key, size_t keylen,
Packit 6c4009
		     const struct mapped_database *mapped, size_t datalen)
Packit 6c4009
{
Packit 6c4009
  unsigned long int hash = __nss_hash (key, keylen) % mapped->head->module;
Packit 6c4009
  size_t datasize = mapped->datasize;
Packit 6c4009
Packit 6c4009
  ref_t trail = mapped->head->array[hash];
Packit 6c4009
  trail = atomic_forced_read (trail);
Packit 6c4009
  ref_t work = trail;
Packit 6c4009
  size_t loop_cnt = datasize / (MINIMUM_HASHENTRY_SIZE
Packit 6c4009
				+ offsetof (struct datahead, data) / 2);
Packit 6c4009
  int tick = 0;
Packit 6c4009
Packit 6c4009
  while (work != ENDREF && work + MINIMUM_HASHENTRY_SIZE <= datasize)
Packit 6c4009
    {
Packit 6c4009
      struct hashentry *here = (struct hashentry *) (mapped->data + work);
Packit 6c4009
      ref_t here_key, here_packet;
Packit 6c4009
Packit 6c4009
#if !_STRING_ARCH_unaligned
Packit 6c4009
      /* Although during garbage collection when moving struct hashentry
Packit 6c4009
	 records around we first copy from old to new location and then
Packit 6c4009
	 adjust pointer from previous hashentry to it, there is no barrier
Packit 6c4009
	 between those memory writes.  It is very unlikely to hit it,
Packit 6c4009
	 so check alignment only if a misaligned load can crash the
Packit 6c4009
	 application.  */
Packit 6c4009
      if ((uintptr_t) here & (__alignof__ (*here) - 1))
Packit 6c4009
	return NULL;
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
      if (type == here->type
Packit 6c4009
	  && keylen == here->len
Packit 6c4009
	  && (here_key = atomic_forced_read (here->key)) + keylen <= datasize
Packit 6c4009
	  && memcmp (key, mapped->data + here_key, keylen) == 0
Packit 6c4009
	  && ((here_packet = atomic_forced_read (here->packet))
Packit 6c4009
	      + sizeof (struct datahead) <= datasize))
Packit 6c4009
	{
Packit 6c4009
	  /* We found the entry.  Increment the appropriate counter.  */
Packit 6c4009
	  struct datahead *dh
Packit 6c4009
	    = (struct datahead *) (mapped->data + here_packet);
Packit 6c4009
Packit 6c4009
#if !_STRING_ARCH_unaligned
Packit 6c4009
	  if ((uintptr_t) dh & (__alignof__ (*dh) - 1))
Packit 6c4009
	    return NULL;
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
	  /* See whether we must ignore the entry or whether something
Packit 6c4009
	     is wrong because garbage collection is in progress.  */
Packit 6c4009
	  if (dh->usable
Packit 6c4009
	      && here_packet + dh->allocsize <= datasize
Packit 6c4009
	      && (here_packet + offsetof (struct datahead, data) + datalen
Packit 6c4009
		  <= datasize))
Packit 6c4009
	    return dh;
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      work = atomic_forced_read (here->next);
Packit 6c4009
      /* Prevent endless loops.  This should never happen but perhaps
Packit 6c4009
	 the database got corrupted, accidentally or deliberately.  */
Packit 6c4009
      if (work == trail || loop_cnt-- == 0)
Packit 6c4009
	break;
Packit 6c4009
      if (tick)
Packit 6c4009
	{
Packit 6c4009
	  struct hashentry *trailelem;
Packit 6c4009
	  trailelem = (struct hashentry *) (mapped->data + trail);
Packit 6c4009
Packit 6c4009
#if !_STRING_ARCH_unaligned
Packit 6c4009
	  /* We have to redo the checks.  Maybe the data changed.  */
Packit 6c4009
	  if ((uintptr_t) trailelem & (__alignof__ (*trailelem) - 1))
Packit 6c4009
	    return NULL;
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
	  if (trail + MINIMUM_HASHENTRY_SIZE > datasize)
Packit 6c4009
	    return NULL;
Packit 6c4009
Packit 6c4009
	  trail = atomic_forced_read (trailelem->next);
Packit 6c4009
	}
Packit 6c4009
      tick = 1 - tick;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  return NULL;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* Create a socket connected to a name. */
Packit 6c4009
int
Packit 6c4009
__nscd_open_socket (const char *key, size_t keylen, request_type type,
Packit 6c4009
		    void *response, size_t responselen)
Packit 6c4009
{
Packit 6c4009
  /* This should never happen and it is something the nscd daemon
Packit 6c4009
     enforces, too.  He it helps to limit the amount of stack
Packit 6c4009
     used.  */
Packit 6c4009
  if (keylen > MAXKEYLEN)
Packit 6c4009
    return -1;
Packit 6c4009
Packit 6c4009
  int saved_errno = errno;
Packit 6c4009
Packit 6c4009
  int sock = open_socket (type, key, keylen);
Packit 6c4009
  if (sock >= 0)
Packit 6c4009
    {
Packit 6c4009
      /* Wait for data.  */
Packit 6c4009
      if (wait_on_socket (sock, 5 * 1000) > 0)
Packit 6c4009
	{
Packit 6c4009
	  ssize_t nbytes = TEMP_FAILURE_RETRY (__read (sock, response,
Packit 6c4009
						       responselen));
Packit 6c4009
	  if (nbytes == (ssize_t) responselen)
Packit 6c4009
	    return sock;
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      __close_nocancel_nostatus (sock);
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  __set_errno (saved_errno);
Packit 6c4009
Packit 6c4009
  return -1;
Packit 6c4009
}