Thu Jun 27 02:49:28 1996 Ulrich Drepper <drepper@cygnus.com>
[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
17 not, 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) APPEND_R1 (name)
52 #define APPEND_R1(name) name##_r
53
54 #define SETFUNC_NAME_STRING STRINGIZE (SETFUNC_NAME)
55 #define GETFUNC_NAME_STRING STRINGIZE (GETFUNC_NAME)
56 #define ENDFUNC_NAME_STRING STRINGIZE (ENDFUNC_NAME)
57 #define DATABASE_NAME_STRING STRINGIZE (DATABASE_NAME)
58 #define STRINGIZE(name) STRINGIZE1 (name)
59 #define STRINGIZE1(name) #name
60
61 #define DB_LOOKUP_FCT CONCAT3_1 (__nss_, DATABASE_NAME, _lookup)
62 #define CONCAT3_1(Pre, Name, Post) CONCAT3_2 (Pre, Name, Post)
63 #define CONCAT3_2(Pre, Name, Post) Pre##Name##Post
64
65 /* Sometimes we need to store error codes in the `h_errno' variable.  */
66 #ifdef NEED_H_ERRNO
67 # define H_ERRNO_PARM , int *h_errnop
68 # define H_ERRNO_VAR , &h_errno
69 #else
70 # define H_ERRNO_PARM
71 # define H_ERRNO_VAR
72 #endif
73
74 /* Some databases take the `stayopen' flag.  */
75 #ifndef STAYOPEN
76 #define STAYOPEN void
77 #define STAYOPEN_VAR
78 #endif
79
80 /* Prototype for the setXXXent functions we use here.  */
81 typedef int (*set_function) (STAYOPEN);
82
83 /* Prototype for the endXXXent functions we use here.  */
84 typedef int (*end_function) (void);
85
86 /* Prototype for the setXXXent functions we use here.  */
87 typedef int (*get_function) (LOOKUP_TYPE *, char *, int H_ERRNO_PARM);
88
89
90 /* This handle for the NSS data base is shared between all
91    set/get/endXXXent functions.  */
92 static service_user *nip;
93 /* Remember the first service_entry, it's always the same.  */
94 static service_user *startp;
95
96 /* Protect above variable against multiple uses at the same time.  */
97 __libc_lock_define_initialized (static, lock);
98
99 /* The lookup function for the first entry of this service.  */
100 extern int DB_LOOKUP_FCT (service_user **nip, const char *name, void **fctp);
101
102
103 void
104 SETFUNC_NAME (STAYOPEN)
105 {
106   set_function fct;
107   int no_more;
108
109 #ifdef NEED__RES
110   if ((_res.options & RES_INIT) == 0 && res_init () == -1)
111     {
112       h_errno = NETDB_INTERNAL;
113       return NULL;
114     }
115 #endif /* need _res */
116
117   __libc_lock_lock (lock);
118
119   if (startp == NULL)
120     {
121       no_more = DB_LOOKUP_FCT (&nip, SETFUNC_NAME_STRING, (void **) &fct);
122       startp = no_more == 0 ? (service_user *) -1 : nip;
123     }
124   else
125     no_more = (nip = startp) != (service_user *) -1;
126
127   /* Cycle through all the services and run their setXXent functions.  */
128   while (! no_more)
129     {
130       /* Ignore status, we force check in __NSS_NEXT.  */
131       (void) (*fct) (STAYOPEN_VAR);
132
133       no_more = __nss_next (&nip, SETFUNC_NAME_STRING, (void **) &fct, 0, 1);
134     }
135
136   __libc_lock_unlock (lock);
137 }
138
139
140 void
141 ENDFUNC_NAME (void)
142 {
143   end_function fct;
144   int no_more;
145
146 #ifdef NEED__RES
147   if ((_res.options & RES_INIT) == 0 && res_init () == -1)
148     {
149       h_errno = NETDB_INTERNAL;
150       return NULL;
151     }
152 #endif /* need _res */
153
154   __libc_lock_lock (lock);
155
156   if (startp == NULL)
157     {
158       no_more = DB_LOOKUP_FCT (&nip, SETFUNC_NAME_STRING, (void **) &fct);
159       startp = no_more == 0 ? (service_user *) -1 : nip;
160     }
161   else
162     no_more = (nip = startp) != (service_user *) -1;
163
164   /* Cycle through all the services and run their endXXent functions.  */
165   while (no_more == 0)
166     {
167       /* Ignore status, we force check in __NSS_NEXT.  */
168       (void) (*fct) ();
169
170       no_more = __nss_next (&nip, ENDFUNC_NAME_STRING, (void **) &fct, 0, 1);
171     }
172
173   __libc_lock_unlock (lock);
174 }
175
176
177 LOOKUP_TYPE *
178 REENTRANT_GETNAME (LOOKUP_TYPE *result, char *buffer, int buflen H_ERRNO_PARM)
179 {
180   get_function fct;
181   int no_more;
182   enum nss_status status = NSS_STATUS_NOTFOUND;
183
184 #ifdef NEED__RES
185   if ((_res.options & RES_INIT) == 0 && res_init () == -1)
186     {
187       h_errno = NETDB_INTERNAL;
188       return NULL;
189     }
190 #endif /* need _res */
191
192   __libc_lock_lock (lock);
193
194   if (nip)
195     /* Continuing a walk-through started before.  */
196     no_more = 0;
197   else
198     {
199       if (startp == NULL)
200         {
201           no_more = DB_LOOKUP_FCT (&nip, SETFUNC_NAME_STRING, (void **) &fct);
202           startp = no_more == 0 ? (service_user *) -1 : nip;
203         }
204       else
205         no_more = (nip = startp) != (service_user *) -1;
206
207       if (no_more != 0)
208         status = NSS_STATUS_UNAVAIL;
209     }
210
211   while (no_more == 0)
212     {
213       status = (*fct) (result, buffer, buflen H_ERRNO_VAR);
214
215       no_more = __nss_next (&nip, GETFUNC_NAME_STRING, (void **) &fct,
216                             status, 0);
217     }
218
219   __libc_lock_unlock (lock);
220
221   return status == NSS_STATUS_SUCCESS ? result : NULL;
222 }