Deleted Added
full compact
1/*
2** Copyright (c) 1999-2002 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#include <sm/gen.h>
11SM_RCSID("@(#)$Id: smdb2.c,v 8.72 2002/05/24 23:09:11 gshapiro Exp $")
11SM_RCSID("@(#)$Id: smdb2.c,v 8.72.2.4 2002/12/03 17:01:15 ca Exp $")
12
13#include <fcntl.h>
14#include <stdlib.h>
15#include <unistd.h>
16
17
18#include <sendmail/sendmail.h>
19#include <libsmdb/smdb.h>
20
21#if (DB_VERSION_MAJOR >= 2)
22
23# define SMDB2_FILE_EXTENSION "db"
24
25struct smdb_db2_database
26{
27 DB *smdb2_db;
28 int smdb2_lock_fd;
29};
30typedef struct smdb_db2_database SMDB_DB2_DATABASE;
31
32/*
33** SMDB_TYPE_TO_DB2_TYPE -- Translates smdb database type to db2 type.
34**
35** Parameters:
36** type -- The type to translate.
37**
38** Returns:
39** The DB2 type that corresponsds to the passed in SMDB type.
40** Returns -1 if there is no equivalent type.
41**
42*/
43
44DBTYPE
45smdb_type_to_db2_type(type)
46 SMDB_DBTYPE type;
47{
48 if (type == SMDB_TYPE_DEFAULT)
49 return DB_HASH;
50
51 if (strncmp(type, SMDB_TYPE_HASH, SMDB_TYPE_HASH_LEN) == 0)
52 return DB_HASH;
53
54 if (strncmp(type, SMDB_TYPE_BTREE, SMDB_TYPE_BTREE_LEN) == 0)
55 return DB_BTREE;
56
57 return DB_UNKNOWN;
58}
59/*
60** DB2_ERROR_TO_SMDB -- Translates db2 errors to smdbe errors
61**
62** Parameters:
63** error -- The error to translate.
64**
65** Returns:
66** The SMDBE error corresponding to the db2 error.
67** If we don't have a corresponding error, it returs errno.
68**
69*/
70
71int
72db2_error_to_smdb(error)
73 int error;
74{
75 int result;
76
77 switch (error)
78 {
79# ifdef DB_INCOMPLETE
80 case DB_INCOMPLETE:
81 result = SMDBE_INCOMPLETE;
82 break;
83# endif /* DB_INCOMPLETE */
84
85# ifdef DB_NOTFOUND
86 case DB_NOTFOUND:
87 result = SMDBE_NOT_FOUND;
88 break;
89# endif /* DB_NOTFOUND */
90
91# ifdef DB_KEYEMPTY
92 case DB_KEYEMPTY:
93 result = SMDBE_KEY_EMPTY;
94 break;
95# endif /* DB_KEYEMPTY */
96
97# ifdef DB_KEYEXIST
98 case DB_KEYEXIST:
99 result = SMDBE_KEY_EXIST;
100 break;
101# endif /* DB_KEYEXIST */
102
103# ifdef DB_LOCK_DEADLOCK
104 case DB_LOCK_DEADLOCK:
105 result = SMDBE_LOCK_DEADLOCK;
106 break;
107# endif /* DB_LOCK_DEADLOCK */
108
109# ifdef DB_LOCK_NOTGRANTED
110 case DB_LOCK_NOTGRANTED:
111 result = SMDBE_LOCK_NOT_GRANTED;
112 break;
113# endif /* DB_LOCK_NOTGRANTED */
114
115# ifdef DB_LOCK_NOTHELD
116 case DB_LOCK_NOTHELD:
117 result = SMDBE_LOCK_NOT_HELD;
118 break;
119# endif /* DB_LOCK_NOTHELD */
120
121# ifdef DB_RUNRECOVERY
122 case DB_RUNRECOVERY:
123 result = SMDBE_RUN_RECOVERY;
124 break;
125# endif /* DB_RUNRECOVERY */
126
127# ifdef DB_OLD_VERSION
128 case DB_OLD_VERSION:
129 result = SMDBE_OLD_VERSION;
130 break;
131# endif /* DB_OLD_VERSION */
132
133 case 0:
134 result = SMDBE_OK;
135 break;
136
137 default:
138 result = error;
139 }
140 return result;
141}
142/*
143** SMDB_PUT_FLAGS_TO_DB2_FLAGS -- Translates smdb put flags to db2 put flags.
144**
145** Parameters:
146** flags -- The flags to translate.
147**
148** Returns:
149** The db2 flags that are equivalent to the smdb flags.
150**
151** Notes:
152** Any invalid flags are ignored.
153**
154*/
155
156unsigned int
157smdb_put_flags_to_db2_flags(flags)
158 SMDB_FLAG flags;
159{
160 int return_flags;
161
162 return_flags = 0;
163
164 if (bitset(SMDBF_NO_OVERWRITE, flags))
165 return_flags |= DB_NOOVERWRITE;
166
167 return return_flags;
168}
169/*
170** SMDB_CURSOR_GET_FLAGS_TO_DB2 -- Translates smdb cursor get flags to db2
171** getflags.
172**
173** Parameters:
174** flags -- The flags to translate.
175**
176** Returns:
177** The db2 flags that are equivalent to the smdb flags.
178**
179** Notes:
180** -1 is returned if flag is unknown.
181**
182*/
183
184int
185smdb_cursor_get_flags_to_db2(flags)
186 SMDB_FLAG flags;
187{
188 switch (flags)
189 {
190 case SMDB_CURSOR_GET_FIRST:
191 return DB_FIRST;
192
193 case SMDB_CURSOR_GET_LAST:
194 return DB_LAST;
195
196 case SMDB_CURSOR_GET_NEXT:
197 return DB_NEXT;
198
199 case SMDB_CURSOR_GET_RANGE:
200 return DB_SET_RANGE;
201
202 default:
203 return -1;
204 }
205}
206
207/*
208** Except for smdb_db_open, the rest of these functions correspond to the
209** interface laid out in smdb.h.
210*/
211
212SMDB_DB2_DATABASE *
213smdb2_malloc_database()
214{
215 SMDB_DB2_DATABASE *db2;
216
217 db2 = (SMDB_DB2_DATABASE *) malloc(sizeof(SMDB_DB2_DATABASE));
218 if (db2 != NULL)
219 db2->smdb2_lock_fd = -1;
220
221 return db2;
222}
223
224int
225smdb2_close(database)
226 SMDB_DATABASE *database;
227{
228 int result;
229 SMDB_DB2_DATABASE *db2 = (SMDB_DB2_DATABASE *) database->smdb_impl;
230 DB *db = ((SMDB_DB2_DATABASE *) database->smdb_impl)->smdb2_db;
231
232 result = db2_error_to_smdb(db->close(db, 0));
233 if (db2->smdb2_lock_fd != -1)
234 close(db2->smdb2_lock_fd);
235
236 free(db2);
237 database->smdb_impl = NULL;
238
239 return result;
240}
241
242int
243smdb2_del(database, key, flags)
244 SMDB_DATABASE *database;
245 SMDB_DBENT *key;
246 unsigned int flags;
247{
248 DB *db = ((SMDB_DB2_DATABASE *) database->smdb_impl)->smdb2_db;
249 DBT dbkey;
250
251 (void) memset(&dbkey, '\0', sizeof dbkey);
252 dbkey.data = key->data;
253 dbkey.size = key->size;
254 return db2_error_to_smdb(db->del(db, NULL, &dbkey, flags));
255}
256
257int
258smdb2_fd(database, fd)
259 SMDB_DATABASE *database;
260 int *fd;
261{
262 DB *db = ((SMDB_DB2_DATABASE *) database->smdb_impl)->smdb2_db;
263
264 return db2_error_to_smdb(db->fd(db, fd));
265}
266
267int
268smdb2_lockfd(database)
269 SMDB_DATABASE *database;
270{
271 SMDB_DB2_DATABASE *db2 = (SMDB_DB2_DATABASE *) database->smdb_impl;
272
273 return db2->smdb2_lock_fd;
274}
275
276int
277smdb2_get(database, key, data, flags)
278 SMDB_DATABASE *database;
279 SMDB_DBENT *key;
280 SMDB_DBENT *data;
281 unsigned int flags;
282{
283 int result;
284 DB *db = ((SMDB_DB2_DATABASE *) database->smdb_impl)->smdb2_db;
285 DBT dbkey, dbdata;
286
287 (void) memset(&dbdata, '\0', sizeof dbdata);
288 (void) memset(&dbkey, '\0', sizeof dbkey);
289 dbkey.data = key->data;
290 dbkey.size = key->size;
291
292 result = db->get(db, NULL, &dbkey, &dbdata, flags);
293 data->data = dbdata.data;
294 data->size = dbdata.size;
295 return db2_error_to_smdb(result);
296}
297
298int
299smdb2_put(database, key, data, flags)
300 SMDB_DATABASE *database;
301 SMDB_DBENT *key;
302 SMDB_DBENT *data;
303 unsigned int flags;
304{
305 DB *db = ((SMDB_DB2_DATABASE *) database->smdb_impl)->smdb2_db;
306 DBT dbkey, dbdata;
307
308 (void) memset(&dbdata, '\0', sizeof dbdata);
309 (void) memset(&dbkey, '\0', sizeof dbkey);
310 dbkey.data = key->data;
311 dbkey.size = key->size;
312 dbdata.data = data->data;
313 dbdata.size = data->size;
314
315 return db2_error_to_smdb(db->put(db, NULL, &dbkey, &dbdata,
316 smdb_put_flags_to_db2_flags(flags)));
317}
318
319
320int
321smdb2_set_owner(database, uid, gid)
322 SMDB_DATABASE *database;
323 uid_t uid;
324 gid_t gid;
325{
326# if HASFCHOWN
327 int fd;
328 int result;
329 DB *db = ((SMDB_DB2_DATABASE *) database->smdb_impl)->smdb2_db;
330
331 result = db->fd(db, &fd);
332 if (result != 0)
333 return result;
334
335 result = fchown(fd, uid, gid);
336 if (result < 0)
337 return errno;
338# endif /* HASFCHOWN */
339
340 return SMDBE_OK;
341}
342
343int
344smdb2_sync(database, flags)
345 SMDB_DATABASE *database;
346 unsigned int flags;
347{
348 DB *db = ((SMDB_DB2_DATABASE *) database->smdb_impl)->smdb2_db;
349
350 return db2_error_to_smdb(db->sync(db, flags));
351}
352
353int
354smdb2_cursor_close(cursor)
355 SMDB_CURSOR *cursor;
356{
357 int ret;
358 DBC *dbc = (DBC *) cursor->smdbc_impl;
359
360 ret = db2_error_to_smdb(dbc->c_close(dbc));
361 free(cursor);
362 return ret;
363}
364
365int
366smdb2_cursor_del(cursor, flags)
367 SMDB_CURSOR *cursor;
368 SMDB_FLAG flags;
369{
370 DBC *dbc = (DBC *) cursor->smdbc_impl;
371
372 return db2_error_to_smdb(dbc->c_del(dbc, 0));
373}
374
375int
376smdb2_cursor_get(cursor, key, value, flags)
377 SMDB_CURSOR *cursor;
378 SMDB_DBENT *key;
379 SMDB_DBENT *value;
380 SMDB_FLAG flags;
381{
382 int db2_flags;
383 int result;
384 DBC *dbc = (DBC *) cursor->smdbc_impl;
385 DBT dbkey, dbdata;
386
387 (void) memset(&dbdata, '\0', sizeof dbdata);
388 (void) memset(&dbkey, '\0', sizeof dbkey);
389
390 db2_flags = smdb_cursor_get_flags_to_db2(flags);
391 result = dbc->c_get(dbc, &dbkey, &dbdata, db2_flags);
392 if (result == DB_NOTFOUND)
393 return SMDBE_LAST_ENTRY;
394 key->data = dbkey.data;
395 key->size = dbkey.size;
396 value->data = dbdata.data;
397 value->size = dbdata.size;
398 return db2_error_to_smdb(result);
399}
400
401int
402smdb2_cursor_put(cursor, key, value, flags)
403 SMDB_CURSOR *cursor;
404 SMDB_DBENT *key;
405 SMDB_DBENT *value;
406 SMDB_FLAG flags;
407{
408 DBC *dbc = (DBC *) cursor->smdbc_impl;
409 DBT dbkey, dbdata;
410
411 (void) memset(&dbdata, '\0', sizeof dbdata);
412 (void) memset(&dbkey, '\0', sizeof dbkey);
413 dbkey.data = key->data;
414 dbkey.size = key->size;
415 dbdata.data = value->data;
416 dbdata.size = value->size;
417
418 return db2_error_to_smdb(dbc->c_put(dbc, &dbkey, &dbdata, 0));
419}
420
421int
422smdb2_cursor(database, cursor, flags)
423 SMDB_DATABASE *database;
424 SMDB_CURSOR **cursor;
425 SMDB_FLAG flags;
426{
427 int result;
428 DB *db = ((SMDB_DB2_DATABASE *) database->smdb_impl)->smdb2_db;
429 DBC *db2_cursor;
430
431# if DB_VERSION_MAJOR > 2 || DB_VERSION_MINOR >= 6
432 result = db->cursor(db, NULL, &db2_cursor, 0);
433# else /* DB_VERSION_MAJOR > 2 || DB_VERSION_MINOR >= 6 */
434 result = db->cursor(db, NULL, &db2_cursor);
435# endif /* DB_VERSION_MAJOR > 2 || DB_VERSION_MINOR >= 6 */
436 if (result != 0)
437 return db2_error_to_smdb(result);
438
439 *cursor = (SMDB_CURSOR *) malloc(sizeof(SMDB_CURSOR));
440 if (*cursor == NULL)
441 return SMDBE_MALLOC;
442
443 (*cursor)->smdbc_close = smdb2_cursor_close;
444 (*cursor)->smdbc_del = smdb2_cursor_del;
445 (*cursor)->smdbc_get = smdb2_cursor_get;
446 (*cursor)->smdbc_put = smdb2_cursor_put;
447 (*cursor)->smdbc_impl = db2_cursor;
448
449 return SMDBE_OK;
450}
451
452# if DB_VERSION_MAJOR == 2
453static int
454smdb_db_open_internal(db_name, db_type, db_flags, db_params, db)
455 char *db_name;
456 DBTYPE db_type;
457 int db_flags;
458 SMDB_DBPARAMS *db_params;
459 DB **db;
460{
461 void *params;
462 DB_INFO db_info;
463
464 params = NULL;
465 (void) memset(&db_info, '\0', sizeof db_info);
466 if (db_params != NULL)
467 {
468 db_info.db_cachesize = db_params->smdbp_cache_size;
469 if (db_type == DB_HASH)
470 db_info.h_nelem = db_params->smdbp_num_elements;
471 if (db_params->smdbp_allow_dup)
472 db_info.flags |= DB_DUP;
473 params = &db_info;
474 }
475 return db_open(db_name, db_type, db_flags, DBMMODE, NULL, params, db);
476}
477# endif /* DB_VERSION_MAJOR == 2 */
478
479# if DB_VERSION_MAJOR > 2
480static int
481smdb_db_open_internal(db_name, db_type, db_flags, db_params, db)
482 char *db_name;
483 DBTYPE db_type;
484 int db_flags;
485 SMDB_DBPARAMS *db_params;
486 DB **db;
487{
488 int result;
489
490 result = db_create(db, NULL, 0);
491 if (result != 0 || *db == NULL)
492 return result;
493
494 if (db_params != NULL)
495 {
496 result = (*db)->set_cachesize(*db, 0,
497 db_params->smdbp_cache_size, 0);
498 if (result != 0)
499 {
500 (void) (*db)->close((*db), 0);
501 *db = NULL;
502 return db2_error_to_smdb(result);
503 }
504 if (db_type == DB_HASH)
505 {
506 result = (*db)->set_h_nelem(*db, db_params->smdbp_num_elements);
507 if (result != 0)
508 {
509 (void) (*db)->close(*db, 0);
510 *db = NULL;
511 return db2_error_to_smdb(result);
512 }
513 }
514 if (db_params->smdbp_allow_dup)
515 {
516 result = (*db)->set_flags(*db, DB_DUP);
517 if (result != 0)
518 {
519 (void) (*db)->close(*db, 0);
520 *db = NULL;
521 return db2_error_to_smdb(result);
522 }
523 }
524 }
525
526 result = (*db)->open(*db, db_name, NULL, db_type, db_flags, DBMMODE);
526 result = (*db)->open(*db,
527 DBTXN /* transaction for DB 4.1 */
528 db_name, NULL, db_type, db_flags, DBMMODE);
529 if (result != 0)
530 {
531 (void) (*db)->close(*db, 0);
532 *db = NULL;
533 }
534 return db2_error_to_smdb(result);
535}
536# endif /* DB_VERSION_MAJOR > 2 */
537/*
538** SMDB_DB_OPEN -- Opens a db database.
539**
540** Parameters:
541** database -- An unallocated database pointer to a pointer.
542** db_name -- The name of the database without extension.
543** mode -- File permisions for a created database.
544** mode_mask -- Mode bits that must match on an opened database.
545** sff -- Flags for safefile.
546** type -- The type of database to open
547** See smdb_type_to_db2_type for valid types.
548** user_info -- User information for file permissions.
549** db_params --
550** An SMDB_DBPARAMS struct including params. These
551** are processed according to the type of the
552** database. Currently supported params (only for
553** HASH type) are:
554** num_elements
555** cache_size
556**
557** Returns:
558** SMDBE_OK -- Success, other errno:
559** SMDBE_MALLOC -- Cannot allocate memory.
560** SMDBE_BAD_OPEN -- db_open didn't return an error, but
561** somehow the DB pointer is NULL.
562** Anything else: translated error from db2
563*/
564
565int
566smdb_db_open(database, db_name, mode, mode_mask, sff, type, user_info, db_params)
567 SMDB_DATABASE **database;
568 char *db_name;
569 int mode;
570 int mode_mask;
571 long sff;
572 SMDB_DBTYPE type;
573 SMDB_USER_INFO *user_info;
574 SMDB_DBPARAMS *db_params;
575{
576 bool lockcreated = false;
577 int result;
578 int db_flags;
579 int lock_fd;
580 int db_fd;
581 SMDB_DATABASE *smdb_db;
582 SMDB_DB2_DATABASE *db2;
583 DB *db;
584 DBTYPE db_type;
585 struct stat stat_info;
586 char db_file_name[MAXPATHLEN];
587
588 *database = NULL;
589
590 result = smdb_add_extension(db_file_name, sizeof db_file_name,
591 db_name, SMDB2_FILE_EXTENSION);
592 if (result != SMDBE_OK)
593 return result;
594
595 result = smdb_setup_file(db_name, SMDB2_FILE_EXTENSION,
596 mode_mask, sff, user_info, &stat_info);
597 if (result != SMDBE_OK)
598 return result;
599
600 lock_fd = -1;
601
602 if (stat_info.st_mode == ST_MODE_NOFILE &&
603 bitset(mode, O_CREAT))
604 lockcreated = true;
605
606 result = smdb_lock_file(&lock_fd, db_name, mode, sff,
607 SMDB2_FILE_EXTENSION);
608 if (result != SMDBE_OK)
609 return result;
610
611 if (lockcreated)
612 {
613 mode |= O_TRUNC;
614 mode &= ~(O_CREAT|O_EXCL);
615 }
616
617 smdb_db = smdb_malloc_database();
618 if (smdb_db == NULL)
619 return SMDBE_MALLOC;
620
621 db2 = smdb2_malloc_database();
622 if (db2 == NULL)
623 return SMDBE_MALLOC;
624
625 db2->smdb2_lock_fd = lock_fd;
626
627 db_type = smdb_type_to_db2_type(type);
628
629 db = NULL;
630
631 db_flags = 0;
632 if (bitset(O_CREAT, mode))
633 db_flags |= DB_CREATE;
634 if (bitset(O_TRUNC, mode))
635 db_flags |= DB_TRUNCATE;
636 if (mode == O_RDONLY)
637 db_flags |= DB_RDONLY;
636# if !HASFLOCK && defined(DB_FCNTL_LOCKING)
637 db_flags |= DB_FCNTL_LOCKING;
638# endif /* !HASFLOCK && defined(DB_FCNTL_LOCKING) */
638 SM_DB_FLAG_ADD(db_flags);
639
640 result = smdb_db_open_internal(db_file_name, db_type,
641 db_flags, db_params, &db);
642
643 if (result == 0 && db != NULL)
644 {
645 result = db->fd(db, &db_fd);
646 if (result == 0)
647 result = SMDBE_OK;
648 }
649 else
650 {
651 /* Try and narrow down on the problem */
652 if (result != 0)
653 result = db2_error_to_smdb(result);
654 else
655 result = SMDBE_BAD_OPEN;
656 }
657
658 if (result == SMDBE_OK)
659 result = smdb_filechanged(db_name, SMDB2_FILE_EXTENSION, db_fd,
660 &stat_info);
661
662 if (result == SMDBE_OK)
663 {
664 /* Everything is ok. Setup driver */
665 db2->smdb2_db = db;
666
667 smdb_db->smdb_close = smdb2_close;
668 smdb_db->smdb_del = smdb2_del;
669 smdb_db->smdb_fd = smdb2_fd;
670 smdb_db->smdb_lockfd = smdb2_lockfd;
671 smdb_db->smdb_get = smdb2_get;
672 smdb_db->smdb_put = smdb2_put;
673 smdb_db->smdb_set_owner = smdb2_set_owner;
674 smdb_db->smdb_sync = smdb2_sync;
675 smdb_db->smdb_cursor = smdb2_cursor;
676 smdb_db->smdb_impl = db2;
677
678 *database = smdb_db;
679
680 return SMDBE_OK;
681 }
682
683 if (db != NULL)
684 db->close(db, 0);
685
686 smdb_unlock_file(db2->smdb2_lock_fd);
687 free(db2);
688 smdb_free_database(smdb_db);
689
690 return result;
691}
692
693#endif /* (DB_VERSION_MAJOR >= 2) */