]> git.ipfire.org Git - thirdparty/glibc.git/blob - nss/nss_db/db-open.c
c3a06794854a281c9475726856336fd235c013e7
[thirdparty/glibc.git] / nss / nss_db / db-open.c
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
40 static void *libdb_handle;
41 enum {
42 nodb,
43 db24,
44 db27
45 } libdb_version;
46 static 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. */
54 static int
55 load_db (void)
56 {
57 static const char *libnames[] = { "libdb.so.3" };
58 int x;
59
60 for(x = 0; x < sizeof (libnames) / sizeof (libnames[0]); ++x)
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");
67 if (libdb_db_open != NULL)
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. */
103 static void __attribute__ ((destructor))
104 unload_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
115 enum nss_status
116 internal_setent (const char *file, NSS_DB **dbp)
117 {
118 enum nss_status status = NSS_STATUS_SUCCESS;
119 int err;
120 void *db;
121
122 if (*dbp == NULL)
123 {
124 if (libdb_db_open == NULL)
125 {
126 __libc_lock_lock (lock);
127
128 err = load_db ();
129
130 __libc_lock_unlock (lock);
131
132 if (err != 0)
133 return NSS_STATUS_UNAVAIL;
134 }
135
136 /* Open the database. Fortunately this interface seems to be the
137 same for all supported versions. */
138 err = DL_CALL_FCT (libdb_db_open,
139 (file, DB_BTREE, DB_RDONLY, 0, NULL, NULL, &db));
140
141 /* Construct the object we pass up. */
142 *dbp = (NSS_DB *) malloc (sizeof (NSS_DB));
143 if (*dbp != NULL)
144 {
145 (*dbp)->db = db;
146
147 /* The functions are at different positions for the different
148 versions. Sigh. */
149 switch (libdb_version)
150 {
151 case db24:
152 (*dbp)->close =
153 (int (*) (void *, uint32_t)) ((struct db24 *) db)->close;
154 (*dbp)->fd =
155 (int (*) (void *, int *)) ((struct db24 *) db)->fd;
156 (*dbp)->get =
157 (int (*) (void *, void *, void *, void *, uint32_t))
158 ((struct db24 *) db)->get;
159 break;
160 case db27:
161 (*dbp)->close =
162 (int (*) (void *, uint32_t)) ((struct db27 *) db)->close;
163 (*dbp)->fd =
164 (int (*) (void *, int *)) ((struct db27 *) db)->fd;
165 (*dbp)->get =
166 (int (*) (void *, void *, void *, void *, uint32_t))
167 ((struct db27 *) db)->get;
168 break;
169 default:
170 abort ();
171 }
172 }
173
174 if (err != 0)
175 {
176 __set_errno (err);
177 *dbp = NULL;
178 status = err == EAGAIN ? NSS_STATUS_TRYAGAIN : NSS_STATUS_UNAVAIL;
179 }
180 else
181 {
182 /* We have to make sure the file is `closed on exec'. */
183 int fd;
184 int result;
185
186 err = DL_CALL_FCT ((*dbp)->fd, (db, &fd));
187 if (err != 0)
188 {
189 __set_errno (err);
190 result = -1;
191 }
192 else
193 {
194 int flags = result = fcntl (fd, F_GETFD, 0);
195
196 if (result >= 0)
197 {
198 flags |= FD_CLOEXEC;
199 result = fcntl (fd, F_SETFD, flags);
200 }
201 }
202 if (result < 0)
203 {
204 /* Something went wrong. Close the stream and return a
205 failure. */
206 DL_CALL_FCT ((*dbp)->close, (db, 0));
207 status = NSS_STATUS_UNAVAIL;
208 }
209
210 if (result < 0)
211 *dbp = NULL;
212 }
213 }
214
215 return status;
216 }
217
218
219 /* Close the database file. */
220 void
221 internal_endent (NSS_DB **dbp)
222 {
223 NSS_DB *db = *dbp;
224 if (db != NULL)
225 {
226 DL_CALL_FCT (db->close, (db->db, 0));
227 *dbp = NULL;
228 }
229 }