Update.
[glibc.git] / nss / getXXent_r.c
blob4e2902d2ca4044ed09d52a0216e0bc833fdd963b
1 /* Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
3 Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
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.
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.
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. */
20 #include <errno.h>
21 #include <bits/libc-lock.h>
23 #include "nsswitch.h"
25 /*******************************************************************\
26 |* Here we assume several symbols to be defined: *|
27 |* *|
28 |* LOOKUP_TYPE - the return type of the function *|
29 |* *|
30 |* SETFUNC_NAME - name of the non-reentrant setXXXent function *|
31 |* *|
32 |* GETFUNC_NAME - name of the non-reentrant getXXXent function *|
33 |* *|
34 |* ENDFUNC_NAME - name of the non-reentrant endXXXent function *|
35 |* *|
36 |* DATABASE_NAME - name of the database the function accesses *|
37 |* (e.g., host, services, ...) *|
38 |* *|
39 |* Optionally the following vars can be defined: *|
40 |* *|
41 |* STAYOPEN - variable declaration for setXXXent function *|
42 |* *|
43 |* STAYOPEN_VAR - variable name for setXXXent function *|
44 |* *|
45 |* NEED_H_ERRNO - an extra parameter will be passed to point to *|
46 |* the global `h_errno' variable. *|
47 |* *|
48 \*******************************************************************/
50 /* To make the real sources a bit prettier. */
51 #define REENTRANT_GETNAME APPEND_R (GETFUNC_NAME)
52 #define APPEND_R(Name) CONCAT2_2 (Name, _r)
53 #define INTERNAL(Name) CONCAT2_2 (__, Name)
54 #define CONCAT2_1(Pre, Post) CONCAT2_2 (Pre, Post)
55 #define CONCAT2_2(Pre, Post) Pre##Post
57 #define SETFUNC_NAME_STRING STRINGIZE (SETFUNC_NAME)
58 #define GETFUNC_NAME_STRING STRINGIZE (REENTRANT_GETNAME)
59 #define ENDFUNC_NAME_STRING STRINGIZE (ENDFUNC_NAME)
60 #define DATABASE_NAME_STRING STRINGIZE (DATABASE_NAME)
61 #define STRINGIZE(Name) STRINGIZE1 (Name)
62 #define STRINGIZE1(Name) #Name
64 #define DB_LOOKUP_FCT CONCAT3_1 (__nss_, DATABASE_NAME, _lookup)
65 #define CONCAT3_1(Pre, Name, Post) CONCAT3_2 (Pre, Name, Post)
66 #define CONCAT3_2(Pre, Name, Post) Pre##Name##Post
68 /* Sometimes we need to store error codes in the `h_errno' variable. */
69 #ifdef NEED_H_ERRNO
70 # define H_ERRNO_PARM , int *h_errnop
71 # define H_ERRNO_VAR , &h_errno
72 #else
73 # define H_ERRNO_PARM
74 # define H_ERRNO_VAR
75 #endif
77 /* Some databases take the `stayopen' flag. */
78 #ifdef STAYOPEN
79 # define STAYOPEN_TMP CONCAT2_1 (STAYOPEN, _tmp)
80 # define STAYOPEN_TMPVAR CONCAT2_1 (STAYOPEN_VAR, _tmp)
81 #else
82 # define STAYOPEN void
83 # define STAYOPEN_VAR
84 # define STAYOPEN_TMPVAR
85 #endif
87 /* Prototype for the setXXXent functions we use here. */
88 typedef enum nss_status (*set_function) (STAYOPEN);
90 /* Prototype for the endXXXent functions we use here. */
91 typedef enum nss_status (*end_function) (void);
93 /* Prototype for the setXXXent functions we use here. */
94 typedef enum nss_status (*get_function) (LOOKUP_TYPE *, char *, size_t, int *
95 H_ERRNO_PARM);
98 /* This handle for the NSS data base is shared between all
99 set/get/endXXXent functions. */
100 static service_user *nip;
101 /* Remember the last service used since the last call to `endXXent'. */
102 static service_user *last_nip;
103 /* Remember the first service_entry, it's always the same. */
104 static service_user *startp;
106 #ifdef STAYOPEN_TMP
107 /* We need to remember the last `stayopen' flag given by the user
108 since the `setent' function is only called for the first available
109 service. */
110 static STAYOPEN_TMP;
111 #endif
113 /* Protect above variable against multiple uses at the same time. */
114 __libc_lock_define_initialized (static, lock)
116 /* The lookup function for the first entry of this service. */
117 extern int DB_LOOKUP_FCT (service_user **nip, const char *name, void **fctp);
119 /* Set up NIP to run through the services. If ALL is zero, use NIP's
120 current location if it's not nil. Return nonzero if there are no
121 services (left). */
122 static enum nss_status
123 setup (void **fctp, const char *func_name, int all)
125 int no_more;
126 if (startp == NULL)
128 no_more = DB_LOOKUP_FCT (&nip, func_name, fctp);
129 startp = no_more ? (service_user *) -1l : nip;
131 else if (startp == (service_user *) -1l)
132 /* No services at all. */
133 return 1;
134 else
136 if (all || !nip)
137 /* Reset to the beginning of the service list. */
138 nip = startp;
139 /* Look up the first function. */
140 no_more = __nss_lookup (&nip, func_name, fctp);
142 return no_more;
145 void
146 SETFUNC_NAME (STAYOPEN)
148 set_function fct;
149 int no_more;
151 #ifdef NEED__RES
152 if ((_res.options & RES_INIT) == 0 && res_init () == -1)
154 __set_h_errno (NETDB_INTERNAL);
155 return;
157 #endif /* need _res */
159 __libc_lock_lock (lock);
161 /* Cycle through the services and run their `setXXent' functions until
162 we find an available service. */
163 no_more = setup ((void **) &fct, SETFUNC_NAME_STRING, 1);
164 while (! no_more)
166 int is_last_nip = nip == last_nip;
167 enum nss_status status = _CALL_DL_FCT (fct, (STAYOPEN_VAR));
169 no_more = __nss_next (&nip, SETFUNC_NAME_STRING, (void **) &fct,
170 status, 0);
171 if (is_last_nip)
172 last_nip = nip;
175 #ifdef STAYOPEN_TMP
176 STAYOPEN_TMPVAR = STAYOPEN_VAR;
177 #endif
179 __libc_lock_unlock (lock);
183 void
184 ENDFUNC_NAME (void)
186 end_function fct;
187 int no_more;
189 #ifdef NEED__RES
190 if ((_res.options & RES_INIT) == 0 && res_init () == -1)
192 __set_h_errno (NETDB_INTERNAL);
193 return;
195 #endif /* need _res */
197 __libc_lock_lock (lock);
199 /* Cycle through all the services and run their endXXent functions. */
200 no_more = setup ((void **) &fct, ENDFUNC_NAME_STRING, 1);
201 while (! no_more)
203 /* Ignore status, we force check in __NSS_NEXT. */
204 _CALL_DL_FCT (fct, ());
206 if (nip == last_nip)
207 /* We have processed all services which were used. */
208 break;
210 no_more = __nss_next (&nip, ENDFUNC_NAME_STRING, (void **) &fct, 0, 1);
212 last_nip = nip = NULL;
214 __libc_lock_unlock (lock);
219 INTERNAL (REENTRANT_GETNAME) (LOOKUP_TYPE *resbuf, char *buffer, size_t buflen,
220 LOOKUP_TYPE **result H_ERRNO_PARM)
222 get_function fct;
223 int no_more;
224 enum nss_status status;
226 #ifdef NEED__RES
227 if ((_res.options & RES_INIT) == 0 && res_init () == -1)
229 __set_h_errno (NETDB_INTERNAL);
230 *result = NULL;
231 return -1;
233 #endif /* need _res */
235 /* Initialize status to return if no more functions are found. */
236 status = NSS_STATUS_NOTFOUND;
238 __libc_lock_lock (lock);
240 /* Run through available functions, starting with the same function last
241 run. We will repeat each function as long as it succeeds, and then go
242 on to the next service action. */
243 no_more = setup ((void **) &fct, GETFUNC_NAME_STRING, 0);
244 while (! no_more)
246 int is_last_nip = nip == last_nip;
248 status = _CALL_DL_FCT (fct,
249 (resbuf, buffer, buflen, &errno H_ERRNO_VAR));
251 /* The the status is NSS_STATUS_TRYAGAIN and errno is ERANGE the
252 provided buffer is too small. In this case we should give
253 the user the possibility to enlarge the buffer and we should
254 not simply go on with the next service (even if the TRYAGAIN
255 action tells us so). */
256 if (status == NSS_STATUS_TRYAGAIN
257 #ifdef NEED_H_ERRNO
258 && *h_errnop == NETDB_INTERNAL
259 #endif
260 && errno == ERANGE)
261 break;
265 no_more = __nss_next (&nip, GETFUNC_NAME_STRING, (void **) &fct,
266 status, 0);
268 if (is_last_nip)
269 last_nip = nip;
271 if (! no_more)
273 /* Call the `setXXent' function. This wasn't done before. */
274 set_function sfct;
276 no_more = __nss_lookup (&nip, SETFUNC_NAME_STRING,
277 (void **) &sfct);
279 if (! no_more)
280 status = _CALL_DL_FCT (sfct, (STAYOPEN_TMPVAR));
281 else
282 status = NSS_STATUS_NOTFOUND;
285 while (! no_more && status != NSS_STATUS_SUCCESS);
288 __libc_lock_unlock (lock);
290 *result = status == NSS_STATUS_SUCCESS ? resbuf : NULL;
291 return status == NSS_STATUS_SUCCESS ? 0 : -1;
293 #define do_weak_alias(n1, n2) weak_alias (n1, n2)
294 do_weak_alias (INTERNAL (REENTRANT_GETNAME), REENTRANT_GETNAME)