Back to index

glibc  2.9
getnssent_r.c
Go to the documentation of this file.
00001 /* Copyright (C) 2000, 2002, 2004, 2007 Free Software Foundation, Inc.
00002    This file is part of the GNU C Library.
00003 
00004    The GNU C Library is free software; you can redistribute it and/or
00005    modify it under the terms of the GNU Lesser General Public
00006    License as published by the Free Software Foundation; either
00007    version 2.1 of the License, or (at your option) any later version.
00008 
00009    The GNU C Library is distributed in the hope that it will be useful,
00010    but WITHOUT ANY WARRANTY; without even the implied warranty of
00011    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012    Lesser General Public License for more details.
00013 
00014    You should have received a copy of the GNU Lesser General Public
00015    License along with the GNU C Library; if not, write to the Free
00016    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00017    02111-1307 USA.  */
00018 
00019 #include <errno.h>
00020 #include <netdb.h>
00021 #include "nsswitch.h"
00022 
00023 /* Set up NIP to run through the services.  If ALL is zero, use NIP's
00024    current location if it's not nil.  Return nonzero if there are no
00025    services (left).  */
00026 static int
00027 setup (const char *func_name, db_lookup_function lookup_fct,
00028        void **fctp, service_user **nip, service_user **startp, int all)
00029 {
00030   int no_more;
00031   if (*startp == NULL)
00032     {
00033       no_more = lookup_fct (nip, func_name, NULL, fctp);
00034       *startp = no_more ? (service_user *) -1l : *nip;
00035     }
00036   else if (*startp == (service_user *) -1l)
00037     /* No services at all.  */
00038     return 1;
00039   else
00040     {
00041       if (all || !*nip)
00042        /* Reset to the beginning of the service list.  */
00043        *nip = *startp;
00044       /* Look up the first function.  */
00045       no_more = __nss_lookup (nip, func_name, NULL, fctp);
00046     }
00047   return no_more;
00048 }
00049 
00050 void
00051 __nss_setent (const char *func_name, db_lookup_function lookup_fct,
00052              service_user **nip, service_user **startp,
00053              service_user **last_nip, int stayopen, int *stayopen_tmp,
00054              int res)
00055 {
00056   union
00057   {
00058     setent_function f;
00059     void *ptr;
00060   } fct;
00061   int no_more;
00062 
00063   if (res && __res_maybe_init (&_res, 0) == -1)
00064     {
00065       __set_h_errno (NETDB_INTERNAL);
00066       return;
00067     }
00068 
00069   /* Cycle through the services and run their `setXXent' functions until
00070      we find an available service.  */
00071   no_more = setup (func_name, lookup_fct, &fct.ptr, nip,
00072                  startp, 1);
00073   while (! no_more)
00074     {
00075       int is_last_nip = *nip == *last_nip;
00076       enum nss_status status;
00077 
00078       if (stayopen_tmp)
00079        status = DL_CALL_FCT (fct.f, (*stayopen_tmp));
00080       else
00081        status = DL_CALL_FCT (fct.f, (0));
00082 
00083       no_more = __nss_next2 (nip, func_name, NULL, &fct.ptr, status, 0);
00084       if (is_last_nip)
00085        *last_nip = *nip;
00086     }
00087 
00088   if (stayopen_tmp)
00089     *stayopen_tmp = stayopen;
00090 }
00091 
00092 
00093 void
00094 __nss_endent (const char *func_name, db_lookup_function lookup_fct,
00095              service_user **nip, service_user **startp,
00096              service_user **last_nip, int res)
00097 {
00098   union
00099   {
00100     endent_function f;
00101     void *ptr;
00102   } fct;
00103   int no_more;
00104 
00105   if (res && __res_maybe_init (&_res, 0) == -1)
00106     {
00107       __set_h_errno (NETDB_INTERNAL);
00108       return;
00109     }
00110 
00111   /* Cycle through all the services and run their endXXent functions.  */
00112   no_more = setup (func_name, lookup_fct, &fct.ptr, nip, startp, 1);
00113   while (! no_more)
00114     {
00115       /* Ignore status, we force check in __NSS_NEXT.  */
00116       DL_CALL_FCT (fct.f, ());
00117 
00118       if (*nip == *last_nip)
00119        /* We have processed all services which were used.  */
00120        break;
00121 
00122       no_more = __nss_next2 (nip, func_name, NULL, &fct.ptr, 0, 1);
00123     }
00124   *last_nip = *nip = NULL;
00125 }
00126 
00127 
00128 int
00129 __nss_getent_r (const char *getent_func_name,
00130               const char *setent_func_name,
00131               db_lookup_function lookup_fct,
00132               service_user **nip, service_user **startp,
00133               service_user **last_nip, int *stayopen_tmp, int res,
00134               void *resbuf, char *buffer, size_t buflen,
00135               void **result, int *h_errnop)
00136 {
00137   union
00138   {
00139     getent_function f;
00140     void *ptr;
00141   } fct;
00142   int no_more;
00143   enum nss_status status;
00144 
00145   if (res && __res_maybe_init (&_res, 0) == -1)
00146     {
00147       *h_errnop = NETDB_INTERNAL;
00148       *result = NULL;
00149       return errno;
00150     }
00151 
00152   /* Initialize status to return if no more functions are found.  */
00153   status = NSS_STATUS_NOTFOUND;
00154 
00155   /* Run through available functions, starting with the same function last
00156      run.  We will repeat each function as long as it succeeds, and then go
00157      on to the next service action.  */
00158   no_more = setup (getent_func_name, lookup_fct, &fct.ptr, nip,
00159                  startp, 0);
00160   while (! no_more)
00161     {
00162       int is_last_nip = *nip == *last_nip;
00163 
00164       status = DL_CALL_FCT (fct.f,
00165                          (resbuf, buffer, buflen, &errno, &h_errno));
00166 
00167       /* The the status is NSS_STATUS_TRYAGAIN and errno is ERANGE the
00168         provided buffer is too small.  In this case we should give
00169         the user the possibility to enlarge the buffer and we should
00170         not simply go on with the next service (even if the TRYAGAIN
00171         action tells us so).  */
00172       if (status == NSS_STATUS_TRYAGAIN
00173          && (h_errnop == NULL || *h_errnop == NETDB_INTERNAL)
00174          && errno == ERANGE)
00175        break;
00176 
00177       do
00178        {
00179          no_more = __nss_next2 (nip, getent_func_name, NULL, &fct.ptr,
00180                              status, 0);
00181 
00182          if (is_last_nip)
00183            *last_nip = *nip;
00184 
00185          if (! no_more)
00186            {
00187              /* Call the `setXXent' function.  This wasn't done before.  */
00188              union
00189              {
00190               setent_function f;
00191               void *ptr;
00192              } sfct;
00193 
00194              no_more = __nss_lookup (nip, setent_func_name, NULL, &sfct.ptr);
00195 
00196              if (! no_more)
00197                {
00198                 if (stayopen_tmp)
00199                   status = DL_CALL_FCT (sfct.f, (*stayopen_tmp));
00200                 else
00201                   status = DL_CALL_FCT (sfct.f, (0));
00202               }
00203              else
00204               status = NSS_STATUS_NOTFOUND;
00205            }
00206        }
00207       while (! no_more && status != NSS_STATUS_SUCCESS);
00208     }
00209 
00210   *result = status == NSS_STATUS_SUCCESS ? resbuf : NULL;
00211   return (status == NSS_STATUS_SUCCESS ? 0
00212          : status != NSS_STATUS_TRYAGAIN ? ENOENT
00213          /* h_errno functions only set errno if h_errno is NETDB_INTERNAL.  */
00214          : (h_errnop == NULL || *h_errnop == NETDB_INTERNAL) ? errno
00215          : EAGAIN);
00216 }