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.
24 /* these are little tdb utility functions that are meant to make
25 dealing with a tdb database a little less cumbersome in Samba */
27 static sig_atomic_t gotalarm;
29 /***************************************************************
30 Signal function to tell us we timed out.
31 ****************************************************************/
33 static void gotalarm_sig(void)
39 /*******************************************************************
40 THIS is a copy of the function CatchSignal found in lib/signal.c
41 I need to copy it there to avoid sucking all of the samba source
44 Catch a signal. This should implement the following semantics:
46 1) The handler remains installed after being called.
47 2) The signal should be blocked during handler execution.
48 ********************************************************************/
50 static void (*TdbCatchSignal(int signum,void (*handler)(int )))(int)
54 struct sigaction oldact;
58 act.sa_handler = handler;
61 * We *want* SIGALRM to interrupt a system call.
64 act.sa_flags = SA_RESTART;
66 sigemptyset(&act.sa_mask);
67 sigaddset(&act.sa_mask,signum);
68 sigaction(signum,&act,&oldact);
69 return oldact.sa_handler;
70 #else /* !HAVE_SIGACTION */
71 /* FIXME: need to handle sigvec and systems with broken signal() */
72 return signal(signum, handler);
78 /***************************************************************
79 Make a TDB_DATA and keep the const warning in one place
80 ****************************************************************/
82 static TDB_DATA make_tdb_data(const char *dptr, size_t dsize)
85 ret.dptr = discard_const_p(char, dptr);
90 /****************************************************************************
91 Lock a chain with timeout (in seconds).
92 ****************************************************************************/
94 static int tdb_chainlock_with_timeout_internal(TDB_CONTEXT *tdb, TDB_DATA key, uint_t timeout, int rw_type)
96 /* Allow tdb_chainlock to be interrupted by an alarm. */
99 tdb_set_lock_alarm(&gotalarm);
102 TdbCatchSignal(SIGALRM, SIGNAL_CAST gotalarm_sig);
106 if (rw_type == F_RDLCK)
107 ret = tdb_chainlock_read(tdb, key);
109 ret = tdb_chainlock(tdb, key);
113 TdbCatchSignal(SIGALRM, SIGNAL_CAST SIG_IGN);
115 tdb->log_fn(tdb, 0, "tdb_chainlock_with_timeout_internal: alarm (%u) timed out for key %s in tdb %s\n",
116 timeout, key.dptr, tdb->name);
117 /* TODO: If we time out waiting for a lock, it might
118 * be nice to use F_GETLK to get the pid of the
119 * process currently holding the lock and print that
120 * as part of the debugging message. -- mbp */
128 /****************************************************************************
129 Write lock a chain. Return -1 if timeout or lock failed.
130 ****************************************************************************/
132 int tdb_chainlock_with_timeout(TDB_CONTEXT *tdb, TDB_DATA key, uint_t timeout)
134 return tdb_chainlock_with_timeout_internal(tdb, key, timeout, F_WRLCK);
137 /****************************************************************************
138 Lock a chain by string. Return -1 if timeout or lock failed.
139 ****************************************************************************/
141 int tdb_lock_bystring(TDB_CONTEXT *tdb, const char *keyval, uint_t timeout)
143 TDB_DATA key = make_tdb_data(keyval, strlen(keyval)+1);
145 return tdb_chainlock_with_timeout_internal(tdb, key, timeout, F_WRLCK);
148 /****************************************************************************
149 Unlock a chain by string.
150 ****************************************************************************/
152 void tdb_unlock_bystring(TDB_CONTEXT *tdb, const char *keyval)
154 TDB_DATA key = make_tdb_data(keyval, strlen(keyval)+1);
156 tdb_chainunlock(tdb, key);
159 /****************************************************************************
160 Read lock a chain by string. Return -1 if timeout or lock failed.
161 ****************************************************************************/
163 int tdb_read_lock_bystring(TDB_CONTEXT *tdb, const char *keyval, uint_t timeout)
165 TDB_DATA key = make_tdb_data(keyval, strlen(keyval)+1);
167 return tdb_chainlock_with_timeout_internal(tdb, key, timeout, F_RDLCK);
170 /****************************************************************************
171 Read unlock a chain by string.
172 ****************************************************************************/
174 void tdb_read_unlock_bystring(TDB_CONTEXT *tdb, const char *keyval)
176 TDB_DATA key = make_tdb_data(keyval, strlen(keyval)+1);
178 tdb_chainunlock_read(tdb, key);
182 /****************************************************************************
183 Fetch a int32_t value by a arbitrary blob key, return -1 if not found.
184 Output is int32_t in native byte order.
185 ****************************************************************************/
187 int32_t tdb_fetch_int32_byblob(TDB_CONTEXT *tdb, const char *keyval, size_t len)
189 TDB_DATA key = make_tdb_data(keyval, len);
193 data = tdb_fetch(tdb, key);
194 if (!data.dptr || data.dsize != sizeof(int32_t)) {
195 SAFE_FREE(data.dptr);
199 ret = IVAL(data.dptr,0);
200 SAFE_FREE(data.dptr);
204 /****************************************************************************
205 Fetch a int32_t value by string key, return -1 if not found.
206 Output is int32_t in native byte order.
207 ****************************************************************************/
209 int32_t tdb_fetch_int32(TDB_CONTEXT *tdb, const char *keystr)
211 return tdb_fetch_int32_byblob(tdb, keystr, strlen(keystr) + 1);
214 /****************************************************************************
215 Store a int32_t value by an arbitary blob key, return 0 on success, -1 on failure.
216 Input is int32_t in native byte order. Output in tdb is in little-endian.
217 ****************************************************************************/
219 int tdb_store_int32_byblob(TDB_CONTEXT *tdb, const char *keystr, size_t len, int32_t v)
221 TDB_DATA key = make_tdb_data(keystr, len);
226 data.dptr = (void *)&v_store;
227 data.dsize = sizeof(int32_t);
229 return tdb_store(tdb, key, data, TDB_REPLACE);
232 /****************************************************************************
233 Store a int32_t value by string key, return 0 on success, -1 on failure.
234 Input is int32_t in native byte order. Output in tdb is in little-endian.
235 ****************************************************************************/
237 int tdb_store_int32(TDB_CONTEXT *tdb, const char *keystr, int32_t v)
239 return tdb_store_int32_byblob(tdb, keystr, strlen(keystr) + 1, v);
242 /****************************************************************************
243 Fetch a uint32_t value by a arbitrary blob key, return -1 if not found.
244 Output is uint32_t in native byte order.
245 ****************************************************************************/
247 BOOL tdb_fetch_uint32_byblob(TDB_CONTEXT *tdb, const char *keyval, size_t len, uint32_t *value)
249 TDB_DATA key = make_tdb_data(keyval, len);
252 data = tdb_fetch(tdb, key);
253 if (!data.dptr || data.dsize != sizeof(uint32_t)) {
254 SAFE_FREE(data.dptr);
258 *value = IVAL(data.dptr,0);
259 SAFE_FREE(data.dptr);
263 /****************************************************************************
264 Fetch a uint32_t value by string key, return -1 if not found.
265 Output is uint32_t in native byte order.
266 ****************************************************************************/
268 BOOL tdb_fetch_uint32(TDB_CONTEXT *tdb, const char *keystr, uint32_t *value)
270 return tdb_fetch_uint32_byblob(tdb, keystr, strlen(keystr) + 1, value);
273 /****************************************************************************
274 Store a uint32_t value by an arbitary blob key, return 0 on success, -1 on failure.
275 Input is uint32_t in native byte order. Output in tdb is in little-endian.
276 ****************************************************************************/
278 BOOL tdb_store_uint32_byblob(TDB_CONTEXT *tdb, const char *keystr, size_t len, uint32_t value)
280 TDB_DATA key = make_tdb_data(keystr, len);
285 SIVAL(&v_store, 0, value);
286 data.dptr = (void *)&v_store;
287 data.dsize = sizeof(uint32_t);
289 if (tdb_store(tdb, key, data, TDB_REPLACE) == -1)
295 /****************************************************************************
296 Store a uint32_t value by string key, return 0 on success, -1 on failure.
297 Input is uint32_t in native byte order. Output in tdb is in little-endian.
298 ****************************************************************************/
300 BOOL tdb_store_uint32(TDB_CONTEXT *tdb, const char *keystr, uint32_t value)
302 return tdb_store_uint32_byblob(tdb, keystr, strlen(keystr) + 1, value);
304 /****************************************************************************
305 Store a buffer by a null terminated string key. Return 0 on success, -1
307 ****************************************************************************/
309 int tdb_store_bystring(TDB_CONTEXT *tdb, const char *keystr, TDB_DATA data, int flags)
311 TDB_DATA key = make_tdb_data(keystr, strlen(keystr)+1);
313 return tdb_store(tdb, key, data, flags);
316 /****************************************************************************
317 Fetch a buffer using a null terminated string key. Don't forget to call
318 free() on the result dptr.
319 ****************************************************************************/
321 TDB_DATA tdb_fetch_bystring(TDB_CONTEXT *tdb, const char *keystr)
323 TDB_DATA key = make_tdb_data(keystr, strlen(keystr)+1);
325 return tdb_fetch(tdb, key);
328 /****************************************************************************
329 Delete an entry using a null terminated string key.
330 ****************************************************************************/
332 int tdb_delete_bystring(TDB_CONTEXT *tdb, const char *keystr)
334 TDB_DATA key = make_tdb_data(keystr, strlen(keystr)+1);
336 return tdb_delete(tdb, key);
339 /****************************************************************************
340 Atomic integer change. Returns old value. To create, set initial value in *oldval.
341 ****************************************************************************/
343 int32_t tdb_change_int32_atomic(TDB_CONTEXT *tdb, const char *keystr, int32_t *oldval, int32_t change_val)
348 if (tdb_lock_bystring(tdb, keystr,0) == -1)
351 if ((val = tdb_fetch_int32(tdb, keystr)) == -1) {
352 /* The lookup failed */
353 if (tdb_error(tdb) != TDB_ERR_NOEXIST) {
354 /* but not because it didn't exist */
358 /* Start with 'old' value */
362 /* It worked, set return value (oldval) to tdb data */
366 /* Increment value for storage and return next time */
369 if (tdb_store_int32(tdb, keystr, val) == -1)
376 tdb_unlock_bystring(tdb, keystr);
380 /****************************************************************************
381 Atomic unsigned integer change. Returns old value. To create, set initial value in *oldval.
382 ****************************************************************************/
384 BOOL tdb_change_uint32_atomic(TDB_CONTEXT *tdb, const char *keystr, uint32_t *oldval, uint32_t change_val)
389 if (tdb_lock_bystring(tdb, keystr,0) == -1)
392 if (!tdb_fetch_uint32(tdb, keystr, &val)) {
394 if (tdb_error(tdb) != TDB_ERR_NOEXIST) {
395 /* and not because it didn't exist */
399 /* Start with 'old' value */
403 /* it worked, set return value (oldval) to tdb data */
408 /* get a new value to store */
411 if (!tdb_store_uint32(tdb, keystr, val))
418 tdb_unlock_bystring(tdb, keystr);
422 /****************************************************************************
423 Useful pair of routines for packing/unpacking data consisting of
424 integers and strings.
425 ****************************************************************************/
427 size_t tdb_pack(TDB_CONTEXT *tdb, char *buf, int bufsize, const char *fmt, ...)
439 const char *fmt0 = fmt;
440 int bufsize0 = bufsize;
445 switch ((c = *fmt++)) {
446 case 'b': /* unsigned 8-bit integer */
448 bt = (uint8_t)va_arg(ap, int);
449 if (bufsize && bufsize >= len)
452 case 'w': /* unsigned 16-bit integer */
454 w = (uint16_t)va_arg(ap, int);
455 if (bufsize && bufsize >= len)
458 case 'd': /* signed 32-bit integer (standard int in most systems) */
460 d = va_arg(ap, uint32_t);
461 if (bufsize && bufsize >= len)
464 case 'p': /* pointer */
466 p = va_arg(ap, void *);
468 if (bufsize && bufsize >= len)
471 case 'P': /* null-terminated string */
472 s = va_arg(ap,char *);
475 if (bufsize && bufsize >= len)
478 case 'f': /* null-terminated string */
479 s = va_arg(ap,char *);
482 if (bufsize && bufsize >= len)
485 case 'B': /* fixed-length string */
487 s = va_arg(ap, char *);
489 if (bufsize && bufsize >= len) {
495 tdb->log_fn(tdb, 0,"Unknown tdb_pack format %c in %s\n",
510 tdb->log_fn(tdb, 18,"tdb_pack(%s, %d) -> %d\n",
511 fmt0, bufsize0, (int)PTR_DIFF(buf, buf0));
513 return PTR_DIFF(buf, buf0);
516 /****************************************************************************
517 Useful pair of routines for packing/unpacking data consisting of
518 integers and strings.
519 ****************************************************************************/
521 int tdb_unpack(TDB_CONTEXT *tdb, char *buf, int bufsize, const char *fmt, ...)
533 const char *fmt0 = fmt;
534 int bufsize0 = bufsize;
539 switch ((c=*fmt++)) {
542 bt = va_arg(ap, uint8_t *);
549 w = va_arg(ap, uint16_t *);
556 d = va_arg(ap, uint32_t *);
563 p = va_arg(ap, void **);
566 *p = (void *)IVAL(buf, 0);
569 s = va_arg(ap,char *);
570 len = strlen(buf) + 1;
571 if (bufsize < len || len > sizeof(pstring))
576 s = va_arg(ap,char *);
577 len = strlen(buf) + 1;
578 if (bufsize < len || len > sizeof(fstring))
583 i = va_arg(ap, int *);
584 b = va_arg(ap, char **);
596 *b = (char *)malloc(*i);
599 memcpy(*b, buf+4, *i);
602 tdb->log_fn(tdb, 0, "Unknown tdb_unpack format %c in %s\n",
615 tdb->log_fn(tdb, 18, "tdb_unpack(%s, %d) -> %d\n",
616 fmt0, bufsize0, (int)PTR_DIFF(buf, buf0));
618 return PTR_DIFF(buf, buf0);
624 /****************************************************************************
625 Allow tdb_delete to be used as a tdb_traversal_fn.
626 ****************************************************************************/
628 int tdb_traverse_delete_fn(TDB_CONTEXT *the_tdb, TDB_DATA key, TDB_DATA dbuf,
631 return tdb_delete(the_tdb, key);
637 * Search across the whole tdb for keys that match the given pattern
638 * return the result as a list of keys
640 * @param tdb pointer to opened tdb file context
641 * @param pattern searching pattern used by fnmatch(3) functions
643 * @return list of keys found by looking up with given pattern
645 TDB_LIST_NODE *tdb_search_keys(TDB_CONTEXT *tdb, const char* pattern)
648 TDB_LIST_NODE *list = NULL;
649 TDB_LIST_NODE *rec = NULL;
651 for (key = tdb_firstkey(tdb); key.dptr; key = next) {
652 /* duplicate key string to ensure null-termination */
653 char *key_str = (char*) strndup(key.dptr, key.dsize);
656 tdb->log_fn(tdb, 0, "tdb_search_keys: strndup() failed!\n");
657 smb_panic("strndup failed!\n");
660 tdb->log_fn(tdb, 18, "checking %s for match to pattern %s\n", key_str, pattern);
662 next = tdb_nextkey(tdb, key);
664 /* do the pattern checking */
665 if (fnmatch(pattern, key_str, 0) == 0) {
666 rec = (TDB_LIST_NODE*) malloc(sizeof(*rec));
671 DLIST_ADD_END(list, rec, TDB_LIST_NODE *);
673 tdb->log_fn(tdb, 18, "checking %s matched pattern %s\n", key_str, pattern);
678 /* free duplicated key string */
688 * Free the list returned by tdb_search_keys
690 * @param node list of results found by tdb_search_keys
692 void tdb_search_list_free(TDB_LIST_NODE* node)
694 TDB_LIST_NODE *next_node;
697 next_node = node->next;
698 SAFE_FREE(node->node_key.dptr);