1
0
mirror of https://sourceware.org/git/glibc.git synced 2025-07-28 00:21:52 +03:00
2000-05-07  Mark Kettenis  <kettenis@gnu.org>

	* nss/nss_db/db-open.c: Cleanup and add comments.  Pretty print.
	Remove duplicate <errno.h> include.  Remove inclusion of
	<libintl.h> 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.
This commit is contained in:
Ulrich Drepper
2000-05-08 04:50:45 +00:00
parent 93414bb97c
commit d1c2a14cdf
5 changed files with 285 additions and 238 deletions

View File

@ -20,35 +20,42 @@
#include <errno.h>
#include <fcntl.h>
#include <dlfcn.h>
#include <errno.h>
#include <stdlib.h>
#include <libintl.h>
#include <string.h>
#include <bits/libc-lock.h>
#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)
{
__set_errno (err);
*dbp = NULL;
return err == EAGAIN ? NSS_STATUS_TRYAGAIN : NSS_STATUS_UNAVAIL;
}
break;
case db30:
err = DL_CALL_FCT (libdb_db_create, (&odb, 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);
if (err != 0)
{
__set_errno (err);
/* Free all resources. */
((struct db30 *) odb)->close (odb, 0);
*dbp = NULL;
return NSS_STATUS_UNAVAIL;
}
break;
default:
abort ();
}
/* Construct the object we pass up. */
db = (NSS_DB *) malloc (sizeof (NSS_DB));
if (db != NULL)
{
db->db = odb;
goto fail;
/* The functions are at different positions for the different
versions. Sigh. */
switch (libdb_version)
if (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, (odb, &fd));
if (err != 0)
{
__set_errno (err);
result = -1;
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
{
int flags = result = fcntl (fd, F_GETFD, 0);
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;
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;
}
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 status;
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;
}