52e2136dd802e4bb163d95fdddf5ad00f1df3f1b
[platform/upstream/glibc.git] / nss / getXXent_r.c
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.
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 <libc-lock.h>
21
22 #include "nsswitch.h"
23
24 /*******************************************************************\
25 |* Here we assume several symbols to be defined:                   *|
26 |*                                                                 *|
27 |* LOOKUP_TYPE   - the return type of the function                 *|
28 |*                                                                 *|
29 |* SETFUNC_NAME  - name of the non-reentrant setXXXent function    *|
30 |*                                                                 *|
31 |* GETFUNC_NAME  - name of the non-reentrant getXXXent function    *|
32 |*                                                                 *|
33 |* ENDFUNC_NAME  - name of the non-reentrant endXXXent function    *|
34 |*                                                                 *|
35 |* DATABASE_NAME - name of the database the function accesses      *|
36 |*                 (e.g., host, services, ...)                     *|
37 |*                                                                 *|
38 |* Optionally the following vars can be defined:                   *|
39 |*                                                                 *|
40 |* STAYOPEN      - variable declaration for setXXXent function     *|
41 |*                                                                 *|
42 |* STAYOPEN_VAR  - variable name for setXXXent function            *|
43 |*                                                                 *|
44 |* NEED_H_ERRNO  - an extra parameter will be passed to point to   *|
45 |*                 the global `h_errno' variable.                  *|
46 |*                                                                 *|
47 \*******************************************************************/
48
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
55
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
62
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
66
67 /* Sometimes we need to store error codes in the `h_errno' variable.  */
68 #ifdef NEED_H_ERRNO
69 # define H_ERRNO_PARM , int *h_errnop
70 # define H_ERRNO_VAR , &h_errno
71 #else
72 # define H_ERRNO_PARM
73 # define H_ERRNO_VAR
74 #endif
75
76 /* Some databases take the `stayopen' flag.  */
77 #ifdef STAYOPEN
78 # define STAYOPEN_TMP CONCAT2_1 (STAYOPEN, _tmp)
79 # define STAYOPEN_TMPVAR CONCAT2_1 (STAYOPEN_VAR, _tmp)
80 #else
81 # define STAYOPEN void
82 # define STAYOPEN_VAR
83 # define STAYOPEN_TMPVAR
84 #endif
85
86 /* Prototype for the setXXXent functions we use here.  */
87 typedef int (*set_function) (STAYOPEN);
88
89 /* Prototype for the endXXXent functions we use here.  */
90 typedef int (*end_function) (void);
91
92 /* Prototype for the setXXXent functions we use here.  */
93 typedef int (*get_function) (LOOKUP_TYPE *, char *, int H_ERRNO_PARM);
94
95
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;
101
102 #ifdef STAYOPEN_TMP
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
105    service.  */
106 static STAYOPEN_TMP;
107 #endif
108
109 /* Protect above variable against multiple uses at the same time.  */
110 __libc_lock_define_initialized (static, lock)
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
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
117    services (left).  */
118 static enum nss_status
119 setup (void **fctp, const char *func_name, int all)
120 {
121   int no_more;
122   if (startp == NULL)
123     {
124       no_more = DB_LOOKUP_FCT (&nip, func_name, fctp);
125       startp = no_more ? (service_user *) -1 : nip;
126     }
127   else if (startp == (service_user *) -1)
128     /* No services at all.  */
129     return 1;
130   else
131     {
132       if (all || !nip)
133         /* Reset to the beginning of the service list.  */
134         nip = startp;
135       /* Look up the first function.  */
136       no_more = __nss_lookup (&nip, func_name, fctp);
137     }
138   return no_more;
139 }
140 \f
141 void
142 SETFUNC_NAME (STAYOPEN)
143 {
144   set_function fct;
145   int no_more;
146
147 #ifdef NEED__RES
148   if ((_res.options & RES_INIT) == 0 && res_init () == -1)
149     {
150       __set_h_errno (NETDB_INTERNAL);
151       return NULL;
152     }
153 #endif /* need _res */
154
155   __libc_lock_lock (lock);
156
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);
160   while (! no_more)
161     {
162       enum nss_status status = (*fct) (STAYOPEN_VAR);
163
164       no_more = __nss_next (&nip, SETFUNC_NAME_STRING, (void **) &fct,
165                             status, 1);
166     }
167   nip = NULL;
168
169 #ifdef STAYOPEN_TMP
170   STAYOPEN_TMPVAR = STAYOPEN_VAR;
171 #endif
172
173   __libc_lock_unlock (lock);
174 }
175
176
177 void
178 ENDFUNC_NAME (void)
179 {
180   end_function fct;
181   int no_more;
182
183 #ifdef NEED__RES
184   if ((_res.options & RES_INIT) == 0 && res_init () == -1)
185     {
186       __set_h_errno (NETDB_INTERNAL);
187       return NULL;
188     }
189 #endif /* need _res */
190
191   __libc_lock_lock (lock);
192
193   /* Cycle through all the services and run their endXXent functions.  */
194   no_more = setup ((void **) &fct, ENDFUNC_NAME_STRING, 1);
195   while (! no_more)
196     {
197       /* Ignore status, we force check in __NSS_NEXT.  */
198       (void) (*fct) ();
199
200       no_more = __nss_next (&nip, ENDFUNC_NAME_STRING, (void **) &fct, 0, 1);
201     }
202   nip = NULL;
203
204   __libc_lock_unlock (lock);
205 }
206
207
208 int
209 INTERNAL (REENTRANT_GETNAME) (LOOKUP_TYPE *resbuf, char *buffer, size_t buflen,
210                               LOOKUP_TYPE **result H_ERRNO_PARM)
211 {
212   get_function fct;
213   int no_more;
214   enum nss_status status;
215
216 #ifdef NEED__RES
217   if ((_res.options & RES_INIT) == 0 && res_init () == -1)
218     {
219       __set_h_errno (NETDB_INTERNAL);
220       return NULL;
221     }
222 #endif /* need _res */
223
224   /* Initialize status to return if no more functions are found.  */
225   status = NSS_STATUS_NOTFOUND;
226
227   __libc_lock_lock (lock);
228
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);
233   while (! no_more)
234     {
235       service_user *current_nip = nip;
236
237       status = (*fct) (resbuf, buffer, buflen H_ERRNO_VAR);
238
239       no_more = __nss_next (&nip, GETFUNC_NAME_STRING, (void **) &fct,
240                             status, 0);
241
242       if (! no_more && current_nip != nip)
243         /* Call the `setXXent' function.  This wasn't done before.  */
244         do
245           {
246             set_function *sfct;
247
248             no_more = __nss_lookup (&nip, SETFUNC_NAME_STRING,
249                                     (void **) &sfct);
250
251             if (! no_more)
252               status = (*sfct) (STAYOPEN_TMPVAR);
253           }
254         while (! no_more && status != NSS_STATUS_SUCCESS);
255     }
256
257   __libc_lock_unlock (lock);
258
259   *result = NSS_STATUS_SUCCESS ? resbuf : NULL;
260   return status == NSS_STATUS_SUCCESS ? 0 : -1;
261 }
262 #define do_weak_alias(n1, n2) weak_alias (n1, n2)
263 do_weak_alias (INTERNAL (REENTRANT_GETNAME), REENTRANT_GETNAME)