diff options
author | Ulrich Drepper <drepper@gmail.com> | 2011-06-14 22:21:51 -0400 |
---|---|---|
committer | Ulrich Drepper <drepper@gmail.com> | 2011-06-15 21:06:18 -0400 |
commit | 2666d441c2d8107b1987b869714189af64b954c6 (patch) | |
tree | c7b8877d691db280202b4c7655907a1165ec84fc /nss/nss_db | |
parent | Rewrite makedb to avoid using db library (diff) | |
download | glibc-2666d441c2d8107b1987b869714189af64b954c6.tar.gz glibc-2666d441c2d8107b1987b869714189af64b954c6.tar.bz2 glibc-2666d441c2d8107b1987b869714189af64b954c6.zip |
Reenable nss_db with a completely new implementation
No longer is Berkeley db used. Instead a simple hash function is used.
The database files are not updated once they are created and therefore
no complicated database is needed.
Diffstat (limited to 'nss/nss_db')
-rw-r--r-- | nss/nss_db/db-XXX.c | 332 | ||||
-rw-r--r-- | nss/nss_db/db-alias.c | 215 | ||||
-rw-r--r-- | nss/nss_db/db-netgrp.c | 94 | ||||
-rw-r--r-- | nss/nss_db/db-open.c | 377 | ||||
-rw-r--r-- | nss/nss_db/dummy-db.h | 333 | ||||
-rw-r--r-- | nss/nss_db/nss_db.h | 96 |
6 files changed, 309 insertions, 1138 deletions
diff --git a/nss/nss_db/db-XXX.c b/nss/nss_db/db-XXX.c index aa8cfd0746..30026b1866 100644 --- a/nss/nss_db/db-XXX.c +++ b/nss/nss_db/db-XXX.c @@ -1,5 +1,5 @@ /* Common code for DB-based databases in nss_db module. - Copyright (C) 1996, 1997, 1998, 1999, 2000 Free Software Foundation, Inc. + Copyright (C) 1996-2000, 2011 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or @@ -19,10 +19,14 @@ #include <dlfcn.h> #include <fcntl.h> +#include <sys/mman.h> #include <bits/libc-lock.h> #include "nsswitch.h" #include "nss_db.h" +/* The hashing function we use. */ +#include "../intl/hash-string.h" + /* These symbols are defined by the including source file: ENTNAME -- database name of the structure and functions (hostent, pwent). @@ -38,25 +42,25 @@ #define DBFILE _PATH_VARDB DATABASE ".db" #ifdef NEED_H_ERRNO -#define H_ERRNO_PROTO , int *herrnop -#define H_ERRNO_ARG , herrnop -#define H_ERRNO_SET(val) (*herrnop = (val)) +# define H_ERRNO_PROTO , int *herrnop +# define H_ERRNO_ARG , herrnop +# define H_ERRNO_SET(val) (*herrnop = (val)) #else -#define H_ERRNO_PROTO -#define H_ERRNO_ARG -#define H_ERRNO_SET(val) ((void) 0) +# define H_ERRNO_PROTO +# define H_ERRNO_ARG +# define H_ERRNO_SET(val) ((void) 0) #endif -/* Locks the static variables in this file. */ -__libc_lock_define_initialized (static, lock) - -/* Maintenance of the shared handle open on the database. */ +/* State for this database. */ +static struct nss_db_map state; +/* Lock to protect the state and global variables. */ +__libc_lock_define (static , lock); -static NSS_DB *db; +/* Maintenance of the shared handle open on the database. */ static int keep_db; -static int entidx; - +static const char *entidx; + /* Open the database. */ enum nss_status CONCAT(_nss_db_set,ENTNAME) (int stayopen) @@ -65,13 +69,13 @@ CONCAT(_nss_db_set,ENTNAME) (int stayopen) __libc_lock_lock (lock); - status = internal_setent (DBFILE, &db); + status = internal_setent (DBFILE, &state); /* Remember STAYOPEN flag. */ - if (db != NULL) + if (status == NSS_STATUS_SUCCESS) keep_db |= stayopen; /* Reset the sequential index. */ - entidx = 0; + entidx = (const char *) state.header + state.header->valstroffset; __libc_lock_unlock (lock); @@ -85,7 +89,7 @@ CONCAT(_nss_db_end,ENTNAME) (void) { __libc_lock_lock (lock); - internal_endent (&db); + internal_endent (&state); /* Reset STAYOPEN flag. */ keep_db = 0; @@ -94,132 +98,128 @@ CONCAT(_nss_db_end,ENTNAME) (void) return NSS_STATUS_SUCCESS; } - -/* Do a database lookup for KEY. */ -static enum nss_status -lookup (DBT *key, struct STRUCTURE *result, - void *buffer, size_t buflen, int *errnop H_ERRNO_PROTO EXTRA_ARGS_DECL) -{ - char *p; - enum nss_status status; - int err; - DBT value; - - /* Open the database. */ - if (db == NULL) - { - status = internal_setent (DBFILE, &db); - if (status != NSS_STATUS_SUCCESS) - { - *errnop = errno; - H_ERRNO_SET (NETDB_INTERNAL); - return status; - } - } - - /* Succeed iff it matches a value that parses correctly. */ - value.flags = 0; - err = DL_CALL_FCT (db->get, (db->db, NULL, key, &value, 0)); - if (err != 0) - { - if (err == db_notfound) - { - H_ERRNO_SET (HOST_NOT_FOUND); - status = NSS_STATUS_NOTFOUND; - } - else - { - *errnop = err; - H_ERRNO_SET (NETDB_INTERNAL); - status = NSS_STATUS_UNAVAIL; - } - } - else if (buflen < value.size) - { - /* No room to copy the data to. */ - *errnop = ERANGE; - H_ERRNO_SET (NETDB_INTERNAL); - status = NSS_STATUS_TRYAGAIN; - } - else - { - /* Copy the result to a safe place. */ - p = (char *) memcpy (buffer, value.data, value.size); - - /* Skip leading blanks. */ - while (isspace (*p)) - ++p; - - err = parse_line (p, result, buffer, buflen, errnop EXTRA_ARGS); - - if (err == 0) - { - /* If the key begins with '0' we are trying to get the next - entry. We want to ignore unparsable lines in this case. */ - if (((char *) key->data)[0] == '0') - { - /* Super magical return value. We need to tell our caller - that it should continue looping. This value cannot - happen in other cases. */ - status = NSS_STATUS_RETURN; - } - else - { - H_ERRNO_SET (HOST_NOT_FOUND); - status = NSS_STATUS_NOTFOUND; - } - } - else if (err < 0) - { - H_ERRNO_SET (NETDB_INTERNAL); - status = NSS_STATUS_TRYAGAIN; - } - else - status = NSS_STATUS_SUCCESS; - } - - if (! keep_db) - internal_endent (&db); - - return status; -} /* Macro for defining lookup functions for this DB-based database. NAME is the name of the lookup; e.g. `pwnam'. + DB_CHAR is index indicator for the database. + KEYPATTERN gives `printf' args to construct a key string; - e.g. `(".%s", name)'. + e.g. `("%d", id)'. KEYSIZE gives the allocation size of a buffer to construct it in; - e.g. `1 + strlen (name)'. + e.g. `1 + sizeof (id) * 4'. - PROTO describes the arguments for the lookup key; - e.g. `const char *name'. + PROTO is the potentially empty list of other parameters. - BREAK_IF_MATCH is ignored, but used by ../nss_files/files-XXX.c. */ + BREAK_IF_MATCH is a block of code which compares `struct STRUCTURE *result' + to the lookup key arguments and does `break;' if they match. */ -#define DB_LOOKUP(name, keysize, keypattern, break_if_match, proto...) \ +#define DB_LOOKUP(name, db_char, keysize, keypattern, break_if_match, proto...)\ enum nss_status \ -_nss_db_get##name##_r (proto, \ - struct STRUCTURE *result, \ - char *buffer, size_t buflen, int *errnop H_ERRNO_PROTO)\ + _nss_db_get##name##_r (proto, struct STRUCTURE *result, \ + char *buffer, size_t buflen, int *errnop H_ERRNO_PROTO)\ { \ - DBT key; \ - enum nss_status status; \ - const size_t size = (keysize) + 1; \ - key.data = __alloca (size); \ - key.size = KEYPRINTF keypattern; \ - key.flags = 0; \ - __libc_lock_lock (lock); \ - status = lookup (&key, result, buffer, buflen, errnop H_ERRNO_ARG \ - EXTRA_ARGS_VALUE); \ - __libc_lock_unlock (lock); \ + enum nss_status status = NSS_STATUS_SUCCESS; \ + struct nss_db_map state = { NULL, 0 }; \ + struct parser_data *data = (void *) buffer; \ + \ + if (buflen < sizeof *data) \ + { \ + *errnop = ERANGE; \ + H_ERRNO_SET (NETDB_INTERNAL); \ + return NSS_STATUS_TRYAGAIN; \ + } \ + \ + status = internal_setent (DBFILE, &state); \ + if (status != NSS_STATUS_SUCCESS) \ + { \ + *errnop = errno; \ + H_ERRNO_SET (NETDB_INTERNAL); \ + return status; \ + } \ + \ + if (status == NSS_STATUS_SUCCESS) \ + { \ + const struct nss_db_header *header = state.header; \ + int i; \ + for (i = 0; i < header->ndbs; ++i) \ + if (header->dbs[i].id == db_char) \ + break; \ + if (i == header->ndbs) \ + { \ + status = NSS_STATUS_UNAVAIL; \ + goto out; \ + } \ + \ + char *key; \ + if (db_char == '.') \ + key = (char *) IGNOREPATTERN keypattern; \ + else \ + { \ + const size_t size = (keysize) + 1; \ + key = alloca (size); \ + \ + KEYPRINTF keypattern; \ + } \ + \ + const stridx_t *hashtable \ + = (const stridx_t *) ((const char *) header \ + + header->dbs[i].hashoffset); \ + const char *valstrtab = (const char *) header + header->valstroffset; \ + uint32_t hashval = __hash_string (key); \ + size_t hidx = hashval % header->dbs[i].hashsize; \ + size_t hval2 = 1 + hashval % (header->dbs[i].hashsize - 2); \ + \ + status = NSS_STATUS_NOTFOUND; \ + while (hashtable[hidx] != ~((stridx_t) 0)) \ + { \ + const char *valstr = valstrtab + hashtable[hidx]; \ + size_t len = strlen (valstr) + 1; \ + if (len > buflen) \ + { \ + /* No room to copy the data to. */ \ + *errnop = ERANGE; \ + H_ERRNO_SET (NETDB_INTERNAL); \ + status = NSS_STATUS_TRYAGAIN; \ + break; \ + } \ + \ + /* Copy the string to a place where it can be modified. */ \ + char *p = memcpy (buffer, valstr, len); \ + \ + int err = parse_line (p, result, data, buflen, errnop \ + EXTRA_ARGS); \ + if (err > 0) \ + { \ + status = NSS_STATUS_SUCCESS; \ + break_if_match; \ + status = NSS_STATUS_NOTFOUND; \ + } \ + else if (err == -1) \ + { \ + H_ERRNO_SET (NETDB_INTERNAL); \ + status = NSS_STATUS_TRYAGAIN; \ + break; \ + } \ + \ + if ((hidx += hval2) >= header->dbs[i].hashsize) \ + hidx -= header->dbs[i].hashsize; \ + } \ + \ + if (status == NSS_STATUS_NOTFOUND) \ + H_ERRNO_SET (HOST_NOT_FOUND); \ + } \ + out: \ + internal_endent (&state); \ + \ return status; \ } -#define KEYPRINTF(pattern, args...) snprintf (key.data, size, pattern ,##args) +#define KEYPRINTF(pattern, args...) snprintf (key, size, pattern ,##args) +#define IGNOREPATTERN(pattern, arg1, args...) (char *) (uintptr_t) arg1 @@ -231,30 +231,72 @@ CONCAT(_nss_db_get,ENTNAME_r) (struct STRUCTURE *result, char *buffer, { /* Return next entry in host file. */ enum nss_status status; - char buf[20]; - DBT key; + struct parser_data *data = (void *) buffer; + + if (buflen < sizeof *data) + { + *errnop = ERANGE; + H_ERRNO_SET (NETDB_INTERNAL); + return NSS_STATUS_TRYAGAIN; + } __libc_lock_lock (lock); - /* Loop until we find a valid entry or hit EOF. See above for the - special meaning of the status value. */ - do + if (state.header == NULL) { - key.size = snprintf (key.data = buf, sizeof buf, "0%u", entidx++); - key.flags = 0; - status = lookup (&key, result, buffer, buflen, errnop H_ERRNO_ARG - EXTRA_ARGS_VALUE); - if (status == NSS_STATUS_TRYAGAIN -#ifdef NEED_H_ERRNO - && *herrnop == NETDB_INTERNAL -#endif - && *errnop == ERANGE) - /* Give the user a chance to get the same entry with a larger - buffer. */ - --entidx; + status = internal_setent (DBFILE, &state); + if (status != NSS_STATUS_SUCCESS) + { + *errnop = errno; + H_ERRNO_SET (NETDB_INTERNAL); + goto out; + } + } + + status = NSS_STATUS_UNAVAIL; + if (state.header != MAP_FAILED) + { + const char *const end = ((const char *) state.header + + state.header->valstroffset + + state.header->valstrlen); + while (entidx < end) + { + const char *next = rawmemchr (entidx, '\0') + 1; + size_t len = next - entidx; + + if (len > buflen) + { + /* No room to copy the data to. */ + *errnop = ERANGE; + H_ERRNO_SET (NETDB_INTERNAL); + status = NSS_STATUS_TRYAGAIN; + break; + } + + /* Copy the string to a place where it can be modified. */ + char *p = memcpy (buffer, entidx, len); + + int err = parse_line (p, result, data, buflen, errnop EXTRA_ARGS); + + if (err > 0) + { + status = NSS_STATUS_SUCCESS; + entidx = next; + break; + } + if (err < 0) + { + H_ERRNO_SET (HOST_NOT_FOUND); + status = NSS_STATUS_NOTFOUND; + break; + } + + /* Continue with the next record, this one is ill-formed. */ + entidx = next; + } } - while (status == NSS_STATUS_RETURN); + out: __libc_lock_unlock (lock); return status; diff --git a/nss/nss_db/db-alias.c b/nss/nss_db/db-alias.c deleted file mode 100644 index de468cc592..0000000000 --- a/nss/nss_db/db-alias.c +++ /dev/null @@ -1,215 +0,0 @@ -/* Mail alias file parser in nss_db module. - Copyright (C) 1996, 1997, 1998, 1999, 2000 Free Software Foundation, Inc. - This file is part of the GNU C Library. - Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 USA. */ - -#include <aliases.h> -#include <alloca.h> -#include <ctype.h> -#include <dlfcn.h> -#include <errno.h> -#include <bits/libc-lock.h> -#include <paths.h> -#include <string.h> - -#include "nsswitch.h" -#include "nss_db.h" - -/* Locks the static variables in this file. */ -__libc_lock_define_initialized (static, lock) - -/* Maintenance of the shared handle open on the database. */ - -static NSS_DB *db; -static int keep_db; -static unsigned int entidx; /* Index for `getaliasent_r'. */ - - -/* Open database. */ -enum nss_status -_nss_db_setaliasent (int stayopen) -{ - enum nss_status status; - - __libc_lock_lock (lock); - - status = internal_setent (_PATH_VARDB "aliases.db", &db); - - /* Remember STAYOPEN flag. */ - if (db != NULL) - keep_db |= stayopen; - - /* Reset the sequential index. */ - entidx = 0; - - __libc_lock_unlock (lock); - - return status; -} - - -/* Close it again. */ -enum nss_status -_nss_db_endaliasent (void) -{ - __libc_lock_lock (lock); - - internal_endent (&db); - - /* Reset STAYOPEN flag. */ - keep_db = 0; - - __libc_lock_unlock (lock); - - return NSS_STATUS_SUCCESS; -} - -/* We provide the parse function here. The parser in libnss_files - cannot be used. The generation of the db file already resolved all - :include: statements so we simply have to parse the list and store - the result. */ -static enum nss_status -lookup (DBT *key, struct aliasent *result, char *buffer, - size_t buflen, int *errnop) -{ - enum nss_status status; - DBT value; - - /* Open the database. */ - if (db == NULL) - { - status = internal_setent (_PATH_VARDB "aliases.db", &db); - if (status != NSS_STATUS_SUCCESS) - { - *errnop = errno; - return status; - } - } - - value.flags = 0; - if (DL_CALL_FCT (db->get, (db->db, NULL, key, &value, 0)) == 0) - { - const char *src = value.data; - char *cp; - size_t cnt; - - result->alias_members_len = 0; - - /* We now have to fill the BUFFER with all the information. */ - if (buflen < key->size + 1) - { - no_more_room: - *errnop = ERANGE; - return NSS_STATUS_TRYAGAIN; - } - - buffer = stpncpy (buffer, key->data, key->size) + 1; - buflen -= key->size + 1; - - while (*src != '\0') - { - const char *end, *upto; - while (isspace (*src)) - ++src; - - end = strchr (src, ','); - if (end == NULL) - end = strchr (src, '\0'); - for (upto = end; upto > src && isspace (upto[-1]); --upto); - - if (upto != src) - { - if ((upto - src) + __alignof__ (char *) > buflen) - goto no_more_room; - buffer = stpncpy (buffer, src, upto - src) + 1; - buflen -= (upto - src) + __alignof (char *); - ++result->alias_members_len; - } - src = end + (*end != '\0'); - } - - /* Now prepare the return. Provide string pointers for the - currently selected aliases. */ - - /* Adjust the pointer so it is aligned for storing pointers. */ - buffer += __alignof__ (char *) - 1; - buffer -= ((buffer - (char *) 0) % __alignof__ (char *)); - result->alias_members = (char **) buffer; - - /* Compute addresses of alias entry strings. */ - cp = result->alias_name; - for (cnt = 0; cnt < result->alias_members_len; ++cnt) - { - cp = strchr (cp, '\0') + 1; - result->alias_members[cnt] = cp; - } - - status = (result->alias_members_len == 0 - ? NSS_STATUS_RETURN : NSS_STATUS_SUCCESS); - } - else - status = NSS_STATUS_NOTFOUND; - - if (! keep_db) - internal_endent (&db); - - return status; -} - -enum nss_status -_nss_db_getaliasent_r (struct aliasent *result, char *buffer, size_t buflen, - int *errnop) -{ - /* Return next entry in alias file. */ - enum nss_status status; - char buf[20]; - DBT key; - - __libc_lock_lock (lock); - key.size = snprintf (key.data = buf, sizeof buf, "0%u", entidx++); - key.flags = 0; - status = lookup (&key, result, buffer, buflen, errnop); - if (status == NSS_STATUS_TRYAGAIN && *errnop == ERANGE) - /* Give the user a chance to get the same entry with a larger buffer. */ - --entidx; - __libc_lock_unlock (lock); - - return status; -} - - -enum nss_status -_nss_db_getaliasbyname_r (const char *name, struct aliasent *result, - char *buffer, size_t buflen, int *errnop) -{ - DBT key; - enum nss_status status; - - key.size = 1 + strlen (name); - - key.data = __alloca (key.size); - ((char *) key.data)[0] = '.'; - memcpy (&((char *) key.data)[1], name, key.size - 1); - key.flags = 0; - - __libc_lock_lock (lock); - status = lookup (&key, result, buffer, buflen, errnop); - __libc_lock_unlock (lock); - - return status; -} diff --git a/nss/nss_db/db-netgrp.c b/nss/nss_db/db-netgrp.c index 47e845a6b9..901d4f50b0 100644 --- a/nss/nss_db/db-netgrp.c +++ b/nss/nss_db/db-netgrp.c @@ -1,5 +1,5 @@ /* Netgroup file parser in nss_db modules. - Copyright (C) 1996, 1997, 1999, 2000 Free Software Foundation, Inc. + Copyright (C) 1996, 1997, 1999, 2000, 2011 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996. @@ -18,6 +18,7 @@ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ +#include <ctype.h> #include <dlfcn.h> #include <errno.h> #include <fcntl.h> @@ -29,55 +30,75 @@ #include "nsswitch.h" #include "nss_db.h" - -#define DBFILE _PATH_VARDB "netgroup.db" +/* The hashing function we use. */ +#include "../intl/hash-string.h" -/* Locks the static variables in this file. */ -__libc_lock_define_initialized (static, lock) +#define DBFILE _PATH_VARDB "netgroup.db" /* Maintenance of the shared handle open on the database. */ -static NSS_DB *db; -static char *entry; -static char *cursor; - enum nss_status -_nss_db_setnetgrent (const char *group) +_nss_db_setnetgrent (const char *group, struct __netgrent *result) { - enum nss_status status; - - __libc_lock_lock (lock); - - status = internal_setent (DBFILE, &db); + struct nss_db_map state; + enum nss_status status = internal_setent (DBFILE, &state); if (status == NSS_STATUS_SUCCESS) { - DBT key = { data: (void *) group, size: strlen (group), flags: 0 }; - DBT value; - - value.flags = 0; - if (DL_CALL_FCT (db->get, (db->db, NULL, &key, &value, 0)) != 0) - status = NSS_STATUS_NOTFOUND; - else - cursor = entry = value.data; + const struct nss_db_header *header = state.header; + const stridx_t *hashtable + = (const stridx_t *) ((const char *) header + + header->dbs[0].hashoffset); + const char *valstrtab = (const char *) header + header->valstroffset; + uint32_t hashval = __hash_string (group); + size_t grouplen = strlen (group); + size_t hidx = hashval % header->dbs[0].hashsize; + size_t hval2 = 1 + hashval % (header->dbs[0].hashsize - 2); + + status = NSS_STATUS_NOTFOUND; + while (hashtable[hidx] != ~((stridx_t) 0)) + { + const char *valstr = valstrtab + hashtable[hidx]; + + if (strncmp (valstr, group, grouplen) == 0 + && isblank (valstr[grouplen])) + { + const char *cp = &valstr[grouplen + 1]; + while (isblank (*cp)) + ++cp; + if (*cp != '\0') + { + result->data = strdup (cp); + if (result->data == NULL) + status = NSS_STATUS_TRYAGAIN; + else + { + status = NSS_STATUS_SUCCESS; + result->cursor = result->data; + } + break; + } + } + + if ((hidx += hval2) >= header->dbs[0].hashsize) + hidx -= header->dbs[0].hashsize; + } + + internal_endent (&state); } - __libc_lock_unlock (lock); - return status; } enum nss_status -_nss_db_endnetgrent (void) +_nss_db_endnetgrent (struct __netgrent *result) { - __libc_lock_lock (lock); - - internal_endent (&db); - - __libc_lock_unlock (lock); - + free (result->data); + result->data = NULL; + result->data_size = 0; + result->cursor = NULL; return NSS_STATUS_SUCCESS; } @@ -91,13 +112,10 @@ enum nss_status _nss_db_getnetgrent_r (struct __netgrent *result, char *buffer, size_t buflen, int *errnop) { - int status; - - __libc_lock_lock (lock); - - status = _nss_netgroup_parseline (&cursor, result, buffer, buflen, errnop); + enum nss_status status; - __libc_lock_unlock (lock); + status = _nss_netgroup_parseline (&result->cursor, result, buffer, buflen, + errnop); return status; } diff --git a/nss/nss_db/db-open.c b/nss/nss_db/db-open.c index 94dfe5b7da..36ce494d02 100644 --- a/nss/nss_db/db-open.c +++ b/nss/nss_db/db-open.c @@ -1,5 +1,5 @@ /* Common database routines for nss_db. - Copyright (C) 2000 Free Software Foundation, Inc. + Copyright (C) 2000, 2011 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or @@ -22,368 +22,51 @@ #include <dlfcn.h> #include <stdlib.h> #include <string.h> -#include <bits/libc-lock.h> +#include <sys/mman.h> +#include <not-cancel.h> -#include "dummy-db.h" +#include <kernel-features.h> #include "nss_db.h" -/* This file contains the functions used to open and close the databases - read by the rest of libnss_db. Not all of them are thread safe; - make sure the caller does the appropriate locking. - - We dynamically load the database library, so that it does not have - to be present when glibc is compiled. Once loaded, the database - library is never never unloaded again until the libnss_db module is - unloaded (from the free_mem routine in nsswitch.c) -- we catch the - unload by providing a shlib destructor. (XXX Does that actually - work?) */ - -/* Handle for the shared Berkeley DB library. If non-null, the - database library is completely loaded and ready to be used by - multithreaded code. */ -static void *libdb_handle; - -/* The version of the Berkeley DB library we are using. */ -enum { - nodb, - db24, - db27, - db30 -} libdb_version; - -/* Pointer to the db_open function. For use with DB 2.x. */ -static int (*libdb_db_open) (const char *, int, - uint32_t, int, void *, void *, void **); - -/* Pointer to the db_create function. For use with DB 3.x. */ -static int (*libdb_db_create) (void *, void *, uint32_t); - -/* Constants which vary from version to version are actually variables - here. */ -int db_first; -int db_next; -int db_nooverwrite; -int db_truncate; -int db_rdonly; -/* Variables which keep track of the error values. */ -int db_keyexist; -int db_notfound; - -/* Locks the static variables in this file. */ -__libc_lock_define_initialized (static, lock) - -/* Dynamically load the database library. Return zero if successful, - non-zero if no suitable version of the library could be loaded. - Must be called with the above lock held if it might run in a - multithreaded context. - - We try currently: - - libdb.so.3: the name used by glibc 2.1 - - libdb-3.0.so: the name used by db-3.0.x - and maybe others in the future. */ - +/* Open the database stored in FILE. If succesful, store either a + pointer to the mapped file or a file handle for the file in H and + return NSS_STATUS_SUCCESS. On failure, return the appropriate + lookup status. */ enum nss_status -load_db (void) -{ - static const char *libnames[] = { "libdb.so.3", "libdb-3.0.so" }; - int x; - - for (x = 0; x < sizeof (libnames) / sizeof (libnames[0]); ++x) - { - libdb_handle = dlopen (libnames[x], RTLD_LAZY); - if (libdb_handle == NULL) - continue; - - /* DB 3.0 has db_create instead of db_open. */ - libdb_db_create = dlsym (libdb_handle, "db_create"); - - if (libdb_db_create == NULL) - /* DB 2.x uses db_open. */ - libdb_db_open = dlsym (libdb_handle, "db_open"); - - if (libdb_db_open != NULL || libdb_db_create != NULL) - { - /* Alright, we got a library. Now find out which version it is. */ - const char *(*db_version) (int *, int *, int *); - - db_version = dlsym (libdb_handle, "db_version"); - if (db_version != NULL) - { - /* Call the function and get the information. */ - int major, minor, subminor; - - DL_CALL_FCT (db_version, (&major, &minor, &subminor)); - switch (major) - { - case 2: - /* Sanity check: Do we have db_open? */ - if (libdb_db_open != NULL) - { - if (minor < 6 || (minor == 6 && subminor < 4)) - { - libdb_version = db24; - db_first = DB24_FIRST; - db_next = DB24_NEXT; - db_nooverwrite = DB24_NOOVERWRITE; - db_truncate = DB24_TRUNCATE; - } - else - { - libdb_version = db27; - db_first = DB27_FIRST; - db_next = DB27_NEXT; - db_nooverwrite = DB27_NOOVERWRITE; - db_truncate = DB27_TRUNCATE; - } - db_keyexist = DB2x_KEYEXIST; - db_notfound = DB2x_NOTFOUND; - db_rdonly = DB2x_RDONLY; - } - break; - - case 3: - /* Sanity check: Do we have db_create? */ - if (libdb_db_create != NULL) - { - libdb_version = db30; - db_first = DB30_FIRST; - db_next = DB30_NEXT; - db_keyexist = DB30_KEYEXIST; - db_notfound = DB30_NOTFOUND; - db_rdonly = DB30_RDONLY; - } - break; - - default: - break; - } - } - - if (libdb_version != nodb) - return NSS_STATUS_SUCCESS; - - /* Clear variables. */ - libdb_db_open = NULL; - libdb_db_create = NULL; - } - - dlclose (libdb_handle); - } - - (void) dlerror (); - return NSS_STATUS_UNAVAIL; -} - -/* Set the `FD_CLOEXEC' flag of FD. Return 0 on success, or -1 on - error with `errno' set. */ -static int -set_cloexec_flag (int fd) +internal_setent (const char *file, struct nss_db_map *mapping) { - int oldflags = fcntl (fd, F_GETFD, 0); - - if (oldflags < 0) - return oldflags; - - oldflags |= FD_CLOEXEC; - - return fcntl (fd, F_SETFD, oldflags); -} - -/* Make sure we don't use the library anymore once we are shutting down. */ -static void __attribute__ ((destructor)) -unload_db (void) -{ - if (libdb_handle != NULL) + enum nss_status status = NSS_STATUS_UNAVAIL; + + int mode = O_RDONLY | O_LARGEFILE; +#ifdef O_CLOEXEC + mode |= O_CLOEXEC; +#endif + int fd = open_not_cancel_2 (file, mode); + if (fd != -1) { - libdb_db_open = NULL; - libdb_db_create = NULL; - libdb_version = nodb; - dlclose (libdb_handle); - } -} - -/* Open the database stored in FILE. If succesful, store the database - handle in *DBP and return NSS_STATUS_SUCCESS. On failure, return - the appropriate lookup status. */ -enum nss_status -internal_setent (const char *file, NSS_DB **dbp) -{ - enum nss_status status = NSS_STATUS_SUCCESS; + struct nss_db_header header; - if (*dbp == NULL) - { - if (libdb_db_open == NULL && libdb_db_create == NULL) + if (read (fd, &header, sizeof (header)) == sizeof (header)) { - __libc_lock_lock (lock); - - if (libdb_db_open == NULL && libdb_db_create == NULL) - status = load_db (); - - __libc_lock_unlock (lock); + mapping->header = mmap (NULL, header.allocate, PROT_READ, + MAP_PRIVATE, fd, 0); + mapping->len = header.allocate; + if (mapping->header != MAP_FAILED) + status = NSS_STATUS_SUCCESS; + else if (errno == ENOMEM) + status = NSS_STATUS_TRYAGAIN; } - if (status == NSS_STATUS_SUCCESS) - status = dbopen (file, db_rdonly, 0, dbp); + close_not_cancel_no_status (fd); } return status; } -/* Close the database *DBP. */ +/* Close the database. */ void -internal_endent (NSS_DB **dbp) -{ - NSS_DB *db = *dbp; - - if (db != NULL) - { - DL_CALL_FCT (db->close, (db->db, 0)); - *dbp = NULL; - } -} - -/* Allocate a cursor for database DB and transaction TXN. On success, - store the cursor in *DBCP and return zero. Otherwise return an - error value. */ -int -db_cursor (void *db, void *txn, NSS_DBC **dbcp) -{ - NSS_DBC *dbc; - int ret; - - dbc = (NSS_DBC *) malloc (sizeof (NSS_DBC)); - if (dbc == NULL) - return ENOMEM; - - switch (libdb_version) - { - case db24: - ret = ((struct db24 *) db)->cursor (db, txn, &dbc->cursor); - - if (ret == 0) - dbc->c_get = ((struct dbc24 *) dbc->cursor)->c_get; - break; - - case db27: - ret = ((struct db27 *) db)->cursor (db, txn, &dbc->cursor, 0); - - if (ret == 0) - dbc->c_get = ((struct dbc27 *) dbc->cursor)->c_get; - break; - - case db30: - ret = ((struct db30 *) db)->cursor (db, txn, &dbc->cursor, 0); - - if (ret == 0) - dbc->c_get = ((struct dbc30 *) dbc->cursor)->c_get; - break; - - default: - abort (); - } - - if (ret != 0) - { - free (dbc); - return ret; - } - - *dbcp = dbc; - - return 0; -} - - -/* Open the database in FNAME, for access specified by FLAGS. If - opening the database causes the file FNAME to be created, it is - created with MODE. If succesful, store the database handle in *DBP - and return NSS_STATUS_SUCCESS. On failure, return the appropriate - lookup status. */ -int -dbopen (const char *fname, int oper, int mode, NSS_DB **dbp) +internal_endent (struct nss_db_map *mapping) { - int err; - int fd; - NSS_DB *db; - - /* Construct the object we pass up. */ - db = (NSS_DB *) calloc (1, sizeof (NSS_DB)); - if (db == NULL) - return NSS_STATUS_UNAVAIL; - - /* Initialize the object. */ - db->cursor = db_cursor; - - /* Actually open the database. */ - switch (libdb_version) - { - case db24: - case db27: - err = DL_CALL_FCT (libdb_db_open, - (fname, DB_BTREE, oper, mode, NULL, NULL, &db->db)); - if (err != 0) - goto fail; - - if (libdb_version) - { - db->close = ((struct db24 *) db->db)->close; - db->fd = ((struct db24 *) db->db)->fd; - db->get = ((struct db24 *) db->db)->get; - db->put = ((struct db24 *) db->db)->put; - } - else - { - db->close = ((struct db27 *) db->db)->close; - db->fd = ((struct db27 *) db->db)->fd; - db->get = ((struct db27 *) db->db)->get; - db->put = ((struct db27 *) db->db)->put; - } - break; - - case db30: - err = DL_CALL_FCT (libdb_db_create, (db->db, NULL, 0)); - if (err != 0) - goto fail; - - db->close = ((struct db30 *) db->db)->close; - db->fd = ((struct db30 *) db->db)->fd; - db->get = ((struct db30 *) db->db)->get; - db->put = ((struct db30 *) db->db)->put; - - err = ((struct db30 *) db->db)->open (db->db, fname, NULL, DB_BTREE, - oper, mode); - if (err != 0) - goto fail; - break; - - default: - abort (); - } - - /* We have to make sure the file is `closed on exec'. */ - err = DL_CALL_FCT (db->fd, (db->db, &fd)); - if (err != 0) - goto fail; - if (set_cloexec_flag (fd) < 0) - goto fail; - - *dbp = db; - - return NSS_STATUS_UNAVAIL; - - fail: - /* Something went wrong. Close the database if necessary. */ - if (db) - { - if (db->db && db->close) - DL_CALL_FCT (db->close, (db->db, 0)); - free (db); - } - - /* Make sure `errno' is set. */ - if (err) - __set_errno (err); - - return err == EAGAIN ? NSS_STATUS_TRYAGAIN : NSS_STATUS_UNAVAIL; + munmap (mapping->header, mapping->len); } diff --git a/nss/nss_db/dummy-db.h b/nss/nss_db/dummy-db.h deleted file mode 100644 index c96bbd93b7..0000000000 --- a/nss/nss_db/dummy-db.h +++ /dev/null @@ -1,333 +0,0 @@ -/* Constants and structures from the various Berkeley DB releases. - Copyright (C) 1999, 2000 Free Software Foundation, Inc. - This file is part of the GNU C Library. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 USA. */ - -#include <stdint.h> - -#include "nss_db.h" - -/* This file contains dummy definitions for various constants and - structures from the Berkeley release. We only provide those - definitions that are actually needed. In case of the structures, - we're only interested in the function pointers, since that's the - interface to the database. Unfortunately the structures have been - changed several times. */ - -/* The value for the btree database type has not been changed (yet?). */ -#define DB_BTREE (1) - -/* Permission flags for all 2.x releases. */ -#define DB2x_RDONLY 0x010000 - -/* The error values for all 2.x releases. */ -#define DB2x_KEYEXIST ( -3) -#define DB2x_NOTFOUND ( -7) - -/* For all 2.x releases up to 2.6.3 we can use the same definitions. - We'll refer to them as 2.4 since that's the version distributed - with glibc 2.1. */ - -/* Access methods from version 2.4. */ -#define DB24_FIRST 0x000020 -#define DB24_NEXT 0x000800 -#define DB24_NOOVERWRITE 0x001000 - -/* Permission flags from version 2.4. */ -#define DB24_TRUNCATE 0x080000 - -/* The DB structure from version 2.4. */ -struct db24 -{ - void *mutexp; - enum { dummy24 } type; - void *dbenv; - void *mp_dbenv; - void *master; - void *internal; - void *mp; - void *mpf; - struct - { - void *tqh_first; - void **tqh_last; - } curs_queue; - struct { - void *lh_first; - } handleq; - struct { - void *le_next; - void **le_prev; - } links; - uint32_t log_fileid; - void *txn; - uint32_t locker; - struct db24_dbt { - void *data; - uint32_t size; - uint32_t ulen; - uint32_t dlen; - uint32_t doff; - uint32_t flags; - } lock_dbt; - struct{ - uint32_t pgno; - uint8_t fileid[20]; - } lock; - size_t pgsize; - void *db_malloc; - /* Functions. */ - int (*close) (void *, uint32_t); - int (*cursor) (void *, void *, void **); - int (*del) (void *, void *, DBT *, uint32_t); - int (*fd) (void *, int *); - int (*get) (void *, void *, DBT *, DBT *, uint32_t); - int (*put) (void *, void *, DBT *, DBT *, uint32_t); - int (*stat) (void *, void *, void *(*)(size_t), uint32_t); - int (*sync) (void *, uint32_t); - uint32_t flags; -}; - -/* The DBC structure for the 2.4 release. */ -struct dbc24 -{ - void *dbp; - void *txn; - struct - { - void *tqe_next; - void **tqe_prev; - } links; - void *internal; - void *c_close; - void *c_del; - int (*c_get) (void *, DBT *, DBT *, uint32_t); - void *c_put; -}; - -/* The 2.7 release is slighty different. */ - -/* Access methods from version 2.7. */ -#define DB27_FIRST 7 -#define DB27_NEXT 15 -#define DB27_NOOVERWRITE 17 - -/* Permission flags from version 2.7. */ -#define DB27_TRUNCATE 0x020000 - -/* The DB structure from version 2.7. */ -struct db27 -{ - void *mutexp; - enum { dummy27 } type; - int byteswapped; - int saved_open_fd; - void *dbenv; - void *mp_dbenv; - void *internal; - void *mp; - void *mpf; - struct - { - void *tqh_first; - void **tqh_last; - } free_queue; - struct - { - void *tqh_first; - void **tqh_last; - } active_queue; - uint8_t fileid[20]; - uint32_t log_fileid; - size_t pgsize; - void *db_malloc; - void *dup_compare; - void *h_hash; - /* Functions. */ - int (*am_close) (void *); - int (*close) (void *, uint32_t); - int (*cursor) (void *, void *, void **, uint32_t); - int (*del) (void *, void *, DBT *, uint32_t); - int (*fd) (void *, int *); - int (*get) (void *, void *, DBT *, DBT *, uint32_t); - int (*join) (void *, void **, uint32_t, void **); - int (*put) (void *, void *, DBT *, DBT *, uint32_t); - int (*stat) (void *, void *, void *(*)(size_t), uint32_t); - int (*sync) (void *, uint32_t); - uint32_t flags; -}; - -/* The DBC structure for version 2.7. */ -struct dbc27 -{ - void *dbp; - void *txn; - struct - { - void *tqe_next; - void **tqe_prev; - } links; - uint32_t lid; - uint32_t locker; - DBT lock_dbt; - struct{ - uint32_t pgno; - uint8_t fileid[20]; - } lock; - size_t mylock; - DBT rkey; - DBT rdata; - void *c_am_close; - void *c_am_destroy; - void *c_close; - void *c_del; - int (*c_get) (void *, DBT *, DBT *, uint32_t); - void *c_put; - void *internal; - uint32_t flags; -}; - -/* Version 3.0 is mostly incompatible with 2.x. */ - -/* Access methods from version 3.0. */ -#define DB30_FIRST 9 -#define DB30_NEXT 17 -#define DB30_NOOVERWRITE 20 - -/* Error values from version 3.0. */ -#define DB30_KEYEXIST (-30997) -#define DB30_NOTFOUND (-30994) - -/* Permission flags from version 3.0. */ -#define DB30_RDONLY 0x000010 -#define DB30_TRUNCATE 0x020000 - -/* The DB structure from version 3.0. */ -struct db30 -{ - size_t pgsize; - void (*db_feedback) (void *, int, int); - void *(*db_malloc) (size_t); - void *(*db_realloc) (void *, size_t); - int (*dup_compare) (const DBT *, const DBT *); - void *dbenv; - enum { dummy30 } type; - void *mpf; - void *mutexp; - u_int8_t fileid[20]; - int32_t log_fileid; - void *open_txn; - void *saved_open_fhp; - struct - { - void *tqh_first; - void **tqh_last; - } free_queue; - struct - { - void *tqh_first; - void **tqh_last; - } active_queue; - void *bt_internal; - void *cj_internal; - void *h_internal; - void *q_internal; - void *xa_internal; - /* Functions. */ - int (*close) (void *, uint32_t); - int (*cursor) (void *, void *, void **, uint32_t); - int (*del) (void *, void *, DBT *, uint32_t); - void (*err) (void *, int, const char *, ...); - void (*errx) (void *, const char *, ...); - int (*fd) (void *, int *); - int (*get) (void *, void *, DBT *, DBT *, uint32_t); - int (*get_byteswapped) (void *); - int (*get_type) (void *); - int (*join) (void *, void **, void **, uint32_t); - int (*open) (void *, const char *, const char *, int, uint32_t, int); - int (*put) (void *, void *, DBT *, DBT *, uint32_t); - int (*remove) (void *, const char *, const char *, uint32_t); - int (*set_cachesize) (void *, uint32_t, uint32_t, int); - int (*set_dup_compare) (void *, int (*)(const DBT *, const DBT *)); - void (*set_errcall) (void *, void (*)(const char *, char *)); - void (*set_errfile) (void *, void *); - void (*set_errpfx) (void *, const char *); - void (*set_feedback) (void *, void (*)(void *, int, int)); - int (*set_flags) (void *, uint32_t); - int (*set_lorder) (void *, int); - int (*set_malloc) (void *, void *(*)(size_t)); - int (*set_pagesize) (void *, uint32_t); - void (*set_paniccall) (void *, void (*)(void *, int)); - int (*set_realloc) (void *, void *(*)(void *, size_t)); - int (*stat) (void *, void *, void *(*)(size_t), uint32_t); - int (*sync) (void *, uint32_t); - int (*upgrade) (void *, const char *, uint32_t); - - int (*set_bt_compare) (void *, int (*)(const DBT *, const DBT *)); - int (*set_bt_maxkey) (void *, uint32_t); - int (*set_bt_minkey) (void *, uint32_t); - int (*set_bt_prefix) (void *, size_t (*)(const DBT *, const DBT *)); - - int (*set_h_ffactor) (void *, uint32_t); - int (*set_h_hash) (void *, uint32_t (*)(const void *, uint32_t)); - int (*set_h_nelem) (void *, uint32_t); - - int (*set_re_delim) (void *, int); - int (*set_re_len) (void *, uint32_t); - int (*set_re_pad) (void *, int); - int (*set_re_source) (void *, const char *); - - uint32_t am_ok; - uint32_t flags; -}; - -/* The DBC structure from version 3.0. */ -struct dbc30 -{ - void *dbp; - void *txn; - struct - { - void *tqe_next; - void **tqe_prev; - } links; - uint32_t lid; /* Default process' locker id. */ - uint32_t locker; /* Locker for this operation. */ - DBT lock_dbt; /* DBT referencing lock. */ - struct - { - uint32_t pgno; - uint8_t fileid[20]; - } lock; - struct - { - size_t off; - uint32_t ndx; - uint32_t gen; - } mylock; - DBT rkey; - DBT rdata; - int (*c_close) (void *); - int (*c_del) (void *, uint32_t); - int (*c_dup) (void *, void **, uint32_t); - int (*c_get) (void *, DBT *, DBT *, uint32_t); - int (*c_put) (void *, DBT *, DBT *, uint32_t); - int (*c_am_close) (void *); - int (*c_am_destroy) (void *); - void *internal; - uint32_t flags; -}; diff --git a/nss/nss_db/nss_db.h b/nss/nss_db/nss_db.h index 0edc9b6bea..a965ae33fe 100644 --- a/nss/nss_db/nss_db.h +++ b/nss/nss_db/nss_db.h @@ -1,5 +1,5 @@ /* Common database open/close routines for nss_db. - Copyright (C) 1999, 2000 Free Software Foundation, Inc. + Copyright (C) 1999, 2000, 2011 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or @@ -22,73 +22,49 @@ #include <nss.h> #include <stdint.h> +#include <bits/libc-lock.h> -/* Variables which keep track of the error values. */ -extern int db_keyexist; -extern int db_notfound; -/* This flag is the same for all versions of the Berkeley DB library. */ -#define DB_CREATE 0x000001 +/* String table index type. */ +typedef uint32_t stridx_t; -/* But constants which vary from version to version are actually - variables here. */ -extern int db_first; -extern int db_next; -extern int db_nooverwrite; -extern int db_truncate; -extern int db_rdonly; - -/* The `DBT' type is the same in all versions we support. */ -typedef struct +/* Database file header. */ +struct nss_db_header { - void *data; - uint32_t size; - uint32_t ulen; - uint32_t dlen; - uint32_t doff; - uint32_t flags; -} DBT; - -/* But the cursor object is very different from version to version. */ -typedef struct + uint32_t magic; +#define NSS_DB_MAGIC 0xdd110601 + uint32_t ndbs; + uint64_t valstroffset; + uint64_t valstrlen; + uint64_t allocate; + struct + { + char id; + char pad[sizeof (uint32_t) - 1]; + uint32_t hashsize; + uint64_t hashoffset; + uint64_t keyidxoffset; + uint64_t keystroffset; + } dbs[0]; +}; + + +/* Information about mapped database. */ +struct nss_db_map { - void *cursor; - int (*c_get) (void *, DBT *, DBT *, uint32_t); -} NSS_DBC; + struct nss_db_header *header; + size_t len; +}; -/* We need a helper function for it. */ -extern int db_cursor (void *db, void *txn, NSS_DBC **dbcp); - -/* This is the wrapper we put around the `DB' structures to provide a - uniform interface to the higher-level functions. */ -typedef struct -{ - void *db; - int (*close) (void *, uint32_t); - int (*cursor) (void *, void *, NSS_DBC **); - int (*fd) (void *, int *); - int (*get) (void *, void *, DBT *, DBT *, uint32_t); - int (*put) (void *, void *, DBT *, DBT *, uint32_t); -} NSS_DB; /* Open the database stored in FILE. If succesful, store the database - handle in *DBP and return NSS_STATUS_SUCCESS. On failure, return - the appropriate lookup status. */ -extern enum nss_status internal_setent (const char *file, NSS_DB **dbp); - -/* Close the database *DBP. */ -extern void internal_endent (NSS_DB **dbp); - -/* Dynamically load the Berkeley DB library. Return zero if - successful, non-zero if no suitable version of the library could be - loaded. */ -extern enum nss_status load_db (void); - -/* Open the database in FNAME, for access specified by FLAGS. If - opening the database causes the file FNAME to be created, it is - created with MODE. If succesful, store the database handle in *DBP - and return NSS_STATUS_SUCCESS. On failure, return the appropriate + handle in *MAPPINGP or a file descriptor for the file in *FDP and + return NSS_STATUS_SUCCESS. On failure, return the appropriate lookup status. */ -extern int dbopen (const char *fname, int oper, int mode, NSS_DB **dbp); +enum nss_status internal_setent (const char *file, + struct nss_db_map *mappingp); + +/* Close the database FD. */ +extern void internal_endent (struct nss_db_map *mapping); #endif /* nss_db.h */ |