(linenum→info "unix/slp.c:2238")

glibc/2.7/nss/getXXbyYY_r.c

    1: /* Copyright (C) 1996-2004, 2006, 2007 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 Lesser General Public
    7:    License as published by the Free Software Foundation; either
    8:    version 2.1 of the 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:    Lesser General Public License for more details.
   14: 
   15:    You should have received a copy of the GNU Lesser General Public
   16:    License along with the GNU C Library; if not, write to the Free
   17:    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
   18:    02111-1307 USA.  */
   19: 
   20: #include <assert.h>
   21: #include <atomic.h>
   22: #include <errno.h>
   23: #include <stdbool.h>
   24: #include "nsswitch.h"
   25: #include "sysdep.h"
   26: #ifdef USE_NSCD
   27: # include <nscd/nscd_proto.h>
   28: #endif
   29: #ifdef NEED__RES_HCONF
   30: # include <resolv/res_hconf.h>
   31: #endif
   32: #ifdef NEED__RES
   33: # include <resolv.h>
   34: #endif
   35: /*******************************************************************\
   36: |* Here we assume several symbols to be defined:                   *|
   37: |*                                                                 *|
   38: |* LOOKUP_TYPE   - the return type of the function                 *|
   39: |*                                                                 *|
   40: |* FUNCTION_NAME - name of the non-reentrant function              *|
   41: |*                                                                 *|
   42: |* DATABASE_NAME - name of the database the function accesses      *|
   43: |*                 (e.g., host, services, ...)                         *|
   44: |*                                                                 *|
   45: |* ADD_PARAMS    - additional parameter, can vary in number        *|
   46: |*                                                                 *|
   47: |* ADD_VARIABLES - names of additional parameter                   *|
   48: |*                                                                 *|
   49: |* Optionally the following vars can be defined:                   *|
   50: |*                                                                 *|
   51: |* NEED_H_ERRNO  - an extra parameter will be passed to point to   *|
   52: |*                 the global `h_errno' variable.              *|
   53: |*                                                                 *|
   54: |* NEED__RES     - the global _res variable might be used so we    *|
   55: |*                 will have to initialize it if necessary     *|
   56: |*                                                                 *|
   57: |* PREPROCESS    - code run before anything else                   *|
   58: |*                                                                 *|
   59: |* POSTPROCESS   - code run after the lookup                       *|
   60: |*                                                                 *|
   61: \*******************************************************************/
   62: 
   63: /* To make the real sources a bit prettier.  */
   64: #define REENTRANT_NAME APPEND_R (FUNCTION_NAME)
   65: #define APPEND_R(name) APPEND_R1 (name)
   66: #define APPEND_R1(name) name##_r
   67: #define INTERNAL(name) INTERNAL1 (name)
   68: #define INTERNAL1(name) __##name
   69: #define NEW(name) NEW1 (name)
   70: #define NEW1(name) __new_##name
   71: 
   72: #ifdef USE_NSCD
   73: # define NSCD_NAME ADD_NSCD (REENTRANT_NAME)
   74: # define ADD_NSCD(name) ADD_NSCD1 (name)
   75: # define ADD_NSCD1(name) __nscd_##name
   76: # define NOT_USENSCD_NAME ADD_NOT_NSCDUSE (DATABASE_NAME)
   77: # define ADD_NOT_NSCDUSE(name) ADD_NOT_NSCDUSE1 (name)
   78: # define ADD_NOT_NSCDUSE1(name) __nss_not_use_nscd_##name
   79: #endif
   80: 
   81: #define FUNCTION_NAME_STRING STRINGIZE (FUNCTION_NAME)
   82: #define REENTRANT_NAME_STRING STRINGIZE (REENTRANT_NAME)
   83: #define DATABASE_NAME_STRING STRINGIZE (DATABASE_NAME)
   84: #define STRINGIZE(name) STRINGIZE1 (name)
   85: #define STRINGIZE1(name) #name
   86: 
   87: #ifndef DB_LOOKUP_FCT
   88: # define DB_LOOKUP_FCT CONCAT3_1 (__nss_, DATABASE_NAME, _lookup)
   89: # define CONCAT3_1(Pre, Name, Post) CONCAT3_2 (Pre, Name, Post)
   90: # define CONCAT3_2(Pre, Name, Post) Pre##Name##Post
   91: #endif
   92: 
   93: /* Sometimes we need to store error codes in the `h_errno' variable.  */
   94: #ifdef NEED_H_ERRNO
   95: # define H_ERRNO_PARM , int *h_errnop
   96: # define H_ERRNO_VAR , h_errnop
   97: # define H_ERRNO_VAR_P h_errnop
   98: #else
   99: # define H_ERRNO_PARM
  100: # define H_ERRNO_VAR
  101: # define H_ERRNO_VAR_P NULL
  102: #endif
  103: 
  104: #ifdef HAVE_AF
  105: # define AF_VAL af
  106: #else
  107: # define AF_VAL AF_INET
  108: #endif
  109: 
  110: /* Type of the lookup function we need here.  */
  111: typedef enum nss_status (*lookup_function) (ADD_PARAMS, LOOKUP_TYPE *, char *,
  112:                                             size_t, int * H_ERRNO_PARM);
  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:      internal_function;
  117: libc_hidden_proto (DB_LOOKUP_FCT)
  118: 
  119: 
  120: int
  121: INTERNAL (REENTRANT_NAME) (ADD_PARAMS, LOOKUP_TYPE *resbuf, char *buffer,
  122:                            size_t buflen, LOOKUP_TYPE **result H_ERRNO_PARM)
  123: {
  124:   static bool startp_initialized;
  125:   static service_user *startp;
  126:   static lookup_function start_fct;
  127:   service_user *nip;
  128:   union
  129:   {
  130:     lookup_function l;
  131:     void *ptr;
  132:   } fct;
  133: 
  134:   int no_more;
  135:   enum nss_status status = NSS_STATUS_UNAVAIL;
  136: #ifdef USE_NSCD
  137:   int nscd_status;
  138: #endif
  139: #ifdef NEED_H_ERRNO
  140:   bool any_service = false;
  141: #endif
  142: 
  143: #ifdef PREPROCESS
  144:   PREPROCESS;
  145: #endif
  146: 
  147: #ifdef HANDLE_DIGITS_DOTS
  148:   switch (__nss_hostname_digits_dots (name, resbuf, &buffer, NULL,
  149:                                       buflen, result, &status, AF_VAL,
  150:                                       H_ERRNO_VAR_P))
  151:     {
  152:     case -1:
  153:       return errno;
  154:     case 1:
  155:       goto done;
  156:     }
  157: #endif
  158: 
  159: #ifdef USE_NSCD
  160:   if (NOT_USENSCD_NAME > 0 && ++NOT_USENSCD_NAME > NSS_NSCD_RETRY)
  161:     NOT_USENSCD_NAME = 0;
  162: 
  163:   if (!NOT_USENSCD_NAME)
  164:     {
  165:       nscd_status = NSCD_NAME (ADD_VARIABLES, resbuf, buffer, buflen, result
  166:                                H_ERRNO_VAR);
  167:       if (nscd_status >= 0)
  168:         return nscd_status;
  169:     }
  170: #endif
  171: 
  172:   if (! startp_initialized)
  173:     {
  174:       no_more = DB_LOOKUP_FCT (&nip, REENTRANT_NAME_STRING, &fct.ptr);
  175:       if (no_more)
  176:         {
  177:           void *tmp_ptr = (service_user *) -1l;
  178:           PTR_MANGLE (tmp_ptr);
  179:           startp = tmp_ptr;
  180:         }
  181:       else
  182:         {
  183: #ifdef NEED__RES
  184:           /* The resolver code will really be used so we have to
  185:              initialize it.  */
  186:           if (__res_maybe_init (&_res, 0) == -1)
  187:             {
  188:               *h_errnop = NETDB_INTERNAL;
  189:               *result = NULL;
  190:               return errno;
  191:             }
  192: #endif /* need _res */
  193: #ifdef NEED__RES_HCONF
  194:           if (!_res_hconf.initialized)
  195:             _res_hconf_init ();
  196: #endif /* need _res_hconf */
  197: 
  198:           void *tmp_ptr = fct.l;
  199:           PTR_MANGLE (tmp_ptr);
  200:           start_fct = tmp_ptr;
  201:           tmp_ptr = nip;
  202:           PTR_MANGLE (tmp_ptr);
  203:           startp = tmp_ptr;
  204:         }
  205: 
  206:       /* Make sure start_fct and startp are written before
  207:          startp_initialized.  */
  208:       atomic_write_barrier ();
  209:       startp_initialized = true;
  210:     }
  211:   else
  212:     {
  213:       fct.l = start_fct;
  214:       PTR_DEMANGLE (fct.l);
  215:       nip = startp;
  216:       PTR_DEMANGLE (nip);
  217:       no_more = nip == (service_user *) -1l;
  218:     }
  219: 
  220:   while (no_more == 0)
  221:     {
  222: #ifdef NEED_H_ERRNO
  223:       any_service = true;
  224: #endif
  225: 
  226:       status = DL_CALL_FCT (fct.l, (ADD_VARIABLES, resbuf, buffer, buflen,
  227:                                     &errno H_ERRNO_VAR));
  228: 
  229:       /* The status is NSS_STATUS_TRYAGAIN and errno is ERANGE the
  230:          provided buffer is too small.  In this case we should give
  231:          the user the possibility to enlarge the buffer and we should
  232:          not simply go on with the next service (even if the TRYAGAIN
  233:          action tells us so).  */
  234:       if (status == NSS_STATUS_TRYAGAIN
  235: #ifdef NEED_H_ERRNO
  236:           && *h_errnop == NETDB_INTERNAL
  237: #endif
  238:           && errno == ERANGE)
  239:         break;
  240: 
  241:       no_more = __nss_next (&nip, REENTRANT_NAME_STRING,
  242:                             &fct.ptr, status, 0);
  243:     }
  244: 
  245: #ifdef HANDLE_DIGITS_DOTS
  246: done:
  247: #endif
  248:   *result = status == NSS_STATUS_SUCCESS ? resbuf : NULL;
  249: #ifdef NEED_H_ERRNO
  250:   if (status != NSS_STATUS_SUCCESS && ! any_service)
  251:     /* We were not able to use any service.  */
  252:     *h_errnop = NO_RECOVERY;
  253: #endif
  254: #ifdef POSTPROCESS
  255:   POSTPROCESS;
  256: #endif
  257: 
  258:   int res;
  259:   if (status == NSS_STATUS_SUCCESS || status == NSS_STATUS_NOTFOUND)
  260:     res = 0;
  261:   /* Don't pass back ERANGE if this is not for a too-small buffer.  */
  262:   else if (errno == ERANGE && status != NSS_STATUS_TRYAGAIN)
  263:     res = EINVAL;
  264: #ifdef NEED_H_ERRNO
  265:   /* These functions only set errno if h_errno is NETDB_INTERNAL.  */
  266:   else if (status == NSS_STATUS_TRYAGAIN && *h_errnop != NETDB_INTERNAL)
  267:     res = EAGAIN;
  268: #endif
  269:   else
  270:     return errno;
  271: 
  272:   __set_errno (res);
  273:   return res;
  274: }
  275: 
  276: 
  277: #include <shlib-compat.h>
  278: #if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_1_2)
  279: #define OLD(name) OLD1 (name)
  280: #define OLD1(name) __old_##name
  281: 
  282: int
  283: attribute_compat_text_section
  284: OLD (REENTRANT_NAME) (ADD_PARAMS, LOOKUP_TYPE *resbuf, char *buffer,
  285:                       size_t buflen, LOOKUP_TYPE **result H_ERRNO_PARM)
  286: {
  287:   int ret = INTERNAL (REENTRANT_NAME) (ADD_VARIABLES, resbuf, buffer,
  288:                                        buflen, result H_ERRNO_VAR);
  289: 
  290:   if (ret != 0 || result == NULL)
  291:     ret = -1;
  292: 
  293:   return ret;
  294: }
  295: 
  296: #define do_symbol_version(real, name, version) \
  297:   compat_symbol (libc, real, name, version)
  298: do_symbol_version (OLD (REENTRANT_NAME), REENTRANT_NAME, GLIBC_2_0);
  299: #endif
  300: 
  301: /* As INTERNAL (REENTRANT_NAME) may be hidden, we need an alias
  302:    in between so that the REENTRANT_NAME@@GLIBC_2.1.2 is not
  303:    hidden too.  */
  304: strong_alias (INTERNAL (REENTRANT_NAME), NEW (REENTRANT_NAME));
  305: 
  306: #define do_default_symbol_version(real, name, version) \
  307:   versioned_symbol (libc, real, name, version)
  308: do_default_symbol_version (NEW (REENTRANT_NAME),
  309:                            REENTRANT_NAME, GLIBC_2_1_2);
  310: 
  311: static_link_warning (REENTRANT_NAME)
Syntax (Markdown)