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