1 /*
2  * Main entry point for database functions.
3  *
4  * Copyright 2007 Andrew Wood, distributed under the Artistic License.
5  */
6 
7 #include "config.h"
8 #include "database.h"
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <signal.h>
13 #ifdef HAVE_FCNTL
14 #include <fcntl.h>
15 #endif
16 
17 #ifdef USING_OBTREE
18 int qdb_obtree_identify(const char *);
19 qdbint_t qdb_obtree_open(const char *, qdb_open_t);
20 int qdb_obtree_fd(qdbint_t);
21 void qdb_obtree_close(qdbint_t);
22 qdb_datum qdb_obtree_fetch(qdbint_t, qdb_datum);
23 int qdb_obtree_store(qdbint_t, qdb_datum, qdb_datum);
24 int qdb_obtree_delete(qdbint_t, qdb_datum);
25 qdb_datum qdb_obtree_firstkey(qdbint_t);
26 qdb_datum qdb_obtree_nextkey(qdbint_t, qdb_datum);
27 char *qdb_obtree_error(void);
28 void qdb_obtree_unlock(qdbint_t);
29 void qdb_obtree_relock(qdbint_t);
30 #endif				/* USING_OBTREE */
31 #ifdef USING_BTREE
32 int qdb_btree_identify(const char *);
33 qdbint_t qdb_btree_open(const char *, qdb_open_t);
34 int qdb_btree_fd(qdbint_t);
35 void qdb_btree_close(qdbint_t);
36 qdb_datum qdb_btree_fetch(qdbint_t, qdb_datum);
37 int qdb_btree_store(qdbint_t, qdb_datum, qdb_datum);
38 int qdb_btree_delete(qdbint_t, qdb_datum);
39 qdb_datum qdb_btree_firstkey(qdbint_t);
40 qdb_datum qdb_btree_nextkey(qdbint_t, qdb_datum);
41 void qdb_btree_optimise(qdbint_t);
42 char *qdb_btree_error(void);
43 void qdb_btree_unlock(qdbint_t);
44 void qdb_btree_relock(qdbint_t);
45 #endif				/* USING_BTREE */
46 #ifdef USING_LIST
47 int qdb_list_identify(const char *);
48 qdbint_t qdb_list_open(const char *, qdb_open_t);
49 int qdb_list_fd(qdbint_t);
50 void qdb_list_close(qdbint_t);
51 qdb_datum qdb_list_fetch(qdbint_t, qdb_datum);
52 int qdb_list_store(qdbint_t, qdb_datum, qdb_datum);
53 int qdb_list_delete(qdbint_t, qdb_datum);
54 qdb_datum qdb_list_firstkey(qdbint_t);
55 qdb_datum qdb_list_nextkey(qdbint_t, qdb_datum);
56 char *qdb_list_error(void);
57 void qdb_list_restore_start(qdbint_t);
58 void qdb_list_restore_end(qdbint_t);
59 #endif				/* USING_LIST */
60 #ifdef USING_GDBM
61 int qdb_gdbm_identify(const char *);
62 qdbint_t qdb_gdbm_open(const char *, qdb_open_t);
63 int qdb_gdbm_fd(qdbint_t);
64 void qdb_gdbm_close(qdbint_t);
65 qdb_datum qdb_gdbm_fetch(qdbint_t, qdb_datum);
66 int qdb_gdbm_store(qdbint_t, qdb_datum, qdb_datum);
67 int qdb_gdbm_delete(qdbint_t, qdb_datum);
68 qdb_datum qdb_gdbm_firstkey(qdbint_t);
69 qdb_datum qdb_gdbm_nextkey(qdbint_t, qdb_datum);
70 void qdb_gdbm_optimise(qdbint_t);
71 char *qdb_gdbm_error(void);
72 #endif				/* USING_GDBM */
73 #ifdef USING_MYSQL
74 int qdb_mysql_identify(const char *);
75 qdbint_t qdb_mysql_open(const char *, qdb_open_t);
76 int qdb_mysql_fd(qdbint_t);
77 void qdb_mysql_close(qdbint_t);
78 qdb_datum qdb_mysql_fetch(qdbint_t, qdb_datum);
79 int qdb_mysql_store(qdbint_t, qdb_datum, qdb_datum);
80 int qdb_mysql_delete(qdbint_t, qdb_datum);
81 qdb_datum qdb_mysql_firstkey(qdbint_t);
82 qdb_datum qdb_mysql_nextkey(qdbint_t, qdb_datum);
83 char *qdb_mysql_error(void);
84 #endif				/* USING_MYSQL */
85 #ifdef USING_SQLITE
86 int qdb_sqlite_identify(const char *);
87 qdbint_t qdb_sqlite_open(const char *, qdb_open_t);
88 int qdb_sqlite_fd(qdbint_t);
89 void qdb_sqlite_close(qdbint_t);
90 qdb_datum qdb_sqlite_fetch(qdbint_t, qdb_datum);
91 int qdb_sqlite_store(qdbint_t, qdb_datum, qdb_datum);
92 int qdb_sqlite_delete(qdbint_t, qdb_datum);
93 qdb_datum qdb_sqlite_firstkey(qdbint_t);
94 qdb_datum qdb_sqlite_nextkey(qdbint_t, qdb_datum);
95 char *qdb_sqlite_error(void);
96 void qdb_sqlite_unlock(qdbint_t);
97 void qdb_sqlite_relock(qdbint_t);
98 #endif				/* USING_SQLITE */
99 
100 struct qdbtype_s {
101 	char *name;
102 	int (*_identify) (const char *);
103 	 qdbint_t(*_open) (const char *, qdb_open_t);
104 	int (*_fd) (qdbint_t);
105 	void (*_close) (qdbint_t);
106 	 qdb_datum(*_fetch) (qdbint_t, qdb_datum);
107 	int (*_store) (qdbint_t, qdb_datum, qdb_datum);
108 	int (*_delete) (qdbint_t, qdb_datum);
109 	 qdb_datum(*_firstkey) (qdbint_t);
110 	 qdb_datum(*_nextkey) (qdbint_t, qdb_datum);
111 	char *(*_error) (void);
112 	void (*_optimise) (qdbint_t);	 /* optional */
113 	void (*_unlock) (qdbint_t);	 /* optional */
114 	void (*_relock) (qdbint_t);	 /* optional */
115 	void (*_restore_start) (qdbint_t);	/* optional */
116 	void (*_restore_end) (qdbint_t); /* optional */
117 };
118 
119 struct qdb_s {
120 	struct qdbtype_s *type;
121 	int typeindex;
122 	struct qdbint_s *data;
123 };
124 
125 static struct qdbtype_s qdb__backends[] = {
126 #ifdef USING_LIST
127 	{
128 	 "list",
129 	 qdb_list_identify,
130 	 qdb_list_open,
131 	 qdb_list_fd,
132 	 qdb_list_close,
133 	 qdb_list_fetch,
134 	 qdb_list_store,
135 	 qdb_list_delete,
136 	 qdb_list_firstkey,
137 	 qdb_list_nextkey,
138 	 qdb_list_error,
139 	 NULL,				    /* optimise */
140 	 NULL,				    /* unlock */
141 	 NULL,				    /* relock */
142 	 qdb_list_restore_start,
143 	 qdb_list_restore_end},
144 #endif
145 #ifdef USING_BTREE
146 	{
147 	 "btree",
148 	 qdb_btree_identify,
149 	 qdb_btree_open,
150 	 qdb_btree_fd,
151 	 qdb_btree_close,
152 	 qdb_btree_fetch,
153 	 qdb_btree_store,
154 	 qdb_btree_delete,
155 	 qdb_btree_firstkey,
156 	 qdb_btree_nextkey,
157 	 qdb_btree_error,
158 	 qdb_btree_optimise,
159 	 qdb_btree_unlock,
160 	 qdb_btree_relock,
161 	 NULL,				    /* restore_start */
162 	 NULL},				    /* restore_end */
163 #endif
164 #ifdef USING_OBTREE
165 	{
166 	 "obtree",
167 	 qdb_obtree_identify,
168 	 qdb_obtree_open,
169 	 qdb_obtree_fd,
170 	 qdb_obtree_close,
171 	 qdb_obtree_fetch,
172 	 qdb_obtree_store,
173 	 qdb_obtree_delete,
174 	 qdb_obtree_firstkey,
175 	 qdb_obtree_nextkey,
176 	 qdb_obtree_error,
177 	 NULL,				    /* optimise */
178 	 qdb_obtree_unlock,
179 	 qdb_obtree_relock,
180 	 NULL,				    /* restore_start */
181 	 NULL},				    /* restore_end */
182 #endif
183 #ifdef USING_GDBM
184 	{
185 	 "GDBM",
186 	 qdb_gdbm_identify,
187 	 qdb_gdbm_open,
188 	 qdb_gdbm_fd,
189 	 qdb_gdbm_close,
190 	 qdb_gdbm_fetch,
191 	 qdb_gdbm_store,
192 	 qdb_gdbm_delete,
193 	 qdb_gdbm_firstkey,
194 	 qdb_gdbm_nextkey,
195 	 qdb_gdbm_error,
196 	 qdb_gdbm_optimise,
197 	 NULL,				    /* unlock */
198 	 NULL,				    /* relock */
199 	 NULL,				    /* restore_start */
200 	 NULL},				    /* restore_end */
201 #endif
202 #ifdef USING_MYSQL
203 	{
204 	 "MySQL",
205 	 qdb_mysql_identify,
206 	 qdb_mysql_open,
207 	 qdb_mysql_fd,
208 	 qdb_mysql_close,
209 	 qdb_mysql_fetch,
210 	 qdb_mysql_store,
211 	 qdb_mysql_delete,
212 	 qdb_mysql_firstkey,
213 	 qdb_mysql_nextkey,
214 	 qdb_mysql_error,
215 	 NULL,				    /* optimise */
216 	 NULL,				    /* unlock */
217 	 NULL,				    /* relock */
218 	 NULL,				    /* restore_start */
219 	 NULL},				    /* restore_end */
220 #endif
221 #ifdef USING_SQLITE
222 	{
223 	 "sqlite",
224 	 qdb_sqlite_identify,
225 	 qdb_sqlite_open,
226 	 qdb_sqlite_fd,
227 	 qdb_sqlite_close,
228 	 qdb_sqlite_fetch,
229 	 qdb_sqlite_store,
230 	 qdb_sqlite_delete,
231 	 qdb_sqlite_firstkey,
232 	 qdb_sqlite_nextkey,
233 	 qdb_sqlite_error,
234 	 NULL,				    /* optimise */
235 	 qdb_sqlite_unlock,
236 	 qdb_sqlite_relock,
237 	 NULL,				    /* restore_start */
238 	 NULL},				    /* restore_end */
239 #endif
240 	{NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
241 };
242 
243 static int qdb__lastbackend = 0;
244 
245 
246 /*
247  * Return a file descriptor for the given database, or -1 on error.
248  */
qdb_fd(qdb_t db)249 int qdb_fd(qdb_t db)
250 {
251 	if (db == NULL)
252 		return -1;
253 	qdb__lastbackend = db->typeindex;
254 	return db->type->_fd(db->data);
255 }
256 
257 
258 /*
259  * Return a string describing the type of the given database, or "(none)" on
260  * error. The string should NOT be free()d.
261  */
qdb_type(qdb_t db)262 char *qdb_type(qdb_t db)
263 {
264 	if (db == NULL)
265 		return "(none)";
266 	return db->type->name;
267 }
268 
269 
270 /*
271  * Open the given database in the given way (new database, read-only, or
272  * read-write); return a qdb_t or NULL on error.
273  */
qdb_open(const char * file,qdb_open_t method)274 qdb_t qdb_open(const char *file, qdb_open_t method)
275 {
276 	int type, i;
277 	qdb_t db;
278 
279 	type = -1;
280 	for (i = 0; type == -1 && qdb__backends[i].name != NULL; i++) {
281 		if (qdb__backends[i]._identify(file))
282 			type = i;
283 	}
284 
285 	/*
286 	 * If no valid type was determined, fall back to obtree if the file
287 	 * already exists, list if not (providing they are both compiled
288 	 * in). If neither is compiled in, fall back to the first available
289 	 * backend in the list.
290 	 */
291 	if (type == -1) {
292 		char *usetype = NULL;
293 		FILE *fptr;
294 
295 #ifdef USING_LIST
296 		usetype = "list";
297 #endif
298 
299 #ifdef USING_OBTREE
300 		fptr = fopen(file, "rb");
301 		if (fptr) {
302 			fclose(fptr);
303 			usetype = "obtree";
304 		}
305 #endif
306 
307 		if (usetype) {
308 			for (i = 0;
309 			     type == -1 && qdb__backends[i].name != NULL;
310 			     i++) {
311 				if (strcmp(qdb__backends[i].name, usetype)
312 				    == 0)
313 					type = i;
314 			}
315 		}
316 
317 		if (type == -1)
318 			type = 0;
319 	}
320 
321 	qdb__lastbackend = type;
322 
323 	db = calloc(1, sizeof(*db));
324 	if (db == NULL) {
325 		return NULL;
326 	}
327 
328 	db->type = &(qdb__backends[type]);
329 	db->typeindex = type;
330 	db->data = db->type->_open(file, method);
331 	if (db->data == NULL) {
332 		free(db);
333 		return NULL;
334 	}
335 
336 	return db;
337 }
338 
339 
340 /*
341  * Close the given database.
342  */
qdb_close(qdb_t db)343 void qdb_close(qdb_t db)
344 {
345 	if (db == NULL)
346 		return;
347 	qdb__lastbackend = db->typeindex;
348 	db->type->_close(db->data);
349 	free(db);
350 }
351 
352 
353 /*
354  * NOTE: From here on down, we take copies of "key" and "val" qdb_datum
355  * objects before sending them on to the backend. For some reason OpenBSD
356  * corrupts the key and val if we just pass them on, but if we pass on
357  * copies, it's OK.
358  */
359 
360 /*
361  * Fetch a value from the database. The datum returned needs its val.data
362  * free()ing after use. If val.data is NULL, no value was found for the
363  * given key.
364  */
qdb_fetch(qdb_t db,qdb_datum key)365 qdb_datum qdb_fetch(qdb_t db, qdb_datum key)
366 {
367 	qdb_datum keycopy;
368 
369 	if (db == NULL) {
370 		qdb_datum val;
371 		val.data = NULL;
372 		val.size = 0;
373 		return val;
374 	}
375 
376 	if (key.data == NULL) {
377 		qdb_datum val;
378 		val.data = NULL;
379 		val.size = 0;
380 		return val;
381 	}
382 
383 	keycopy = key;
384 
385 	qdb__lastbackend = db->typeindex;
386 	return db->type->_fetch(db->data, keycopy);
387 }
388 
389 
390 /*
391  * Store the given key with the given value into the database, replacing any
392  * existing value for that key. Returns nonzero on error.
393  */
qdb_store(qdb_t db,qdb_datum key,qdb_datum val)394 int qdb_store(qdb_t db, qdb_datum key, qdb_datum val)
395 {
396 	qdb_datum keycopy, valcopy;
397 
398 	if (db == NULL)
399 		return 1;
400 
401 	if ((key.data == NULL) || (val.data == NULL))
402 		return 1;
403 
404 	keycopy = key;
405 	valcopy = val;
406 
407 	qdb__lastbackend = db->typeindex;
408 	return db->type->_store(db->data, keycopy, valcopy);
409 }
410 
411 
412 /*
413  * Delete the given key from the database. Returns nonzero on error.
414  */
qdb_delete(qdb_t db,qdb_datum key)415 int qdb_delete(qdb_t db, qdb_datum key)
416 {
417 	qdb_datum keycopy;
418 
419 	if (db == NULL)
420 		return 1;
421 
422 	if (key.data == NULL)
423 		return 1;
424 
425 	keycopy = key;
426 
427 	qdb__lastbackend = db->typeindex;
428 	return db->type->_delete(db->data, keycopy);
429 }
430 
431 
432 /*
433  * Return the "first" key in the database, suitable for using with repeated
434  * calls to qdb_nextkey() to walk through every key in the database.
435  */
qdb_firstkey(qdb_t db)436 qdb_datum qdb_firstkey(qdb_t db)
437 {
438 	qdb__lastbackend = db->typeindex;
439 	return db->type->_firstkey(db->data);
440 }
441 
442 
443 /*
444  * Return the "next" key in the database, or key.data=NULL when all keys
445  * have been returned.
446  */
qdb_nextkey(qdb_t db,qdb_datum key)447 qdb_datum qdb_nextkey(qdb_t db, qdb_datum key)
448 {
449 	qdb_datum keycopy;
450 
451 	keycopy = key;
452 
453 	qdb__lastbackend = db->typeindex;
454 	return db->type->_nextkey(db->data, keycopy);
455 }
456 
457 
458 /*
459  * Reorganise the database for better efficiency.
460  */
qdb_optimise(qdb_t db)461 void qdb_optimise(qdb_t db)
462 {
463 	qdb__lastbackend = db->typeindex;
464 	if (db->type->_optimise == NULL)
465 		return;
466 	db->type->_optimise(db->data);
467 }
468 
469 
470 /*
471  * Return a string describing the last database error to occur.
472  */
qdb_error(void)473 char *qdb_error(void)
474 {
475 	return qdb__backends[qdb__lastbackend]._error();
476 }
477 
478 
479 /*
480  * Temporarily release the lock on the database.
481  */
qdb_unlock(qdb_t db)482 void qdb_unlock(qdb_t db)
483 {
484 	qdb__lastbackend = db->typeindex;
485 	if (db->type->_unlock == NULL)
486 		return;
487 	db->type->_unlock(db->data);
488 }
489 
490 
491 /*
492  * Reassert the lock on the database.
493  */
qdb_relock(qdb_t db)494 void qdb_relock(qdb_t db)
495 {
496 	qdb__lastbackend = db->typeindex;
497 	if (db->type->_relock == NULL)
498 		return;
499 	db->type->_relock(db->data);
500 }
501 
502 
503 /*
504  * Tell the database that a restore operation is starting.
505  */
qdb_restore_start(qdb_t db)506 void qdb_restore_start(qdb_t db)
507 {
508 	qdb__lastbackend = db->typeindex;
509 	if (db->type->_restore_start == NULL)
510 		return;
511 	db->type->_restore_start(db->data);
512 }
513 
514 
515 /*
516  * Tell the database that a restore operation is ending.
517  */
qdb_restore_end(qdb_t db)518 void qdb_restore_end(qdb_t db)
519 {
520 	qdb__lastbackend = db->typeindex;
521 	if (db->type->_restore_end == NULL)
522 		return;
523 	db->type->_restore_end(db->data);
524 }
525 
526 
527 /*
528  * Utility functions that can be used by the back-end follow.
529  */
530 
531 
532 /*
533  * Block common interrupt signals, so a user doesn't accidentally kill this
534  * process while it's doing something critical to data integrity.
535  */
qdb_int__sig_block(void)536 void qdb_int__sig_block(void)
537 {
538 #ifdef SIGHUP
539 	signal(SIGHUP, SIG_IGN);	    /* RATS: ignore (OK) */
540 #endif
541 #ifdef SIGINT
542 	signal(SIGINT, SIG_IGN);	    /* RATS: ignore (OK) */
543 #endif
544 #ifdef SIGQUIT
545 	signal(SIGQUIT, SIG_IGN);	    /* RATS: ignore (OK) */
546 #endif
547 #ifdef SIGTERM
548 	signal(SIGTERM, SIG_IGN);	    /* RATS: ignore (OK) */
549 #endif
550 }
551 
552 
553 /*
554  * Unblock previously blocked signals.
555  */
qdb_int__sig_unblock(void)556 void qdb_int__sig_unblock(void)
557 {
558 #ifdef SIGHUP
559 	signal(SIGHUP, SIG_DFL);	    /* RATS: ignore (OK) */
560 #endif
561 #ifdef SIGINT
562 	signal(SIGINT, SIG_DFL);	    /* RATS: ignore (OK) */
563 #endif
564 #ifdef SIGQUIT
565 	signal(SIGQUIT, SIG_DFL);	    /* RATS: ignore (OK) */
566 #endif
567 #ifdef SIGTERM
568 	signal(SIGTERM, SIG_DFL);	    /* RATS: ignore (OK) */
569 #endif
570 }
571 
572 
573 /*
574  * Obtain / release a read or write lock on the database. Returns zero on
575  * success, 1 on error. Blocks until a lock can be obtained. Keeps track of
576  * the number of times locked, so we don't accidentally try to lock a file
577  * descriptor twice.
578  */
qdb_int__lock(int fd,int lock_type,int * lockcount)579 int qdb_int__lock(int fd, int lock_type, int *lockcount)
580 {
581 #ifdef HAVE_FCNTL
582 	struct flock lock;
583 	int lockdummy = 0;
584 
585 	if (lockcount == NULL)
586 		lockcount = &lockdummy;
587 
588 	if ((lock_type == F_UNLCK) && (*lockcount > 1)) {
589 		*lockcount = (*lockcount) - 1;
590 		return 0;
591 	} else if ((lock_type != F_UNLCK) && (*lockcount > 0)) {
592 		*lockcount = (*lockcount) + 1;
593 		return 0;
594 	}
595 
596 	lock.l_whence = SEEK_SET;
597 	lock.l_start = 0;
598 	lock.l_len = 0;
599 
600 	lock.l_type = lock_type;
601 
602 	if (fcntl(fd, F_SETLKW, &lock)) {
603 		return 1;
604 	}
605 
606 	if (lock_type == F_UNLCK) {
607 		*lockcount = (*lockcount) - 1;
608 	} else {
609 		*lockcount = (*lockcount) + 1;
610 	}
611 
612 #endif				/* HAVE_FCNTL */
613 	return 0;
614 }
615 
616 
617 /* EOF */
618