From d1c2a14cdfd71fea547c9ec0db7eff85991bdd11 Mon Sep 17 00:00:00 2001 From: Ulrich Drepper Date: Mon, 8 May 2000 04:50:45 +0000 Subject: Update. 2000-05-07 Mark Kettenis * nss/nss_db/db-open.c: Cleanup and add comments. Pretty print. Remove duplicate include. Remove inclusion of and "nsswitch.h". (set_cloexec_flag): New function, broken out of dbopen. (dbopen): Changed return type to `enum nss_status'. Mostly rewritten to make sure that we do not report NSS_STATUS_SUCCESS if something went wrong. Remove unnecessary casts. (internal_setent): Change return type to nss_status. Document, and make sure that the function behaves accordingly. Make dynamically loading the database library really thread-safe and return NSS_STATUS_UNAVAIL if it failed. (db_cursor): Return ENOMEM is memory allocation failed. Remove unecessary casts. * nss/nss_db/dummy-db.h: Add copyright notice. Improve documentation. (struct dbc24, struct dbc27): Use DBT type in parameter lists for c_get function member. * nss/nss_db/nss_db.h: Add and tweak some comments. (DBT): Move typedef before NSS_DBC typedef. (NSS_DBC, NSS_DB): Use DBT in function member parameter lists. --- nss/nss_db/db-open.c | 299 ++++++++++++++++++++++++-------------------------- nss/nss_db/dummy-db.h | 120 +++++++++++--------- nss/nss_db/nss_db.h | 64 ++++++----- 3 files changed, 253 insertions(+), 230 deletions(-) (limited to 'nss/nss_db') diff --git a/nss/nss_db/db-open.c b/nss/nss_db/db-open.c index 470af04..6a21a0a 100644 --- a/nss/nss_db/db-open.c +++ b/nss/nss_db/db-open.c @@ -20,35 +20,42 @@ #include #include #include -#include #include -#include +#include #include #include "dummy-db.h" -#include "nsswitch.h" #include "nss_db.h" /* This file contains the functions used to open and close the databases - read by the rest of libnss_db. They are not thread safe; the caller - must handle locking. + 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, libdb is never - unloaded again unless this library is unloaded (from the free_mem - routine in nsswitch.c) - we catch the unload by providing a shlib - destructor. (XXX Does it work?) */ - + 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 @@ -65,13 +72,17 @@ int db_notfound; /* Locks the static variables in this file. */ __libc_lock_define_initialized (static, lock) -/* Dynamically load the database library. +/* 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. */ - -int + +enum nss_status load_db (void) { static const char *libnames[] = { "libdb.so.3", "libdb-3.0.so" }; @@ -83,11 +94,11 @@ load_db (void) if (libdb_handle == NULL) continue; - /* db 3.0 has db_create instead of db_open. */ + /* 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. */ + /* DB 2.x uses db_open. */ libdb_db_open = dlsym (libdb_handle, "db_open"); if (libdb_db_open != NULL || libdb_db_create != NULL) @@ -129,6 +140,7 @@ load_db (void) db_rdonly = DB2x_RDONLY; } break; + case 3: /* Sanity check: Do we have db_create? */ if (libdb_db_create != NULL) @@ -141,12 +153,14 @@ load_db (void) db_rdonly = DB30_RDONLY; } break; + default: break; } } + if (libdb_version != nodb) - return 0; + return NSS_STATUS_SUCCESS; /* Clear variables. */ libdb_db_open = NULL; @@ -157,7 +171,22 @@ load_db (void) } (void) dlerror (); - return 1; + 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) +{ + 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. */ @@ -173,6 +202,9 @@ unload_db (void) } } +/* 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) { @@ -184,26 +216,26 @@ internal_setent (const char *file, NSS_DB **dbp) { __libc_lock_lock (lock); - status = load_db (); + if (libdb_db_open == NULL && libdb_db_create == NULL) + status = load_db (); __libc_lock_unlock (lock); - - if (status != 0) - return status; } - status = dbopen (file, db_rdonly, 0, dbp); + if (status == NSS_STATUS_SUCCESS) + status = dbopen (file, db_rdonly, 0, dbp); } return status; } -/* Close the database file. */ +/* Close the database *DBP. */ void internal_endent (NSS_DB **dbp) { NSS_DB *db = *dbp; + if (db != NULL) { DL_CALL_FCT (db->close, (db->db, 0)); @@ -211,188 +243,147 @@ internal_endent (NSS_DB **dbp) } } +/* 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) { - void *ptr; - NSS_DBC *dbc = NULL; + 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, &ptr); + 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, &ptr, 0); + 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, &ptr, 0); + 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) + if (ret != 0) { - dbc = (NSS_DBC *) malloc (sizeof (NSS_DBC)); - if (dbc == NULL) - return 1; - dbc->cursor = ptr; - - switch (libdb_version) - { - case db24: - dbc->c_get = - (int (*) (void *, void *, void *, uint32_t)) - ((struct dbc24 *) ptr)->c_get; - break; - case db27: - dbc->c_get = - (int (*) (void *, void *, void *, uint32_t)) - ((struct dbc27 *) ptr)->c_get; - break; - case db30: - dbc->c_get = - (int (*) (void *, void *, void *, uint32_t)) - ((struct dbc30 *) ptr)->c_get; - default: - abort (); - } + free (dbc); + return ret; } *dbcp = dbc; - return ret; + 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) { int err; - int result; int fd; - void *odb; - enum nss_status status = NSS_STATUS_SUCCESS; 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, &odb)); + (fname, DB_BTREE, oper, mode, NULL, NULL, &db->db)); if (err != 0) + goto fail; + + if (libdb_version) { - __set_errno (err); - *dbp = NULL; - return err == EAGAIN ? NSS_STATUS_TRYAGAIN : NSS_STATUS_UNAVAIL; + 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, (&odb, NULL, 0)); + err = DL_CALL_FCT (libdb_db_create, (db->db, NULL, 0)); if (err != 0) - { - __set_errno (err); - *dbp = NULL; - return err == EAGAIN ? NSS_STATUS_TRYAGAIN : NSS_STATUS_UNAVAIL; - } - err = ((struct db30 *) odb)->open (odb, fname, NULL, DB_BTREE, - oper, mode); + 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) - { - __set_errno (err); - /* Free all resources. */ - ((struct db30 *) odb)->close (odb, 0); - *dbp = NULL; - return NSS_STATUS_UNAVAIL; - } + goto fail; break; + default: abort (); } - - /* Construct the object we pass up. */ - db = (NSS_DB *) malloc (sizeof (NSS_DB)); - if (db != NULL) - { - db->db = odb; - /* The functions are at different positions for the different - versions. Sigh. */ - switch (libdb_version) - { - case db24: - db->close = - (int (*) (void *, uint32_t)) ((struct db24 *) odb)->close; - db->fd = - (int (*) (void *, int *)) ((struct db24 *) odb)->fd; - db->get = - (int (*) (void *, void *, void *, void *, uint32_t)) - ((struct db24 *) odb)->get; - db->put = - (int (*) (void *, void *, void *, void *, uint32_t)) - ((struct db24 *) odb)->put; - break; - case db27: - db->close = - (int (*) (void *, uint32_t)) ((struct db27 *) odb)->close; - db->fd = - (int (*) (void *, int *)) ((struct db27 *) odb)->fd; - db->get = - (int (*) (void *, void *, void *, void *, uint32_t)) - ((struct db27 *) odb)->get; - db->put = - (int (*) (void *, void *, void *, void *, uint32_t)) - ((struct db27 *) odb)->put; - break; - case db30: - db->close = - (int (*) (void *, uint32_t)) ((struct db30 *) odb)->close; - db->fd = - (int (*) (void *, int *)) ((struct db30 *) odb)->fd; - db->get = - (int (*) (void *, void *, void *, void *, uint32_t)) - ((struct db30 *) odb)->get; - db->put = - (int (*) (void *, void *, void *, void *, uint32_t)) - ((struct db30 *) odb)->put; - break; - default: - abort (); - } - db->cursor = db_cursor; + /* 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; - /* We have to make sure the file is `closed on exec'. */ - err = DL_CALL_FCT (db->fd, (odb, &fd)); - if (err != 0) - { - __set_errno (err); - result = -1; - } - else - { - int flags = result = fcntl (fd, F_GETFD, 0); + *dbp = db; - if (result >= 0) - { - flags |= FD_CLOEXEC; - result = fcntl (fd, F_SETFD, flags); - } - } - if (result < 0) - { - /* Something went wrong. Close the stream and return a - failure. */ - DL_CALL_FCT (db->close, (odb, 0)); - free (db); - status = NSS_STATUS_UNAVAIL; - db = NULL; - } + 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); } - *dbp = db; - - return status; + + /* Make sure `errno' is set. */ + if (err) + __set_errno (err); + + return err == EAGAIN ? NSS_STATUS_TRYAGAIN : NSS_STATUS_UNAVAIL; } diff --git a/nss/nss_db/dummy-db.h b/nss/nss_db/dummy-db.h index 66b5416..75d7bac 100644 --- a/nss/nss_db/dummy-db.h +++ b/nss/nss_db/dummy-db.h @@ -1,31 +1,56 @@ +/* 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 Library General Public License as + published by the Free Software Foundation; either version 2 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + #include #include "nss_db.h" -/* This file contains dummy definitions of the DB structure of the - Berkeley DB. We are only interested in the function pointers since - this is the interface to the database. Unfortunately the structure - changed over time and we have to take this into account. */ +/* 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 values to select the database type are unchanged over the version. - Define only what we really need. */ +/* The value for the btree database type has not been changed (yet?). */ #define DB_BTREE (1) -/* Permission flags. */ +/* Permission flags for all 2.x releases. */ #define DB2x_RDONLY 0x010000 -/* Access methods. */ +/* 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 -/* The error values that are needed. */ -#define DB2x_KEYEXIST ( -3) -#define DB2x_NOTFOUND ( -7) - +/* Permission flags from version 2.4. */ +#define DB24_TRUNCATE 0x080000 -/* This is for the db-2.x version up to 2.x.y. We use the name `db24' since - this is the version which was shipped with glibc 2.1. */ +/* The DB structure from version 2.4. */ struct db24 { void *mutexp; @@ -77,7 +102,7 @@ struct db24 uint32_t flags; }; - +/* The DBC structure for the 2.4 release. */ struct dbc24 { void *dbp; @@ -90,15 +115,21 @@ struct dbc24 void *internal; void *c_close; void *c_del; - int (*c_get) (void *, void *, void *, uint32_t); + int (*c_get) (void *, DBT *, DBT *, uint32_t); void *c_put; }; -/* Flags which changed. */ -#define DB24_TRUNCATE 0x080000 +/* 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 -/* Versions for 2.7, slightly incompatible with version 2.4. */ +/* The DB structure from version 2.7. */ struct db27 { void *mutexp; @@ -133,14 +164,14 @@ struct db27 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 (*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; @@ -164,21 +195,28 @@ struct dbc27 void *c_am_destroy; void *c_close; void *c_del; - int (*c_get) (void *, void *, void *, uint32_t); + int (*c_get) (void *, DBT *, DBT *, uint32_t); void *c_put; void *internal; uint32_t flags; }; -/* Flags which changed. */ -#define DB27_TRUNCATE 0x020000 +/* Version 3.0 is mostly incompatible with 2.x. */ -/* Access methods. */ -#define DB27_FIRST 7 -#define DB27_NEXT 15 -#define DB27_NOOVERWRITE 17 +/* Access methods from version 3.0. */ +#define DB30_FIRST 9 +#define DB30_NEXT 17 +#define DB30_NOOVERWRITE 20 -/* Versions for 3.0, incompatible with version 2.x. */ +/* 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; @@ -238,16 +276,16 @@ struct db30 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); @@ -257,7 +295,7 @@ struct db30 uint32_t flags; }; - +/* The DBC structure from version 3.0. */ struct dbc30 { void *dbp; @@ -293,19 +331,3 @@ struct dbc30 void *internal; uint32_t flags; }; - -/* Flags which changed. */ -#define DB30_TRUNCATE 0x020000 - -/* Access methods. */ -#define DB30_FIRST 9 -#define DB30_NEXT 17 -#define DB30_NOOVERWRITE 20 - -/* Permission flags are changed. */ -#define DB30_RDONLY 0x000010 - - -/* The error values that are needed. */ -#define DB30_KEYEXIST (-30997) -#define DB30_NOTFOUND (-30994) diff --git a/nss/nss_db/nss_db.h b/nss/nss_db/nss_db.h index 8abec2d..4ace9ed 100644 --- a/nss/nss_db/nss_db.h +++ b/nss/nss_db/nss_db.h @@ -20,32 +20,44 @@ #ifndef _NSS_DB_H #define _NSS_DB_H 1 +#include #include /* Variables which keep track of the error values. */ extern int db_keyexist; extern int db_notfound; -/* Constants which vary from version to version are actually variables - here. */ +/* This flag is the same for all versions of the Berkeley DB library. */ +#define DB_CREATE 0x000001 + +/* 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; -/* Flags are also unchanged. */ -#define DB_CREATE 0x000001 - +/* The `DBT' type is the same in all versions we support. */ +typedef struct +{ + void *data; + uint32_t size; + uint32_t ulen; + uint32_t dlen; + uint32_t doff; + uint32_t flags; +} DBT; -/* Similarly we have to handle the cursor object. It is also very - different from version to version. */ +/* But the cursor object is very different from version to version. */ typedef struct { void *cursor; - int (*c_get) (void *, void *, void *, uint32_t); + int (*c_get) (void *, DBT *, DBT *, uint32_t); } NSS_DBC; +/* 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. */ @@ -55,30 +67,28 @@ typedef struct int (*close) (void *, uint32_t); int (*cursor) (void *, void *, NSS_DBC **); int (*fd) (void *, int *); - int (*get) (void *, void *, void *, void *, uint32_t); - int (*put) (void *, void *, void *, void *, uint32_t); + 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); -/* The `DBT' type is the same in all versions we support. */ -typedef struct { - void *data; - uint32_t size; - uint32_t ulen; - uint32_t dlen; - uint32_t doff; - uint32_t flags; -} DBT; - +/* Close the database *DBP. */ +extern void internal_endent (NSS_DB **dbp); -/* Private routines to nss_db. - You must have included nsswitch.h and db.h before this file. */ +/* 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); -extern enum nss_status internal_setent (const char *file, NSS_DB **dbp); -extern void internal_endent (NSS_DB **dbp); -extern int db_cursor (void *db, void *txn, NSS_DBC **dbcp); -extern int 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 + lookup status. */ extern int dbopen (const char *fname, int oper, int mode, NSS_DB **dbp); - #endif /* nss_db.h */ -- cgit v1.1