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

@ -1,3 +1,27 @@
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.
2000-05-07 H.J. Lu <hjl@gnu.org>
* csu/initfini.c: Moved to ....

View File

@ -733,8 +733,8 @@ _nl_find_msg (domain_file, msgid, index)
found:
/* The translation was found at index ACT. If we have to convert the
string to use a different character set, this is the time. */
result = (char *) domain->data
+ W (domain->must_swap, domain->trans_tab[act].offset);
result = ((char *) domain->data
+ W (domain->must_swap, domain->trans_tab[act].offset));
#if defined _LIBC || HAVE_ICONV
if (

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)
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;
/* 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;
/* 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, (odb, &fd));
if (err != 0)
{
__set_errno (err);
result = -1;
}
else
{
int flags = result = fcntl (fd, F_GETFD, 0);
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;
}
}
*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;
}

View File

@ -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 <stdint.h>
#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
/* Versions for 2.7, slightly incompatible with version 2.4. */
/* Permission flags from version 2.7. */
#define DB27_TRUNCATE 0x020000
/* The DB structure from version 2.7. */
struct db27
{
void *mutexp;
@ -140,7 +171,7 @@ struct db27
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;
@ -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)

View File

@ -20,32 +20,44 @@
#ifndef _NSS_DB_H
#define _NSS_DB_H 1
#include <nss.h>
#include <stdint.h>
/* 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;
/* 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;
/* Private routines to nss_db.
You must have included nsswitch.h and db.h before this file. */
/* 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);
extern int db_cursor (void *db, void *txn, NSS_DBC **dbcp);
extern int load_db (void);
/* 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
lookup status. */
extern int dbopen (const char *fname, int oper, int mode, NSS_DB **dbp);
#endif /* nss_db.h */