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