update from main archive 961113
[kopensolaris-gnu/glibc.git] / nss / nss_db / db-XXX.c
1 /* Common code for DB-based databases in nss_db module.
2    Copyright (C) 1996 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 <db.h>
21 #include <fcntl.h>
22 #include <libc-lock.h>
23 #include "nsswitch.h"
24
25 /* These symbols are defined by the including source file:
26
27    ENTNAME -- database name of the structure and functions (hostent, pwent).
28    STRUCTURE -- struct name, define only if not ENTNAME (passwd, group).
29    DATABASE -- database file name, ("hosts", "passwd")
30
31    NEED_H_ERRNO - defined iff an arg `int *herrnop' is used.
32 */
33
34 #define ENTNAME_r       CONCAT(ENTNAME,_r)
35
36 #include <paths.h>
37 #define DBFILE          _PATH_VARDB DATABASE ".db"
38
39 #ifdef NEED_H_ERRNO
40 #define H_ERRNO_PROTO   , int *herrnop
41 #define H_ERRNO_ARG     , herrnop
42 #define H_ERRNO_SET(val) (*herrnop = (val))
43 #else
44 #define H_ERRNO_PROTO
45 #define H_ERRNO_ARG
46 #define H_ERRNO_SET(val) ((void) 0)
47 #endif
48
49 /* Locks the static variables in this file.  */
50 __libc_lock_define_initialized (static, lock)
51 \f
52 /* Maintenance of the shared handle open on the database.  */
53
54 static DB *db;
55 static int keep_db;
56 static unsigned int entidx;     /* Index for `getENTNAME'. */
57
58 /* Open database file if not already opened.  */
59 static enum nss_status
60 internal_setent (int stayopen)
61 {
62   enum nss_status status = NSS_STATUS_SUCCESS;
63
64   if (db == NULL)
65     {
66       db = dbopen (DBFILE, O_RDONLY, 0, DB_BTREE, NULL);
67
68       if (db == NULL)
69         status = NSS_STATUS_UNAVAIL;
70     }
71
72   /* Remember STAYOPEN flag.  */
73   if (db != NULL)
74     keep_db |= stayopen;
75
76   return status;
77 }
78
79
80 /* Thread-safe, exported version of that.  */
81 enum nss_status
82 CONCAT(_nss_db_set,ENTNAME) (int stayopen)
83 {
84   enum nss_status status;
85
86   __libc_lock_lock (lock);
87
88   status = internal_setent (stayopen);
89
90   /* Reset the sequential index.  */
91   entidx = 0;
92
93   __libc_lock_unlock (lock);
94
95   return status;
96 }
97
98
99 /* Close the database file.  */
100 static void
101 internal_endent (void)
102 {
103   if (db != NULL)
104     {
105       (*db->close) (db);
106       db = NULL;
107     }
108 }
109
110
111 /* Thread-safe, exported version of that.  */
112 enum nss_status
113 CONCAT(_nss_db_end,ENTNAME) (void)
114 {
115   __libc_lock_lock (lock);
116
117   internal_endent ();
118
119   /* Reset STAYOPEN flag.  */
120   keep_db = 0;
121
122   __libc_lock_unlock (lock);
123
124   return NSS_STATUS_SUCCESS;
125 }
126 \f
127 /* Do a database lookup for KEY.  */
128 static enum nss_status
129 lookup (const DBT *key, struct STRUCTURE *result,
130         void *buffer, int buflen H_ERRNO_PROTO)
131 {
132   enum nss_status status;
133   DBT value;
134
135   /* Open the database.  */
136   status = internal_setent (keep_db);
137   if (status != NSS_STATUS_SUCCESS)
138     return status;
139
140   /* Succeed iff it matches a value that parses correctly.  */
141   status = (((*db->get) (db, key, &value, 0) == 0 &&
142              parse_line (value.data, result, buffer, buflen))
143             ? NSS_STATUS_SUCCESS : NSS_STATUS_NOTFOUND);
144
145   if (! keep_db)
146     internal_endent ();
147
148   return status;
149 }
150
151
152 /* Macro for defining lookup functions for this DB-based database.
153
154    NAME is the name of the lookup; e.g. `pwnam'.
155
156    KEYPATTERN gives `printf' args to construct a key string;
157    e.g. `(".%s", name)'.
158
159    KEYSIZE gives the allocation size of a buffer to construct it in;
160    e.g. `1 + strlen (name)'.
161
162    PROTO describes the arguments for the lookup key;
163    e.g. `const char *name'.
164
165    BREAK_IF_MATCH is ignored, but used by ../nss_files/files-XXX.c.  */
166
167 #define DB_LOOKUP(name, keysize, keypattern, break_if_match, proto...)        \
168 enum nss_status                                                               \
169 _nss_db_get##name##_r (proto,                                                 \
170                        struct STRUCTURE *result,                              \
171                        char *buffer, size_t buflen H_ERRNO_PROTO)             \
172 {                                                                             \
173   DBT key;                                                                    \
174   enum nss_status status;                                                     \
175   const size_t size = (keysize);                                              \
176   key.data = __alloca (size);                                                 \
177   key.size = KEYPRINTF keypattern;                                            \
178   __libc_lock_lock (lock);                                                    \
179   status = lookup (&key, result, buffer, buflen H_ERRNO_ARG);                 \
180   __libc_lock_unlock (lock);                                                  \
181   return status;                                                              \
182 }
183
184 #define KEYPRINTF(pattern, args...) snprintf (key.data, size, pattern ,##args)
185 \f
186
187
188
189 /* Return the next entry from the database file, doing locking.  */
190 enum nss_status
191 CONCAT(_nss_db_get,ENTNAME_r) (struct STRUCTURE *result,
192                                char *buffer, size_t buflen H_ERRNO_PROTO)
193 {
194   /* Return next entry in host file.  */
195   enum nss_status status;
196   char buf[20];
197   DBT key;
198
199   __libc_lock_lock (lock);
200   key.size = 1 + snprintf (key.data = buf, sizeof buf, "0%u", entidx++);
201   status = lookup (&key, result, buffer, buflen H_ERRNO_ARG);
202   __libc_lock_unlock (lock);
203
204   return status;
205 }