(get_mapping): Move reading mapfd.
[kopensolaris-gnu/glibc.git] / nscd / nscd_helper.c
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.
5
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.
10
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.
15
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.  */
20
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>
37
38 #include "nscd-client.h"
39
40
41 ssize_t
42 __readall (int fd, void *buf, size_t len)
43 {
44   size_t n = len;
45   ssize_t ret;
46   do
47     {
48       ret = TEMP_FAILURE_RETRY (__read (fd, buf, n));
49       if (ret <= 0)
50         break;
51       buf = (char *) buf + ret;
52       n -= ret;
53     }
54   while (n > 0);
55   return ret < 0 ? ret : len - n;
56 }
57
58
59 ssize_t
60 __readvall (int fd, const struct iovec *iov, int iovcnt)
61 {
62   ssize_t ret = TEMP_FAILURE_RETRY (__readv (fd, iov, iovcnt));
63   if (ret <= 0)
64     return ret;
65
66   size_t total = 0;
67   for (int i = 0; i < iovcnt; ++i)
68     total += iov[i].iov_len;
69
70   if (ret < total)
71     {
72       struct iovec iov_buf[iovcnt];
73       ssize_t r = ret;
74
75       struct iovec *iovp = memcpy (iov_buf, iov, iovcnt * sizeof (*iov));
76       do
77         {
78           while (iovp->iov_len <= r)
79             {
80               r -= iovp->iov_len;
81               --iovcnt;
82               ++iovp;
83             }
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;
90         }
91       while (ret < total);
92       if (r < 0)
93         ret = r;
94     }
95   return ret;
96 }
97
98
99 static int
100 open_socket (request_type type, const char *key, size_t keylen)
101 {
102   int sock = __socket (PF_UNIX, SOCK_STREAM, 0);
103   if (sock < 0)
104     return -1;
105
106   struct
107   {
108     request_header req;
109     char key[keylen];
110   } reqdata;
111   size_t real_sizeof_reqdata = sizeof (request_header) + keylen;
112
113   /* Make socket non-blocking.  */
114   __fcntl (sock, F_SETFL, O_RDWR | O_NONBLOCK);
115
116   struct sockaddr_un sun;
117   sun.sun_family = AF_UNIX;
118   strcpy (sun.sun_path, _PATH_NSCDSOCKET);
119   if (__connect (sock, (struct sockaddr *) &sun, sizeof (sun)) < 0
120       && errno != EINPROGRESS)
121     goto out;
122
123   reqdata.req.version = NSCD_VERSION;
124   reqdata.req.type = type;
125   reqdata.req.key_len = keylen;
126
127   memcpy (reqdata.key, key, keylen);
128
129   bool first_try = true;
130   struct timeval tvend;
131   /* Fake initializing tvend.  */
132   asm ("" : "=m" (tvend));
133   while (1)
134     {
135 #ifndef MSG_NOSIGNAL
136 # define MSG_NOSIGNAL 0
137 #endif
138       ssize_t wres = TEMP_FAILURE_RETRY (__send (sock, &reqdata,
139                                                  real_sizeof_reqdata,
140                                                  MSG_NOSIGNAL));
141       if (__builtin_expect (wres == (ssize_t) real_sizeof_reqdata, 1))
142         /* We managed to send the request.  */
143         return sock;
144
145       if (wres != -1 || errno != EAGAIN)
146         /* Something is really wrong, no chance to continue.  */
147         break;
148
149       /* The daemon is busy wait for it.  */
150       int to;
151       struct timeval now;
152       (void) __gettimeofday (&now, NULL);
153       if (first_try)
154         {
155           tvend.tv_usec = now.tv_usec;
156           tvend.tv_sec = now.tv_sec + 5;
157           to = 5 * 1000;
158           first_try = false;
159         }
160       else
161         to = ((tvend.tv_sec - now.tv_sec) * 1000
162               + (tvend.tv_usec - now.tv_usec) / 1000);
163
164       struct pollfd fds[1];
165       fds[0].fd = sock;
166       fds[0].events = POLLOUT | POLLERR | POLLHUP;
167       if (__poll (fds, 1, to) <= 0)
168         /* The connection timed out or broke down.  */
169         break;
170
171       /* We try to write again.  */
172     }
173
174  out:
175   close_not_cancel_no_status (sock);
176
177   return -1;
178 }
179
180
181 void
182 __nscd_unmap (struct mapped_database *mapped)
183 {
184   assert (mapped->counter == 0);
185   __munmap ((void *) mapped->head, mapped->mapsize);
186   free (mapped);
187 }
188
189
190 static int
191 wait_on_socket (int sock)
192 {
193   struct pollfd fds[1];
194   fds[0].fd = sock;
195   fds[0].events = POLLIN | POLLERR | POLLHUP;
196   int n = __poll (fds, 1, 5 * 1000);
197   if (n == -1 && __builtin_expect (errno == EINTR, 0))
198     {
199       /* Handle the case where the poll() call is interrupted by a
200          signal.  We cannot just use TEMP_FAILURE_RETRY since it might
201          lead to infinite loops.  */
202       struct timeval now;
203       (void) __gettimeofday (&now, NULL);
204       long int end = (now.tv_sec + 5) * 1000 + (now.tv_usec + 500) / 1000;
205       while (1)
206         {
207           long int timeout = end - (now.tv_sec * 1000
208                                     + (now.tv_usec + 500) / 1000);
209           n = __poll (fds, 1, timeout);
210           if (n != -1 || errno != EINTR)
211             break;
212           (void) __gettimeofday (&now, NULL);
213         }
214     }
215
216   return n;
217 }
218
219
220 /* Try to get a file descriptor for the shared meory segment
221    containing the database.  */
222 static struct mapped_database *
223 get_mapping (request_type type, const char *key,
224              struct mapped_database **mappedp)
225 {
226   struct mapped_database *result = NO_MAPPING;
227 #ifdef SCM_RIGHTS
228   const size_t keylen = strlen (key) + 1;
229   int saved_errno = errno;
230
231   int mapfd = -1;
232   char resdata[keylen];
233
234   /* Open a socket and send the request.  */
235   int sock = open_socket (type, key, keylen);
236   if (sock < 0)
237     goto out;
238
239   /* Room for the data sent along with the file descriptor.  We expect
240      the key name back.  */
241   struct iovec iov[1];
242   iov[0].iov_base = resdata;
243   iov[0].iov_len = keylen;
244
245   union
246   {
247     struct cmsghdr hdr;
248     char bytes[CMSG_SPACE (sizeof (int))];
249   } buf;
250   struct msghdr msg = { .msg_iov = iov, .msg_iovlen = 1,
251                         .msg_control = buf.bytes,
252                         .msg_controllen = sizeof (buf) };
253   struct cmsghdr *cmsg = CMSG_FIRSTHDR (&msg);
254
255   cmsg->cmsg_level = SOL_SOCKET;
256   cmsg->cmsg_type = SCM_RIGHTS;
257   cmsg->cmsg_len = CMSG_LEN (sizeof (int));
258
259   /* This access is well-aligned since BUF is correctly aligned for an
260      int and CMSG_DATA preserves this alignment.  */
261   *(int *) CMSG_DATA (cmsg) = -1;
262
263   msg.msg_controllen = cmsg->cmsg_len;
264
265   if (wait_on_socket (sock) <= 0)
266     goto out_close2;
267
268   if (__builtin_expect (TEMP_FAILURE_RETRY (__recvmsg (sock, &msg, 0))
269                         != keylen, 0))
270     goto out_close2;
271
272   if (__builtin_expect (CMSG_FIRSTHDR (&msg) == NULL
273                         || (CMSG_FIRSTHDR (&msg)->cmsg_len
274                             != CMSG_LEN (sizeof (int))), 0))
275     goto out_close2;
276
277   mapfd = *(int *) CMSG_DATA (cmsg);
278
279   struct stat64 st;
280   if (__builtin_expect (strcmp (resdata, key) != 0, 0)
281       || __builtin_expect (fstat64 (mapfd, &st) != 0, 0)
282       || __builtin_expect (st.st_size < sizeof (struct database_pers_head), 0))
283     goto out_close;
284
285   struct database_pers_head head;
286   if (__builtin_expect (TEMP_FAILURE_RETRY (__pread (mapfd, &head,
287                                                      sizeof (head), 0))
288                         != sizeof (head), 0))
289     goto out_close;
290
291   if (__builtin_expect (head.version != DB_VERSION, 0)
292       || __builtin_expect (head.header_size != sizeof (head), 0)
293       /* This really should not happen but who knows, maybe the update
294          thread got stuck.  */
295       || __builtin_expect (! head.nscd_certainly_running
296                            && head.timestamp + MAPPING_TIMEOUT < time (NULL),
297                            0))
298     goto out_close;
299
300   size_t size = (sizeof (head) + roundup (head.module * sizeof (ref_t), ALIGN)
301                  + head.data_size);
302
303   if (__builtin_expect (st.st_size < size, 0))
304     goto out_close;
305
306   /* The file is large enough, map it now.  */
307   void *mapping = __mmap (NULL, size, PROT_READ, MAP_SHARED, mapfd, 0);
308   if (__builtin_expect (mapping != MAP_FAILED, 1))
309     {
310       /* Allocate a record for the mapping.  */
311       struct mapped_database *newp = malloc (sizeof (*newp));
312       if (newp == NULL)
313         {
314           /* Ugh, after all we went through the memory allocation failed.  */
315           __munmap (mapping, size);
316           goto out_close;
317         }
318
319       newp->head = mapping;
320       newp->data = ((char *) mapping + head.header_size
321                     + roundup (head.module * sizeof (ref_t), ALIGN));
322       newp->mapsize = size;
323       newp->datasize = head.data_size;
324       /* Set counter to 1 to show it is usable.  */
325       newp->counter = 1;
326
327       result = newp;
328     }
329
330  out_close:
331   __close (mapfd);
332  out_close2:
333   __close (sock);
334  out:
335   __set_errno (saved_errno);
336 #endif  /* SCM_RIGHTS */
337
338   struct mapped_database *oldval = *mappedp;
339   *mappedp = result;
340
341   if (oldval != NULL && atomic_decrement_val (&oldval->counter) == 0)
342     __nscd_unmap (oldval);
343
344   return result;
345 }
346
347
348 struct mapped_database *
349 __nscd_get_map_ref (request_type type, const char *name,
350                     volatile struct locked_map_ptr *mapptr, int *gc_cyclep)
351 {
352   struct mapped_database *cur = mapptr->mapped;
353   if (cur == NO_MAPPING)
354     return cur;
355
356   int cnt = 0;
357   while (__builtin_expect (atomic_compare_and_exchange_val_acq (&mapptr->lock,
358                                                                 1, 0) != 0, 0))
359     {
360       // XXX Best number of rounds?
361       if (__builtin_expect (++cnt > 5, 0))
362         return NO_MAPPING;
363
364       atomic_delay ();
365     }
366
367   cur = mapptr->mapped;
368
369   if (__builtin_expect (cur != NO_MAPPING, 1))
370     {
371       /* If not mapped or timestamp not updated, request new map.  */
372       if (cur == NULL
373           || (cur->head->nscd_certainly_running == 0
374               && cur->head->timestamp + MAPPING_TIMEOUT < time (NULL))
375           || cur->head->data_size > cur->datasize)
376         cur = get_mapping (type, name,
377                            (struct mapped_database **) &mapptr->mapped);
378
379       if (__builtin_expect (cur != NO_MAPPING, 1))
380         {
381           if (__builtin_expect (((*gc_cyclep = cur->head->gc_cycle) & 1) != 0,
382                                 0))
383             cur = NO_MAPPING;
384           else
385             atomic_increment (&cur->counter);
386         }
387     }
388
389   mapptr->lock = 0;
390
391   return cur;
392 }
393
394
395 /* Don't return const struct datahead *, as eventhough the record
396    is normally constant, it can change arbitrarily during nscd
397    garbage collection.  */
398 struct datahead *
399 __nscd_cache_search (request_type type, const char *key, size_t keylen,
400                      const struct mapped_database *mapped)
401 {
402   unsigned long int hash = __nis_hash (key, keylen) % mapped->head->module;
403   size_t datasize = mapped->datasize;
404
405   ref_t work = mapped->head->array[hash];
406   while (work != ENDREF && work + sizeof (struct hashentry) <= datasize)
407     {
408       struct hashentry *here = (struct hashentry *) (mapped->data + work);
409
410 #ifndef _STRING_ARCH_unaligned
411       /* Although during garbage collection when moving struct hashentry
412          records around we first copy from old to new location and then
413          adjust pointer from previous hashentry to it, there is no barrier
414          between those memory writes.  It is very unlikely to hit it,
415          so check alignment only if a misaligned load can crash the
416          application.  */
417       if ((uintptr_t) here & (__alignof__ (*here) - 1))
418         return NULL;
419 #endif
420
421       if (type == here->type
422           && keylen == here->len
423           && here->key + keylen <= datasize
424           && memcmp (key, mapped->data + here->key, keylen) == 0
425           && here->packet + sizeof (struct datahead) <= datasize)
426         {
427           /* We found the entry.  Increment the appropriate counter.  */
428           struct datahead *dh
429             = (struct datahead *) (mapped->data + here->packet);
430
431 #ifndef _STRING_ARCH_unaligned
432           if ((uintptr_t) dh & (__alignof__ (*dh) - 1))
433             return NULL;
434 #endif
435
436           /* See whether we must ignore the entry or whether something
437              is wrong because garbage collection is in progress.  */
438           if (dh->usable && here->packet + dh->allocsize <= datasize)
439             return dh;
440         }
441
442       work = here->next;
443     }
444
445   return NULL;
446 }
447
448
449 /* Create a socket connected to a name. */
450 int
451 __nscd_open_socket (const char *key, size_t keylen, request_type type,
452                     void *response, size_t responselen)
453 {
454   /* This should never happen and it is something the nscd daemon
455      enforces, too.  He it helps to limit the amount of stack
456      used.  */
457   if (keylen > MAXKEYLEN)
458     return -1;
459
460   int saved_errno = errno;
461
462   int sock = open_socket (type, key, keylen);
463   if (sock >= 0)
464     {
465       /* Wait for data.  */
466       if (wait_on_socket (sock) > 0)
467         {
468           ssize_t nbytes = TEMP_FAILURE_RETRY (__read (sock, response,
469                                                        responselen));
470           if (nbytes == (ssize_t) responselen)
471             return sock;
472         }
473
474       close_not_cancel_no_status (sock);
475     }
476
477   __set_errno (saved_errno);
478
479   return -1;
480 }