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