[BZ #715]
[platform/upstream/glibc.git] / nss / getXXbyYY_r.c
1 /* Copyright (C) 1996-2002, 2003, 2004 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
3    Contributed by Ulrich Drepper <drepper@cygnus.com>, 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, write to the Free
17    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
18    02111-1307 USA.  */
19
20 #include <assert.h>
21 #include <errno.h>
22 #include <stdbool.h>
23 #include "nsswitch.h"
24 #ifdef USE_NSCD
25 # include <nscd/nscd_proto.h>
26 #endif
27 #ifdef NEED__RES_HCONF
28 # include <resolv/res_hconf.h>
29 #endif
30 #ifdef NEED__RES
31 # include <resolv.h>
32 #endif
33 /*******************************************************************\
34 |* Here we assume several symbols to be defined:                   *|
35 |*                                                                 *|
36 |* LOOKUP_TYPE   - the return type of the function                 *|
37 |*                                                                 *|
38 |* FUNCTION_NAME - name of the non-reentrant function              *|
39 |*                                                                 *|
40 |* DATABASE_NAME - name of the database the function accesses      *|
41 |*                 (e.g., host, services, ...)                     *|
42 |*                                                                 *|
43 |* ADD_PARAMS    - additional parameter, can vary in number        *|
44 |*                                                                 *|
45 |* ADD_VARIABLES - names of additional parameter                   *|
46 |*                                                                 *|
47 |* Optionally the following vars can be defined:                   *|
48 |*                                                                 *|
49 |* NEED_H_ERRNO  - an extra parameter will be passed to point to   *|
50 |*                 the global `h_errno' variable.                  *|
51 |*                                                                 *|
52 |* NEED__RES     - the global _res variable might be used so we    *|
53 |*                 will have to initialize it if necessary         *|
54 |*                                                                 *|
55 |* PREPROCESS    - code run before anything else                   *|
56 |*                                                                 *|
57 |* POSTPROCESS   - code run after the lookup                       *|
58 |*                                                                 *|
59 \*******************************************************************/
60
61 /* To make the real sources a bit prettier.  */
62 #define REENTRANT_NAME APPEND_R (FUNCTION_NAME)
63 #define APPEND_R(name) APPEND_R1 (name)
64 #define APPEND_R1(name) name##_r
65 #define INTERNAL(name) INTERNAL1 (name)
66 #define INTERNAL1(name) __##name
67 #define NEW(name) NEW1 (name)
68 #define NEW1(name) __new_##name
69
70 #ifdef USE_NSCD
71 # define NSCD_NAME ADD_NSCD (REENTRANT_NAME)
72 # define ADD_NSCD(name) ADD_NSCD1 (name)
73 # define ADD_NSCD1(name) __nscd_##name
74 # define NOT_USENSCD_NAME ADD_NOT_NSCDUSE (DATABASE_NAME)
75 # define ADD_NOT_NSCDUSE(name) ADD_NOT_NSCDUSE1 (name)
76 # define ADD_NOT_NSCDUSE1(name) __nss_not_use_nscd_##name
77 #endif
78
79 #define FUNCTION_NAME_STRING STRINGIZE (FUNCTION_NAME)
80 #define REENTRANT_NAME_STRING STRINGIZE (REENTRANT_NAME)
81 #define DATABASE_NAME_STRING STRINGIZE (DATABASE_NAME)
82 #define STRINGIZE(name) STRINGIZE1 (name)
83 #define STRINGIZE1(name) #name
84
85 #ifndef DB_LOOKUP_FCT
86 # define DB_LOOKUP_FCT CONCAT3_1 (__nss_, DATABASE_NAME, _lookup)
87 # define CONCAT3_1(Pre, Name, Post) CONCAT3_2 (Pre, Name, Post)
88 # define CONCAT3_2(Pre, Name, Post) Pre##Name##Post
89 #endif
90
91 /* Sometimes we need to store error codes in the `h_errno' variable.  */
92 #ifdef NEED_H_ERRNO
93 # define H_ERRNO_PARM , int *h_errnop
94 # define H_ERRNO_VAR , h_errnop
95 # define H_ERRNO_VAR_P h_errnop
96 #else
97 # define H_ERRNO_PARM
98 # define H_ERRNO_VAR
99 # define H_ERRNO_VAR_P NULL
100 #endif
101
102 #ifdef HAVE_AF
103 # define AF_VAL af
104 #else
105 # define AF_VAL AF_INET
106 #endif
107
108 /* Type of the lookup function we need here.  */
109 typedef enum nss_status (*lookup_function) (ADD_PARAMS, LOOKUP_TYPE *, char *,
110                                             size_t, int * H_ERRNO_PARM);
111
112 /* The lookup function for the first entry of this service.  */
113 extern int DB_LOOKUP_FCT (service_user **nip, const char *name, void **fctp)
114      internal_function;
115 libc_hidden_proto (DB_LOOKUP_FCT)
116
117
118 int
119 INTERNAL (REENTRANT_NAME) (ADD_PARAMS, LOOKUP_TYPE *resbuf, char *buffer,
120                            size_t buflen, LOOKUP_TYPE **result H_ERRNO_PARM)
121 {
122   static service_user *startp;
123   static lookup_function start_fct;
124   service_user *nip;
125   union
126   {
127     lookup_function l;
128     void *ptr;
129   } fct;
130
131   int no_more;
132   enum nss_status status = NSS_STATUS_UNAVAIL;
133 #ifdef USE_NSCD
134   int nscd_status;
135 #endif
136 #ifdef NEED_H_ERRNO
137   bool any_service = false;
138 #endif
139
140 #ifdef PREPROCESS
141   PREPROCESS;
142 #endif
143
144 #ifdef HANDLE_DIGITS_DOTS
145   switch (__nss_hostname_digits_dots (name, resbuf, &buffer, NULL,
146                                       buflen, result, &status, AF_VAL,
147                                       H_ERRNO_VAR_P))
148     {
149     case -1:
150       return errno;
151     case 1:
152       goto done;
153     }
154 #endif
155
156 #ifdef USE_NSCD
157   if (NOT_USENSCD_NAME > 0 && ++NOT_USENSCD_NAME > NSS_NSCD_RETRY)
158     NOT_USENSCD_NAME = 0;
159
160   if (!NOT_USENSCD_NAME)
161     {
162       nscd_status = NSCD_NAME (ADD_VARIABLES, resbuf, buffer, buflen, result
163                                H_ERRNO_VAR);
164       if (nscd_status >= 0)
165         return nscd_status;
166     }
167 #endif
168
169   if (startp == NULL)
170     {
171       no_more = DB_LOOKUP_FCT (&nip, REENTRANT_NAME_STRING, &fct.ptr);
172       if (no_more)
173         startp = (service_user *) -1l;
174       else
175         {
176           startp = nip;
177           start_fct = fct.l;
178
179 #ifdef NEED__RES
180           /* The resolver code will really be used so we have to
181              initialize it.  */
182           if (__res_maybe_init (&_res, 0) == -1)
183             {
184               *h_errnop = NETDB_INTERNAL;
185               *result = NULL;
186               return errno;
187             }
188 #endif /* need _res */
189 #ifdef NEED__RES_HCONF
190           if (!_res_hconf.initialized)
191             _res_hconf_init ();
192 #endif /* need _res_hconf */
193         }
194     }
195   else
196     {
197       fct.l = start_fct;
198       no_more = (nip = startp) == (service_user *) -1l;
199     }
200
201   while (no_more == 0)
202     {
203 #ifdef NEED_H_ERRNO
204       any_service = true;
205 #endif
206
207       status = DL_CALL_FCT (fct.l, (ADD_VARIABLES, resbuf, buffer, buflen,
208                                     &errno H_ERRNO_VAR));
209
210       /* The status is NSS_STATUS_TRYAGAIN and errno is ERANGE the
211          provided buffer is too small.  In this case we should give
212          the user the possibility to enlarge the buffer and we should
213          not simply go on with the next service (even if the TRYAGAIN
214          action tells us so).  */
215       if (status == NSS_STATUS_TRYAGAIN
216 #ifdef NEED_H_ERRNO
217           && *h_errnop == NETDB_INTERNAL
218 #endif
219           && errno == ERANGE)
220         break;
221
222       no_more = __nss_next (&nip, REENTRANT_NAME_STRING,
223                             &fct.ptr, status, 0);
224     }
225
226 #ifdef HANDLE_DIGITS_DOTS
227 done:
228 #endif
229   *result = status == NSS_STATUS_SUCCESS ? resbuf : NULL;
230 #ifdef NEED_H_ERRNO
231   if (status != NSS_STATUS_SUCCESS && ! any_service)
232     /* We were not able to use any service.  */
233     *h_errnop = NO_RECOVERY;
234 #endif
235 #ifdef POSTPROCESS
236   POSTPROCESS;
237 #endif
238
239   int res;
240   if (status == NSS_STATUS_SUCCESS || status == NSS_STATUS_NOTFOUND)
241     res = 0;
242   /* Don't pass back ERANGE if this is not for a too-small buffer.  */
243   else if (errno == ERANGE && status != NSS_STATUS_TRYAGAIN)
244     res = EINVAL;
245 #ifdef NEED_H_ERRNO
246   /* These functions only set errno if h_errno is NETDB_INTERNAL.  */
247   else if (status == NSS_STATUS_TRYAGAIN && *h_errnop != NETDB_INTERNAL)
248     res = EAGAIN;
249 #endif
250   else
251     return errno;
252
253   __set_errno (res);
254   return res;
255 }
256
257
258 #include <shlib-compat.h>
259 #if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_1_2)
260 #define OLD(name) OLD1 (name)
261 #define OLD1(name) __old_##name
262
263 int
264 attribute_compat_text_section
265 OLD (REENTRANT_NAME) (ADD_PARAMS, LOOKUP_TYPE *resbuf, char *buffer,
266                       size_t buflen, LOOKUP_TYPE **result H_ERRNO_PARM)
267 {
268   int ret = INTERNAL (REENTRANT_NAME) (ADD_VARIABLES, resbuf, buffer,
269                                        buflen, result H_ERRNO_VAR);
270
271   if (ret != 0 || result == NULL)
272     ret = -1;
273
274   return ret;
275 }
276
277 #define do_symbol_version(real, name, version) \
278   compat_symbol (libc, real, name, version)
279 do_symbol_version (OLD (REENTRANT_NAME), REENTRANT_NAME, GLIBC_2_0);
280 #endif
281
282 /* As INTERNAL (REENTRANT_NAME) may be hidden, we need an alias
283    in between so that the REENTRANT_NAME@@GLIBC_2.1.2 is not
284    hidden too.  */
285 strong_alias (INTERNAL (REENTRANT_NAME), NEW (REENTRANT_NAME));
286
287 #define do_default_symbol_version(real, name, version) \
288   versioned_symbol (libc, real, name, version)
289 do_default_symbol_version (NEW (REENTRANT_NAME),
290                            REENTRANT_NAME, GLIBC_2_1_2);
291
292 static_link_warning (REENTRANT_NAME)