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