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