about summary refs log tree commit diff
path: root/nss/nss_db/db-open.c
diff options
context:
space:
mode:
Diffstat (limited to 'nss/nss_db/db-open.c')
-rw-r--r--nss/nss_db/db-open.c377
1 files changed, 30 insertions, 347 deletions
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);
 }