1 /* Copyright (C) 1996 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 <libc-lock.h>
24 /*******************************************************************\
25 |* Here we assume several symbols to be defined: *|
27 |* LOOKUP_TYPE - the return type of the function *|
29 |* SETFUNC_NAME - name of the non-reentrant setXXXent function *|
31 |* GETFUNC_NAME - name of the non-reentrant getXXXent function *|
33 |* ENDFUNC_NAME - name of the non-reentrant endXXXent function *|
35 |* DATABASE_NAME - name of the database the function accesses *|
36 |* (e.g., host, services, ...) *|
38 |* Optionally the following vars can be defined: *|
40 |* STAYOPEN - variable declaration for setXXXent function *|
42 |* STAYOPEN_VAR - variable name for setXXXent function *|
44 |* NEED_H_ERRNO - an extra parameter will be passed to point to *|
45 |* the global `h_errno' variable. *|
47 \*******************************************************************/
49 /* To make the real sources a bit prettier. */
50 #define REENTRANT_GETNAME APPEND_R (GETFUNC_NAME)
51 #define APPEND_R(Name) CONCAT2_2 (Name, _r)
52 #define INTERNAL(Name) CONCAT2_2 (__, Name)
53 #define CONCAT2_1(Pre, Post) CONCAT2_2 (Pre, Post)
54 #define CONCAT2_2(Pre, Post) Pre##Post
56 #define SETFUNC_NAME_STRING STRINGIZE (SETFUNC_NAME)
57 #define GETFUNC_NAME_STRING STRINGIZE (REENTRANT_GETNAME)
58 #define ENDFUNC_NAME_STRING STRINGIZE (ENDFUNC_NAME)
59 #define DATABASE_NAME_STRING STRINGIZE (DATABASE_NAME)
60 #define STRINGIZE(Name) STRINGIZE1 (Name)
61 #define STRINGIZE1(Name) #Name
63 #define DB_LOOKUP_FCT CONCAT3_1 (__nss_, DATABASE_NAME, _lookup)
64 #define CONCAT3_1(Pre, Name, Post) CONCAT3_2 (Pre, Name, Post)
65 #define CONCAT3_2(Pre, Name, Post) Pre##Name##Post
67 /* Sometimes we need to store error codes in the `h_errno' variable. */
69 # define H_ERRNO_PARM , int *h_errnop
70 # define H_ERRNO_VAR , &h_errno
76 /* Some databases take the `stayopen' flag. */
78 # define STAYOPEN_TMP CONCAT2_1 (STAYOPEN, _tmp)
79 # define STAYOPEN_TMPVAR CONCAT2_1 (STAYOPEN_VAR, _tmp)
81 # define STAYOPEN void
83 # define STAYOPEN_TMPVAR
86 /* Prototype for the setXXXent functions we use here. */
87 typedef int (*set_function) (STAYOPEN);
89 /* Prototype for the endXXXent functions we use here. */
90 typedef int (*end_function) (void);
92 /* Prototype for the setXXXent functions we use here. */
93 typedef int (*get_function) (LOOKUP_TYPE *, char *, int H_ERRNO_PARM);
96 /* This handle for the NSS data base is shared between all
97 set/get/endXXXent functions. */
98 static service_user *nip;
99 /* Remember the first service_entry, it's always the same. */
100 static service_user *startp;
103 /* We need to remember the last `stayopen' flag given by the user
104 since the `setent' function is only called for the first available
109 /* Protect above variable against multiple uses at the same time. */
110 __libc_lock_define_initialized (static, lock)
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);
115 /* Set up NIP to run through the services. If ALL is zero, use NIP's
116 current location if it's not nil. Return nonzero if there are no
118 static enum nss_status
119 setup (void **fctp, const char *func_name, int all)
124 no_more = DB_LOOKUP_FCT (&nip, func_name, fctp);
125 startp = no_more ? (service_user *) -1 : nip;
127 else if (startp == (service_user *) -1)
128 /* No services at all. */
133 /* Reset to the beginning of the service list. */
135 /* Look up the first function. */
136 no_more = __nss_lookup (&nip, func_name, fctp);
142 SETFUNC_NAME (STAYOPEN)
148 if ((_res.options & RES_INIT) == 0 && res_init () == -1)
150 __set_h_errno (NETDB_INTERNAL);
153 #endif /* need _res */
155 __libc_lock_lock (lock);
157 /* Cycle through the services and run their `setXXent' functions until
158 we find an available service. */
159 no_more = setup ((void **) &fct, SETFUNC_NAME_STRING, 1);
162 enum nss_status status = (*fct) (STAYOPEN_VAR);
164 no_more = __nss_next (&nip, SETFUNC_NAME_STRING, (void **) &fct,
170 STAYOPEN_TMPVAR = STAYOPEN_VAR;
173 __libc_lock_unlock (lock);
184 if ((_res.options & RES_INIT) == 0 && res_init () == -1)
186 __set_h_errno (NETDB_INTERNAL);
189 #endif /* need _res */
191 __libc_lock_lock (lock);
193 /* Cycle through all the services and run their endXXent functions. */
194 no_more = setup ((void **) &fct, ENDFUNC_NAME_STRING, 1);
197 /* Ignore status, we force check in __NSS_NEXT. */
200 no_more = __nss_next (&nip, ENDFUNC_NAME_STRING, (void **) &fct, 0, 1);
204 __libc_lock_unlock (lock);
209 INTERNAL (REENTRANT_GETNAME) (LOOKUP_TYPE *resbuf, char *buffer, size_t buflen,
210 LOOKUP_TYPE **result H_ERRNO_PARM)
214 enum nss_status status;
217 if ((_res.options & RES_INIT) == 0 && res_init () == -1)
219 __set_h_errno (NETDB_INTERNAL);
222 #endif /* need _res */
224 /* Initialize status to return if no more functions are found. */
225 status = NSS_STATUS_NOTFOUND;
227 __libc_lock_lock (lock);
229 /* Run through available functions, starting with the same function last
230 run. We will repeat each function as long as it succeeds, and then go
231 on to the next service action. */
232 no_more = setup ((void **) &fct, GETFUNC_NAME_STRING, 0);
235 service_user *current_nip = nip;
237 status = (*fct) (resbuf, buffer, buflen H_ERRNO_VAR);
239 no_more = __nss_next (&nip, GETFUNC_NAME_STRING, (void **) &fct,
242 if (! no_more && current_nip != nip)
243 /* Call the `setXXent' function. This wasn't done before. */
248 no_more = __nss_lookup (&nip, SETFUNC_NAME_STRING,
252 status = (*sfct) (STAYOPEN_TMPVAR);
254 while (! no_more && status != NSS_STATUS_SUCCESS);
257 __libc_lock_unlock (lock);
259 *result = NSS_STATUS_SUCCESS ? resbuf : NULL;
260 return status == NSS_STATUS_SUCCESS ? 0 : -1;
262 #define do_weak_alias(n1, n2) weak_alias (n1, n2)
263 do_weak_alias (INTERNAL (REENTRANT_GETNAME), REENTRANT_GETNAME)