xref: /freebsd/contrib/sendmail/libsmdb/smdb1.c (revision 5521ff5a4d1929056e7ffc982fac3341ca54df7c)
1 /*
2 ** Copyright (c) 1999-2000 Sendmail, Inc. and its suppliers.
3 **	All rights reserved.
4 **
5 ** By using this file, you agree to the terms and conditions set
6 ** forth in the LICENSE file which can be found at the top level of
7 ** the sendmail distribution.
8 */
9 
10 #ifndef lint
11 static char id[] = "@(#)$Id: smdb1.c,v 8.43.4.3 2000/10/05 23:06:30 gshapiro Exp $";
12 #endif /* ! lint */
13 
14 #include <unistd.h>
15 #include <stdlib.h>
16 #include <fcntl.h>
17 
18 #include <sendmail/sendmail.h>
19 #include <libsmdb/smdb.h>
20 
21 #if (DB_VERSION_MAJOR == 1)
22 
23 # define SMDB1_FILE_EXTENSION "db"
24 
25 struct smdb_db1_struct
26 {
27 	DB	*smdb1_db;
28 	int	smdb1_lock_fd;
29 	bool	smdb1_cursor_in_use;
30 };
31 typedef struct smdb_db1_struct SMDB_DB1_DATABASE;
32 
33 struct smdb_db1_cursor
34 {
35 	SMDB_DB1_DATABASE	*db;
36 };
37 typedef struct smdb_db1_cursor SMDB_DB1_CURSOR;
38 
39 /*
40 **  SMDB_TYPE_TO_DB1_TYPE -- Translates smdb database type to db1 type.
41 **
42 **	Parameters:
43 **		type -- The type to translate.
44 **
45 **	Returns:
46 **		The DB1 type that corresponsds to the passed in SMDB type.
47 **		Returns -1 if there is no equivalent type.
48 **
49 */
50 
51 DBTYPE
52 smdb_type_to_db1_type(type)
53 	SMDB_DBTYPE type;
54 {
55 	if (type == SMDB_TYPE_DEFAULT)
56 		return DB_HASH;
57 
58 	if (strncmp(type, SMDB_TYPE_HASH, SMDB_TYPE_HASH_LEN) == 0)
59 		return DB_HASH;
60 
61 	if (strncmp(type, SMDB_TYPE_BTREE, SMDB_TYPE_BTREE_LEN) == 0)
62 		return DB_BTREE;
63 
64 	/* Should never get here thanks to test in smdb_db_open() */
65 	return DB_HASH;
66 }
67 
68 
69 /*
70 **  SMDB_PUT_FLAGS_TO_DB1_FLAGS -- Translates smdb put flags to db1 put flags.
71 **
72 **	Parameters:
73 **		flags -- The flags to translate.
74 **
75 **	Returns:
76 **		The db1 flags that are equivalent to the smdb flags.
77 **
78 **	Notes:
79 **		Any invalid flags are ignored.
80 **
81 */
82 
83 u_int
84 smdb_put_flags_to_db1_flags(flags)
85 	SMDB_FLAG flags;
86 {
87 	int return_flags;
88 
89 	return_flags = 0;
90 
91 	if (bitset(SMDBF_NO_OVERWRITE, flags))
92 		return_flags |= R_NOOVERWRITE;
93 
94 	return return_flags;
95 }
96 
97 /*
98 **  SMDB_CURSOR_GET_FLAGS_TO_SMDB1
99 **
100 **	Parameters:
101 **		flags -- The flags to translate.
102 **
103 **	Returns:
104 **		The db1 flags that are equivalent to the smdb flags.
105 **
106 **	Notes:
107 **		Returns -1 if we don't support the flag.
108 **
109 */
110 
111 int
112 smdb_cursor_get_flags_to_smdb1(flags)
113 	SMDB_FLAG flags;
114 {
115 	switch(flags)
116 	{
117 		case SMDB_CURSOR_GET_FIRST:
118 			return R_FIRST;
119 
120 		case SMDB_CURSOR_GET_LAST:
121 			return R_LAST;
122 
123 		case SMDB_CURSOR_GET_NEXT:
124 			return R_NEXT;
125 
126 		case SMDB_CURSOR_GET_RANGE:
127 			return R_CURSOR;
128 
129 		default:
130 			return -1;
131 	}
132 }
133 
134 SMDB_DB1_DATABASE *
135 smdb1_malloc_database()
136 {
137 	SMDB_DB1_DATABASE *db1;
138 
139 	db1 = (SMDB_DB1_DATABASE *) malloc(sizeof(SMDB_DB1_DATABASE));
140 
141 	if (db1 != NULL)
142 	{
143 		db1->smdb1_lock_fd = -1;
144 		db1->smdb1_cursor_in_use = FALSE;
145 	}
146 
147 	return db1;
148 }
149 
150 /*
151 ** The rest of these function correspond to the interface laid out
152 ** in smdb.h.
153 */
154 
155 int
156 smdb1_close(database)
157 	SMDB_DATABASE *database;
158 {
159 	SMDB_DB1_DATABASE *db1 = (SMDB_DB1_DATABASE *) database->smdb_impl;
160 	DB *db = ((SMDB_DB1_DATABASE *) database->smdb_impl)->smdb1_db;
161 
162 	if (db1->smdb1_lock_fd != -1)
163 		(void) close(db1->smdb1_lock_fd);
164 
165 	free(db1);
166 	database->smdb_impl = NULL;
167 
168 	return db->close(db);
169 }
170 
171 int
172 smdb1_del(database, key, flags)
173 	SMDB_DATABASE *database;
174 	SMDB_DBENT *key;
175 	u_int flags;
176 {
177 	DB *db = ((SMDB_DB1_DATABASE *) database->smdb_impl)->smdb1_db;
178 	DBT dbkey;
179 
180 	memset(&dbkey, '\0', sizeof dbkey);
181 	dbkey.data = key->data;
182 	dbkey.size = key->size;
183 	return db->del(db, &dbkey, flags);
184 }
185 
186 int
187 smdb1_fd(database, fd)
188 	SMDB_DATABASE *database;
189 	int *fd;
190 {
191 	DB *db = ((SMDB_DB1_DATABASE *) database->smdb_impl)->smdb1_db;
192 
193 	*fd = db->fd(db);
194 	if (*fd == -1)
195 		return errno;
196 
197 	return SMDBE_OK;
198 }
199 
200 int
201 smdb1_lockfd(database)
202 	SMDB_DATABASE *database;
203 {
204 	SMDB_DB1_DATABASE *db1 = (SMDB_DB1_DATABASE *) database->smdb_impl;
205 
206 	return db1->smdb1_lock_fd;
207 }
208 
209 
210 int
211 smdb1_get(database, key, data, flags)
212 	SMDB_DATABASE *database;
213 	SMDB_DBENT *key;
214 	SMDB_DBENT *data;
215 	u_int flags;
216 {
217 	int result;
218 	DB *db = ((SMDB_DB1_DATABASE *) database->smdb_impl)->smdb1_db;
219 	DBT dbkey, dbdata;
220 
221 	memset(&dbdata, '\0', sizeof dbdata);
222 	memset(&dbkey, '\0', sizeof dbkey);
223 	dbkey.data = key->data;
224 	dbkey.size = key->size;
225 
226 	result = db->get(db, &dbkey, &dbdata, flags);
227 	if (result != 0)
228 	{
229 		if (result == 1)
230 			return SMDBE_NOT_FOUND;
231 		return errno;
232 	}
233 	data->data = dbdata.data;
234 	data->size = dbdata.size;
235 	return SMDBE_OK;
236 }
237 
238 int
239 smdb1_put(database, key, data, flags)
240 	SMDB_DATABASE *database;
241 	SMDB_DBENT *key;
242 	SMDB_DBENT *data;
243 	u_int flags;
244 {
245 	DB *db = ((SMDB_DB1_DATABASE *) database->smdb_impl)->smdb1_db;
246 	DBT dbkey, dbdata;
247 
248 	memset(&dbdata, '\0', sizeof dbdata);
249 	memset(&dbkey, '\0', sizeof dbkey);
250 	dbkey.data = key->data;
251 	dbkey.size = key->size;
252 	dbdata.data = data->data;
253 	dbdata.size = data->size;
254 
255 	return db->put(db, &dbkey, &dbdata,
256 		       smdb_put_flags_to_db1_flags(flags));
257 }
258 
259 int
260 smdb1_set_owner(database, uid, gid)
261 	SMDB_DATABASE *database;
262 	uid_t uid;
263 	gid_t gid;
264 {
265 # if HASFCHOWN
266 	int fd;
267 	int result;
268 	DB *db = ((SMDB_DB1_DATABASE *) database->smdb_impl)->smdb1_db;
269 
270 	fd = db->fd(db);
271 	if (fd == -1)
272 		return errno;
273 
274 	result = fchown(fd, uid, gid);
275 	if (result < 0)
276 		return errno;
277 # endif /* HASFCHOWN */
278 
279 	return SMDBE_OK;
280 }
281 
282 int
283 smdb1_sync(database, flags)
284 	SMDB_DATABASE *database;
285 	u_int flags;
286 {
287 	DB *db = ((SMDB_DB1_DATABASE *) database->smdb_impl)->smdb1_db;
288 
289 	return db->sync(db, flags);
290 }
291 
292 int
293 smdb1_cursor_close(cursor)
294 	SMDB_CURSOR *cursor;
295 {
296 	SMDB_DB1_CURSOR *db1_cursor = (SMDB_DB1_CURSOR *) cursor->smdbc_impl;
297 	SMDB_DB1_DATABASE *db1 = db1_cursor->db;
298 
299 	if (!db1->smdb1_cursor_in_use)
300 		return SMDBE_NOT_A_VALID_CURSOR;
301 
302 	db1->smdb1_cursor_in_use = FALSE;
303 	free(cursor);
304 
305 	return SMDBE_OK;
306 }
307 
308 int
309 smdb1_cursor_del(cursor, flags)
310 	SMDB_CURSOR *cursor;
311 	u_int flags;
312 {
313 	SMDB_DB1_CURSOR *db1_cursor = (SMDB_DB1_CURSOR *) cursor->smdbc_impl;
314 	SMDB_DB1_DATABASE *db1 = db1_cursor->db;
315 	DB *db = db1->smdb1_db;
316 
317 	return db->del(db, NULL, R_CURSOR);
318 }
319 
320 int
321 smdb1_cursor_get(cursor, key, value, flags)
322 	SMDB_CURSOR *cursor;
323 	SMDB_DBENT *key;
324 	SMDB_DBENT *value;
325 	SMDB_FLAG flags;
326 {
327 	int db1_flags;
328 	int result;
329 	SMDB_DB1_CURSOR *db1_cursor = (SMDB_DB1_CURSOR *) cursor->smdbc_impl;
330 	SMDB_DB1_DATABASE *db1 = db1_cursor->db;
331 	DB *db = db1->smdb1_db;
332 	DBT dbkey, dbdata;
333 
334 	memset(&dbdata, '\0', sizeof dbdata);
335 	memset(&dbkey, '\0', sizeof dbkey);
336 
337 	db1_flags = smdb_cursor_get_flags_to_smdb1(flags);
338 	result = db->seq(db, &dbkey, &dbdata, db1_flags);
339 	if (result == -1)
340 		return errno;
341 	if (result == 1)
342 		return SMDBE_LAST_ENTRY;
343 	value->data = dbdata.data;
344 	value->size = dbdata.size;
345 	key->data = dbkey.data;
346 	key->size = dbkey.size;
347 	return SMDBE_OK;
348 }
349 
350 int
351 smdb1_cursor_put(cursor, key, value, flags)
352 	SMDB_CURSOR *cursor;
353 	SMDB_DBENT *key;
354 	SMDB_DBENT *value;
355 	SMDB_FLAG flags;
356 {
357 	SMDB_DB1_CURSOR *db1_cursor = (SMDB_DB1_CURSOR *) cursor->smdbc_impl;
358 	SMDB_DB1_DATABASE *db1 = db1_cursor->db;
359 	DB *db = db1->smdb1_db;
360 	DBT dbkey, dbdata;
361 
362 	memset(&dbdata, '\0', sizeof dbdata);
363 	memset(&dbkey, '\0', sizeof dbkey);
364 	dbkey.data = key->data;
365 	dbkey.size = key->size;
366 	dbdata.data = value->data;
367 	dbdata.size = value->size;
368 
369 	return db->put(db, &dbkey, &dbdata, R_CURSOR);
370 }
371 
372 int
373 smdb1_cursor(database, cursor, flags)
374 	SMDB_DATABASE *database;
375 	SMDB_CURSOR **cursor;
376 	u_int flags;
377 {
378 	SMDB_DB1_DATABASE *db1 = (SMDB_DB1_DATABASE *) database->smdb_impl;
379 	SMDB_CURSOR *cur;
380 	SMDB_DB1_CURSOR *db1_cursor;
381 
382 	if (db1->smdb1_cursor_in_use)
383 		return SMDBE_ONLY_SUPPORTS_ONE_CURSOR;
384 
385 	db1->smdb1_cursor_in_use = TRUE;
386 	db1_cursor = (SMDB_DB1_CURSOR *) malloc(sizeof(SMDB_DB1_CURSOR));
387 	db1_cursor->db = db1;
388 
389 	cur = (SMDB_CURSOR *) malloc(sizeof(SMDB_CURSOR));
390 
391 	if (cur == NULL)
392 		return SMDBE_MALLOC;
393 
394 	cur->smdbc_impl = db1_cursor;
395 	cur->smdbc_close = smdb1_cursor_close;
396 	cur->smdbc_del = smdb1_cursor_del;
397 	cur->smdbc_get = smdb1_cursor_get;
398 	cur->smdbc_put = smdb1_cursor_put;
399 	*cursor = cur;
400 
401 	return SMDBE_OK;
402 }
403 
404 /*
405 **  SMDB_DB_OPEN -- Opens a db1 database.
406 **
407 **	Parameters:
408 **		database -- An unallocated database pointer to a pointer.
409 **		db_name -- The name of the database without extension.
410 **		mode -- File permisions on the database if created.
411 **		mode_mask -- Mode bits that must match on an existing database.
412 **		sff -- Flags for safefile.
413 **		type -- The type of database to open
414 **			See smdb_type_to_db1_type for valid types.
415 **		user_info -- Information on the user to use for file
416 **			    permissions.
417 **		db_params --
418 **			An SMDB_DBPARAMS struct including params. These
419 **			are processed according to the type of the
420 **			database. Currently supported params (only for
421 **			HASH type) are:
422 **			   num_elements
423 **			   cache_size
424 **
425 **	Returns:
426 **		SMDBE_OK -- Success, otherwise errno.
427 */
428 
429 int
430 smdb_db_open(database, db_name, mode, mode_mask, sff, type, user_info,
431 	     db_params)
432 	SMDB_DATABASE **database;
433 	char *db_name;
434 	int mode;
435 	int mode_mask;
436 	long sff;
437 	SMDB_DBTYPE type;
438 	SMDB_USER_INFO *user_info;
439 	SMDB_DBPARAMS *db_params;
440 {
441 	int db_fd;
442 	int lock_fd;
443 	int result;
444 	void *params;
445 	SMDB_DATABASE *smdb_db;
446 	SMDB_DB1_DATABASE *db1;
447 	DB *db;
448 	HASHINFO hash_info;
449 	BTREEINFO btree_info;
450 	DBTYPE db_type;
451 	struct stat stat_info;
452 	char db_file_name[SMDB_MAX_NAME_LEN];
453 
454 	if (type == NULL ||
455 	    (strncmp(SMDB_TYPE_HASH, type, SMDB_TYPE_HASH_LEN) != 0 &&
456 	     strncmp(SMDB_TYPE_BTREE, type, SMDB_TYPE_BTREE_LEN) != 0))
457 		return SMDBE_UNKNOWN_DB_TYPE;
458 
459 	result = smdb_add_extension(db_file_name, SMDB_MAX_NAME_LEN,
460 				    db_name, SMDB1_FILE_EXTENSION);
461 	if (result != SMDBE_OK)
462 		return result;
463 
464 	result = smdb_setup_file(db_name, SMDB1_FILE_EXTENSION, mode_mask,
465 				 sff, user_info, &stat_info);
466 	if (result != SMDBE_OK)
467 		return result;
468 
469 	lock_fd = -1;
470 # if O_EXLOCK
471 	mode |= O_EXLOCK;
472 # else /* O_EXLOCK */
473 	result = smdb_lock_file(&lock_fd, db_name, mode, sff,
474 				SMDB1_FILE_EXTENSION);
475 	if (result != SMDBE_OK)
476 		return result;
477 # endif /* O_EXLOCK */
478 
479 	*database = NULL;
480 
481 	smdb_db = smdb_malloc_database();
482 	db1 = smdb1_malloc_database();
483 	if (smdb_db == NULL || db1 == NULL)
484 		return SMDBE_MALLOC;
485 	db1->smdb1_lock_fd = lock_fd;
486 
487 	params = NULL;
488 	if (db_params != NULL &&
489 	    (strncmp(SMDB_TYPE_HASH, type, SMDB_TYPE_HASH_LEN) == 0))
490 	{
491 		memset(&hash_info, '\0', sizeof hash_info);
492 		hash_info.nelem = db_params->smdbp_num_elements;
493 		hash_info.cachesize = db_params->smdbp_cache_size;
494 		params = &hash_info;
495 	}
496 
497 	if (db_params != NULL &&
498 	    (strncmp(SMDB_TYPE_BTREE, type, SMDB_TYPE_BTREE_LEN) == 0))
499 	{
500 		memset(&btree_info, '\0', sizeof btree_info);
501 		btree_info.cachesize = db_params->smdbp_cache_size;
502 		if (db_params->smdbp_allow_dup)
503 			btree_info.flags |= R_DUP;
504 		params = &btree_info;
505 	}
506 
507 	db_type = smdb_type_to_db1_type(type);
508 	db = dbopen(db_file_name, mode, 0644, db_type, params);
509 	if (db != NULL)
510 	{
511 		db_fd = db->fd(db);
512 		result = smdb_filechanged(db_name, SMDB1_FILE_EXTENSION, db_fd,
513 					  &stat_info);
514 	}
515 	else
516 	{
517 		if (errno == 0)
518 			result = SMDBE_BAD_OPEN;
519 		else
520 			result = errno;
521 	}
522 
523 	if (result == SMDBE_OK)
524 	{
525 		/* Everything is ok. Setup driver */
526 		db1->smdb1_db = db;
527 
528 		smdb_db->smdb_close = smdb1_close;
529 		smdb_db->smdb_del = smdb1_del;
530 		smdb_db->smdb_fd = smdb1_fd;
531 		smdb_db->smdb_lockfd = smdb1_lockfd;
532 		smdb_db->smdb_get = smdb1_get;
533 		smdb_db->smdb_put = smdb1_put;
534 		smdb_db->smdb_set_owner = smdb1_set_owner;
535 		smdb_db->smdb_sync = smdb1_sync;
536 		smdb_db->smdb_cursor = smdb1_cursor;
537 		smdb_db->smdb_impl = db1;
538 
539 		*database = smdb_db;
540 		return SMDBE_OK;
541 	}
542 
543 	if (db != NULL)
544 		(void) db->close(db);
545 
546 	/* Error opening database */
547 	(void) smdb_unlock_file(db1->smdb1_lock_fd);
548 	free(db1);
549 	smdb_free_database(smdb_db);
550 
551 	return result;
552 }
553 
554 #endif /* (DB_VERSION_MAJOR == 1) */
555