Back to index

glibc  2.9
getXXbyYY_r.c
Go to the documentation of this file.
00001 /* Copyright (C) 1996-2004, 2006, 2007 Free Software Foundation, Inc.
00002    This file is part of the GNU C Library.
00003    Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
00004 
00005    The GNU C Library is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Lesser General Public
00007    License as published by the Free Software Foundation; either
00008    version 2.1 of the License, or (at your option) any later version.
00009 
00010    The GNU C Library is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013    Lesser General Public License for more details.
00014 
00015    You should have received a copy of the GNU Lesser General Public
00016    License along with the GNU C Library; if not, write to the Free
00017    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00018    02111-1307 USA.  */
00019 
00020 #include <assert.h>
00021 #include <atomic.h>
00022 #include <errno.h>
00023 #include <stdbool.h>
00024 #include "nsswitch.h"
00025 #include "sysdep.h"
00026 #ifdef USE_NSCD
00027 # include <nscd/nscd_proto.h>
00028 #endif
00029 #ifdef NEED__RES_HCONF
00030 # include <resolv/res_hconf.h>
00031 #endif
00032 #ifdef NEED__RES
00033 # include <resolv.h>
00034 #endif
00035 /*******************************************************************\
00036 |* Here we assume several symbols to be defined:           *|
00037 |*                                                         *|
00038 |* LOOKUP_TYPE   - the return type of the function                *|
00039 |*                                                         *|
00040 |* FUNCTION_NAME - name of the non-reentrant function             *|
00041 |*                                                         *|
00042 |* DATABASE_NAME - name of the database the function accesses     *|
00043 |*               (e.g., host, services, ...)                      *|
00044 |*                                                         *|
00045 |* ADD_PARAMS    - additional parameters, can vary in number      *|
00046 |*                                                         *|
00047 |* ADD_VARIABLES - names of additional parameters                 *|
00048 |*                                                         *|
00049 |* Optionally the following vars can be defined:           *|
00050 |*                                                         *|
00051 |* EXTRA_PARAMS  - optional parameters, can vary in number        *|
00052 |*                                                         *|
00053 |* EXTRA_VARIABLES - names of optional parameter           *|
00054 |*                                                         *|
00055 |* FUNCTION_NAME - alternative name of the non-reentrant function  *|
00056 |*                                                         *|
00057 |* NEED_H_ERRNO  - an extra parameter will be passed to point to   *|
00058 |*               the global `h_errno' variable.            *|
00059 |*                                                         *|
00060 |* NEED__RES     - the global _res variable might be used so we          *|
00061 |*               will have to initialize it if necessary          *|
00062 |*                                                         *|
00063 |* PREPROCESS    - code run before anything else           *|
00064 |*                                                         *|
00065 |* POSTPROCESS   - code run after the lookup                      *|
00066 |*                                                         *|
00067 \*******************************************************************/
00068 
00069 /* To make the real sources a bit prettier.  */
00070 #define REENTRANT_NAME APPEND_R (FUNCTION_NAME)
00071 #ifdef FUNCTION2_NAME
00072 # define REENTRANT2_NAME APPEND_R (FUNCTION2_NAME)
00073 #else
00074 # define REENTRANT2_NAME NULL
00075 #endif
00076 #define APPEND_R(name) APPEND_R1 (name)
00077 #define APPEND_R1(name) name##_r
00078 #define INTERNAL(name) INTERNAL1 (name)
00079 #define INTERNAL1(name) __##name
00080 #define NEW(name) NEW1 (name)
00081 #define NEW1(name) __new_##name
00082 
00083 #ifdef USE_NSCD
00084 # define NSCD_NAME ADD_NSCD (REENTRANT_NAME)
00085 # define ADD_NSCD(name) ADD_NSCD1 (name)
00086 # define ADD_NSCD1(name) __nscd_##name
00087 # define NOT_USENSCD_NAME ADD_NOT_NSCDUSE (DATABASE_NAME)
00088 # define ADD_NOT_NSCDUSE(name) ADD_NOT_NSCDUSE1 (name)
00089 # define ADD_NOT_NSCDUSE1(name) __nss_not_use_nscd_##name
00090 #endif
00091 
00092 #define FUNCTION_NAME_STRING STRINGIZE (FUNCTION_NAME)
00093 #define REENTRANT_NAME_STRING STRINGIZE (REENTRANT_NAME)
00094 #ifdef FUNCTION2_NAME
00095 # define REENTRANT2_NAME_STRING STRINGIZE (REENTRANT2_NAME)
00096 #else
00097 # define REENTRANT2_NAME_STRING NULL
00098 #endif
00099 #define DATABASE_NAME_STRING STRINGIZE (DATABASE_NAME)
00100 #define STRINGIZE(name) STRINGIZE1 (name)
00101 #define STRINGIZE1(name) #name
00102 
00103 #ifndef DB_LOOKUP_FCT
00104 # define DB_LOOKUP_FCT CONCAT3_1 (__nss_, DATABASE_NAME, _lookup2)
00105 # define CONCAT3_1(Pre, Name, Post) CONCAT3_2 (Pre, Name, Post)
00106 # define CONCAT3_2(Pre, Name, Post) Pre##Name##Post
00107 #endif
00108 
00109 /* Sometimes we need to store error codes in the `h_errno' variable.  */
00110 #ifdef NEED_H_ERRNO
00111 # define H_ERRNO_PARM , int *h_errnop
00112 # define H_ERRNO_VAR , h_errnop
00113 # define H_ERRNO_VAR_P h_errnop
00114 #else
00115 # define H_ERRNO_PARM
00116 # define H_ERRNO_VAR
00117 # define H_ERRNO_VAR_P NULL
00118 #endif
00119 
00120 #ifndef EXTRA_PARAMS
00121 # define EXTRA_PARAMS
00122 #endif
00123 #ifndef EXTRA_VARIABLES
00124 # define EXTRA_VARIABLES
00125 #endif
00126 
00127 #ifdef HAVE_AF
00128 # define AF_VAL af
00129 #else
00130 # define AF_VAL AF_INET
00131 #endif
00132 
00133 /* Type of the lookup function we need here.  */
00134 typedef enum nss_status (*lookup_function) (ADD_PARAMS, LOOKUP_TYPE *, char *,
00135                                        size_t, int * H_ERRNO_PARM
00136                                        EXTRA_PARAMS);
00137 
00138 /* The lookup function for the first entry of this service.  */
00139 extern int DB_LOOKUP_FCT (service_user **nip, const char *name,
00140                        const char *name2, void **fctp)
00141      internal_function;
00142 libc_hidden_proto (DB_LOOKUP_FCT)
00143 
00144 
00145 int
00146 INTERNAL (REENTRANT_NAME) (ADD_PARAMS, LOOKUP_TYPE *resbuf, char *buffer,
00147                         size_t buflen, LOOKUP_TYPE **result H_ERRNO_PARM
00148                         EXTRA_PARAMS)
00149 {
00150   static bool startp_initialized;
00151   static service_user *startp;
00152   static lookup_function start_fct;
00153   service_user *nip;
00154   union
00155   {
00156     lookup_function l;
00157     void *ptr;
00158   } fct;
00159 
00160   int no_more;
00161   enum nss_status status = NSS_STATUS_UNAVAIL;
00162 #ifdef USE_NSCD
00163   int nscd_status;
00164 #endif
00165 #ifdef NEED_H_ERRNO
00166   bool any_service = false;
00167 #endif
00168 
00169 #ifdef PREPROCESS
00170   PREPROCESS;
00171 #endif
00172 
00173 #ifdef HANDLE_DIGITS_DOTS
00174   switch (__nss_hostname_digits_dots (name, resbuf, &buffer, NULL,
00175                                   buflen, result, &status, AF_VAL,
00176                                   H_ERRNO_VAR_P))
00177     {
00178     case -1:
00179       return errno;
00180     case 1:
00181       goto done;
00182     }
00183 #endif
00184 
00185 #ifdef USE_NSCD
00186   if (NOT_USENSCD_NAME > 0 && ++NOT_USENSCD_NAME > NSS_NSCD_RETRY)
00187     NOT_USENSCD_NAME = 0;
00188 
00189   if (!NOT_USENSCD_NAME)
00190     {
00191       nscd_status = NSCD_NAME (ADD_VARIABLES, resbuf, buffer, buflen, result
00192                             H_ERRNO_VAR);
00193       if (nscd_status >= 0)
00194        return nscd_status;
00195     }
00196 #endif
00197 
00198   if (! startp_initialized)
00199     {
00200       no_more = DB_LOOKUP_FCT (&nip, REENTRANT_NAME_STRING,
00201                             REENTRANT2_NAME_STRING, &fct.ptr);
00202       if (no_more)
00203        {
00204          void *tmp_ptr = (service_user *) -1l;
00205          PTR_MANGLE (tmp_ptr);
00206          startp = tmp_ptr;
00207        }
00208       else
00209        {
00210 #ifdef NEED__RES
00211          /* The resolver code will really be used so we have to
00212             initialize it.  */
00213          if (__res_maybe_init (&_res, 0) == -1)
00214            {
00215              *h_errnop = NETDB_INTERNAL;
00216              *result = NULL;
00217              return errno;
00218            }
00219 #endif /* need _res */
00220 #ifdef NEED__RES_HCONF
00221          if (!_res_hconf.initialized)
00222            _res_hconf_init ();
00223 #endif /* need _res_hconf */
00224 
00225          void *tmp_ptr = fct.l;
00226          PTR_MANGLE (tmp_ptr);
00227          start_fct = tmp_ptr;
00228          tmp_ptr = nip;
00229          PTR_MANGLE (tmp_ptr);
00230          startp = tmp_ptr;
00231        }
00232 
00233       /* Make sure start_fct and startp are written before
00234         startp_initialized.  */
00235       atomic_write_barrier ();
00236       startp_initialized = true;
00237     }
00238   else
00239     {
00240       fct.l = start_fct;
00241       PTR_DEMANGLE (fct.l);
00242       nip = startp;
00243       PTR_DEMANGLE (nip);
00244       no_more = nip == (service_user *) -1l;
00245     }
00246 
00247   while (no_more == 0)
00248     {
00249 #ifdef NEED_H_ERRNO
00250       any_service = true;
00251 #endif
00252 
00253       status = DL_CALL_FCT (fct.l, (ADD_VARIABLES, resbuf, buffer, buflen,
00254                                 &errno H_ERRNO_VAR EXTRA_VARIABLES));
00255 
00256       /* The status is NSS_STATUS_TRYAGAIN and errno is ERANGE the
00257         provided buffer is too small.  In this case we should give
00258         the user the possibility to enlarge the buffer and we should
00259         not simply go on with the next service (even if the TRYAGAIN
00260         action tells us so).  */
00261       if (status == NSS_STATUS_TRYAGAIN
00262 #ifdef NEED_H_ERRNO
00263          && *h_errnop == NETDB_INTERNAL
00264 #endif
00265          && errno == ERANGE)
00266        break;
00267 
00268       no_more = __nss_next2 (&nip, REENTRANT_NAME_STRING,
00269                           REENTRANT2_NAME_STRING, &fct.ptr, status, 0);
00270     }
00271 
00272 #ifdef HANDLE_DIGITS_DOTS
00273 done:
00274 #endif
00275   *result = status == NSS_STATUS_SUCCESS ? resbuf : NULL;
00276 #ifdef NEED_H_ERRNO
00277   if (status != NSS_STATUS_SUCCESS && ! any_service)
00278     /* We were not able to use any service.  */
00279     *h_errnop = NO_RECOVERY;
00280 #endif
00281 #ifdef POSTPROCESS
00282   POSTPROCESS;
00283 #endif
00284 
00285   int res;
00286   if (status == NSS_STATUS_SUCCESS || status == NSS_STATUS_NOTFOUND)
00287     res = 0;
00288   /* Don't pass back ERANGE if this is not for a too-small buffer.  */
00289   else if (errno == ERANGE && status != NSS_STATUS_TRYAGAIN)
00290     res = EINVAL;
00291 #ifdef NEED_H_ERRNO
00292   /* These functions only set errno if h_errno is NETDB_INTERNAL.  */
00293   else if (status == NSS_STATUS_TRYAGAIN && *h_errnop != NETDB_INTERNAL)
00294     res = EAGAIN;
00295 #endif
00296   else
00297     return errno;
00298 
00299   __set_errno (res);
00300   return res;
00301 }
00302 
00303 
00304 #ifndef FUNCTION2_NAME
00305 # include <shlib-compat.h>
00306 # if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_1_2)
00307 #  define OLD(name) OLD1 (name)
00308 #  define OLD1(name) __old_##name
00309 
00310 int
00311 attribute_compat_text_section
00312 OLD (REENTRANT_NAME) (ADD_PARAMS, LOOKUP_TYPE *resbuf, char *buffer,
00313                     size_t buflen, LOOKUP_TYPE **result H_ERRNO_PARM)
00314 {
00315   int ret = INTERNAL (REENTRANT_NAME) (ADD_VARIABLES, resbuf, buffer,
00316                                    buflen, result H_ERRNO_VAR);
00317 
00318   if (ret != 0 || result == NULL)
00319     ret = -1;
00320 
00321   return ret;
00322 }
00323 
00324 #  define do_symbol_version(real, name, version) \
00325   compat_symbol (libc, real, name, version)
00326 do_symbol_version (OLD (REENTRANT_NAME), REENTRANT_NAME, GLIBC_2_0);
00327 # endif
00328 
00329 /* As INTERNAL (REENTRANT_NAME) may be hidden, we need an alias
00330    in between so that the REENTRANT_NAME@@GLIBC_2.1.2 is not
00331    hidden too.  */
00332 strong_alias (INTERNAL (REENTRANT_NAME), NEW (REENTRANT_NAME));
00333 
00334 # define do_default_symbol_version(real, name, version) \
00335   versioned_symbol (libc, real, name, version)
00336 do_default_symbol_version (NEW (REENTRANT_NAME),
00337                         REENTRANT_NAME, GLIBC_2_1_2);
00338 #endif
00339 
00340 static_link_warning (REENTRANT_NAME)