2.5-18.1
[glibc.git] / nscd / nscd_helper.c
blob71ea53e19d79b7a3d23df9328b1eefd29444f648
1 /* Copyright (C) 1998-2002,2003,2004,2005,2006,2007
2 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
4 Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998.
6 The GNU C Library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
11 The GNU C Library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public
17 License along with the GNU C Library; if not, write to the Free
18 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19 02111-1307 USA. */
21 #include <assert.h>
22 #include <errno.h>
23 #include <fcntl.h>
24 #include <stdbool.h>
25 #include <string.h>
26 #include <time.h>
27 #include <unistd.h>
28 #include <sys/mman.h>
29 #include <sys/poll.h>
30 #include <sys/socket.h>
31 #include <sys/stat.h>
32 #include <sys/time.h>
33 #include <sys/uio.h>
34 #include <sys/un.h>
35 #include <not-cancel.h>
36 #include <nis/rpcsvc/nis.h>
38 #include "nscd-client.h"
41 ssize_t
42 __readall (int fd, void *buf, size_t len)
44 size_t n = len;
45 ssize_t ret;
48 ret = TEMP_FAILURE_RETRY (__read (fd, buf, n));
49 if (ret <= 0)
50 break;
51 buf = (char *) buf + ret;
52 n -= ret;
54 while (n > 0);
55 return ret < 0 ? ret : len - n;
59 ssize_t
60 __readvall (int fd, const struct iovec *iov, int iovcnt)
62 ssize_t ret = TEMP_FAILURE_RETRY (__readv (fd, iov, iovcnt));
63 if (ret <= 0)
64 return ret;
66 size_t total = 0;
67 for (int i = 0; i < iovcnt; ++i)
68 total += iov[i].iov_len;
70 if (ret < total)
72 struct iovec iov_buf[iovcnt];
73 ssize_t r = ret;
75 struct iovec *iovp = memcpy (iov_buf, iov, iovcnt * sizeof (*iov));
78 while (iovp->iov_len <= r)
80 r -= iovp->iov_len;
81 --iovcnt;
82 ++iovp;
84 iovp->iov_base = (char *) iovp->iov_base + r;
85 iovp->iov_len -= r;
86 r = TEMP_FAILURE_RETRY (__readv (fd, iovp, iovcnt));
87 if (r <= 0)
88 break;
89 ret += r;
91 while (ret < total);
92 if (r < 0)
93 ret = r;
95 return ret;
99 static int
100 open_socket (void)
102 int sock = __socket (PF_UNIX, SOCK_STREAM, 0);
103 if (sock < 0)
104 return -1;
106 /* Make socket non-blocking. */
107 int fl = __fcntl (sock, F_GETFL);
108 if (fl != -1)
109 __fcntl (sock, F_SETFL, fl | O_NONBLOCK);
111 struct sockaddr_un sun;
112 sun.sun_family = AF_UNIX;
113 strcpy (sun.sun_path, _PATH_NSCDSOCKET);
114 if (__connect (sock, (struct sockaddr *) &sun, sizeof (sun)) < 0
115 && errno != EINPROGRESS)
116 goto out;
118 struct pollfd fds[1];
119 fds[0].fd = sock;
120 fds[0].events = POLLOUT | POLLERR | POLLHUP;
121 if (__poll (fds, 1, 5 * 1000) > 0)
122 /* Success. We do not check for success of the connect call here.
123 If it failed, the following operations will fail. */
124 return sock;
126 out:
127 close_not_cancel_no_status (sock);
129 return -1;
133 void
134 __nscd_unmap (struct mapped_database *mapped)
136 assert (mapped->counter == 0);
137 __munmap ((void *) mapped->head, mapped->mapsize);
138 free (mapped);
142 static int
143 wait_on_socket (int sock)
145 struct pollfd fds[1];
146 fds[0].fd = sock;
147 fds[0].events = POLLIN | POLLERR | POLLHUP;
148 int n = __poll (fds, 1, 5 * 1000);
149 if (n == -1 && __builtin_expect (errno == EINTR, 0))
151 /* Handle the case where the poll() call is interrupted by a
152 signal. We cannot just use TEMP_FAILURE_RETRY since it might
153 lead to infinite loops. */
154 struct timeval now;
155 (void) __gettimeofday (&now, NULL);
156 long int end = (now.tv_sec + 5) * 1000 + (now.tv_usec + 500) / 1000;
157 while (1)
159 long int timeout = end - (now.tv_sec * 1000
160 + (now.tv_usec + 500) / 1000);
161 n = __poll (fds, 1, timeout);
162 if (n != -1 || errno != EINTR)
163 break;
164 (void) __gettimeofday (&now, NULL);
168 return n;
172 /* Try to get a file descriptor for the shared meory segment
173 containing the database. */
174 static struct mapped_database *
175 get_mapping (request_type type, const char *key,
176 struct mapped_database **mappedp)
178 struct mapped_database *result = NO_MAPPING;
179 #ifdef SCM_RIGHTS
180 const size_t keylen = strlen (key) + 1;
181 int saved_errno = errno;
183 int mapfd = -1;
185 /* Send the request. */
186 struct
188 request_header req;
189 char key[keylen];
190 } reqdata;
191 size_t real_sizeof_reqdata = sizeof (request_header) + keylen;
193 int sock = open_socket ();
194 if (sock < 0)
195 goto out;
197 reqdata.req.version = NSCD_VERSION;
198 reqdata.req.type = type;
199 reqdata.req.key_len = keylen;
200 memcpy (reqdata.key, key, keylen);
202 # ifndef MSG_NOSIGNAL
203 # define MSG_NOSIGNAL 0
204 # endif
205 if (__builtin_expect (TEMP_FAILURE_RETRY (__send (sock, &reqdata,
206 real_sizeof_reqdata,
207 MSG_NOSIGNAL))
208 != real_sizeof_reqdata, 0))
209 /* We cannot even write the request. */
210 goto out_close2;
212 /* Room for the data sent along with the file descriptor. We expect
213 the key name back. */
214 # define resdata reqdata.key
215 struct iovec iov[1];
216 iov[0].iov_base = resdata;
217 iov[0].iov_len = keylen;
219 union
221 struct cmsghdr hdr;
222 char bytes[CMSG_SPACE (sizeof (int))];
223 } buf;
224 struct msghdr msg = { .msg_iov = iov, .msg_iovlen = 1,
225 .msg_control = buf.bytes,
226 .msg_controllen = sizeof (buf) };
227 struct cmsghdr *cmsg = CMSG_FIRSTHDR (&msg);
229 cmsg->cmsg_level = SOL_SOCKET;
230 cmsg->cmsg_type = SCM_RIGHTS;
231 cmsg->cmsg_len = CMSG_LEN (sizeof (int));
233 /* This access is well-aligned since BUF is correctly aligned for an
234 int and CMSG_DATA preserves this alignment. */
235 *(int *) CMSG_DATA (cmsg) = -1;
237 msg.msg_controllen = cmsg->cmsg_len;
239 if (wait_on_socket (sock) <= 0)
240 goto out_close2;
242 if (__builtin_expect (TEMP_FAILURE_RETRY (__recvmsg (sock, &msg, 0))
243 != keylen, 0))
244 goto out_close2;
246 if (__builtin_expect (CMSG_FIRSTHDR (&msg) == NULL
247 || (CMSG_FIRSTHDR (&msg)->cmsg_len
248 != CMSG_LEN (sizeof (int))), 0))
249 goto out_close2;
251 mapfd = *(int *) CMSG_DATA (cmsg);
253 struct stat64 st;
254 if (__builtin_expect (strcmp (resdata, key) != 0, 0)
255 || __builtin_expect (fstat64 (mapfd, &st) != 0, 0)
256 || __builtin_expect (st.st_size < sizeof (struct database_pers_head), 0))
257 goto out_close;
259 struct database_pers_head head;
260 if (__builtin_expect (TEMP_FAILURE_RETRY (__pread (mapfd, &head,
261 sizeof (head), 0))
262 != sizeof (head), 0))
263 goto out_close;
265 if (__builtin_expect (head.version != DB_VERSION, 0)
266 || __builtin_expect (head.header_size != sizeof (head), 0)
267 /* This really should not happen but who knows, maybe the update
268 thread got stuck. */
269 || __builtin_expect (! head.nscd_certainly_running
270 && head.timestamp + MAPPING_TIMEOUT < time (NULL),
272 goto out_close;
274 size_t size = (sizeof (head) + roundup (head.module * sizeof (ref_t), ALIGN)
275 + head.data_size);
277 if (__builtin_expect (st.st_size < size, 0))
278 goto out_close;
280 /* The file is large enough, map it now. */
281 void *mapping = __mmap (NULL, size, PROT_READ, MAP_SHARED, mapfd, 0);
282 if (__builtin_expect (mapping != MAP_FAILED, 1))
284 /* Allocate a record for the mapping. */
285 struct mapped_database *newp = malloc (sizeof (*newp));
286 if (newp == NULL)
288 /* Ugh, after all we went through the memory allocation failed. */
289 __munmap (mapping, size);
290 goto out_close;
293 newp->head = mapping;
294 newp->data = ((char *) mapping + head.header_size
295 + roundup (head.module * sizeof (ref_t), ALIGN));
296 newp->mapsize = size;
297 newp->datasize = head.data_size;
298 /* Set counter to 1 to show it is usable. */
299 newp->counter = 1;
301 result = newp;
304 out_close:
305 __close (mapfd);
306 out_close2:
307 __close (sock);
308 out:
309 __set_errno (saved_errno);
310 #endif /* SCM_RIGHTS */
312 struct mapped_database *oldval = *mappedp;
313 *mappedp = result;
315 if (oldval != NULL && atomic_decrement_val (&oldval->counter) == 0)
316 __nscd_unmap (oldval);
318 return result;
322 struct mapped_database *
323 __nscd_get_map_ref (request_type type, const char *name,
324 volatile struct locked_map_ptr *mapptr, int *gc_cyclep)
326 struct mapped_database *cur = mapptr->mapped;
327 if (cur == NO_MAPPING)
328 return cur;
330 int cnt = 0;
331 while (__builtin_expect (atomic_compare_and_exchange_val_acq (&mapptr->lock,
332 1, 0) != 0, 0))
334 // XXX Best number of rounds?
335 if (__builtin_expect (++cnt > 5, 0))
336 return NO_MAPPING;
338 atomic_delay ();
341 cur = mapptr->mapped;
343 if (__builtin_expect (cur != NO_MAPPING, 1))
345 /* If not mapped or timestamp not updated, request new map. */
346 if (cur == NULL
347 || (cur->head->nscd_certainly_running == 0
348 && cur->head->timestamp + MAPPING_TIMEOUT < time (NULL))
349 || cur->head->data_size > cur->datasize)
350 cur = get_mapping (type, name,
351 (struct mapped_database **) &mapptr->mapped);
353 if (__builtin_expect (cur != NO_MAPPING, 1))
355 if (__builtin_expect (((*gc_cyclep = cur->head->gc_cycle) & 1) != 0,
357 cur = NO_MAPPING;
358 else
359 atomic_increment (&cur->counter);
363 mapptr->lock = 0;
365 return cur;
369 /* Don't return const struct datahead *, as eventhough the record
370 is normally constant, it can change arbitrarily during nscd
371 garbage collection. */
372 struct datahead *
373 __nscd_cache_search (request_type type, const char *key, size_t keylen,
374 const struct mapped_database *mapped)
376 unsigned long int hash = __nis_hash (key, keylen) % mapped->head->module;
377 size_t datasize = mapped->datasize;
379 ref_t work = mapped->head->array[hash];
380 while (work != ENDREF && work + sizeof (struct hashentry) <= datasize)
382 struct hashentry *here = (struct hashentry *) (mapped->data + work);
384 #ifndef _STRING_ARCH_unaligned
385 /* Although during garbage collection when moving struct hashentry
386 records around we first copy from old to new location and then
387 adjust pointer from previous hashentry to it, there is no barrier
388 between those memory writes. It is very unlikely to hit it,
389 so check alignment only if a misaligned load can crash the
390 application. */
391 if ((uintptr_t) here & (__alignof__ (*here) - 1))
392 return NULL;
393 #endif
395 if (type == here->type
396 && keylen == here->len
397 && here->key + keylen <= datasize
398 && memcmp (key, mapped->data + here->key, keylen) == 0
399 && here->packet + sizeof (struct datahead) <= datasize)
401 /* We found the entry. Increment the appropriate counter. */
402 struct datahead *dh
403 = (struct datahead *) (mapped->data + here->packet);
405 #ifndef _STRING_ARCH_unaligned
406 if ((uintptr_t) dh & (__alignof__ (*dh) - 1))
407 return NULL;
408 #endif
410 /* See whether we must ignore the entry or whether something
411 is wrong because garbage collection is in progress. */
412 if (dh->usable && here->packet + dh->allocsize <= datasize)
413 return dh;
416 work = here->next;
419 return NULL;
423 /* Create a socket connected to a name. */
425 __nscd_open_socket (const char *key, size_t keylen, request_type type,
426 void *response, size_t responselen)
428 int saved_errno = errno;
430 int sock = open_socket ();
431 if (sock >= 0)
433 request_header req;
434 req.version = NSCD_VERSION;
435 req.type = type;
436 req.key_len = keylen;
438 struct iovec vec[2];
439 vec[0].iov_base = &req;
440 vec[0].iov_len = sizeof (request_header);
441 vec[1].iov_base = (void *) key;
442 vec[1].iov_len = keylen;
444 ssize_t nbytes = TEMP_FAILURE_RETRY (__writev (sock, vec, 2));
445 if (nbytes == (ssize_t) (sizeof (request_header) + keylen)
446 /* Wait for data. */
447 && wait_on_socket (sock) > 0)
449 nbytes = TEMP_FAILURE_RETRY (__read (sock, response, responselen));
450 if (nbytes == (ssize_t) responselen)
451 return sock;
454 close_not_cancel_no_status (sock);
457 __set_errno (saved_errno);
459 return -1;