r5296: - only include the tdb headers where they are needed
[kai/samba.git] / source / lib / tdb / common / tdbutil.c
1 /* 
2    Unix SMB/CIFS implementation.
3    tdb utility functions
4    Copyright (C) Andrew Tridgell 1992-1998
5    
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.
10    
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.
15    
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.
19 */
20
21 #include "includes.h"
22 #include "lib/tdb/include/tdbutil.h"
23 #include "system/glob.h"
24 #include "system/wait.h"
25 #include "dlinklist.h"
26
27 /* these are little tdb utility functions that are meant to make
28    dealing with a tdb database a little less cumbersome in Samba */
29
30 static sig_atomic_t gotalarm;
31
32 /***************************************************************
33  Signal function to tell us we timed out.
34 ****************************************************************/
35
36 static void gotalarm_sig(void)
37 {
38         gotalarm = 1;
39 }
40
41
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
45  into tdb.
46
47  Catch a signal. This should implement the following semantics:
48
49  1) The handler remains installed after being called.
50  2) The signal should be blocked during handler execution.
51 ********************************************************************/
52
53 static void (*TdbCatchSignal(int signum,void (*handler)(int )))(int)
54 {
55 #ifdef HAVE_SIGACTION
56         struct sigaction act;
57         struct sigaction oldact;
58
59         ZERO_STRUCT(act);
60
61         act.sa_handler = handler;
62 #ifdef SA_RESTART
63         /*
64          * We *want* SIGALRM to interrupt a system call.
65          */
66         if(signum != SIGALRM)
67                 act.sa_flags = SA_RESTART;
68 #endif
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);
76 #endif
77 }
78
79
80
81 /***************************************************************
82  Make a TDB_DATA and keep the const warning in one place
83 ****************************************************************/
84
85 static TDB_DATA make_tdb_data(const char *dptr, size_t dsize)
86 {
87         TDB_DATA ret;
88         ret.dptr = discard_const_p(char, dptr);
89         ret.dsize = dsize;
90         return ret;
91 }
92
93 /****************************************************************************
94  Lock a chain with timeout (in seconds).
95 ****************************************************************************/
96
97 static int tdb_chainlock_with_timeout_internal(TDB_CONTEXT *tdb, TDB_DATA key, uint_t timeout, int rw_type)
98 {
99         /* Allow tdb_chainlock to be interrupted by an alarm. */
100         int ret;
101         gotalarm = 0;
102         tdb_set_lock_alarm(&gotalarm);
103
104         if (timeout) {
105                 TdbCatchSignal(SIGALRM, SIGNAL_CAST gotalarm_sig);
106                 alarm(timeout);
107         }
108
109         if (rw_type == F_RDLCK)
110                 ret = tdb_chainlock_read(tdb, key);
111         else
112                 ret = tdb_chainlock(tdb, key);
113
114         if (timeout) {
115                 alarm(0);
116                 TdbCatchSignal(SIGALRM, SIGNAL_CAST SIG_IGN);
117                 if (gotalarm) {
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 */
124                         return -1;
125                 }
126         }
127
128         return ret;
129 }
130
131 /****************************************************************************
132  Write lock a chain. Return -1 if timeout or lock failed.
133 ****************************************************************************/
134
135 int tdb_chainlock_with_timeout(TDB_CONTEXT *tdb, TDB_DATA key, uint_t timeout)
136 {
137         return tdb_chainlock_with_timeout_internal(tdb, key, timeout, F_WRLCK);
138 }
139
140 /****************************************************************************
141  Lock a chain by string. Return -1 if timeout or lock failed.
142 ****************************************************************************/
143
144 int tdb_lock_bystring(TDB_CONTEXT *tdb, const char *keyval, uint_t timeout)
145 {
146         TDB_DATA key = make_tdb_data(keyval, strlen(keyval)+1);
147         
148         return tdb_chainlock_with_timeout_internal(tdb, key, timeout, F_WRLCK);
149 }
150
151 /****************************************************************************
152  Unlock a chain by string.
153 ****************************************************************************/
154
155 void tdb_unlock_bystring(TDB_CONTEXT *tdb, const char *keyval)
156 {
157         TDB_DATA key = make_tdb_data(keyval, strlen(keyval)+1);
158
159         tdb_chainunlock(tdb, key);
160 }
161
162 /****************************************************************************
163  Read lock a chain by string. Return -1 if timeout or lock failed.
164 ****************************************************************************/
165
166 int tdb_read_lock_bystring(TDB_CONTEXT *tdb, const char *keyval, uint_t timeout)
167 {
168         TDB_DATA key = make_tdb_data(keyval, strlen(keyval)+1);
169         
170         return tdb_chainlock_with_timeout_internal(tdb, key, timeout, F_RDLCK);
171 }
172
173 /****************************************************************************
174  Read unlock a chain by string.
175 ****************************************************************************/
176
177 void tdb_read_unlock_bystring(TDB_CONTEXT *tdb, const char *keyval)
178 {
179         TDB_DATA key = make_tdb_data(keyval, strlen(keyval)+1);
180         
181         tdb_chainunlock_read(tdb, key);
182 }
183
184
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 ****************************************************************************/
189
190 int32_t tdb_fetch_int32_byblob(TDB_CONTEXT *tdb, const char *keyval, size_t len)
191 {
192         TDB_DATA key = make_tdb_data(keyval, len);
193         TDB_DATA data;
194         int32_t ret;
195
196         data = tdb_fetch(tdb, key);
197         if (!data.dptr || data.dsize != sizeof(int32_t)) {
198                 SAFE_FREE(data.dptr);
199                 return -1;
200         }
201
202         ret = IVAL(data.dptr,0);
203         SAFE_FREE(data.dptr);
204         return ret;
205 }
206
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 ****************************************************************************/
211
212 int32_t tdb_fetch_int32(TDB_CONTEXT *tdb, const char *keystr)
213 {
214         return tdb_fetch_int32_byblob(tdb, keystr, strlen(keystr) + 1);
215 }
216
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 ****************************************************************************/
221
222 int tdb_store_int32_byblob(TDB_CONTEXT *tdb, const char *keystr, size_t len, int32_t v)
223 {
224         TDB_DATA key = make_tdb_data(keystr, len);
225         TDB_DATA data;
226         int32_t v_store;
227
228         SIVAL(&v_store,0,v);
229         data.dptr = (void *)&v_store;
230         data.dsize = sizeof(int32_t);
231
232         return tdb_store(tdb, key, data, TDB_REPLACE);
233 }
234
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 ****************************************************************************/
239
240 int tdb_store_int32(TDB_CONTEXT *tdb, const char *keystr, int32_t v)
241 {
242         return tdb_store_int32_byblob(tdb, keystr, strlen(keystr) + 1, v);
243 }
244
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 ****************************************************************************/
249
250 BOOL tdb_fetch_uint32_byblob(TDB_CONTEXT *tdb, const char *keyval, size_t len, uint32_t *value)
251 {
252         TDB_DATA key = make_tdb_data(keyval, len);
253         TDB_DATA data;
254
255         data = tdb_fetch(tdb, key);
256         if (!data.dptr || data.dsize != sizeof(uint32_t)) {
257                 SAFE_FREE(data.dptr);
258                 return False;
259         }
260
261         *value = IVAL(data.dptr,0);
262         SAFE_FREE(data.dptr);
263         return True;
264 }
265
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 ****************************************************************************/
270
271 BOOL tdb_fetch_uint32(TDB_CONTEXT *tdb, const char *keystr, uint32_t *value)
272 {
273         return tdb_fetch_uint32_byblob(tdb, keystr, strlen(keystr) + 1, value);
274 }
275
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 ****************************************************************************/
280
281 BOOL tdb_store_uint32_byblob(TDB_CONTEXT *tdb, const char *keystr, size_t len, uint32_t value)
282 {
283         TDB_DATA key = make_tdb_data(keystr, len);
284         TDB_DATA data;
285         uint32_t v_store;
286         BOOL ret = True;
287
288         SIVAL(&v_store, 0, value);
289         data.dptr = (void *)&v_store;
290         data.dsize = sizeof(uint32_t);
291
292         if (tdb_store(tdb, key, data, TDB_REPLACE) == -1)
293                 ret = False;
294
295         return ret;
296 }
297
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 ****************************************************************************/
302
303 BOOL tdb_store_uint32(TDB_CONTEXT *tdb, const char *keystr, uint32_t value)
304 {
305         return tdb_store_uint32_byblob(tdb, keystr, strlen(keystr) + 1, value);
306 }
307 /****************************************************************************
308  Store a buffer by a null terminated string key.  Return 0 on success, -1
309  on failure.
310 ****************************************************************************/
311
312 int tdb_store_bystring(TDB_CONTEXT *tdb, const char *keystr, TDB_DATA data, int flags)
313 {
314         TDB_DATA key = make_tdb_data(keystr, strlen(keystr)+1);
315         
316         return tdb_store(tdb, key, data, flags);
317 }
318
319 /****************************************************************************
320  Fetch a buffer using a null terminated string key.  Don't forget to call
321  free() on the result dptr.
322 ****************************************************************************/
323
324 TDB_DATA tdb_fetch_bystring(TDB_CONTEXT *tdb, const char *keystr)
325 {
326         TDB_DATA key = make_tdb_data(keystr, strlen(keystr)+1);
327
328         return tdb_fetch(tdb, key);
329 }
330
331 /****************************************************************************
332  Delete an entry using a null terminated string key. 
333 ****************************************************************************/
334
335 int tdb_delete_bystring(TDB_CONTEXT *tdb, const char *keystr)
336 {
337         TDB_DATA key = make_tdb_data(keystr, strlen(keystr)+1);
338
339         return tdb_delete(tdb, key);
340 }
341
342 /****************************************************************************
343  Atomic integer change. Returns old value. To create, set initial value in *oldval. 
344 ****************************************************************************/
345
346 int32_t tdb_change_int32_atomic(TDB_CONTEXT *tdb, const char *keystr, int32_t *oldval, int32_t change_val)
347 {
348         int32_t val;
349         int32_t ret = -1;
350
351         if (tdb_lock_bystring(tdb, keystr,0) == -1)
352                 return -1;
353
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 */
358                         goto err_out;
359                 }
360                 
361                 /* Start with 'old' value */
362                 val = *oldval;
363
364         } else {
365                 /* It worked, set return value (oldval) to tdb data */
366                 *oldval = val;
367         }
368
369         /* Increment value for storage and return next time */
370         val += change_val;
371                 
372         if (tdb_store_int32(tdb, keystr, val) == -1)
373                 goto err_out;
374
375         ret = 0;
376
377   err_out:
378
379         tdb_unlock_bystring(tdb, keystr);
380         return ret;
381 }
382
383 /****************************************************************************
384  Atomic unsigned integer change. Returns old value. To create, set initial value in *oldval. 
385 ****************************************************************************/
386
387 BOOL tdb_change_uint32_atomic(TDB_CONTEXT *tdb, const char *keystr, uint32_t *oldval, uint32_t change_val)
388 {
389         uint32_t val;
390         BOOL ret = False;
391
392         if (tdb_lock_bystring(tdb, keystr,0) == -1)
393                 return False;
394
395         if (!tdb_fetch_uint32(tdb, keystr, &val)) {
396                 /* It failed */
397                 if (tdb_error(tdb) != TDB_ERR_NOEXIST) { 
398                         /* and not because it didn't exist */
399                         goto err_out;
400                 }
401
402                 /* Start with 'old' value */
403                 val = *oldval;
404
405         } else {
406                 /* it worked, set return value (oldval) to tdb data */
407                 *oldval = val;
408
409         }
410
411         /* get a new value to store */
412         val += change_val;
413                 
414         if (!tdb_store_uint32(tdb, keystr, val))
415                 goto err_out;
416
417         ret = True;
418
419   err_out:
420
421         tdb_unlock_bystring(tdb, keystr);
422         return ret;
423 }
424
425 /****************************************************************************
426  Useful pair of routines for packing/unpacking data consisting of
427  integers and strings.
428 ****************************************************************************/
429
430 size_t tdb_pack(TDB_CONTEXT *tdb, char *buf, int bufsize, const char *fmt, ...)
431 {
432         va_list ap;
433         uint8_t bt;
434         uint16_t w;
435         uint32_t d;
436         int i;
437         void *p;
438         int len;
439         char *s;
440         char c;
441         char *buf0 = buf;
442         const char *fmt0 = fmt;
443         int bufsize0 = bufsize;
444
445         va_start(ap, fmt);
446
447         while (*fmt) {
448                 switch ((c = *fmt++)) {
449                 case 'b': /* unsigned 8-bit integer */
450                         len = 1;
451                         bt = (uint8_t)va_arg(ap, int);
452                         if (bufsize && bufsize >= len)
453                                 SSVAL(buf, 0, bt);
454                         break;
455                 case 'w': /* unsigned 16-bit integer */
456                         len = 2;
457                         w = (uint16_t)va_arg(ap, int);
458                         if (bufsize && bufsize >= len)
459                                 SSVAL(buf, 0, w);
460                         break;
461                 case 'd': /* signed 32-bit integer (standard int in most systems) */
462                         len = 4;
463                         d = va_arg(ap, uint32_t);
464                         if (bufsize && bufsize >= len)
465                                 SIVAL(buf, 0, d);
466                         break;
467                 case 'p': /* pointer */
468                         len = 4;
469                         p = va_arg(ap, void *);
470                         d = p?1:0;
471                         if (bufsize && bufsize >= len)
472                                 SIVAL(buf, 0, d);
473                         break;
474                 case 'P': /* null-terminated string */
475                         s = va_arg(ap,char *);
476                         w = strlen(s);
477                         len = w + 1;
478                         if (bufsize && bufsize >= len)
479                                 memcpy(buf, s, len);
480                         break;
481                 case 'f': /* null-terminated string */
482                         s = va_arg(ap,char *);
483                         w = strlen(s);
484                         len = w + 1;
485                         if (bufsize && bufsize >= len)
486                                 memcpy(buf, s, len);
487                         break;
488                 case 'B': /* fixed-length string */
489                         i = va_arg(ap, int);
490                         s = va_arg(ap, char *);
491                         len = 4+i;
492                         if (bufsize && bufsize >= len) {
493                                 SIVAL(buf, 0, i);
494                                 memcpy(buf+4, s, i);
495                         }
496                         break;
497                 default:
498                         tdb->log_fn(tdb, 0,"Unknown tdb_pack format %c in %s\n", 
499                                     c, fmt);
500                         len = 0;
501                         break;
502                 }
503
504                 buf += len;
505                 if (bufsize)
506                         bufsize -= len;
507                 if (bufsize < 0)
508                         bufsize = 0;
509         }
510
511         va_end(ap);
512
513         tdb->log_fn(tdb, 18,"tdb_pack(%s, %d) -> %d\n", 
514                     fmt0, bufsize0, (int)PTR_DIFF(buf, buf0));
515         
516         return PTR_DIFF(buf, buf0);
517 }
518
519 /****************************************************************************
520  Useful pair of routines for packing/unpacking data consisting of
521  integers and strings.
522 ****************************************************************************/
523
524 int tdb_unpack(TDB_CONTEXT *tdb, char *buf, int bufsize, const char *fmt, ...)
525 {
526         va_list ap;
527         uint8_t *bt;
528         uint16_t *w;
529         uint32_t *d;
530         int len;
531         int *i;
532         void **p;
533         char *s, **b;
534         char c;
535         char *buf0 = buf;
536         const char *fmt0 = fmt;
537         int bufsize0 = bufsize;
538
539         va_start(ap, fmt);
540         
541         while (*fmt) {
542                 switch ((c=*fmt++)) {
543                 case 'b':
544                         len = 1;
545                         bt = va_arg(ap, uint8_t *);
546                         if (bufsize < len)
547                                 goto no_space;
548                         *bt = SVAL(buf, 0);
549                         break;
550                 case 'w':
551                         len = 2;
552                         w = va_arg(ap, uint16_t *);
553                         if (bufsize < len)
554                                 goto no_space;
555                         *w = SVAL(buf, 0);
556                         break;
557                 case 'd':
558                         len = 4;
559                         d = va_arg(ap, uint32_t *);
560                         if (bufsize < len)
561                                 goto no_space;
562                         *d = IVAL(buf, 0);
563                         break;
564                 case 'p':
565                         len = 4;
566                         p = va_arg(ap, void **);
567                         if (bufsize < len)
568                                 goto no_space;
569                         *p = (void *)IVAL(buf, 0);
570                         break;
571                 case 'P':
572                         s = va_arg(ap,char *);
573                         len = strlen(buf) + 1;
574                         if (bufsize < len || len > sizeof(pstring))
575                                 goto no_space;
576                         memcpy(s, buf, len);
577                         break;
578                 case 'f':
579                         s = va_arg(ap,char *);
580                         len = strlen(buf) + 1;
581                         if (bufsize < len || len > sizeof(fstring))
582                                 goto no_space;
583                         memcpy(s, buf, len);
584                         break;
585                 case 'B':
586                         i = va_arg(ap, int *);
587                         b = va_arg(ap, char **);
588                         len = 4;
589                         if (bufsize < len)
590                                 goto no_space;
591                         *i = IVAL(buf, 0);
592                         if (! *i) {
593                                 *b = NULL;
594                                 break;
595                         }
596                         len += *i;
597                         if (bufsize < len)
598                                 goto no_space;
599                         *b = (char *)malloc(*i);
600                         if (! *b)
601                                 goto no_space;
602                         memcpy(*b, buf+4, *i);
603                         break;
604                 default:
605                         tdb->log_fn(tdb, 0, "Unknown tdb_unpack format %c in %s\n", 
606                                  c, fmt);
607
608                         len = 0;
609                         break;
610                 }
611
612                 buf += len;
613                 bufsize -= len;
614         }
615
616         va_end(ap);
617
618         tdb->log_fn(tdb, 18, "tdb_unpack(%s, %d) -> %d\n", 
619                     fmt0, bufsize0, (int)PTR_DIFF(buf, buf0));
620
621         return PTR_DIFF(buf, buf0);
622
623  no_space:
624         return -1;
625 }
626
627 /****************************************************************************
628  Allow tdb_delete to be used as a tdb_traversal_fn.
629 ****************************************************************************/
630
631 int tdb_traverse_delete_fn(TDB_CONTEXT *the_tdb, TDB_DATA key, TDB_DATA dbuf,
632                      void *state)
633 {
634     return tdb_delete(the_tdb, key);
635 }
636
637
638
639 /**
640  * Search across the whole tdb for keys that match the given pattern
641  * return the result as a list of keys
642  *
643  * @param tdb pointer to opened tdb file context
644  * @param pattern searching pattern used by fnmatch(3) functions
645  *
646  * @return list of keys found by looking up with given pattern
647  **/
648 TDB_LIST_NODE *tdb_search_keys(TDB_CONTEXT *tdb, const char* pattern)
649 {
650         TDB_DATA key, next;
651         TDB_LIST_NODE *list = NULL;
652         TDB_LIST_NODE *rec = NULL;
653         
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);
657 #if 0
658                 if (!key_str) {
659                         tdb->log_fn(tdb, 0, "tdb_search_keys: strndup() failed!\n");
660                         smb_panic("strndup failed!\n");
661                 }
662 #endif
663                 tdb->log_fn(tdb, 18, "checking %s for match to pattern %s\n", key_str, pattern);
664                 
665                 next = tdb_nextkey(tdb, key);
666
667                 /* do the pattern checking */
668                 if (fnmatch(pattern, key_str, 0) == 0) {
669                         rec = (TDB_LIST_NODE*) malloc(sizeof(*rec));
670                         ZERO_STRUCTP(rec);
671
672                         rec->node_key = key;
673         
674                         DLIST_ADD_END(list, rec, TDB_LIST_NODE *);
675                 
676                         tdb->log_fn(tdb, 18, "checking %s matched pattern %s\n", key_str, pattern);
677                 } else {
678                         free(key.dptr);
679                 }
680                 
681                 /* free duplicated key string */
682                 free(key_str);
683         }
684         
685         return list;
686
687 }
688
689
690 /**
691  * Free the list returned by tdb_search_keys
692  *
693  * @param node list of results found by tdb_search_keys
694  **/
695 void tdb_search_list_free(TDB_LIST_NODE* node)
696 {
697         TDB_LIST_NODE *next_node;
698         
699         while (node) {
700                 next_node = node->next;
701                 SAFE_FREE(node->node_key.dptr);
702                 SAFE_FREE(node);
703                 node = next_node;
704         }
705 }