2 Unix SMB/CIFS implementation.
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.
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)
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
)
49 ret
.dptr
= CONST_DISCARD(uint8
*, dptr
);
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. */
75 CatchSignal(SIGALRM
, SIGNAL_CAST gotalarm_sig
);
79 if (rw_type
== F_RDLCK
)
80 ret
= tdb_chainlock_read(tdb
, key
);
82 ret
= tdb_chainlock(tdb
, key
);
86 CatchSignal(SIGALRM
, SIGNAL_CAST SIG_IGN
);
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 */
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
,
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
)
173 data
= tdb_fetch(tdb
, key
);
174 if (!data
.dptr
|| data
.dsize
!= sizeof(int32
)) {
175 SAFE_FREE(data
.dptr
);
179 ret
= IVAL(data
.dptr
,0);
180 SAFE_FREE(data
.dptr
);
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
)
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
)
234 data
= tdb_fetch(tdb
, key
);
235 if (!data
.dptr
|| data
.dsize
!= sizeof(uint32
)) {
236 SAFE_FREE(data
.dptr
);
240 *value
= IVAL(data
.dptr
,0);
241 SAFE_FREE(data
.dptr
);
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
)
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)
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
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
)
341 if (tdb_lock_bystring(tdb
, keystr
) == -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 */
351 /* Start with 'old' value */
355 /* It worked, set return value (oldval) to tdb data */
359 /* Increment value for storage and return next time */
362 if (tdb_store_int32(tdb
, keystr
, val
) == -1)
369 tdb_unlock_bystring(tdb
, keystr
);
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
)
382 if (tdb_lock_bystring(tdb
, keystr
) == -1)
385 if (!tdb_fetch_uint32(tdb
, keystr
, &val
)) {
387 if (tdb_error(tdb
) != TDB_ERR_NOEXIST
) {
388 /* and not because it didn't exist */
392 /* Start with 'old' value */
396 /* it worked, set return value (oldval) to tdb data */
401 /* get a new value to store */
404 if (!tdb_store_uint32(tdb
, keystr
, val
))
411 tdb_unlock_bystring(tdb
, keystr
);
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
)
431 const char *fmt0
= fmt
;
432 int bufsize0
= bufsize
;
435 switch ((c
= *fmt
++)) {
436 case 'b': /* unsigned 8-bit integer */
438 bt
= (uint8
)va_arg(ap
, int);
439 if (bufsize
&& bufsize
>= len
)
442 case 'w': /* unsigned 16-bit integer */
444 w
= (uint16
)va_arg(ap
, int);
445 if (bufsize
&& bufsize
>= len
)
448 case 'd': /* signed 32-bit integer (standard int in most systems) */
450 d
= va_arg(ap
, uint32
);
451 if (bufsize
&& bufsize
>= len
)
454 case 'p': /* pointer */
456 p
= va_arg(ap
, void *);
458 if (bufsize
&& bufsize
>= len
)
461 case 'P': /* null-terminated string */
462 s
= va_arg(ap
,char *);
465 if (bufsize
&& bufsize
>= len
)
468 case 'f': /* null-terminated string */
469 s
= va_arg(ap
,char *);
472 if (bufsize
&& bufsize
>= len
)
475 case 'B': /* fixed-length string */
477 s
= va_arg(ap
, char *);
479 if (bufsize
&& bufsize
>= len
) {
485 DEBUG(0,("Unknown tdb_pack format %c in %s\n",
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
, ...)
510 result
= tdb_pack_va(buf
, bufsize
, fmt
, ap
);
515 BOOL
tdb_pack_append(TALLOC_CTX
*mem_ctx
, uint8
**buf
, size_t *len
,
516 const char *fmt
, ...)
522 len1
= tdb_pack_va(NULL
, 0, fmt
, ap
);
525 if (mem_ctx
!= NULL
) {
526 *buf
= TALLOC_REALLOC_ARRAY(mem_ctx
, *buf
, uint8
,
529 *buf
= SMB_REALLOC_ARRAY(*buf
, uint8
, (*len
) + len1
);
537 len2
= tdb_pack_va((*buf
)+(*len
), len1
, fmt
, ap
);
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
, ...)
565 const uint8
*buf0
= buf
;
566 const char *fmt0
= fmt
;
567 int bufsize0
= bufsize
;
572 switch ((c
=*fmt
++)) {
575 bt
= va_arg(ap
, uint8
*);
582 w
= va_arg(ap
, uint16
*);
589 d
= va_arg(ap
, uint32
*);
596 p
= va_arg(ap
, void **);
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
);
607 s
= va_arg(ap
,char *);
608 len
= strlen((const char *)buf
) + 1;
609 if (bufsize
< len
|| len
> sizeof(pstring
))
614 s
= va_arg(ap
,char *);
615 len
= strlen((const char *)buf
) + 1;
616 if (bufsize
< len
|| len
> sizeof(fstring
))
621 i
= va_arg(ap
, int *);
622 b
= va_arg(ap
, char **);
634 *b
= (char *)SMB_MALLOC(*i
);
637 memcpy(*b
, buf
+4, *i
);
640 DEBUG(0,("Unknown tdb_unpack format %c in %s\n",
653 DEBUG(18,("tdb_unpack(%s, %d) -> %d\n",
654 fmt0
, bufsize0
, (int)PTR_DIFF(buf
, buf0
)));
656 return PTR_DIFF(buf
, buf0
);
663 /****************************************************************************
664 Log tdb messages via DEBUG().
665 ****************************************************************************/
667 static void tdb_log(TDB_CONTEXT
*tdb
, enum tdb_debug_level level
, const char *format
, ...)
672 va_start(ap
, format
);
673 vasprintf(&ptr
, format
, ap
);
679 DEBUG((int)level
, ("tdb(%s): %s", tdb_name(tdb
) ? tdb_name(tdb
) : "unnamed", 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
)
692 struct tdb_logging_context log_ctx
;
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
);
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
,
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
)
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
);
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
);
754 DLIST_ADD_END(list
, rec
, TDB_LIST_NODE
*);
756 DEBUG(18, ("checking %s matched pattern %s\n", key_str
, pattern
));
761 /* free duplicated key string */
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
;
780 next_node
= node
->next
;
781 SAFE_FREE(node
->node_key
.dptr
);
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
,
797 if ((res
= tdb_transaction_start(tdb
)) != 0) {
798 DEBUG(5, ("tdb_transaction_start failed\n"));
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");
810 if ((res
= tdb_transaction_commit(tdb
)) != 0) {
811 DEBUG(5, ("tdb_transaction_commit failed\n"));
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
)
826 if ((res
= tdb_transaction_start(tdb
)) != 0) {
827 DEBUG(5, ("tdb_transaction_start failed\n"));
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");
839 if ((res
= tdb_transaction_commit(tdb
)) != 0) {
840 DEBUG(5, ("tdb_transaction_commit failed\n"));
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
, ...)
859 va_start(ap
, format
);
860 vasprintf(&ptr
, format
, ap
);
864 case TDB_DEBUG_FATAL
:
867 case TDB_DEBUG_ERROR
:
870 case TDB_DEBUG_WARNING
:
873 case TDB_DEBUG_TRACE
:
881 const char *name
= tdb_name(tdb
);
882 DEBUG(debuglevel
, ("tdb(%s): %s", name
? name
: "unnamed", 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
)
893 DLIST_REMOVE(tdb_list
, w
);
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
)
906 struct tdb_logging_context log_ctx
;
907 log_ctx
.log_fn
= tdb_wrap_log
;
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
);
928 if (!(w
->name
= talloc_strdup(w
, name
))) {
933 w
->tdb
= tdb_open_ex(name
, hash_size
, tdb_flags
,
934 open_flags
, mode
, &log_ctx
, NULL
);
935 if (w
->tdb
== NULL
) {
940 talloc_set_destructor(w
, tdb_wrap_destructor
);
942 DLIST_ADD(tdb_list
, 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
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
}
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
,
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);
1009 v_status
.tdb_error
= True
;
1010 v_status
.success
= False
;
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",
1018 v_status
.bad_freelist
= True
;
1019 v_status
.success
= False
;
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",
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"));
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. */
1051 DEBUG(10, ("tdb_validate_child: writing status to pipe\n"));
1052 write (pfd
, (const char *)&v_status
, sizeof(v_status
));
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;
1065 struct tdb_validation_status v_status
;
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.");
1094 DEBUG(10, ("tdb_validate: fork succeeded, child PID = %d\n",
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
));
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
;
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
));
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"));
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 "
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
)));
1156 if (WCOREDUMP(child_status
)) {
1157 DEBUGADD(10, ("core dumped\n"));
1160 ret
= WTERMSIG(child_status
);
1162 if (WIFSTOPPED(child_status
)) {
1163 DEBUG(10, ("tdb_validate: child was stopped "
1165 WSTOPSIG(child_status
)));
1166 ret
= WSTOPSIG(child_status
);