]> git.ipfire.org Git - thirdparty/glibc.git/blame - nss/nss_db/db-open.c
Update.
[thirdparty/glibc.git] / nss / nss_db / db-open.c
CommitLineData
9a6450d5
UD
1/* Common database open/close routines for nss_db.
2 Copyright (C) 1999, 2000 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
4
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public License as
7 published by the Free Software Foundation; either version 2 of the
8 License, or (at your option) any later version.
9
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public
16 License along with the GNU C Library; see the file COPYING.LIB. If not,
17 write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA. */
19
20#include <fcntl.h>
21#include <dlfcn.h>
22#include <errno.h>
23#include <stdlib.h>
24#include <bits/libc-lock.h>
25
26#include "dummy-db.h"
27#include "nsswitch.h"
28#include "nss_db.h"
29
30/* This file contains the functions used to open and close the databases
31 read by the rest of libnss_db. They are not thread safe; the caller
32 must handle locking.
33
34 We dynamically load the database library, so that it does not have
35 to be present when glibc is compiled. Once loaded, libdb is never
36 unloaded again unless this library is unloaded (from the free_mem
37 routine in nsswitch.c) - we catch the unload by providing a shlib
38 destructor. (XXX Does it work?) */
39
40static void *libdb_handle;
41enum {
42 nodb,
43 db24,
44 db27
45} libdb_version;
46static int (*libdb_db_open) (const char *, int,
47 uint32_t, int, void *, void *, void **);
48
49/* Locks the static variables in this file. */
50__libc_lock_define_initialized (static, lock)
51
52/* Dynamically load the database library.
53 We try libdb2.so.3, maybe others in the future. */
54static int
55load_db (void)
56{
57 static const char *libnames[] = { "libdb.so.3" };
58 int x;
59
793bd4d9 60 for(x = 0; x < sizeof (libnames) / sizeof (libnames[0]); ++x)
9a6450d5
UD
61 {
62 libdb_handle = dlopen (libnames[x], RTLD_LAZY);
63 if (libdb_handle == NULL)
64 continue;
65
66 libdb_db_open = dlsym (libdb_handle, "db_open");
793bd4d9 67 if (libdb_db_open != NULL)
9a6450d5
UD
68 {
69 /* Alright, we got a library. Now find out which version it is. */
70 const char *(*db_version) (int *, int *, int *);
71
72 db_version = dlsym (libdb_handle, "db_version");
73 if (db_version != NULL)
74 {
75 /* Call the function and get the information. */
76 int major, minor, subminor;
77
78 DL_CALL_FCT (db_version, (&major, &minor, &subminor));
79 if (major == 2)
80 {
81 /* We currently cannot handle other versions than the
82 2.x series. */
83 if (minor < 6 || (minor == 6 && subminor < 4))
84 libdb_version = db24;
85 else
86 libdb_version = db27;
87 }
88 }
89
90 if (libdb_version != nodb)
91 return 0;
92 }
93
94 dlclose (libdb_handle);
95 }
96
97 (void) dlerror ();
98 return 1;
99}
100
101
102/* Make sure we don't use the library anymore once we are shutting down. */
103static void __attribute__ ((destructor))
104unload_db (void)
105{
106 if (libdb_handle != NULL)
107 {
108 libdb_db_open = NULL;
109 libdb_version = nodb;
110 dlclose (libdb_handle);
111 }
112}
113
114
115enum nss_status
116internal_setent (const char *file, NSS_DB **dbp)
117{
118 enum nss_status status = NSS_STATUS_SUCCESS;
119 int err;
120 void *db;
cbc85992
UD
121 int fd;
122 int result;
123
9a6450d5
UD
124
125 if (*dbp == NULL)
126 {
127 if (libdb_db_open == NULL)
128 {
129 __libc_lock_lock (lock);
130
131 err = load_db ();
132
133 __libc_lock_unlock (lock);
134
135 if (err != 0)
136 return NSS_STATUS_UNAVAIL;
137 }
138
139 /* Open the database. Fortunately this interface seems to be the
140 same for all supported versions. */
141 err = DL_CALL_FCT (libdb_db_open,
142 (file, DB_BTREE, DB_RDONLY, 0, NULL, NULL, &db));
143
cbc85992
UD
144 if (err != 0)
145 {
146 __set_errno (err);
147 *dbp = NULL;
148 return err == EAGAIN ? NSS_STATUS_TRYAGAIN : NSS_STATUS_UNAVAIL;
149 }
150
9a6450d5
UD
151 /* Construct the object we pass up. */
152 *dbp = (NSS_DB *) malloc (sizeof (NSS_DB));
cbc85992
UD
153 if (*dbp == NULL)
154 return NSS_STATUS_UNAVAIL;
155
156 (*dbp)->db = db;
157
158 /* The functions are at different positions for the different
159 versions. Sigh. */
160 switch (libdb_version)
9a6450d5 161 {
cbc85992
UD
162 case db24:
163 (*dbp)->close =
164 (int (*) (void *, uint32_t)) ((struct db24 *) db)->close;
165 (*dbp)->fd =
166 (int (*) (void *, int *)) ((struct db24 *) db)->fd;
167 (*dbp)->get =
168 (int (*) (void *, void *, void *, void *, uint32_t))
169 ((struct db24 *) db)->get;
170 break;
171 case db27:
172 (*dbp)->close =
173 (int (*) (void *, uint32_t)) ((struct db27 *) db)->close;
174 (*dbp)->fd =
175 (int (*) (void *, int *)) ((struct db27 *) db)->fd;
176 (*dbp)->get =
177 (int (*) (void *, void *, void *, void *, uint32_t))
178 ((struct db27 *) db)->get;
179 break;
180 default:
181 abort ();
9a6450d5
UD
182 }
183
cbc85992
UD
184 /* We have to make sure the file is `closed on exec'. */
185 err = DL_CALL_FCT ((*dbp)->fd, (db, &fd));
9a6450d5
UD
186 if (err != 0)
187 {
188 __set_errno (err);
cbc85992 189 result = -1;
9a6450d5
UD
190 }
191 else
192 {
cbc85992 193 int flags = result = fcntl (fd, F_GETFD, 0);
9a6450d5 194
cbc85992 195 if (result >= 0)
9a6450d5 196 {
cbc85992
UD
197 flags |= FD_CLOEXEC;
198 result = fcntl (fd, F_SETFD, flags);
9a6450d5 199 }
cbc85992
UD
200 }
201 if (result < 0)
202 {
203 /* Something went wrong. Close the stream and return a
204 failure. */
205 DL_CALL_FCT ((*dbp)->close, (db, 0));
206 status = NSS_STATUS_UNAVAIL;
207 free (*dbp);
208 *dbp = NULL;
9a6450d5
UD
209 }
210 }
211
212 return status;
213}
214
215
216/* Close the database file. */
217void
218internal_endent (NSS_DB **dbp)
219{
220 NSS_DB *db = *dbp;
221 if (db != NULL)
222 {
223 DL_CALL_FCT (db->close, (db->db, 0));
224 *dbp = NULL;
225 }
226}