Use glibc_likely instead __builtin_expect.
[jlayton/glibc.git] / nis / nss_nis / nis-rpc.c
1 /* Copyright (C) 1996-2014 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
3    Contributed by Thorsten Kukuk <kukuk@suse.de>, 1996.
4
5    The GNU C Library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Lesser General Public
7    License as published by the Free Software Foundation; either
8    version 2.1 of the License, or (at your option) any later version.
9
10    The GNU C Library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Lesser General Public License for more details.
14
15    You should have received a copy of the GNU Lesser General Public
16    License along with the GNU C Library; if not, see
17    <http://www.gnu.org/licenses/>.  */
18
19 #include <nss.h>
20 #include <netdb.h>
21 #include <ctype.h>
22 #include <errno.h>
23 #include <string.h>
24 #include <bits/libc-lock.h>
25 #include <rpcsvc/yp.h>
26 #include <rpcsvc/ypclnt.h>
27
28 #include "nss-nis.h"
29
30 /* Get the declaration of the parser function.  */
31 #define ENTNAME rpcent
32 #define EXTERN_PARSER
33 #include <nss/nss_files/files-parse.c>
34
35 __libc_lock_define_initialized (static, lock)
36
37 static intern_t intern;
38
39
40 static void
41 internal_nis_endrpcent (intern_t *intern)
42 {
43   struct response_t *curr = intern->next;
44
45   while (curr != NULL)
46     {
47       struct response_t *last = curr;
48       curr = curr->next;
49       free (last);
50     }
51
52   intern->next = intern->start = NULL;
53 }
54
55 static enum nss_status
56 internal_nis_setrpcent (intern_t *intern)
57 {
58   char *domainname;
59   struct ypall_callback ypcb;
60   enum nss_status status;
61
62   if (yp_get_default_domain (&domainname))
63     return NSS_STATUS_UNAVAIL;
64
65   internal_nis_endrpcent (intern);
66
67   ypcb.foreach = _nis_saveit;
68   ypcb.data = (char *) intern;
69   status = yperr2nss (yp_all (domainname, "rpc.bynumber", &ypcb));
70
71   /* Mark the last buffer as full.  */
72   if (intern->next != NULL)
73     intern->next->size = intern->offset;
74
75   intern->next = intern->start;
76   intern->offset = 0;
77
78   return status;
79 }
80
81 enum nss_status
82 _nss_nis_setrpcent (int stayopen)
83 {
84   enum nss_status status;
85
86   __libc_lock_lock (lock);
87
88   status = internal_nis_setrpcent (&intern);
89
90   __libc_lock_unlock (lock);
91
92   return status;
93 }
94
95 enum nss_status
96 _nss_nis_endrpcent (void)
97 {
98   __libc_lock_lock (lock);
99
100   internal_nis_endrpcent (&intern);
101
102   __libc_lock_unlock (lock);
103
104   return NSS_STATUS_SUCCESS;
105 }
106
107 static enum nss_status
108 internal_nis_getrpcent_r (struct rpcent *rpc, char *buffer, size_t buflen,
109                           int *errnop, intern_t *intern)
110 {
111   struct parser_data *pdata = (void *) buffer;
112   int parse_res;
113   char *p;
114
115   if (intern->start == NULL)
116     internal_nis_setrpcent (intern);
117
118   if (intern->next == NULL)
119     /* Not one entry in the map.  */
120     return NSS_STATUS_NOTFOUND;
121
122   /* Get the next entry until we found a correct one. */
123   do
124     {
125       struct response_t *bucket = intern->next;
126
127       if (__glibc_unlikely (intern->offset >= bucket->size))
128         {
129           if (bucket->next == NULL)
130             return NSS_STATUS_NOTFOUND;
131
132           /* We look at all the content in the current bucket.  Go on
133              to the next.  */
134           bucket = intern->next = bucket->next;
135           intern->offset = 0;
136         }
137
138       for (p = &bucket->mem[intern->offset]; isspace (*p); ++p)
139         ++intern->offset;
140
141       size_t len = strlen (p) + 1;
142       if (__glibc_unlikely (len > buflen))
143         {
144           *errnop = ERANGE;
145           return NSS_STATUS_TRYAGAIN;
146         }
147
148       /* We unfortunately have to copy the data in the user-provided
149          buffer because that buffer might be around for a very long
150          time and the servent structure must remain valid.  If we would
151          rely on the BUCKET memory the next 'setservent' or 'endservent'
152          call would destroy it.
153
154          The important thing is that it is a single NUL-terminated
155          string.  This is what the parsing routine expects.  */
156       p = memcpy (buffer, &bucket->mem[intern->offset], len);
157
158       parse_res = _nss_files_parse_rpcent (p, rpc, pdata, buflen, errnop);
159       if (__glibc_unlikely (parse_res == -1))
160         return NSS_STATUS_TRYAGAIN;
161
162       intern->offset += len;
163     }
164   while (!parse_res);
165
166   return NSS_STATUS_SUCCESS;
167 }
168
169 enum nss_status
170 _nss_nis_getrpcent_r (struct rpcent *rpc, char *buffer, size_t buflen,
171                       int *errnop)
172 {
173   enum nss_status status;
174
175   __libc_lock_lock (lock);
176
177   status = internal_nis_getrpcent_r (rpc, buffer, buflen, errnop, &intern);
178
179   __libc_lock_unlock (lock);
180
181   return status;
182 }
183
184 enum nss_status
185 _nss_nis_getrpcbyname_r (const char *name, struct rpcent *rpc,
186                          char *buffer, size_t buflen, int *errnop)
187 {
188   if (name == NULL)
189     {
190       *errnop = EINVAL;
191       return NSS_STATUS_UNAVAIL;
192     }
193
194   intern_t data = { NULL, NULL, 0 };
195   enum nss_status status = internal_nis_setrpcent (&data);
196   if (__glibc_unlikely (status != NSS_STATUS_SUCCESS))
197     return status;
198
199   int found = 0;
200   while (!found &&
201          ((status = internal_nis_getrpcent_r (rpc, buffer, buflen, errnop,
202                                               &data)) == NSS_STATUS_SUCCESS))
203     {
204       if (strcmp (rpc->r_name, name) == 0)
205         found = 1;
206       else
207         {
208           int i = 0;
209
210           while (rpc->r_aliases[i] != NULL)
211             {
212               if (strcmp (rpc->r_aliases[i], name) == 0)
213                 {
214                   found = 1;
215                   break;
216                 }
217               else
218                 ++i;
219             }
220         }
221     }
222
223   internal_nis_endrpcent (&data);
224
225   if (__glibc_unlikely (!found && status == NSS_STATUS_SUCCESS))
226     return NSS_STATUS_NOTFOUND;
227
228   return status;
229 }
230
231 enum nss_status
232 _nss_nis_getrpcbynumber_r (int number, struct rpcent *rpc,
233                            char *buffer, size_t buflen, int *errnop)
234 {
235   char *domain;
236   if (__glibc_unlikely (yp_get_default_domain (&domain)))
237     return NSS_STATUS_UNAVAIL;
238
239   char buf[32];
240   int nlen = snprintf (buf, sizeof (buf), "%d", number);
241
242   char *result;
243   int len;
244   int yperr = yp_match (domain, "rpc.bynumber", buf, nlen, &result, &len);
245
246   if (__glibc_unlikely (yperr != YPERR_SUCCESS))
247     {
248       enum nss_status retval = yperr2nss (yperr);
249
250       if (retval == NSS_STATUS_TRYAGAIN)
251         *errnop = errno;
252       return retval;
253     }
254
255   if (__glibc_unlikely ((size_t) (len + 1) > buflen))
256     {
257       free (result);
258       *errnop = ERANGE;
259       return NSS_STATUS_TRYAGAIN;
260     }
261
262   char *p = strncpy (buffer, result, len);
263   buffer[len] = '\0';
264   while (isspace (*p))
265     ++p;
266   free (result);
267
268   int parse_res = _nss_files_parse_rpcent (p, rpc, (void  *) buffer, buflen,
269                                            errnop);
270   if (__glibc_unlikely (parse_res < 1))
271     {
272       if (parse_res == -1)
273         return NSS_STATUS_TRYAGAIN;
274       else
275         return NSS_STATUS_NOTFOUND;
276     }
277   else
278     return NSS_STATUS_SUCCESS;
279 }