Make libm-test-support code clear exceptions after each test.
[glibc.git] / nss / getnssent_r.c
blob5fdbf3be0061aae172d2649efcf1390a8ce90a6c
1 /* Copyright (C) 2000-2017 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
4 The GNU C Library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) any later version.
9 The GNU C Library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
14 You should have received a copy of the GNU Lesser General Public
15 License along with the GNU C Library; if not, see
16 <http://www.gnu.org/licenses/>. */
18 #include <errno.h>
19 #include <netdb.h>
20 #include "nsswitch.h"
22 /* Set up NIP to run through the services. If ALL is zero, use NIP's
23 current location if it's not nil. Return nonzero if there are no
24 services (left). */
25 static int
26 setup (const char *func_name, db_lookup_function lookup_fct,
27 void **fctp, service_user **nip, service_user **startp, int all)
29 int no_more;
30 if (*startp == NULL)
32 no_more = lookup_fct (nip, func_name, NULL, fctp);
33 *startp = no_more ? (service_user *) -1l : *nip;
35 else if (*startp == (service_user *) -1l)
36 /* No services at all. */
37 return 1;
38 else
40 if (all || !*nip)
41 /* Reset to the beginning of the service list. */
42 *nip = *startp;
43 /* Look up the first function. */
44 no_more = __nss_lookup (nip, func_name, NULL, fctp);
46 return no_more;
49 void
50 __nss_setent (const char *func_name, db_lookup_function lookup_fct,
51 service_user **nip, service_user **startp,
52 service_user **last_nip, int stayopen, int *stayopen_tmp,
53 int res)
55 union
57 setent_function f;
58 void *ptr;
59 } fct;
60 int no_more;
62 if (res && __res_maybe_init (&_res, 0) == -1)
64 __set_h_errno (NETDB_INTERNAL);
65 return;
68 /* Cycle through the services and run their `setXXent' functions until
69 we find an available service. */
70 no_more = setup (func_name, lookup_fct, &fct.ptr, nip,
71 startp, 1);
72 while (! no_more)
74 int is_last_nip = *nip == *last_nip;
75 enum nss_status status;
77 if (stayopen_tmp)
78 status = DL_CALL_FCT (fct.f, (*stayopen_tmp));
79 else
80 status = DL_CALL_FCT (fct.f, (0));
83 /* This is a special-case. When [SUCCESS=merge] is in play,
84 _nss_next2() will skip to the next database. Due to the
85 implementation of that function, we can't know whether we're
86 in an enumeration or an individual lookup, which behaves
87 differently with regards to merging. We'll treat SUCCESS as
88 an indication to start the enumeration at this database. */
89 if (nss_next_action (*nip, status) == NSS_ACTION_MERGE)
90 no_more = 1;
91 else
92 no_more = __nss_next2 (nip, func_name, NULL, &fct.ptr, status, 0);
94 if (is_last_nip)
95 *last_nip = *nip;
98 if (stayopen_tmp)
99 *stayopen_tmp = stayopen;
103 void
104 __nss_endent (const char *func_name, db_lookup_function lookup_fct,
105 service_user **nip, service_user **startp,
106 service_user **last_nip, int res)
108 union
110 endent_function f;
111 void *ptr;
112 } fct;
113 int no_more;
115 if (res && __res_maybe_init (&_res, 0) == -1)
117 __set_h_errno (NETDB_INTERNAL);
118 return;
121 /* Cycle through all the services and run their endXXent functions. */
122 no_more = setup (func_name, lookup_fct, &fct.ptr, nip, startp, 1);
123 while (! no_more)
125 /* Ignore status, we force check in __NSS_NEXT. */
126 DL_CALL_FCT (fct.f, ());
128 if (*nip == *last_nip)
129 /* We have processed all services which were used. */
130 break;
132 no_more = __nss_next2 (nip, func_name, NULL, &fct.ptr, 0, 1);
134 *last_nip = *nip = NULL;
139 __nss_getent_r (const char *getent_func_name,
140 const char *setent_func_name,
141 db_lookup_function lookup_fct,
142 service_user **nip, service_user **startp,
143 service_user **last_nip, int *stayopen_tmp, int res,
144 void *resbuf, char *buffer, size_t buflen,
145 void **result, int *h_errnop)
147 union
149 getent_function f;
150 void *ptr;
151 } fct;
152 int no_more;
153 enum nss_status status;
155 if (res && __res_maybe_init (&_res, 0) == -1)
157 *h_errnop = NETDB_INTERNAL;
158 *result = NULL;
159 return errno;
162 /* Initialize status to return if no more functions are found. */
163 status = NSS_STATUS_NOTFOUND;
165 /* Run through available functions, starting with the same function last
166 run. We will repeat each function as long as it succeeds, and then go
167 on to the next service action. */
168 no_more = setup (getent_func_name, lookup_fct, &fct.ptr, nip,
169 startp, 0);
170 while (! no_more)
172 int is_last_nip = *nip == *last_nip;
174 status = DL_CALL_FCT (fct.f,
175 (resbuf, buffer, buflen, &errno, &h_errno));
177 /* The status is NSS_STATUS_TRYAGAIN and errno is ERANGE the
178 provided buffer is too small. In this case we should give
179 the user the possibility to enlarge the buffer and we should
180 not simply go on with the next service (even if the TRYAGAIN
181 action tells us so). */
182 if (status == NSS_STATUS_TRYAGAIN
183 && (h_errnop == NULL || *h_errnop == NETDB_INTERNAL)
184 && errno == ERANGE)
185 break;
189 /* This is a special-case. When [SUCCESS=merge] is in play,
190 _nss_next2() will skip to the next database. Due to the
191 implementation of that function, we can't know whether we're
192 in an enumeration or an individual lookup, which behaves
193 differently with regards to merging. We'll treat SUCCESS as
194 an indication to return the results here. */
195 if (status == NSS_STATUS_SUCCESS
196 && nss_next_action (*nip, status) == NSS_ACTION_MERGE)
197 no_more = 1;
198 else
199 no_more = __nss_next2 (nip, getent_func_name, NULL, &fct.ptr,
200 status, 0);
202 if (is_last_nip)
203 *last_nip = *nip;
205 if (! no_more)
207 /* Call the `setXXent' function. This wasn't done before. */
208 union
210 setent_function f;
211 void *ptr;
212 } sfct;
214 no_more = __nss_lookup (nip, setent_func_name, NULL, &sfct.ptr);
216 if (! no_more)
218 if (stayopen_tmp)
219 status = DL_CALL_FCT (sfct.f, (*stayopen_tmp));
220 else
221 status = DL_CALL_FCT (sfct.f, (0));
223 else
224 status = NSS_STATUS_NOTFOUND;
227 while (! no_more && status != NSS_STATUS_SUCCESS);
230 *result = status == NSS_STATUS_SUCCESS ? resbuf : NULL;
231 return (status == NSS_STATUS_SUCCESS ? 0
232 : status != NSS_STATUS_TRYAGAIN ? ENOENT
233 /* h_errno functions only set errno if h_errno is NETDB_INTERNAL. */
234 : (h_errnop == NULL || *h_errnop == NETDB_INTERNAL) ? errno
235 : EAGAIN);