2 Unix SMB/CIFS implementation.
4 Copyright (C) Andrew Tridgell 1992-1998
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 #include "lib/tdb/include/tdbutil.h"
23 #include "system/glob.h"
24 #include "system/wait.h"
25 #include "dlinklist.h"
27 /* these are little tdb utility functions that are meant to make
28 dealing with a tdb database a little less cumbersome in Samba */
30 static sig_atomic_t gotalarm;
32 /***************************************************************
33 Signal function to tell us we timed out.
34 ****************************************************************/
36 static void gotalarm_sig(void)
42 /*******************************************************************
43 THIS is a copy of the function CatchSignal found in lib/signal.c
44 I need to copy it there to avoid sucking all of the samba source
47 Catch a signal. This should implement the following semantics:
49 1) The handler remains installed after being called.
50 2) The signal should be blocked during handler execution.
51 ********************************************************************/
53 static void (*TdbCatchSignal(int signum,void (*handler)(int )))(int)
57 struct sigaction oldact;
61 act.sa_handler = handler;
64 * We *want* SIGALRM to interrupt a system call.
67 act.sa_flags = SA_RESTART;
69 sigemptyset(&act.sa_mask);
70 sigaddset(&act.sa_mask,signum);
71 sigaction(signum,&act,&oldact);
72 return oldact.sa_handler;
73 #else /* !HAVE_SIGACTION */
74 /* FIXME: need to handle sigvec and systems with broken signal() */
75 return signal(signum, handler);
81 /***************************************************************
82 Make a TDB_DATA and keep the const warning in one place
83 ****************************************************************/
85 static TDB_DATA make_tdb_data(const char *dptr, size_t dsize)
88 ret.dptr = discard_const_p(char, dptr);
93 /****************************************************************************
94 Lock a chain with timeout (in seconds).
95 ****************************************************************************/
97 static int tdb_chainlock_with_timeout_internal(TDB_CONTEXT *tdb, TDB_DATA key, uint_t timeout, int rw_type)
99 /* Allow tdb_chainlock to be interrupted by an alarm. */
102 tdb_set_lock_alarm(&gotalarm);
105 TdbCatchSignal(SIGALRM, SIGNAL_CAST gotalarm_sig);
109 if (rw_type == F_RDLCK)
110 ret = tdb_chainlock_read(tdb, key);
112 ret = tdb_chainlock(tdb, key);
116 TdbCatchSignal(SIGALRM, SIGNAL_CAST SIG_IGN);
118 tdb->log_fn(tdb, 0, "tdb_chainlock_with_timeout_internal: alarm (%u) timed out for key %s in tdb %s\n",
119 timeout, key.dptr, tdb->name);
120 /* TODO: If we time out waiting for a lock, it might
121 * be nice to use F_GETLK to get the pid of the
122 * process currently holding the lock and print that
123 * as part of the debugging message. -- mbp */
131 /****************************************************************************
132 Write lock a chain. Return -1 if timeout or lock failed.
133 ****************************************************************************/
135 int tdb_chainlock_with_timeout(TDB_CONTEXT *tdb, TDB_DATA key, uint_t timeout)
137 return tdb_chainlock_with_timeout_internal(tdb, key, timeout, F_WRLCK);
140 /****************************************************************************
141 Lock a chain by string. Return -1 if timeout or lock failed.
142 ****************************************************************************/
144 int tdb_lock_bystring(TDB_CONTEXT *tdb, const char *keyval, uint_t timeout)
146 TDB_DATA key = make_tdb_data(keyval, strlen(keyval)+1);
148 return tdb_chainlock_with_timeout_internal(tdb, key, timeout, F_WRLCK);
151 /****************************************************************************
152 Unlock a chain by string.
153 ****************************************************************************/
155 void tdb_unlock_bystring(TDB_CONTEXT *tdb, const char *keyval)
157 TDB_DATA key = make_tdb_data(keyval, strlen(keyval)+1);
159 tdb_chainunlock(tdb, key);
162 /****************************************************************************
163 Read lock a chain by string. Return -1 if timeout or lock failed.
164 ****************************************************************************/
166 int tdb_read_lock_bystring(TDB_CONTEXT *tdb, const char *keyval, uint_t timeout)
168 TDB_DATA key = make_tdb_data(keyval, strlen(keyval)+1);
170 return tdb_chainlock_with_timeout_internal(tdb, key, timeout, F_RDLCK);
173 /****************************************************************************
174 Read unlock a chain by string.
175 ****************************************************************************/
177 void tdb_read_unlock_bystring(TDB_CONTEXT *tdb, const char *keyval)
179 TDB_DATA key = make_tdb_data(keyval, strlen(keyval)+1);
181 tdb_chainunlock_read(tdb, key);
185 /****************************************************************************
186 Fetch a int32_t value by a arbitrary blob key, return -1 if not found.
187 Output is int32_t in native byte order.
188 ****************************************************************************/
190 int32_t tdb_fetch_int32_byblob(TDB_CONTEXT *tdb, const char *keyval, size_t len)
192 TDB_DATA key = make_tdb_data(keyval, len);
196 data = tdb_fetch(tdb, key);
197 if (!data.dptr || data.dsize != sizeof(int32_t)) {
198 SAFE_FREE(data.dptr);
202 ret = IVAL(data.dptr,0);
203 SAFE_FREE(data.dptr);
207 /****************************************************************************
208 Fetch a int32_t value by string key, return -1 if not found.
209 Output is int32_t in native byte order.
210 ****************************************************************************/
212 int32_t tdb_fetch_int32(TDB_CONTEXT *tdb, const char *keystr)
214 return tdb_fetch_int32_byblob(tdb, keystr, strlen(keystr) + 1);
217 /****************************************************************************
218 Store a int32_t value by an arbitary blob key, return 0 on success, -1 on failure.
219 Input is int32_t in native byte order. Output in tdb is in little-endian.
220 ****************************************************************************/
222 int tdb_store_int32_byblob(TDB_CONTEXT *tdb, const char *keystr, size_t len, int32_t v)
224 TDB_DATA key = make_tdb_data(keystr, len);
229 data.dptr = (void *)&v_store;
230 data.dsize = sizeof(int32_t);
232 return tdb_store(tdb, key, data, TDB_REPLACE);
235 /****************************************************************************
236 Store a int32_t value by string key, return 0 on success, -1 on failure.
237 Input is int32_t in native byte order. Output in tdb is in little-endian.
238 ****************************************************************************/
240 int tdb_store_int32(TDB_CONTEXT *tdb, const char *keystr, int32_t v)
242 return tdb_store_int32_byblob(tdb, keystr, strlen(keystr) + 1, v);
245 /****************************************************************************
246 Fetch a uint32_t value by a arbitrary blob key, return -1 if not found.
247 Output is uint32_t in native byte order.
248 ****************************************************************************/
250 BOOL tdb_fetch_uint32_byblob(TDB_CONTEXT *tdb, const char *keyval, size_t len, uint32_t *value)
252 TDB_DATA key = make_tdb_data(keyval, len);
255 data = tdb_fetch(tdb, key);
256 if (!data.dptr || data.dsize != sizeof(uint32_t)) {
257 SAFE_FREE(data.dptr);
261 *value = IVAL(data.dptr,0);
262 SAFE_FREE(data.dptr);
266 /****************************************************************************
267 Fetch a uint32_t value by string key, return -1 if not found.
268 Output is uint32_t in native byte order.
269 ****************************************************************************/
271 BOOL tdb_fetch_uint32(TDB_CONTEXT *tdb, const char *keystr, uint32_t *value)
273 return tdb_fetch_uint32_byblob(tdb, keystr, strlen(keystr) + 1, value);
276 /****************************************************************************
277 Store a uint32_t value by an arbitary blob key, return 0 on success, -1 on failure.
278 Input is uint32_t in native byte order. Output in tdb is in little-endian.
279 ****************************************************************************/
281 BOOL tdb_store_uint32_byblob(TDB_CONTEXT *tdb, const char *keystr, size_t len, uint32_t value)
283 TDB_DATA key = make_tdb_data(keystr, len);
288 SIVAL(&v_store, 0, value);
289 data.dptr = (void *)&v_store;
290 data.dsize = sizeof(uint32_t);
292 if (tdb_store(tdb, key, data, TDB_REPLACE) == -1)
298 /****************************************************************************
299 Store a uint32_t value by string key, return 0 on success, -1 on failure.
300 Input is uint32_t in native byte order. Output in tdb is in little-endian.
301 ****************************************************************************/
303 BOOL tdb_store_uint32(TDB_CONTEXT *tdb, const char *keystr, uint32_t value)
305 return tdb_store_uint32_byblob(tdb, keystr, strlen(keystr) + 1, value);
307 /****************************************************************************
308 Store a buffer by a null terminated string key. Return 0 on success, -1
310 ****************************************************************************/
312 int tdb_store_bystring(TDB_CONTEXT *tdb, const char *keystr, TDB_DATA data, int flags)
314 TDB_DATA key = make_tdb_data(keystr, strlen(keystr)+1);
316 return tdb_store(tdb, key, data, flags);
319 /****************************************************************************
320 Fetch a buffer using a null terminated string key. Don't forget to call
321 free() on the result dptr.
322 ****************************************************************************/
324 TDB_DATA tdb_fetch_bystring(TDB_CONTEXT *tdb, const char *keystr)
326 TDB_DATA key = make_tdb_data(keystr, strlen(keystr)+1);
328 return tdb_fetch(tdb, key);
331 /****************************************************************************
332 Delete an entry using a null terminated string key.
333 ****************************************************************************/
335 int tdb_delete_bystring(TDB_CONTEXT *tdb, const char *keystr)
337 TDB_DATA key = make_tdb_data(keystr, strlen(keystr)+1);
339 return tdb_delete(tdb, key);
342 /****************************************************************************
343 Atomic integer change. Returns old value. To create, set initial value in *oldval.
344 ****************************************************************************/
346 int32_t tdb_change_int32_atomic(TDB_CONTEXT *tdb, const char *keystr, int32_t *oldval, int32_t change_val)
351 if (tdb_lock_bystring(tdb, keystr,0) == -1)
354 if ((val = tdb_fetch_int32(tdb, keystr)) == -1) {
355 /* The lookup failed */
356 if (tdb_error(tdb) != TDB_ERR_NOEXIST) {
357 /* but not because it didn't exist */
361 /* Start with 'old' value */
365 /* It worked, set return value (oldval) to tdb data */
369 /* Increment value for storage and return next time */
372 if (tdb_store_int32(tdb, keystr, val) == -1)
379 tdb_unlock_bystring(tdb, keystr);
383 /****************************************************************************
384 Atomic unsigned integer change. Returns old value. To create, set initial value in *oldval.
385 ****************************************************************************/
387 BOOL tdb_change_uint32_atomic(TDB_CONTEXT *tdb, const char *keystr, uint32_t *oldval, uint32_t change_val)
392 if (tdb_lock_bystring(tdb, keystr,0) == -1)
395 if (!tdb_fetch_uint32(tdb, keystr, &val)) {
397 if (tdb_error(tdb) != TDB_ERR_NOEXIST) {
398 /* and not because it didn't exist */
402 /* Start with 'old' value */
406 /* it worked, set return value (oldval) to tdb data */
411 /* get a new value to store */
414 if (!tdb_store_uint32(tdb, keystr, val))
421 tdb_unlock_bystring(tdb, keystr);
425 /****************************************************************************
426 Useful pair of routines for packing/unpacking data consisting of
427 integers and strings.
428 ****************************************************************************/
430 size_t tdb_pack(TDB_CONTEXT *tdb, char *buf, int bufsize, const char *fmt, ...)
442 const char *fmt0 = fmt;
443 int bufsize0 = bufsize;
448 switch ((c = *fmt++)) {
449 case 'b': /* unsigned 8-bit integer */
451 bt = (uint8_t)va_arg(ap, int);
452 if (bufsize && bufsize >= len)
455 case 'w': /* unsigned 16-bit integer */
457 w = (uint16_t)va_arg(ap, int);
458 if (bufsize && bufsize >= len)
461 case 'd': /* signed 32-bit integer (standard int in most systems) */
463 d = va_arg(ap, uint32_t);
464 if (bufsize && bufsize >= len)
467 case 'p': /* pointer */
469 p = va_arg(ap, void *);
471 if (bufsize && bufsize >= len)
474 case 'P': /* null-terminated string */
475 s = va_arg(ap,char *);
478 if (bufsize && bufsize >= len)
481 case 'f': /* null-terminated string */
482 s = va_arg(ap,char *);
485 if (bufsize && bufsize >= len)
488 case 'B': /* fixed-length string */
490 s = va_arg(ap, char *);
492 if (bufsize && bufsize >= len) {
498 tdb->log_fn(tdb, 0,"Unknown tdb_pack format %c in %s\n",
513 tdb->log_fn(tdb, 18,"tdb_pack(%s, %d) -> %d\n",
514 fmt0, bufsize0, (int)PTR_DIFF(buf, buf0));
516 return PTR_DIFF(buf, buf0);
519 /****************************************************************************
520 Useful pair of routines for packing/unpacking data consisting of
521 integers and strings.
522 ****************************************************************************/
524 int tdb_unpack(TDB_CONTEXT *tdb, char *buf, int bufsize, const char *fmt, ...)
536 const char *fmt0 = fmt;
537 int bufsize0 = bufsize;
542 switch ((c=*fmt++)) {
545 bt = va_arg(ap, uint8_t *);
552 w = va_arg(ap, uint16_t *);
559 d = va_arg(ap, uint32_t *);
566 p = va_arg(ap, void **);
569 *p = (void *)IVAL(buf, 0);
572 s = va_arg(ap,char *);
573 len = strlen(buf) + 1;
574 if (bufsize < len || len > sizeof(pstring))
579 s = va_arg(ap,char *);
580 len = strlen(buf) + 1;
581 if (bufsize < len || len > sizeof(fstring))
586 i = va_arg(ap, int *);
587 b = va_arg(ap, char **);
599 *b = (char *)malloc(*i);
602 memcpy(*b, buf+4, *i);
605 tdb->log_fn(tdb, 0, "Unknown tdb_unpack format %c in %s\n",
618 tdb->log_fn(tdb, 18, "tdb_unpack(%s, %d) -> %d\n",
619 fmt0, bufsize0, (int)PTR_DIFF(buf, buf0));
621 return PTR_DIFF(buf, buf0);
627 /****************************************************************************
628 Allow tdb_delete to be used as a tdb_traversal_fn.
629 ****************************************************************************/
631 int tdb_traverse_delete_fn(TDB_CONTEXT *the_tdb, TDB_DATA key, TDB_DATA dbuf,
634 return tdb_delete(the_tdb, key);
640 * Search across the whole tdb for keys that match the given pattern
641 * return the result as a list of keys
643 * @param tdb pointer to opened tdb file context
644 * @param pattern searching pattern used by fnmatch(3) functions
646 * @return list of keys found by looking up with given pattern
648 TDB_LIST_NODE *tdb_search_keys(TDB_CONTEXT *tdb, const char* pattern)
651 TDB_LIST_NODE *list = NULL;
652 TDB_LIST_NODE *rec = NULL;
654 for (key = tdb_firstkey(tdb); key.dptr; key = next) {
655 /* duplicate key string to ensure null-termination */
656 char *key_str = (char*) strndup(key.dptr, key.dsize);
659 tdb->log_fn(tdb, 0, "tdb_search_keys: strndup() failed!\n");
660 smb_panic("strndup failed!\n");
663 tdb->log_fn(tdb, 18, "checking %s for match to pattern %s\n", key_str, pattern);
665 next = tdb_nextkey(tdb, key);
667 /* do the pattern checking */
668 if (fnmatch(pattern, key_str, 0) == 0) {
669 rec = (TDB_LIST_NODE*) malloc(sizeof(*rec));
674 DLIST_ADD_END(list, rec, TDB_LIST_NODE *);
676 tdb->log_fn(tdb, 18, "checking %s matched pattern %s\n", key_str, pattern);
681 /* free duplicated key string */
691 * Free the list returned by tdb_search_keys
693 * @param node list of results found by tdb_search_keys
695 void tdb_search_list_free(TDB_LIST_NODE* node)
697 TDB_LIST_NODE *next_node;
700 next_node = node->next;
701 SAFE_FREE(node->node_key.dptr);