Back to index

glibc  2.9
db-XXX.c
Go to the documentation of this file.
00001 /* Common code for DB-based databases in nss_db module.
00002    Copyright (C) 1996, 1997, 1998, 1999, 2000 Free Software Foundation, Inc.
00003    This file is part of the GNU C Library.
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 <dlfcn.h>
00021 #include <fcntl.h>
00022 #include <bits/libc-lock.h>
00023 #include "nsswitch.h"
00024 #include "nss_db.h"
00025 
00026 /* These symbols are defined by the including source file:
00027 
00028    ENTNAME -- database name of the structure and functions (hostent, pwent).
00029    STRUCTURE -- struct name, define only if not ENTNAME (passwd, group).
00030    DATABASE -- database file name, ("hosts", "passwd")
00031 
00032    NEED_H_ERRNO - defined iff an arg `int *herrnop' is used.
00033 */
00034 
00035 #define ENTNAME_r    CONCAT(ENTNAME,_r)
00036 
00037 #include <paths.h>
00038 #define       DBFILE        _PATH_VARDB DATABASE ".db"
00039 
00040 #ifdef NEED_H_ERRNO
00041 #define H_ERRNO_PROTO       , int *herrnop
00042 #define H_ERRNO_ARG  , herrnop
00043 #define H_ERRNO_SET(val) (*herrnop = (val))
00044 #else
00045 #define H_ERRNO_PROTO
00046 #define H_ERRNO_ARG
00047 #define H_ERRNO_SET(val) ((void) 0)
00048 #endif
00049 
00050 /* Locks the static variables in this file.  */
00051 __libc_lock_define_initialized (static, lock)
00052 
00053 /* Maintenance of the shared handle open on the database.  */
00054 
00055 static NSS_DB *db;
00056 static int keep_db;
00057 static int entidx;
00058 
00059 
00060 /* Open the database.  */
00061 enum nss_status
00062 CONCAT(_nss_db_set,ENTNAME) (int stayopen)
00063 {
00064   enum nss_status status;
00065 
00066   __libc_lock_lock (lock);
00067 
00068   status = internal_setent (DBFILE, &db);
00069 
00070   /* Remember STAYOPEN flag.  */
00071   if (db != NULL)
00072     keep_db |= stayopen;
00073   /* Reset the sequential index.  */
00074   entidx = 0;
00075 
00076   __libc_lock_unlock (lock);
00077 
00078   return status;
00079 }
00080 
00081 
00082 /* Close it again.  */
00083 enum nss_status
00084 CONCAT(_nss_db_end,ENTNAME) (void)
00085 {
00086   __libc_lock_lock (lock);
00087 
00088   internal_endent (&db);
00089 
00090   /* Reset STAYOPEN flag.  */
00091   keep_db = 0;
00092 
00093   __libc_lock_unlock (lock);
00094 
00095   return NSS_STATUS_SUCCESS;
00096 }
00097 
00098 /* Do a database lookup for KEY.  */
00099 static enum nss_status
00100 lookup (DBT *key, struct STRUCTURE *result,
00101        void *buffer, size_t buflen, int *errnop H_ERRNO_PROTO EXTRA_ARGS_DECL)
00102 {
00103   char *p;
00104   enum nss_status status;
00105   int err;
00106   DBT value;
00107 
00108   /* Open the database.  */
00109   if (db == NULL)
00110     {
00111       status = internal_setent (DBFILE, &db);
00112       if (status != NSS_STATUS_SUCCESS)
00113        {
00114          *errnop = errno;
00115          H_ERRNO_SET (NETDB_INTERNAL);
00116          return status;
00117        }
00118     }
00119 
00120   /* Succeed iff it matches a value that parses correctly.  */
00121   value.flags = 0;
00122   err = DL_CALL_FCT (db->get, (db->db, NULL, key, &value, 0));
00123   if (err != 0)
00124     {
00125       if (err == db_notfound)
00126        {
00127          H_ERRNO_SET (HOST_NOT_FOUND);
00128          status = NSS_STATUS_NOTFOUND;
00129        }
00130       else
00131        {
00132          *errnop = err;
00133          H_ERRNO_SET (NETDB_INTERNAL);
00134          status = NSS_STATUS_UNAVAIL;
00135        }
00136     }
00137   else if (buflen < value.size)
00138     {
00139       /* No room to copy the data to.  */
00140       *errnop = ERANGE;
00141       H_ERRNO_SET (NETDB_INTERNAL);
00142       status = NSS_STATUS_TRYAGAIN;
00143     }
00144   else
00145     {
00146       /* Copy the result to a safe place.  */
00147       p = (char *) memcpy (buffer, value.data, value.size);
00148 
00149       /* Skip leading blanks.  */
00150       while (isspace (*p))
00151        ++p;
00152 
00153       err = parse_line (p, result, buffer, buflen, errnop EXTRA_ARGS);
00154 
00155       if (err == 0)
00156        {
00157          /* If the key begins with '0' we are trying to get the next
00158             entry.  We want to ignore unparsable lines in this case.  */
00159          if (((char *) key->data)[0] == '0')
00160            {
00161              /* Super magical return value.  We need to tell our caller
00162                that it should continue looping.  This value cannot
00163                happen in other cases.  */
00164              status = NSS_STATUS_RETURN;
00165            }
00166          else
00167            {
00168              H_ERRNO_SET (HOST_NOT_FOUND);
00169              status = NSS_STATUS_NOTFOUND;
00170            }
00171        }
00172       else if (err < 0)
00173        {
00174          H_ERRNO_SET (NETDB_INTERNAL);
00175          status = NSS_STATUS_TRYAGAIN;
00176        }
00177       else
00178        status = NSS_STATUS_SUCCESS;
00179     }
00180 
00181   if (! keep_db)
00182     internal_endent (&db);
00183 
00184   return status;
00185 }
00186 
00187 
00188 /* Macro for defining lookup functions for this DB-based database.
00189 
00190    NAME is the name of the lookup; e.g. `pwnam'.
00191 
00192    KEYPATTERN gives `printf' args to construct a key string;
00193    e.g. `(".%s", name)'.
00194 
00195    KEYSIZE gives the allocation size of a buffer to construct it in;
00196    e.g. `1 + strlen (name)'.
00197 
00198    PROTO describes the arguments for the lookup key;
00199    e.g. `const char *name'.
00200 
00201    BREAK_IF_MATCH is ignored, but used by ../nss_files/files-XXX.c.  */
00202 
00203 #define DB_LOOKUP(name, keysize, keypattern, break_if_match, proto...)             \
00204 enum nss_status                                                             \
00205 _nss_db_get##name##_r (proto,                                               \
00206                      struct STRUCTURE *result,                       \
00207                      char *buffer, size_t buflen, int *errnop H_ERRNO_PROTO)\
00208 {                                                                    \
00209   DBT key;                                                           \
00210   enum nss_status status;                                            \
00211   const size_t size = (keysize) + 1;                                        \
00212   key.data = __alloca (size);                                               \
00213   key.size = KEYPRINTF keypattern;                                   \
00214   key.flags = 0;                                                     \
00215   __libc_lock_lock (lock);                                           \
00216   status = lookup (&key, result, buffer, buflen, errnop H_ERRNO_ARG         \
00217                  EXTRA_ARGS_VALUE);                                         \
00218   __libc_lock_unlock (lock);                                                \
00219   return status;                                                     \
00220 }
00221 
00222 #define KEYPRINTF(pattern, args...) snprintf (key.data, size, pattern ,##args)
00223 
00224 
00225 
00226 
00227 /* Return the next entry from the database file, doing locking.  */
00228 enum nss_status
00229 CONCAT(_nss_db_get,ENTNAME_r) (struct STRUCTURE *result, char *buffer,
00230                             size_t buflen, int *errnop H_ERRNO_PROTO)
00231 {
00232   /* Return next entry in host file.  */
00233   enum nss_status status;
00234   char buf[20];
00235   DBT key;
00236 
00237   __libc_lock_lock (lock);
00238 
00239   /* Loop until we find a valid entry or hit EOF.  See above for the
00240      special meaning of the status value.  */
00241   do
00242     {
00243       key.size = snprintf (key.data = buf, sizeof buf, "0%u", entidx++);
00244       key.flags = 0;
00245       status = lookup (&key, result, buffer, buflen, errnop H_ERRNO_ARG
00246                      EXTRA_ARGS_VALUE);
00247       if (status == NSS_STATUS_TRYAGAIN
00248 #ifdef NEED_H_ERRNO
00249          && *herrnop == NETDB_INTERNAL
00250 #endif
00251          && *errnop == ERANGE)
00252        /* Give the user a chance to get the same entry with a larger
00253           buffer.  */
00254        --entidx;
00255     }
00256   while (status == NSS_STATUS_RETURN);
00257 
00258   __libc_lock_unlock (lock);
00259 
00260   return status;
00261 }