r23751: Call tdb_close even when validation was not successful.
[Samba/bb.git] / source / lib / util_tdb.c
blob5f9a5115b6bfc61070ad3aa35ff6aa399f419f59
1 /*
2 Unix SMB/CIFS implementation.
3 tdb utility functions
4 Copyright (C) Andrew Tridgell 1992-1998
5 Copyright (C) Rafal Szczesniak 2002
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 #include "includes.h"
23 #undef malloc
24 #undef realloc
25 #undef calloc
26 #undef strdup
28 /* these are little tdb utility functions that are meant to make
29 dealing with a tdb database a little less cumbersome in Samba */
31 static SIG_ATOMIC_T gotalarm;
33 /***************************************************************
34 Signal function to tell us we timed out.
35 ****************************************************************/
37 static void gotalarm_sig(void)
39 gotalarm = 1;
42 /***************************************************************
43 Make a TDB_DATA and keep the const warning in one place
44 ****************************************************************/
46 TDB_DATA make_tdb_data(const uint8 *dptr, size_t dsize)
48 TDB_DATA ret;
49 ret.dptr = CONST_DISCARD(uint8 *, dptr);
50 ret.dsize = dsize;
51 return ret;
54 TDB_DATA string_tdb_data(const char *string)
56 return make_tdb_data((const uint8 *)string, string ? strlen(string) : 0 );
59 TDB_DATA string_term_tdb_data(const char *string)
61 return make_tdb_data((const uint8 *)string, string ? strlen(string) + 1 : 0);
64 /****************************************************************************
65 Lock a chain with timeout (in seconds).
66 ****************************************************************************/
68 static int tdb_chainlock_with_timeout_internal( TDB_CONTEXT *tdb, TDB_DATA key, unsigned int timeout, int rw_type)
70 /* Allow tdb_chainlock to be interrupted by an alarm. */
71 int ret;
72 gotalarm = 0;
74 if (timeout) {
75 CatchSignal(SIGALRM, SIGNAL_CAST gotalarm_sig);
76 alarm(timeout);
79 if (rw_type == F_RDLCK)
80 ret = tdb_chainlock_read(tdb, key);
81 else
82 ret = tdb_chainlock(tdb, key);
84 if (timeout) {
85 alarm(0);
86 CatchSignal(SIGALRM, SIGNAL_CAST SIG_IGN);
87 if (gotalarm) {
88 DEBUG(0,("tdb_chainlock_with_timeout_internal: alarm (%u) timed out for key %s in tdb %s\n",
89 timeout, key.dptr, tdb_name(tdb)));
90 /* TODO: If we time out waiting for a lock, it might
91 * be nice to use F_GETLK to get the pid of the
92 * process currently holding the lock and print that
93 * as part of the debugging message. -- mbp */
94 return -1;
98 return ret;
101 /****************************************************************************
102 Write lock a chain. Return -1 if timeout or lock failed.
103 ****************************************************************************/
105 int tdb_chainlock_with_timeout( TDB_CONTEXT *tdb, TDB_DATA key, unsigned int timeout)
107 return tdb_chainlock_with_timeout_internal(tdb, key, timeout, F_WRLCK);
110 /****************************************************************************
111 Lock a chain by string. Return -1 if timeout or lock failed.
112 ****************************************************************************/
114 int tdb_lock_bystring(TDB_CONTEXT *tdb, const char *keyval)
116 TDB_DATA key = string_term_tdb_data(keyval);
118 return tdb_chainlock(tdb, key);
121 int tdb_lock_bystring_with_timeout(TDB_CONTEXT *tdb, const char *keyval,
122 int timeout)
124 TDB_DATA key = string_term_tdb_data(keyval);
126 return tdb_chainlock_with_timeout(tdb, key, timeout);
129 /****************************************************************************
130 Unlock a chain by string.
131 ****************************************************************************/
133 void tdb_unlock_bystring(TDB_CONTEXT *tdb, const char *keyval)
135 TDB_DATA key = string_term_tdb_data(keyval);
137 tdb_chainunlock(tdb, key);
140 /****************************************************************************
141 Read lock a chain by string. Return -1 if timeout or lock failed.
142 ****************************************************************************/
144 int tdb_read_lock_bystring_with_timeout(TDB_CONTEXT *tdb, const char *keyval, unsigned int timeout)
146 TDB_DATA key = string_term_tdb_data(keyval);
148 return tdb_chainlock_with_timeout_internal(tdb, key, timeout, F_RDLCK);
151 /****************************************************************************
152 Read unlock a chain by string.
153 ****************************************************************************/
155 void tdb_read_unlock_bystring(TDB_CONTEXT *tdb, const char *keyval)
157 TDB_DATA key = string_term_tdb_data(keyval);
159 tdb_chainunlock_read(tdb, key);
163 /****************************************************************************
164 Fetch a int32 value by a arbitrary blob key, return -1 if not found.
165 Output is int32 in native byte order.
166 ****************************************************************************/
168 int32 tdb_fetch_int32_byblob(TDB_CONTEXT *tdb, TDB_DATA key)
170 TDB_DATA data;
171 int32 ret;
173 data = tdb_fetch(tdb, key);
174 if (!data.dptr || data.dsize != sizeof(int32)) {
175 SAFE_FREE(data.dptr);
176 return -1;
179 ret = IVAL(data.dptr,0);
180 SAFE_FREE(data.dptr);
181 return ret;
184 /****************************************************************************
185 Fetch a int32 value by string key, return -1 if not found.
186 Output is int32 in native byte order.
187 ****************************************************************************/
189 int32 tdb_fetch_int32(TDB_CONTEXT *tdb, const char *keystr)
191 TDB_DATA key = string_term_tdb_data(keystr);
193 return tdb_fetch_int32_byblob(tdb, key);
196 /****************************************************************************
197 Store a int32 value by an arbitary blob key, return 0 on success, -1 on failure.
198 Input is int32 in native byte order. Output in tdb is in little-endian.
199 ****************************************************************************/
201 int tdb_store_int32_byblob(TDB_CONTEXT *tdb, TDB_DATA key, int32 v)
203 TDB_DATA data;
204 int32 v_store;
206 SIVAL(&v_store,0,v);
207 data.dptr = (uint8 *)&v_store;
208 data.dsize = sizeof(int32);
210 return tdb_store(tdb, key, data, TDB_REPLACE);
213 /****************************************************************************
214 Store a int32 value by string key, return 0 on success, -1 on failure.
215 Input is int32 in native byte order. Output in tdb is in little-endian.
216 ****************************************************************************/
218 int tdb_store_int32(TDB_CONTEXT *tdb, const char *keystr, int32 v)
220 TDB_DATA key = string_term_tdb_data(keystr);
222 return tdb_store_int32_byblob(tdb, key, v);
225 /****************************************************************************
226 Fetch a uint32 value by a arbitrary blob key, return -1 if not found.
227 Output is uint32 in native byte order.
228 ****************************************************************************/
230 BOOL tdb_fetch_uint32_byblob(TDB_CONTEXT *tdb, TDB_DATA key, uint32 *value)
232 TDB_DATA data;
234 data = tdb_fetch(tdb, key);
235 if (!data.dptr || data.dsize != sizeof(uint32)) {
236 SAFE_FREE(data.dptr);
237 return False;
240 *value = IVAL(data.dptr,0);
241 SAFE_FREE(data.dptr);
242 return True;
245 /****************************************************************************
246 Fetch a uint32 value by string key, return -1 if not found.
247 Output is uint32 in native byte order.
248 ****************************************************************************/
250 BOOL tdb_fetch_uint32(TDB_CONTEXT *tdb, const char *keystr, uint32 *value)
252 TDB_DATA key = string_term_tdb_data(keystr);
254 return tdb_fetch_uint32_byblob(tdb, key, value);
257 /****************************************************************************
258 Store a uint32 value by an arbitary blob key, return 0 on success, -1 on failure.
259 Input is uint32 in native byte order. Output in tdb is in little-endian.
260 ****************************************************************************/
262 BOOL tdb_store_uint32_byblob(TDB_CONTEXT *tdb, TDB_DATA key, uint32 value)
264 TDB_DATA data;
265 uint32 v_store;
266 BOOL ret = True;
268 SIVAL(&v_store, 0, value);
269 data.dptr = (uint8 *)&v_store;
270 data.dsize = sizeof(uint32);
272 if (tdb_store(tdb, key, data, TDB_REPLACE) == -1)
273 ret = False;
275 return ret;
278 /****************************************************************************
279 Store a uint32 value by string key, return 0 on success, -1 on failure.
280 Input is uint32 in native byte order. Output in tdb is in little-endian.
281 ****************************************************************************/
283 BOOL tdb_store_uint32(TDB_CONTEXT *tdb, const char *keystr, uint32 value)
285 TDB_DATA key = string_term_tdb_data(keystr);
287 return tdb_store_uint32_byblob(tdb, key, value);
289 /****************************************************************************
290 Store a buffer by a null terminated string key. Return 0 on success, -1
291 on failure.
292 ****************************************************************************/
294 int tdb_store_bystring(TDB_CONTEXT *tdb, const char *keystr, TDB_DATA data, int flags)
296 TDB_DATA key = string_term_tdb_data(keystr);
298 return tdb_store(tdb, key, data, flags);
301 int tdb_trans_store_bystring(TDB_CONTEXT *tdb, const char *keystr,
302 TDB_DATA data, int flags)
304 TDB_DATA key = string_term_tdb_data(keystr);
306 return tdb_trans_store(tdb, key, data, flags);
309 /****************************************************************************
310 Fetch a buffer using a null terminated string key. Don't forget to call
311 free() on the result dptr.
312 ****************************************************************************/
314 TDB_DATA tdb_fetch_bystring(TDB_CONTEXT *tdb, const char *keystr)
316 TDB_DATA key = string_term_tdb_data(keystr);
318 return tdb_fetch(tdb, key);
321 /****************************************************************************
322 Delete an entry using a null terminated string key.
323 ****************************************************************************/
325 int tdb_delete_bystring(TDB_CONTEXT *tdb, const char *keystr)
327 TDB_DATA key = string_term_tdb_data(keystr);
329 return tdb_delete(tdb, key);
332 /****************************************************************************
333 Atomic integer change. Returns old value. To create, set initial value in *oldval.
334 ****************************************************************************/
336 int32 tdb_change_int32_atomic(TDB_CONTEXT *tdb, const char *keystr, int32 *oldval, int32 change_val)
338 int32 val;
339 int32 ret = -1;
341 if (tdb_lock_bystring(tdb, keystr) == -1)
342 return -1;
344 if ((val = tdb_fetch_int32(tdb, keystr)) == -1) {
345 /* The lookup failed */
346 if (tdb_error(tdb) != TDB_ERR_NOEXIST) {
347 /* but not because it didn't exist */
348 goto err_out;
351 /* Start with 'old' value */
352 val = *oldval;
354 } else {
355 /* It worked, set return value (oldval) to tdb data */
356 *oldval = val;
359 /* Increment value for storage and return next time */
360 val += change_val;
362 if (tdb_store_int32(tdb, keystr, val) == -1)
363 goto err_out;
365 ret = 0;
367 err_out:
369 tdb_unlock_bystring(tdb, keystr);
370 return ret;
373 /****************************************************************************
374 Atomic unsigned integer change. Returns old value. To create, set initial value in *oldval.
375 ****************************************************************************/
377 BOOL tdb_change_uint32_atomic(TDB_CONTEXT *tdb, const char *keystr, uint32 *oldval, uint32 change_val)
379 uint32 val;
380 BOOL ret = False;
382 if (tdb_lock_bystring(tdb, keystr) == -1)
383 return False;
385 if (!tdb_fetch_uint32(tdb, keystr, &val)) {
386 /* It failed */
387 if (tdb_error(tdb) != TDB_ERR_NOEXIST) {
388 /* and not because it didn't exist */
389 goto err_out;
392 /* Start with 'old' value */
393 val = *oldval;
395 } else {
396 /* it worked, set return value (oldval) to tdb data */
397 *oldval = val;
401 /* get a new value to store */
402 val += change_val;
404 if (!tdb_store_uint32(tdb, keystr, val))
405 goto err_out;
407 ret = True;
409 err_out:
411 tdb_unlock_bystring(tdb, keystr);
412 return ret;
415 /****************************************************************************
416 Useful pair of routines for packing/unpacking data consisting of
417 integers and strings.
418 ****************************************************************************/
420 size_t tdb_pack_va(uint8 *buf, int bufsize, const char *fmt, va_list ap)
422 uint8 bt;
423 uint16 w;
424 uint32 d;
425 int i;
426 void *p;
427 int len;
428 char *s;
429 char c;
430 uint8 *buf0 = buf;
431 const char *fmt0 = fmt;
432 int bufsize0 = bufsize;
434 while (*fmt) {
435 switch ((c = *fmt++)) {
436 case 'b': /* unsigned 8-bit integer */
437 len = 1;
438 bt = (uint8)va_arg(ap, int);
439 if (bufsize && bufsize >= len)
440 SSVAL(buf, 0, bt);
441 break;
442 case 'w': /* unsigned 16-bit integer */
443 len = 2;
444 w = (uint16)va_arg(ap, int);
445 if (bufsize && bufsize >= len)
446 SSVAL(buf, 0, w);
447 break;
448 case 'd': /* signed 32-bit integer (standard int in most systems) */
449 len = 4;
450 d = va_arg(ap, uint32);
451 if (bufsize && bufsize >= len)
452 SIVAL(buf, 0, d);
453 break;
454 case 'p': /* pointer */
455 len = 4;
456 p = va_arg(ap, void *);
457 d = p?1:0;
458 if (bufsize && bufsize >= len)
459 SIVAL(buf, 0, d);
460 break;
461 case 'P': /* null-terminated string */
462 s = va_arg(ap,char *);
463 w = strlen(s);
464 len = w + 1;
465 if (bufsize && bufsize >= len)
466 memcpy(buf, s, len);
467 break;
468 case 'f': /* null-terminated string */
469 s = va_arg(ap,char *);
470 w = strlen(s);
471 len = w + 1;
472 if (bufsize && bufsize >= len)
473 memcpy(buf, s, len);
474 break;
475 case 'B': /* fixed-length string */
476 i = va_arg(ap, int);
477 s = va_arg(ap, char *);
478 len = 4+i;
479 if (bufsize && bufsize >= len) {
480 SIVAL(buf, 0, i);
481 memcpy(buf+4, s, i);
483 break;
484 default:
485 DEBUG(0,("Unknown tdb_pack format %c in %s\n",
486 c, fmt));
487 len = 0;
488 break;
491 buf += len;
492 if (bufsize)
493 bufsize -= len;
494 if (bufsize < 0)
495 bufsize = 0;
498 DEBUG(18,("tdb_pack_va(%s, %d) -> %d\n",
499 fmt0, bufsize0, (int)PTR_DIFF(buf, buf0)));
501 return PTR_DIFF(buf, buf0);
504 size_t tdb_pack(uint8 *buf, int bufsize, const char *fmt, ...)
506 va_list ap;
507 size_t result;
509 va_start(ap, fmt);
510 result = tdb_pack_va(buf, bufsize, fmt, ap);
511 va_end(ap);
512 return result;
515 BOOL tdb_pack_append(TALLOC_CTX *mem_ctx, uint8 **buf, size_t *len,
516 const char *fmt, ...)
518 va_list ap;
519 size_t len1, len2;
521 va_start(ap, fmt);
522 len1 = tdb_pack_va(NULL, 0, fmt, ap);
523 va_end(ap);
525 if (mem_ctx != NULL) {
526 *buf = TALLOC_REALLOC_ARRAY(mem_ctx, *buf, uint8,
527 (*len) + len1);
528 } else {
529 *buf = SMB_REALLOC_ARRAY(*buf, uint8, (*len) + len1);
532 if (*buf == NULL) {
533 return False;
536 va_start(ap, fmt);
537 len2 = tdb_pack_va((*buf)+(*len), len1, fmt, ap);
538 va_end(ap);
540 if (len1 != len2) {
541 return False;
544 *len += len2;
546 return True;
549 /****************************************************************************
550 Useful pair of routines for packing/unpacking data consisting of
551 integers and strings.
552 ****************************************************************************/
554 int tdb_unpack(const uint8 *buf, int bufsize, const char *fmt, ...)
556 va_list ap;
557 uint8 *bt;
558 uint16 *w;
559 uint32 *d;
560 int len;
561 int *i;
562 void **p;
563 char *s, **b;
564 char c;
565 const uint8 *buf0 = buf;
566 const char *fmt0 = fmt;
567 int bufsize0 = bufsize;
569 va_start(ap, fmt);
571 while (*fmt) {
572 switch ((c=*fmt++)) {
573 case 'b':
574 len = 1;
575 bt = va_arg(ap, uint8 *);
576 if (bufsize < len)
577 goto no_space;
578 *bt = SVAL(buf, 0);
579 break;
580 case 'w':
581 len = 2;
582 w = va_arg(ap, uint16 *);
583 if (bufsize < len)
584 goto no_space;
585 *w = SVAL(buf, 0);
586 break;
587 case 'd':
588 len = 4;
589 d = va_arg(ap, uint32 *);
590 if (bufsize < len)
591 goto no_space;
592 *d = IVAL(buf, 0);
593 break;
594 case 'p':
595 len = 4;
596 p = va_arg(ap, void **);
597 if (bufsize < len)
598 goto no_space;
600 * This isn't a real pointer - only a token (1 or 0)
601 * to mark the fact a pointer is present.
604 *p = (void *)(IVAL(buf, 0) ? (void *)1 : NULL);
605 break;
606 case 'P':
607 s = va_arg(ap,char *);
608 len = strlen((const char *)buf) + 1;
609 if (bufsize < len || len > sizeof(pstring))
610 goto no_space;
611 memcpy(s, buf, len);
612 break;
613 case 'f':
614 s = va_arg(ap,char *);
615 len = strlen((const char *)buf) + 1;
616 if (bufsize < len || len > sizeof(fstring))
617 goto no_space;
618 memcpy(s, buf, len);
619 break;
620 case 'B':
621 i = va_arg(ap, int *);
622 b = va_arg(ap, char **);
623 len = 4;
624 if (bufsize < len)
625 goto no_space;
626 *i = IVAL(buf, 0);
627 if (! *i) {
628 *b = NULL;
629 break;
631 len += *i;
632 if (bufsize < len)
633 goto no_space;
634 *b = (char *)SMB_MALLOC(*i);
635 if (! *b)
636 goto no_space;
637 memcpy(*b, buf+4, *i);
638 break;
639 default:
640 DEBUG(0,("Unknown tdb_unpack format %c in %s\n",
641 c, fmt));
643 len = 0;
644 break;
647 buf += len;
648 bufsize -= len;
651 va_end(ap);
653 DEBUG(18,("tdb_unpack(%s, %d) -> %d\n",
654 fmt0, bufsize0, (int)PTR_DIFF(buf, buf0)));
656 return PTR_DIFF(buf, buf0);
658 no_space:
659 return -1;
663 /****************************************************************************
664 Log tdb messages via DEBUG().
665 ****************************************************************************/
667 static void tdb_log(TDB_CONTEXT *tdb, enum tdb_debug_level level, const char *format, ...)
669 va_list ap;
670 char *ptr = NULL;
672 va_start(ap, format);
673 vasprintf(&ptr, format, ap);
674 va_end(ap);
676 if (!ptr || !*ptr)
677 return;
679 DEBUG((int)level, ("tdb(%s): %s", tdb_name(tdb) ? tdb_name(tdb) : "unnamed", ptr));
680 SAFE_FREE(ptr);
683 /****************************************************************************
684 Like tdb_open() but also setup a logging function that redirects to
685 the samba DEBUG() system.
686 ****************************************************************************/
688 TDB_CONTEXT *tdb_open_log(const char *name, int hash_size, int tdb_flags,
689 int open_flags, mode_t mode)
691 TDB_CONTEXT *tdb;
692 struct tdb_logging_context log_ctx;
694 if (!lp_use_mmap())
695 tdb_flags |= TDB_NOMMAP;
697 log_ctx.log_fn = tdb_log;
698 log_ctx.log_private = NULL;
700 tdb = tdb_open_ex(name, hash_size, tdb_flags,
701 open_flags, mode, &log_ctx, NULL);
702 if (!tdb)
703 return NULL;
705 return tdb;
708 /****************************************************************************
709 Allow tdb_delete to be used as a tdb_traversal_fn.
710 ****************************************************************************/
712 int tdb_traverse_delete_fn(TDB_CONTEXT *the_tdb, TDB_DATA key, TDB_DATA dbuf,
713 void *state)
715 return tdb_delete(the_tdb, key);
721 * Search across the whole tdb for keys that match the given pattern
722 * return the result as a list of keys
724 * @param tdb pointer to opened tdb file context
725 * @param pattern searching pattern used by fnmatch(3) functions
727 * @return list of keys found by looking up with given pattern
729 TDB_LIST_NODE *tdb_search_keys(TDB_CONTEXT *tdb, const char* pattern)
731 TDB_DATA key, next;
732 TDB_LIST_NODE *list = NULL;
733 TDB_LIST_NODE *rec = NULL;
735 for (key = tdb_firstkey(tdb); key.dptr; key = next) {
736 /* duplicate key string to ensure null-termination */
737 char *key_str = SMB_STRNDUP((const char *)key.dptr, key.dsize);
738 if (!key_str) {
739 DEBUG(0, ("tdb_search_keys: strndup() failed!\n"));
740 smb_panic("strndup failed!\n");
743 DEBUG(18, ("checking %s for match to pattern %s\n", key_str, pattern));
745 next = tdb_nextkey(tdb, key);
747 /* do the pattern checking */
748 if (fnmatch(pattern, key_str, 0) == 0) {
749 rec = SMB_MALLOC_P(TDB_LIST_NODE);
750 ZERO_STRUCTP(rec);
752 rec->node_key = key;
754 DLIST_ADD_END(list, rec, TDB_LIST_NODE *);
756 DEBUG(18, ("checking %s matched pattern %s\n", key_str, pattern));
757 } else {
758 free(key.dptr);
761 /* free duplicated key string */
762 free(key_str);
765 return list;
771 * Free the list returned by tdb_search_keys
773 * @param node list of results found by tdb_search_keys
775 void tdb_search_list_free(TDB_LIST_NODE* node)
777 TDB_LIST_NODE *next_node;
779 while (node) {
780 next_node = node->next;
781 SAFE_FREE(node->node_key.dptr);
782 SAFE_FREE(node);
783 node = next_node;
787 /****************************************************************************
788 tdb_store, wrapped in a transaction. This way we make sure that a process
789 that dies within writing does not leave a corrupt tdb behind.
790 ****************************************************************************/
792 int tdb_trans_store(struct tdb_context *tdb, TDB_DATA key, TDB_DATA dbuf,
793 int flag)
795 int res;
797 if ((res = tdb_transaction_start(tdb)) != 0) {
798 DEBUG(5, ("tdb_transaction_start failed\n"));
799 return res;
802 if ((res = tdb_store(tdb, key, dbuf, flag)) != 0) {
803 DEBUG(10, ("tdb_store failed\n"));
804 if (tdb_transaction_cancel(tdb) != 0) {
805 smb_panic("Cancelling transaction failed");
807 return res;
810 if ((res = tdb_transaction_commit(tdb)) != 0) {
811 DEBUG(5, ("tdb_transaction_commit failed\n"));
814 return res;
817 /****************************************************************************
818 tdb_delete, wrapped in a transaction. This way we make sure that a process
819 that dies within deleting does not leave a corrupt tdb behind.
820 ****************************************************************************/
822 int tdb_trans_delete(struct tdb_context *tdb, TDB_DATA key)
824 int res;
826 if ((res = tdb_transaction_start(tdb)) != 0) {
827 DEBUG(5, ("tdb_transaction_start failed\n"));
828 return res;
831 if ((res = tdb_delete(tdb, key)) != 0) {
832 DEBUG(10, ("tdb_delete failed\n"));
833 if (tdb_transaction_cancel(tdb) != 0) {
834 smb_panic("Cancelling transaction failed");
836 return res;
839 if ((res = tdb_transaction_commit(tdb)) != 0) {
840 DEBUG(5, ("tdb_transaction_commit failed\n"));
843 return res;
847 Log tdb messages via DEBUG().
849 static void tdb_wrap_log(TDB_CONTEXT *tdb, enum tdb_debug_level level,
850 const char *format, ...) PRINTF_ATTRIBUTE(3,4);
852 static void tdb_wrap_log(TDB_CONTEXT *tdb, enum tdb_debug_level level,
853 const char *format, ...)
855 va_list ap;
856 char *ptr = NULL;
857 int debuglevel = 0;
859 va_start(ap, format);
860 vasprintf(&ptr, format, ap);
861 va_end(ap);
863 switch (level) {
864 case TDB_DEBUG_FATAL:
865 debug_level = 0;
866 break;
867 case TDB_DEBUG_ERROR:
868 debuglevel = 1;
869 break;
870 case TDB_DEBUG_WARNING:
871 debuglevel = 2;
872 break;
873 case TDB_DEBUG_TRACE:
874 debuglevel = 5;
875 break;
876 default:
877 debuglevel = 0;
880 if (ptr != NULL) {
881 const char *name = tdb_name(tdb);
882 DEBUG(debuglevel, ("tdb(%s): %s", name ? name : "unnamed", ptr));
883 free(ptr);
887 static struct tdb_wrap *tdb_list;
889 /* destroy the last connection to a tdb */
890 static int tdb_wrap_destructor(struct tdb_wrap *w)
892 tdb_close(w->tdb);
893 DLIST_REMOVE(tdb_list, w);
894 return 0;
898 wrapped connection to a tdb database
899 to close just talloc_free() the tdb_wrap pointer
901 struct tdb_wrap *tdb_wrap_open(TALLOC_CTX *mem_ctx,
902 const char *name, int hash_size, int tdb_flags,
903 int open_flags, mode_t mode)
905 struct tdb_wrap *w;
906 struct tdb_logging_context log_ctx;
907 log_ctx.log_fn = tdb_wrap_log;
909 if (!lp_use_mmap())
910 tdb_flags |= TDB_NOMMAP;
912 for (w=tdb_list;w;w=w->next) {
913 if (strcmp(name, w->name) == 0) {
915 * Yes, talloc_reference is exactly what we want
916 * here. Otherwise we would have to implement our own
917 * reference counting.
919 return talloc_reference(mem_ctx, w);
923 w = talloc(mem_ctx, struct tdb_wrap);
924 if (w == NULL) {
925 return NULL;
928 if (!(w->name = talloc_strdup(w, name))) {
929 talloc_free(w);
930 return NULL;
933 w->tdb = tdb_open_ex(name, hash_size, tdb_flags,
934 open_flags, mode, &log_ctx, NULL);
935 if (w->tdb == NULL) {
936 talloc_free(w);
937 return NULL;
940 talloc_set_destructor(w, tdb_wrap_destructor);
942 DLIST_ADD(tdb_list, w);
944 return w;
947 NTSTATUS map_nt_error_from_tdb(enum TDB_ERROR err)
949 struct { enum TDB_ERROR err; NTSTATUS status; } map[] =
950 { { TDB_SUCCESS, NT_STATUS_OK },
951 { TDB_ERR_CORRUPT, NT_STATUS_INTERNAL_DB_CORRUPTION },
952 { TDB_ERR_IO, NT_STATUS_UNEXPECTED_IO_ERROR },
953 { TDB_ERR_OOM, NT_STATUS_NO_MEMORY },
954 { TDB_ERR_EXISTS, NT_STATUS_OBJECT_NAME_COLLISION },
957 * TDB_ERR_LOCK is very broad, we could for example
958 * distinguish between fcntl locks and invalid lock
959 * sequences. So NT_STATUS_FILE_LOCK_CONFLICT is a
960 * compromise.
962 { TDB_ERR_LOCK, NT_STATUS_FILE_LOCK_CONFLICT },
964 * The next two ones in the enum are not actually used
966 { TDB_ERR_NOLOCK, NT_STATUS_FILE_LOCK_CONFLICT },
967 { TDB_ERR_LOCK_TIMEOUT, NT_STATUS_FILE_LOCK_CONFLICT },
968 { TDB_ERR_NOEXIST, NT_STATUS_NOT_FOUND },
969 { TDB_ERR_EINVAL, NT_STATUS_INVALID_PARAMETER },
970 { TDB_ERR_RDONLY, NT_STATUS_ACCESS_DENIED }
973 int i;
975 for (i=0; i < sizeof(map) / sizeof(map[0]); i++) {
976 if (err == map[i].err) {
977 return map[i].status;
981 return NT_STATUS_INTERNAL_ERROR;
985 /*********************************************************************
986 * the following is a generic validation mechanism for tdbs.
987 *********************************************************************/
990 * internal validation function, executed by the child.
992 static int tdb_validate_child(const char *tdb_path,
993 tdb_validate_data_func validate_fn,
994 int pfd)
996 int ret = -1;
997 int num_entries = 0;
998 TDB_CONTEXT *tdb = NULL;
999 struct tdb_validation_status v_status;
1001 v_status.tdb_error = False;
1002 v_status.bad_freelist = False;
1003 v_status.bad_entry = False;
1004 v_status.unknown_key = False;
1005 v_status.success = True;
1007 tdb = tdb_open_log(tdb_path, 0, TDB_DEFAULT, O_RDONLY, 0);
1008 if (!tdb) {
1009 v_status.tdb_error = True;
1010 v_status.success = False;
1011 goto out;
1014 /* Check the cache freelist is good. */
1015 if (tdb_validate_freelist(tdb, &num_entries) == -1) {
1016 DEBUG(0,("tdb_validate_child: bad freelist in cache %s\n",
1017 tdb_path));
1018 v_status.bad_freelist = True;
1019 v_status.success = False;
1020 goto out;
1023 DEBUG(10,("tdb_validate_child: cache %s freelist has %d entries\n",
1024 tdb_path, num_entries));
1026 /* Now traverse the cache to validate it. */
1027 num_entries = tdb_traverse(tdb, validate_fn, (void *)&v_status);
1028 if (num_entries == -1 || !(v_status.success)) {
1029 DEBUG(0,("tdb_validate_child: cache %s traverse failed\n",
1030 tdb_path));
1031 if (!(v_status.success)) {
1032 if (v_status.bad_entry) {
1033 DEBUGADD(0, (" -> bad entry found\n"));
1035 if (v_status.unknown_key) {
1036 DEBUGADD(0, (" -> unknown key encountered\n"));
1039 goto out;
1042 DEBUG(10,("tdb_validate_child: cache %s is good "
1043 "with %d entries\n", tdb_path, num_entries));
1044 ret = 0; /* Cache is good. */
1046 out:
1047 if (tdb) {
1048 tdb_close(tdb);
1051 DEBUG(10, ("tdb_validate_child: writing status to pipe\n"));
1052 write (pfd, (const char *)&v_status, sizeof(v_status));
1053 close(pfd);
1055 return ret;
1058 int tdb_validate(const char *tdb_path, tdb_validate_data_func validate_fn)
1060 pid_t child_pid = -1;
1061 int child_status = 0;
1062 int wait_pid = 0;
1063 int ret = -1;
1064 int pipe_fds[2];
1065 struct tdb_validation_status v_status;
1066 int bytes_read = 0;
1068 /* fork and let the child do the validation.
1069 * benefit: no need to twist signal handlers and panic functions.
1070 * just let the child panic. we catch the signal.
1071 * communicate the extended status struct over a pipe. */
1073 if (pipe(pipe_fds) != 0) {
1074 DEBUG(0, ("tdb_validate: unable to create pipe, "
1075 "error %s", strerror(errno)));
1076 smb_panic("winbind_validate_cache: unable to create pipe.");
1079 DEBUG(10, ("tdb_validate: forking to let child do validation.\n"));
1080 child_pid = sys_fork();
1081 if (child_pid == 0) {
1082 DEBUG(10, ("tdb_validate (validation child): created\n"));
1083 close(pipe_fds[0]); /* close reading fd */
1084 DEBUG(10, ("tdb_validate (validation child): "
1085 "calling tdb_validate_child\n"));
1086 exit(tdb_validate_child(tdb_path, validate_fn, pipe_fds[1]));
1088 else if (child_pid < 0) {
1089 smb_panic("tdb_validate: fork for validation failed.");
1092 /* parent */
1094 DEBUG(10, ("tdb_validate: fork succeeded, child PID = %d\n",
1095 child_pid));
1096 close(pipe_fds[1]); /* close writing fd */
1098 v_status.success = True;
1099 v_status.bad_entry = False;
1100 v_status.unknown_key = False;
1102 DEBUG(10, ("tdb_validate: reading from pipe.\n"));
1103 bytes_read = read(pipe_fds[0], (void *)&v_status, sizeof(v_status));
1104 close(pipe_fds[0]);
1106 if (bytes_read != sizeof(v_status)) {
1107 DEBUG(10, ("tdb_validate: read %d bytes from pipe "
1108 "but expected %d", bytes_read, (int)sizeof(v_status)));
1109 DEBUGADD(10, (" -> assuming child crashed\n"));
1110 v_status.success = False;
1112 else {
1113 DEBUG(10, ("tdb_validate: read status from child\n"));
1114 DEBUGADD(10, (" * tdb error: %s\n", v_status.tdb_error ? "yes" : "no"));
1115 DEBUGADD(10, (" * bad freelist: %s\n", v_status.bad_freelist ? "yes" : "no"));
1116 DEBUGADD(10, (" * bad entry: %s\n", v_status.bad_entry ? "yes" : "no"));
1117 DEBUGADD(10, (" * unknown key: %s\n", v_status.unknown_key ? "yes" : "no"));
1118 DEBUGADD(10, (" => overall success: %s\n", v_status.success ? "yes" : "no"));
1121 if (!v_status.success) {
1122 DEBUG(10, ("tdb_validate: validation not successful.\n"));
1123 DEBUGADD(10, ("removing tdb %s.\n", tdb_path));
1124 unlink(tdb_path);
1127 DEBUG(10, ("tdb_validate: waiting for child to finish...\n"));
1128 while ((wait_pid = sys_waitpid(child_pid, &child_status, 0)) < 0) {
1129 if (errno == EINTR) {
1130 DEBUG(10, ("tdb_validate: got signal during "
1131 "waitpid, retrying\n"));
1132 errno = 0;
1133 continue;
1135 DEBUG(0, ("tdb_validate: waitpid failed with "
1136 "errno %s\n", strerror(errno)));
1137 smb_panic("tdb_validate: waitpid failed.");
1139 if (wait_pid != child_pid) {
1140 DEBUG(0, ("tdb_validate: waitpid returned pid %d, "
1141 "but %d was expexted\n", wait_pid, child_pid));
1142 smb_panic("tdb_validate: waitpid returned "
1143 "unexpected PID.");
1146 DEBUG(10, ("tdb_validate: validating child returned.\n"));
1147 if (WIFEXITED(child_status)) {
1148 DEBUG(10, ("tdb_validate: child exited, code %d.\n",
1149 WEXITSTATUS(child_status)));
1150 ret = WEXITSTATUS(child_status);
1152 if (WIFSIGNALED(child_status)) {
1153 DEBUG(10, ("tdb_validate: child terminated "
1154 "by signal %d\n", WTERMSIG(child_status)));
1155 #ifdef WCOREDUMP
1156 if (WCOREDUMP(child_status)) {
1157 DEBUGADD(10, ("core dumped\n"));
1159 #endif
1160 ret = WTERMSIG(child_status);
1162 if (WIFSTOPPED(child_status)) {
1163 DEBUG(10, ("tdb_validate: child was stopped "
1164 "by signal %d\n",
1165 WSTOPSIG(child_status)));
1166 ret = WSTOPSIG(child_status);
1169 return ret;