[NEED__RES]: Include <resolv.h>.
[kopensolaris-gnu/glibc.git] / nss / getXXent_r.c
1 /* Copyright (C) 1996,97,98,99,2000 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 Library General Public License as
7    published by the Free Software Foundation; either version 2 of the
8    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    Library General Public License for more details.
14
15    You should have received a copy of the GNU Library General Public
16    License along with the GNU C Library; see the file COPYING.LIB.  If not,
17    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18    Boston, MA 02111-1307, USA.  */
19
20 #include <errno.h>
21 #include <bits/libc-lock.h>
22
23 #include "nsswitch.h"
24
25 #ifdef NEED__RES
26 # include <resolv.h>
27 #endif
28
29 /*******************************************************************\
30 |* Here we assume several symbols to be defined:                   *|
31 |*                                                                 *|
32 |* LOOKUP_TYPE   - the return type of the function                 *|
33 |*                                                                 *|
34 |* SETFUNC_NAME  - name of the non-reentrant setXXXent function    *|
35 |*                                                                 *|
36 |* GETFUNC_NAME  - name of the non-reentrant getXXXent function    *|
37 |*                                                                 *|
38 |* ENDFUNC_NAME  - name of the non-reentrant endXXXent function    *|
39 |*                                                                 *|
40 |* DATABASE_NAME - name of the database the function accesses      *|
41 |*                 (e.g., host, services, ...)                     *|
42 |*                                                                 *|
43 |* Optionally the following vars can be defined:                   *|
44 |*                                                                 *|
45 |* STAYOPEN      - variable declaration for setXXXent function     *|
46 |*                                                                 *|
47 |* STAYOPEN_VAR  - variable name for setXXXent function            *|
48 |*                                                                 *|
49 |* NEED_H_ERRNO  - an extra parameter will be passed to point to   *|
50 |*                 the global `h_errno' variable.                  *|
51 |*                                                                 *|
52 \*******************************************************************/
53
54 /* To make the real sources a bit prettier.  */
55 #define REENTRANT_GETNAME APPEND_R (GETFUNC_NAME)
56 #define APPEND_R(Name) CONCAT2_2 (Name, _r)
57 #define INTERNAL(Name) CONCAT2_2 (__, Name)
58 #define CONCAT2_1(Pre, Post) CONCAT2_2 (Pre, Post)
59 #define CONCAT2_2(Pre, Post) Pre##Post
60
61 #define SETFUNC_NAME_STRING STRINGIZE (SETFUNC_NAME)
62 #define GETFUNC_NAME_STRING STRINGIZE (REENTRANT_GETNAME)
63 #define ENDFUNC_NAME_STRING STRINGIZE (ENDFUNC_NAME)
64 #define DATABASE_NAME_STRING STRINGIZE (DATABASE_NAME)
65 #define STRINGIZE(Name) STRINGIZE1 (Name)
66 #define STRINGIZE1(Name) #Name
67
68 #define DB_LOOKUP_FCT CONCAT3_1 (__nss_, DATABASE_NAME, _lookup)
69 #define CONCAT3_1(Pre, Name, Post) CONCAT3_2 (Pre, Name, Post)
70 #define CONCAT3_2(Pre, Name, Post) Pre##Name##Post
71
72 /* Sometimes we need to store error codes in the `h_errno' variable.  */
73 #ifdef NEED_H_ERRNO
74 # define H_ERRNO_PARM , int *h_errnop
75 # define H_ERRNO_VAR , &h_errno
76 #else
77 # define H_ERRNO_PARM
78 # define H_ERRNO_VAR
79 #endif
80
81 /* Some databases take the `stayopen' flag.  */
82 #ifdef STAYOPEN
83 # define STAYOPEN_TMP CONCAT2_1 (STAYOPEN, _tmp)
84 # define STAYOPEN_TMPVAR CONCAT2_1 (STAYOPEN_VAR, _tmp)
85 #else
86 # define STAYOPEN void
87 # define STAYOPEN_VAR
88 # define STAYOPEN_TMPVAR
89 #endif
90
91 /* Prototype for the setXXXent functions we use here.  */
92 typedef enum nss_status (*set_function) (STAYOPEN);
93
94 /* Prototype for the endXXXent functions we use here.  */
95 typedef enum nss_status (*end_function) (void);
96
97 /* Prototype for the setXXXent functions we use here.  */
98 typedef enum nss_status (*get_function) (LOOKUP_TYPE *, char *, size_t, int *
99                                          H_ERRNO_PARM);
100
101
102 /* This handle for the NSS data base is shared between all
103    set/get/endXXXent functions.  */
104 static service_user *nip;
105 /* Remember the last service used since the last call to  `endXXent'.  */
106 static service_user *last_nip;
107 /* Remember the first service_entry, it's always the same.  */
108 static service_user *startp;
109
110 #ifdef STAYOPEN_TMP
111 /* We need to remember the last `stayopen' flag given by the user
112    since the `setent' function is only called for the first available
113    service.  */
114 static STAYOPEN_TMP;
115 #endif
116
117 /* Protect above variable against multiple uses at the same time.  */
118 __libc_lock_define_initialized (static, lock)
119
120 /* The lookup function for the first entry of this service.  */
121 extern int DB_LOOKUP_FCT (service_user **nip, const char *name, void **fctp);
122
123 /* Set up NIP to run through the services.  If ALL is zero, use NIP's
124    current location if it's not nil.  Return nonzero if there are no
125    services (left).  */
126 static enum nss_status
127 setup (void **fctp, const char *func_name, int all)
128 {
129   int no_more;
130   if (startp == NULL)
131     {
132       no_more = DB_LOOKUP_FCT (&nip, func_name, fctp);
133       startp = no_more ? (service_user *) -1l : nip;
134     }
135   else if (startp == (service_user *) -1l)
136     /* No services at all.  */
137     return 1;
138   else
139     {
140       if (all || !nip)
141         /* Reset to the beginning of the service list.  */
142         nip = startp;
143       /* Look up the first function.  */
144       no_more = __nss_lookup (&nip, func_name, fctp);
145     }
146   return no_more;
147 }
148 \f
149 void
150 SETFUNC_NAME (STAYOPEN)
151 {
152   set_function fct;
153   int no_more;
154
155 #ifdef NEED__RES
156   if ((_res.options & RES_INIT) == 0 && __res_ninit (&_res) == -1)
157     {
158       __set_h_errno (NETDB_INTERNAL);
159       return;
160     }
161 #endif /* need _res */
162
163   __libc_lock_lock (lock);
164
165   /* Cycle through the services and run their `setXXent' functions until
166      we find an available service.  */
167   no_more = setup ((void **) &fct, SETFUNC_NAME_STRING, 1);
168   while (! no_more)
169     {
170       int is_last_nip = nip == last_nip;
171       enum nss_status status = DL_CALL_FCT (fct, (STAYOPEN_VAR));
172
173       no_more = __nss_next (&nip, SETFUNC_NAME_STRING, (void **) &fct,
174                             status, 0);
175       if (is_last_nip)
176         last_nip = nip;
177     }
178
179 #ifdef STAYOPEN_TMP
180   STAYOPEN_TMPVAR = STAYOPEN_VAR;
181 #endif
182
183   __libc_lock_unlock (lock);
184 }
185
186
187 void
188 ENDFUNC_NAME (void)
189 {
190   end_function fct;
191   int no_more;
192
193 #ifdef NEED__RES
194   if ((_res.options & RES_INIT) == 0 && __res_ninit (&_res) == -1)
195     {
196       __set_h_errno (NETDB_INTERNAL);
197       return;
198     }
199 #endif /* need _res */
200
201   __libc_lock_lock (lock);
202
203   /* Cycle through all the services and run their endXXent functions.  */
204   no_more = setup ((void **) &fct, ENDFUNC_NAME_STRING, 1);
205   while (! no_more)
206     {
207       /* Ignore status, we force check in __NSS_NEXT.  */
208       DL_CALL_FCT (fct, ());
209
210       if (nip == last_nip)
211         /* We have processed all services which were used.  */
212         break;
213
214       no_more = __nss_next (&nip, ENDFUNC_NAME_STRING, (void **) &fct, 0, 1);
215     }
216   last_nip = nip = NULL;
217
218   __libc_lock_unlock (lock);
219 }
220
221
222 int
223 INTERNAL (REENTRANT_GETNAME) (LOOKUP_TYPE *resbuf, char *buffer, size_t buflen,
224                               LOOKUP_TYPE **result H_ERRNO_PARM)
225 {
226   get_function fct;
227   int no_more;
228   enum nss_status status;
229
230 #ifdef NEED__RES
231   if ((_res.options & RES_INIT) == 0 && __res_ninit (&_res) == -1)
232     {
233       __set_h_errno (NETDB_INTERNAL);
234       *result = NULL;
235       return errno;
236     }
237 #endif /* need _res */
238
239   /* Initialize status to return if no more functions are found.  */
240   status = NSS_STATUS_NOTFOUND;
241
242   __libc_lock_lock (lock);
243
244   /* Run through available functions, starting with the same function last
245      run.  We will repeat each function as long as it succeeds, and then go
246      on to the next service action.  */
247   no_more = setup ((void **) &fct, GETFUNC_NAME_STRING, 0);
248   while (! no_more)
249     {
250       int is_last_nip = nip == last_nip;
251
252       status = DL_CALL_FCT (fct,
253                              (resbuf, buffer, buflen, &errno H_ERRNO_VAR));
254
255       /* The the status is NSS_STATUS_TRYAGAIN and errno is ERANGE the
256          provided buffer is too small.  In this case we should give
257          the user the possibility to enlarge the buffer and we should
258          not simply go on with the next service (even if the TRYAGAIN
259          action tells us so).  */
260       if (status == NSS_STATUS_TRYAGAIN
261 #ifdef NEED_H_ERRNO
262           && *h_errnop == NETDB_INTERNAL
263 #endif
264           && errno == ERANGE)
265         break;
266
267       do
268         {
269           no_more = __nss_next (&nip, GETFUNC_NAME_STRING, (void **) &fct,
270                                 status, 0);
271
272           if (is_last_nip)
273             last_nip = nip;
274
275           if (! no_more)
276             {
277               /* Call the `setXXent' function.  This wasn't done before.  */
278               set_function sfct;
279
280               no_more = __nss_lookup (&nip, SETFUNC_NAME_STRING,
281                                       (void **) &sfct);
282
283               if (! no_more)
284                 status = DL_CALL_FCT (sfct, (STAYOPEN_TMPVAR));
285               else
286                 status = NSS_STATUS_NOTFOUND;
287             }
288         }
289       while (! no_more && status != NSS_STATUS_SUCCESS);
290     }
291
292   __libc_lock_unlock (lock);
293
294   *result = status == NSS_STATUS_SUCCESS ? resbuf : NULL;
295   return status == NSS_STATUS_SUCCESS ? 0 : errno;
296 }
297
298
299 #include <shlib-compat.h>
300 #if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_1_2)
301 #define OLD(name) OLD1 (name)
302 #define OLD1(name) __old_##name
303
304 int
305 OLD (REENTRANT_GETNAME) (LOOKUP_TYPE *resbuf, char *buffer, size_t buflen,
306                          LOOKUP_TYPE **result H_ERRNO_PARM)
307 {
308   int ret = INTERNAL (REENTRANT_GETNAME) (resbuf, buffer, buflen,
309                                           result H_ERRNO_VAR);
310
311   if (ret != 0)
312     ret = -1;
313
314   return ret;
315 }
316
317 #define do_symbol_version(real, name, version) \
318   compat_symbol (libc, real, name, version)
319 do_symbol_version (OLD (REENTRANT_GETNAME), REENTRANT_GETNAME, GLIBC_2_0);
320
321 #define do_default_symbol_version(real, name, version) \
322   versioned_symbol (libc, real, name, version)
323 do_default_symbol_version (INTERNAL (REENTRANT_GETNAME),
324                            REENTRANT_GETNAME, GLIBC_2_1_2);
325 #else
326 #define do_weak_alias(n1, n2) weak_alias (n1, n2)
327 do_weak_alias (INTERNAL (REENTRANT_GETNAME), REENTRANT_GETNAME)
328 #endif