(__nss_disable_nscd): New function.
[kopensolaris-gnu/glibc.git] / nss / getXXbyYY_r.c
1 /* Copyright (C) 1996-2002, 2003 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 #ifndef HAVE_TYPE
103 # define TYPE_VAR_P NULL
104 # define FLAGS_VAR 0
105 #endif
106
107 #ifdef HAVE_AF
108 # define AF_VAR_P &af
109 #else
110 # define AF_VAR_P NULL
111 #endif
112
113 /* Type of the lookup function we need here.  */
114 typedef enum nss_status (*lookup_function) (ADD_PARAMS, LOOKUP_TYPE *, char *,
115                                             size_t, int * H_ERRNO_PARM);
116
117 /* The lookup function for the first entry of this service.  */
118 extern int DB_LOOKUP_FCT (service_user **nip, const char *name, void **fctp)
119      internal_function;
120 libc_hidden_proto (DB_LOOKUP_FCT)
121
122 /* Interval in which we transfer retry to contact the NSCD.  */
123 #define NSS_NSCD_RETRY  100
124
125
126 int
127 INTERNAL (REENTRANT_NAME) (ADD_PARAMS, LOOKUP_TYPE *resbuf, char *buffer,
128                            size_t buflen, LOOKUP_TYPE **result H_ERRNO_PARM)
129 {
130   static service_user *startp;
131   static lookup_function start_fct;
132   service_user *nip;
133   union
134   {
135     lookup_function l;
136     void *ptr;
137   } fct;
138
139   int no_more;
140   enum nss_status status = NSS_STATUS_UNAVAIL;
141 #ifdef USE_NSCD
142   int nscd_status;
143 #endif
144 #ifdef NEED_H_ERRNO
145   bool any_service = false;
146 #endif
147
148 #ifdef PREPROCESS
149   PREPROCESS;
150 #endif
151
152 #ifdef HANDLE_DIGITS_DOTS
153   switch (__nss_hostname_digits_dots (name, resbuf, &buffer, NULL,
154                                       buflen, result, &status,
155                                       TYPE_VAR_P, FLAGS_VAR, AF_VAR_P,
156                                       H_ERRNO_VAR_P))
157     {
158     case -1:
159       return errno;
160     case 1:
161       goto done;
162     }
163 #endif
164
165 #ifdef USE_NSCD
166   if (NOT_USENSCD_NAME > 0 && ++NOT_USENSCD_NAME > NSS_NSCD_RETRY)
167     NOT_USENSCD_NAME = 0;
168
169   if (!NOT_USENSCD_NAME)
170     {
171       nscd_status = NSCD_NAME (ADD_VARIABLES, resbuf, buffer, buflen
172                                H_ERRNO_VAR);
173       if (nscd_status >= 0)
174         {
175           *result = nscd_status == 0 ? resbuf : NULL;
176           return nscd_status;
177         }
178     }
179 #endif
180
181   if (startp == NULL)
182     {
183       no_more = DB_LOOKUP_FCT (&nip, REENTRANT_NAME_STRING, &fct.ptr);
184       if (no_more)
185         startp = (service_user *) -1l;
186       else
187         {
188           startp = nip;
189           start_fct = fct.l;
190
191 #ifdef NEED__RES
192           /* The resolver code will really be used so we have to
193              initialize it.  */
194           if ((_res.options & RES_INIT) == 0 && __res_ninit (&_res) == -1)
195             {
196               *h_errnop = NETDB_INTERNAL;
197               *result = NULL;
198               return errno;
199             }
200 #endif /* need _res */
201 #ifdef NEED__RES_HCONF
202           if (!_res_hconf.initialized)
203             _res_hconf_init ();
204 #endif /* need _res_hconf */
205         }
206     }
207   else
208     {
209       fct.l = start_fct;
210       no_more = (nip = startp) == (service_user *) -1l;
211     }
212
213   while (no_more == 0)
214     {
215 #ifdef NEED_H_ERRNO
216       any_service = true;
217 #endif
218
219       status = DL_CALL_FCT (fct.l, (ADD_VARIABLES, resbuf, buffer, buflen,
220                                     &errno H_ERRNO_VAR));
221
222       /* The status is NSS_STATUS_TRYAGAIN and errno is ERANGE the
223          provided buffer is too small.  In this case we should give
224          the user the possibility to enlarge the buffer and we should
225          not simply go on with the next service (even if the TRYAGAIN
226          action tells us so).  */
227       if (status == NSS_STATUS_TRYAGAIN
228 #ifdef NEED_H_ERRNO
229           && *h_errnop == NETDB_INTERNAL
230 #endif
231           && errno == ERANGE)
232         break;
233
234       no_more = __nss_next (&nip, REENTRANT_NAME_STRING,
235                             &fct.ptr, status, 0);
236     }
237
238 #ifdef HANDLE_DIGITS_DOTS
239 done:
240 #endif
241   *result = status == NSS_STATUS_SUCCESS ? resbuf : NULL;
242 #ifdef NEED_H_ERRNO
243   if (status != NSS_STATUS_SUCCESS && ! any_service)
244     /* We were not able to use any service.  */
245     *h_errnop = NO_RECOVERY;
246 #endif
247 #ifdef POSTPROCESS
248   POSTPROCESS;
249 #endif
250   return (status != NSS_STATUS_TRYAGAIN ? 0
251 #ifdef NEED_H_ERRNO
252           /* These functions only set errno if h_errno is NETDB_INTERNAL.  */
253           : *h_errnop != NETDB_INTERNAL ? EAGAIN
254 #endif
255           : errno);
256 }
257
258
259 #include <shlib-compat.h>
260 #if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_1_2)
261 #define OLD(name) OLD1 (name)
262 #define OLD1(name) __old_##name
263
264 int
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);