Optimize a bit by using mempcpy.
[kopensolaris-gnu/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 <bits/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 *, size_t 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 last service used since the last call to  `endXXent'.  */
100 static service_user *last_nip;
101 /* Remember the first service_entry, it's always the same.  */
102 static service_user *startp;
103
104 #ifdef STAYOPEN_TMP
105 /* We need to remember the last `stayopen' flag given by the user
106    since the `setent' function is only called for the first available
107    service.  */
108 static STAYOPEN_TMP;
109 #endif
110
111 /* Protect above variable against multiple uses at the same time.  */
112 __libc_lock_define_initialized (static, lock)
113
114 /* The lookup function for the first entry of this service.  */
115 extern int DB_LOOKUP_FCT (service_user **nip, const char *name, void **fctp);
116
117 /* Set up NIP to run through the services.  If ALL is zero, use NIP's
118    current location if it's not nil.  Return nonzero if there are no
119    services (left).  */
120 static enum nss_status
121 setup (void **fctp, const char *func_name, int all)
122 {
123   int no_more;
124   if (startp == NULL)
125     {
126       no_more = DB_LOOKUP_FCT (&nip, func_name, fctp);
127       startp = no_more ? (service_user *) -1l : nip;
128     }
129   else if (startp == (service_user *) -1l)
130     /* No services at all.  */
131     return 1;
132   else
133     {
134       if (all || !nip)
135         /* Reset to the beginning of the service list.  */
136         nip = startp;
137       /* Look up the first function.  */
138       no_more = __nss_lookup (&nip, func_name, fctp);
139     }
140   return no_more;
141 }
142 \f
143 void
144 SETFUNC_NAME (STAYOPEN)
145 {
146   set_function fct;
147   int no_more;
148
149 #ifdef NEED__RES
150   if ((_res.options & RES_INIT) == 0 && res_init () == -1)
151     {
152       __set_h_errno (NETDB_INTERNAL);
153       return;
154     }
155 #endif /* need _res */
156
157   __libc_lock_lock (lock);
158
159   /* Cycle through the services and run their `setXXent' functions until
160      we find an available service.  */
161   no_more = setup ((void **) &fct, SETFUNC_NAME_STRING, 1);
162   while (! no_more)
163     {
164       int is_last_nip = nip == last_nip;
165       enum nss_status status = (*fct) (STAYOPEN_VAR);
166
167       no_more = __nss_next (&nip, SETFUNC_NAME_STRING, (void **) &fct,
168                             status, 0);
169       if (is_last_nip)
170         last_nip = nip;
171     }
172
173 #ifdef STAYOPEN_TMP
174   STAYOPEN_TMPVAR = STAYOPEN_VAR;
175 #endif
176
177   __libc_lock_unlock (lock);
178 }
179
180
181 void
182 ENDFUNC_NAME (void)
183 {
184   end_function fct;
185   int no_more;
186
187 #ifdef NEED__RES
188   if ((_res.options & RES_INIT) == 0 && res_init () == -1)
189     {
190       __set_h_errno (NETDB_INTERNAL);
191       return;
192     }
193 #endif /* need _res */
194
195   __libc_lock_lock (lock);
196
197   /* Cycle through all the services and run their endXXent functions.  */
198   no_more = setup ((void **) &fct, ENDFUNC_NAME_STRING, 1);
199   while (! no_more)
200     {
201       /* Ignore status, we force check in __NSS_NEXT.  */
202       (void) (*fct) ();
203
204       if (nip == last_nip)
205         /* We have processed all services which were used.  */
206         break;
207
208       no_more = __nss_next (&nip, ENDFUNC_NAME_STRING, (void **) &fct, 0, 1);
209     }
210   last_nip = nip = NULL;
211
212   __libc_lock_unlock (lock);
213 }
214
215
216 int
217 INTERNAL (REENTRANT_GETNAME) (LOOKUP_TYPE *resbuf, char *buffer, size_t buflen,
218                               LOOKUP_TYPE **result H_ERRNO_PARM)
219 {
220   get_function fct;
221   int no_more;
222   enum nss_status status;
223
224 #ifdef NEED__RES
225   if ((_res.options & RES_INIT) == 0 && res_init () == -1)
226     {
227       __set_h_errno (NETDB_INTERNAL);
228       *result = NULL;
229       return -1;
230     }
231 #endif /* need _res */
232
233   /* Initialize status to return if no more functions are found.  */
234   status = NSS_STATUS_NOTFOUND;
235
236   __libc_lock_lock (lock);
237
238   /* Run through available functions, starting with the same function last
239      run.  We will repeat each function as long as it succeeds, and then go
240      on to the next service action.  */
241   no_more = setup ((void **) &fct, GETFUNC_NAME_STRING, 0);
242   while (! no_more)
243     {
244       int is_last_nip = nip == last_nip;
245       service_user *current_nip = nip;
246
247       status = (*fct) (resbuf, buffer, buflen H_ERRNO_VAR);
248
249       no_more = __nss_next (&nip, GETFUNC_NAME_STRING, (void **) &fct,
250                             status, 0);
251
252       if (is_last_nip)
253         last_nip = nip;
254
255       if (! no_more && current_nip != nip)
256         /* Call the `setXXent' function.  This wasn't done before.  */
257         do
258           {
259             set_function sfct;
260
261             no_more = __nss_lookup (&nip, SETFUNC_NAME_STRING,
262                                     (void **) &sfct);
263
264             if (! no_more)
265               status = (*sfct) (STAYOPEN_TMPVAR);
266             else
267               status = NSS_STATUS_NOTFOUND;
268           }
269         while (! no_more && status != NSS_STATUS_SUCCESS);
270     }
271
272   __libc_lock_unlock (lock);
273
274   *result = status == NSS_STATUS_SUCCESS ? resbuf : NULL;
275   return status == NSS_STATUS_SUCCESS ? 0 : -1;
276 }
277 #define do_weak_alias(n1, n2) weak_alias (n1, n2)
278 do_weak_alias (INTERNAL (REENTRANT_GETNAME), REENTRANT_GETNAME)