mirror of
https://github.com/samba-team/samba.git
synced 2025-01-10 01:18:15 +03:00
ctdb-build: Change from ctdb-util to samba-util
Remove local lib/util and lib/tdb-wrap. Update wscript, packaging and includes.h. The only potentially surprising thing here is a fake samba-util subsystem that just depends on samba-util-core. As explained in a comment: When a combined build is implemented, CTDB will wanted to build against samba-util rather than samba-util-core. Similarly, other Samba subsystems expect samba-util. So, for a standalone build, just define a fake samba-util subsystem that pulls in samba-util-core. Signed-off-by: Martin Schwenke <martin@meltin.net> Reviewed-by: Volker Lendecke <vl@samba.org>
This commit is contained in:
parent
43266be945
commit
59c3025706
@ -7,7 +7,7 @@ else
|
||||
fi
|
||||
|
||||
CFLAGS="-Wall -g -D_GNU_SOURCE" ./configure \
|
||||
--builtin-libraries=replace,popt \
|
||||
--builtin-libraries=replace,popt,samba-debug,socket-blocking,tdb-wrap \
|
||||
--bundled-libraries=!talloc,!tevent,!tdb \
|
||||
--minimum-library-version=talloc:2.0.8,tdb:1.2.11,tevent:0.9.16 \
|
||||
--prefix=/usr \
|
||||
|
@ -38,17 +38,7 @@
|
||||
#define discard_const(ptr) ((void *)((intptr_t)(ptr)))
|
||||
#endif
|
||||
|
||||
struct timeval timeval_zero(void);
|
||||
bool timeval_is_zero(const struct timeval *tv);
|
||||
struct timeval timeval_current(void);
|
||||
struct timeval timeval_set(uint32_t secs, uint32_t usecs);
|
||||
int timeval_compare(const struct timeval *tv1, const struct timeval *tv2);
|
||||
struct timeval timeval_until(const struct timeval *tv1,
|
||||
const struct timeval *tv2);
|
||||
_PUBLIC_ struct timeval timeval_current_ofs(uint32_t secs, uint32_t usecs);
|
||||
double timeval_elapsed(struct timeval *tv);
|
||||
|
||||
#include "lib/util/debug.h"
|
||||
#include "lib/util/util.h"
|
||||
#include "lib/util/samba_util.h"
|
||||
|
||||
#endif /* _CTDB_INCLUDES_H */
|
||||
|
@ -1,113 +0,0 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
|
||||
database wrap functions
|
||||
|
||||
Copyright (C) Andrew Tridgell 2004
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/*
|
||||
the stupidity of the unix fcntl locking design forces us to never
|
||||
allow a database file to be opened twice in the same process. These
|
||||
wrappers provide convenient access to a tdb or ldb, taking advantage
|
||||
of talloc destructors to ensure that only a single open is done
|
||||
*/
|
||||
|
||||
#include "replace.h"
|
||||
#include "lib/util/dlinklist.h"
|
||||
#include "lib/util/debug.h"
|
||||
|
||||
#include "ctdb_logging.h"
|
||||
|
||||
#include "tdb_wrap.h"
|
||||
|
||||
static struct tdb_wrap *tdb_list;
|
||||
|
||||
|
||||
|
||||
/* destroy the last connection to a tdb */
|
||||
static int tdb_wrap_destructor(struct tdb_wrap *w)
|
||||
{
|
||||
tdb_close(w->tdb);
|
||||
DLIST_REMOVE(tdb_list, w);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void log_fn(struct tdb_context *tdb, enum tdb_debug_level level, const char *fmt, ...)
|
||||
{
|
||||
if (level <= TDB_DEBUG_ERROR) {
|
||||
va_list ap;
|
||||
char *ptr = NULL;
|
||||
int ret;
|
||||
|
||||
va_start(ap, fmt);
|
||||
ret = vasprintf(&ptr, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
if (ret != -1) {
|
||||
const char *name = tdb_name(tdb);
|
||||
DEBUG(level,
|
||||
("%s:%s", name ? name : "unnamed tdb", ptr));
|
||||
free(ptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
wrapped connection to a tdb database
|
||||
to close just talloc_free() the tdb_wrap pointer
|
||||
*/
|
||||
struct tdb_wrap *tdb_wrap_open(TALLOC_CTX *mem_ctx,
|
||||
const char *name, int hash_size, int tdb_flags,
|
||||
int open_flags, mode_t mode)
|
||||
{
|
||||
struct tdb_wrap *w;
|
||||
struct tdb_logging_context log_ctx;
|
||||
|
||||
log_ctx.log_fn = log_fn;
|
||||
log_ctx.log_private = NULL;
|
||||
|
||||
for (w=tdb_list;w;w=w->next) {
|
||||
if (strcmp(name, w->name) == 0) {
|
||||
return talloc_reference(mem_ctx, w);
|
||||
}
|
||||
}
|
||||
|
||||
w = talloc(mem_ctx, struct tdb_wrap);
|
||||
if (w == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
w->name = talloc_strdup(w, name);
|
||||
if (w->name == NULL) {
|
||||
talloc_free(w);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
w->tdb = tdb_open_ex(name, hash_size, tdb_flags,
|
||||
open_flags, mode, &log_ctx, NULL);
|
||||
if (w->tdb == NULL) {
|
||||
talloc_free(w);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
talloc_set_destructor(w, tdb_wrap_destructor);
|
||||
|
||||
DLIST_ADD(tdb_list, w);
|
||||
|
||||
return w;
|
||||
}
|
@ -1,39 +0,0 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
|
||||
database wrap headers
|
||||
|
||||
Copyright (C) Andrew Tridgell 2004
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _DB_WRAP_H
|
||||
#define _DB_WRAP_H
|
||||
|
||||
#include <talloc.h>
|
||||
#include <tdb.h>
|
||||
|
||||
struct tdb_wrap {
|
||||
struct tdb_context *tdb;
|
||||
|
||||
const char *name;
|
||||
struct tdb_wrap *next, *prev;
|
||||
};
|
||||
|
||||
struct tdb_wrap *tdb_wrap_open(TALLOC_CTX *mem_ctx,
|
||||
const char *name, int hash_size, int tdb_flags,
|
||||
int open_flags, mode_t mode);
|
||||
|
||||
#endif /* _DB_WRAP_H */
|
@ -1,7 +0,0 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
bld.SAMBA_SUBSYSTEM('tdb-wrap',
|
||||
source='tdb_wrap.c',
|
||||
deps='tdb talloc',
|
||||
local_include=False
|
||||
)
|
@ -1,115 +0,0 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
ctdb debug functions
|
||||
Copyright (C) Volker Lendecke 2007
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "replace.h"
|
||||
#include "system/filesys.h"
|
||||
#include <ctype.h>
|
||||
#include <assert.h>
|
||||
#include "debug.h"
|
||||
|
||||
int DEBUGLEVEL;
|
||||
|
||||
static void print_asc(int level, const uint8_t *buf, size_t len)
|
||||
{
|
||||
int i;
|
||||
for (i=0;i<len;i++) {
|
||||
DEBUGADD(level,("%c", isprint(buf[i])?buf[i]:'.'));
|
||||
}
|
||||
}
|
||||
|
||||
void dump_data(int level, const uint8_t *buf, size_t len)
|
||||
{
|
||||
int i=0;
|
||||
|
||||
if (len<=0) return;
|
||||
|
||||
if (!DEBUGLVL(level)) return;
|
||||
|
||||
DEBUG(level, (__location__ " dump data of size %i:\n", (int)len));
|
||||
DEBUGADD(level,("[%03X] ",i));
|
||||
for (i=0;i<len;) {
|
||||
DEBUGADD(level,("%02X ",(int)buf[i]));
|
||||
i++;
|
||||
if (i%8 == 0) DEBUGADD(level,(" "));
|
||||
if (i%16 == 0) {
|
||||
print_asc(level,&buf[i-16],8); DEBUGADD(level,(" "));
|
||||
print_asc(level,&buf[i-8],8); DEBUGADD(level,("\n"));
|
||||
if (i<len) DEBUGADD(level,("[%03X] ",i));
|
||||
}
|
||||
}
|
||||
if (i%16) {
|
||||
int n;
|
||||
n = 16 - (i%16);
|
||||
DEBUGADD(level,(" "));
|
||||
if (n>8) DEBUGADD(level,(" "));
|
||||
while (n--) DEBUGADD(level,(" "));
|
||||
n = MIN(8,i%16);
|
||||
print_asc(level,&buf[i-(i%16)],n); DEBUGADD(level,( " " ));
|
||||
n = (i%16) - n;
|
||||
if (n>0) print_asc(level,&buf[i-n],n);
|
||||
DEBUGADD(level,("\n"));
|
||||
}
|
||||
DEBUG(level, (__location__ " dump data of size %i finished\n", (int)len));
|
||||
}
|
||||
|
||||
/* state variables for the debug system */
|
||||
static struct {
|
||||
debug_callback_fn callback;
|
||||
void *callback_private;
|
||||
} state;
|
||||
|
||||
static int current_msg_level = 0;
|
||||
|
||||
void debug_set_callback(void *private_ptr, debug_callback_fn fn)
|
||||
{
|
||||
assert(fn != NULL);
|
||||
|
||||
state.callback_private = private_ptr;
|
||||
state.callback = fn;
|
||||
}
|
||||
|
||||
bool dbghdr(int level, const char *location, const char *func)
|
||||
{
|
||||
current_msg_level = level;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool dbgtext( const char *format_str, ... )
|
||||
{
|
||||
va_list ap;
|
||||
char *msgbuf = NULL;
|
||||
int res;
|
||||
|
||||
va_start(ap, format_str);
|
||||
res = vasprintf(&msgbuf, format_str, ap);
|
||||
va_end(ap);
|
||||
if (res == -1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (state.callback != NULL) {
|
||||
state.callback(state.callback_private,
|
||||
current_msg_level, msgbuf);
|
||||
} else {
|
||||
write(2, msgbuf, strlen(msgbuf));
|
||||
}
|
||||
|
||||
free(msgbuf);
|
||||
return true;
|
||||
}
|
@ -1,39 +0,0 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
ctdb debug functions
|
||||
Copyright (C) Volker Lendecke 2007
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef UTIL_DEBUG_H
|
||||
#define UTIL_DEBUG_H
|
||||
|
||||
bool dbgtext( const char *, ... ) PRINTF_ATTRIBUTE(1,2);
|
||||
bool dbghdr( int level, const char *location, const char *func);
|
||||
void dump_data(int level, const uint8_t *buf1, size_t len);
|
||||
|
||||
extern int DEBUGLEVEL;
|
||||
|
||||
#define DEBUGLVL(lvl) ((lvl) <= DEBUGLEVEL)
|
||||
#define DEBUG( lvl, body ) \
|
||||
(void)( ((lvl) <= DEBUGLEVEL) \
|
||||
&& (dbghdr( lvl, __location__, __FUNCTION__ )) \
|
||||
&& (dbgtext body) )
|
||||
#define DEBUGADD(lvl, body) DEBUG(lvl, body)
|
||||
|
||||
typedef void (*debug_callback_fn)(void *private_ptr, int level, const char *msg);
|
||||
void debug_set_callback(void *private_ptr, debug_callback_fn fn);
|
||||
|
||||
#endif /* UTIL_DEBUG_H */
|
@ -1,181 +0,0 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
some simple double linked list macros
|
||||
|
||||
Copyright (C) Andrew Tridgell 1998-2010
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* To use these macros you must have a structure containing a next and
|
||||
prev pointer */
|
||||
|
||||
#ifndef _DLINKLIST_H
|
||||
#define _DLINKLIST_H
|
||||
|
||||
/*
|
||||
February 2010 - changed list format to have a prev pointer from the
|
||||
list head. This makes DLIST_ADD_END() O(1) even though we only have
|
||||
one list pointer.
|
||||
|
||||
The scheme is as follows:
|
||||
|
||||
1) with no entries in the list:
|
||||
list_head == NULL
|
||||
|
||||
2) with 1 entry in the list:
|
||||
list_head->next == NULL
|
||||
list_head->prev == list_head
|
||||
|
||||
3) with 2 entries in the list:
|
||||
list_head->next == element2
|
||||
list_head->prev == element2
|
||||
element2->prev == list_head
|
||||
element2->next == NULL
|
||||
|
||||
4) with N entries in the list:
|
||||
list_head->next == element2
|
||||
list_head->prev == elementN
|
||||
elementN->prev == element{N-1}
|
||||
elementN->next == NULL
|
||||
|
||||
This allows us to find the tail of the list by using
|
||||
list_head->prev, which means we can add to the end of the list in
|
||||
O(1) time
|
||||
|
||||
|
||||
Note that the 'type' arguments below are no longer needed, but
|
||||
are kept for now to prevent an incompatible argument change
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
add an element at the front of a list
|
||||
*/
|
||||
#define DLIST_ADD(list, p) \
|
||||
do { \
|
||||
if (!(list)) { \
|
||||
(p)->prev = (list) = (p); \
|
||||
(p)->next = NULL; \
|
||||
} else { \
|
||||
(p)->prev = (list)->prev; \
|
||||
(list)->prev = (p); \
|
||||
(p)->next = (list); \
|
||||
(list) = (p); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
remove an element from a list
|
||||
Note that the element doesn't have to be in the list. If it
|
||||
isn't then this is a no-op
|
||||
*/
|
||||
#define DLIST_REMOVE(list, p) \
|
||||
do { \
|
||||
if ((p) == (list)) { \
|
||||
if ((p)->next) (p)->next->prev = (p)->prev; \
|
||||
(list) = (p)->next; \
|
||||
} else if ((list) && (p) == (list)->prev) { \
|
||||
(p)->prev->next = NULL; \
|
||||
(list)->prev = (p)->prev; \
|
||||
} else { \
|
||||
if ((p)->prev) (p)->prev->next = (p)->next; \
|
||||
if ((p)->next) (p)->next->prev = (p)->prev; \
|
||||
} \
|
||||
if ((p) != (list)) (p)->next = (p)->prev = NULL; \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
find the head of the list given any element in it.
|
||||
Note that this costs O(N), so you should avoid this macro
|
||||
if at all possible!
|
||||
*/
|
||||
#define DLIST_HEAD(p, result_head) \
|
||||
do { \
|
||||
(result_head) = (p); \
|
||||
while (DLIST_PREV(result_head)) (result_head) = (result_head)->prev; \
|
||||
} while(0)
|
||||
|
||||
/* return the last element in the list */
|
||||
#define DLIST_TAIL(list) ((list)?(list)->prev:NULL)
|
||||
|
||||
/* return the previous element in the list. */
|
||||
#define DLIST_PREV(p) (((p)->prev && (p)->prev->next != NULL)?(p)->prev:NULL)
|
||||
|
||||
/* insert 'p' after the given element 'el' in a list. If el is NULL then
|
||||
this is the same as a DLIST_ADD() */
|
||||
#define DLIST_ADD_AFTER(list, p, el) \
|
||||
do { \
|
||||
if (!(list) || !(el)) { \
|
||||
DLIST_ADD(list, p); \
|
||||
} else { \
|
||||
(p)->prev = (el); \
|
||||
(p)->next = (el)->next; \
|
||||
(el)->next = (p); \
|
||||
if ((p)->next) (p)->next->prev = (p); \
|
||||
if ((list)->prev == (el)) (list)->prev = (p); \
|
||||
}\
|
||||
} while (0)
|
||||
|
||||
|
||||
/*
|
||||
add to the end of a list.
|
||||
Note that 'type' is ignored
|
||||
*/
|
||||
#define DLIST_ADD_END(list, p, type) \
|
||||
do { \
|
||||
if (!(list)) { \
|
||||
DLIST_ADD(list, p); \
|
||||
} else { \
|
||||
DLIST_ADD_AFTER(list, p, (list)->prev); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/* promote an element to the front of a list */
|
||||
#define DLIST_PROMOTE(list, p) \
|
||||
do { \
|
||||
DLIST_REMOVE(list, p); \
|
||||
DLIST_ADD(list, p); \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
demote an element to the end of a list.
|
||||
Note that 'type' is ignored
|
||||
*/
|
||||
#define DLIST_DEMOTE(list, p, type) \
|
||||
do { \
|
||||
DLIST_REMOVE(list, p); \
|
||||
DLIST_ADD_END(list, p, NULL); \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
concatenate two lists - putting all elements of the 2nd list at the
|
||||
end of the first list.
|
||||
Note that 'type' is ignored
|
||||
*/
|
||||
#define DLIST_CONCATENATE(list1, list2, type) \
|
||||
do { \
|
||||
if (!(list1)) { \
|
||||
(list1) = (list2); \
|
||||
} else { \
|
||||
(list1)->prev->next = (list2); \
|
||||
if (list2) { \
|
||||
void *_tmplist = (void *)(list1)->prev; \
|
||||
(list1)->prev = (list2)->prev; \
|
||||
(list2)->prev = _tmplist; \
|
||||
} \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#endif /* _DLINKLIST_H */
|
@ -1,235 +0,0 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
Critical Fault handling
|
||||
Copyright (C) Andrew Tridgell 1992-1998
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include "system/wait.h"
|
||||
#include "system/filesys.h"
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief Fault handling
|
||||
*/
|
||||
|
||||
/* the registered fault handler */
|
||||
static struct {
|
||||
const char *name;
|
||||
void (*fault_handler)(int sig);
|
||||
} fault_handlers;
|
||||
|
||||
static const char *progname;
|
||||
|
||||
#ifdef HAVE_BACKTRACE
|
||||
#include <execinfo.h>
|
||||
#elif HAVE_LIBEXC_H
|
||||
#include <libexc.h>
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Write backtrace to debug log
|
||||
*/
|
||||
_PUBLIC_ void call_backtrace(void)
|
||||
{
|
||||
#ifdef HAVE_BACKTRACE
|
||||
#ifndef BACKTRACE_STACK_SIZE
|
||||
#define BACKTRACE_STACK_SIZE 64
|
||||
#endif
|
||||
void *backtrace_stack[BACKTRACE_STACK_SIZE];
|
||||
size_t backtrace_size;
|
||||
char **backtrace_strings;
|
||||
|
||||
/* get the backtrace (stack frames) */
|
||||
backtrace_size = backtrace(backtrace_stack,BACKTRACE_STACK_SIZE);
|
||||
backtrace_strings = backtrace_symbols(backtrace_stack, backtrace_size);
|
||||
|
||||
DEBUG(0, ("BACKTRACE: %lu stack frames:\n",
|
||||
(unsigned long)backtrace_size));
|
||||
|
||||
if (backtrace_strings) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < backtrace_size; i++)
|
||||
DEBUGADD(0, (" #%u %s\n", i, backtrace_strings[i]));
|
||||
|
||||
/* Leak the backtrace_strings, rather than risk what free() might do */
|
||||
}
|
||||
|
||||
#elif HAVE_LIBEXC
|
||||
|
||||
#define NAMESIZE 32 /* Arbitrary */
|
||||
#ifndef BACKTRACE_STACK_SIZE
|
||||
#define BACKTRACE_STACK_SIZE 64
|
||||
#endif
|
||||
|
||||
/* The IRIX libexc library provides an API for unwinding the stack. See
|
||||
* libexc(3) for details. Apparantly trace_back_stack leaks memory, but
|
||||
* since we are about to abort anyway, it hardly matters.
|
||||
*
|
||||
* Note that if we paniced due to a SIGSEGV or SIGBUS (or similar) this
|
||||
* will fail with a nasty message upon failing to open the /proc entry.
|
||||
*/
|
||||
{
|
||||
uint64_t addrs[BACKTRACE_STACK_SIZE];
|
||||
char * names[BACKTRACE_STACK_SIZE];
|
||||
char namebuf[BACKTRACE_STACK_SIZE * NAMESIZE];
|
||||
|
||||
int i;
|
||||
int levels;
|
||||
|
||||
ZERO_ARRAY(addrs);
|
||||
ZERO_ARRAY(names);
|
||||
ZERO_ARRAY(namebuf);
|
||||
|
||||
for (i = 0; i < BACKTRACE_STACK_SIZE; i++) {
|
||||
names[i] = namebuf + (i * NAMESIZE);
|
||||
}
|
||||
|
||||
levels = trace_back_stack(0, addrs, names,
|
||||
BACKTRACE_STACK_SIZE, NAMESIZE);
|
||||
|
||||
DEBUG(0, ("BACKTRACE: %d stack frames:\n", levels));
|
||||
for (i = 0; i < levels; i++) {
|
||||
DEBUGADD(0, (" #%d 0x%llx %s\n", i, addrs[i], names[i]));
|
||||
}
|
||||
}
|
||||
#undef NAMESIZE
|
||||
#else
|
||||
DEBUG(0, ("call_backtrace: not implemented\n"));
|
||||
#endif
|
||||
}
|
||||
|
||||
_PUBLIC_ const char *panic_action = NULL;
|
||||
_PUBLIC_ void (*pre_panic_action_hook)(void) = NULL;
|
||||
_PUBLIC_ void (*post_panic_action_hook)(void) = NULL;
|
||||
|
||||
/**
|
||||
Something really nasty happened - panic !
|
||||
**/
|
||||
_PUBLIC_ void smb_panic(const char *why)
|
||||
{
|
||||
int result;
|
||||
|
||||
if (panic_action && *panic_action) {
|
||||
char pidstr[20];
|
||||
char cmdstring[200];
|
||||
strlcpy(cmdstring, panic_action, sizeof(cmdstring));
|
||||
snprintf(pidstr, sizeof(pidstr), "%u", getpid());
|
||||
all_string_sub(cmdstring, "%PID%", pidstr, sizeof(cmdstring));
|
||||
if (progname) {
|
||||
all_string_sub(cmdstring, "%PROG%", progname, sizeof(cmdstring));
|
||||
}
|
||||
DEBUG(0, ("smb_panic(): calling panic action [%s]\n", cmdstring));
|
||||
|
||||
if (pre_panic_action_hook) {
|
||||
pre_panic_action_hook();
|
||||
}
|
||||
|
||||
result = system(cmdstring);
|
||||
|
||||
if (post_panic_action_hook) {
|
||||
post_panic_action_hook();
|
||||
}
|
||||
|
||||
if (result == -1)
|
||||
DEBUG(0, ("smb_panic(): fork failed in panic action: %s\n",
|
||||
strerror(errno)));
|
||||
else
|
||||
DEBUG(0, ("smb_panic(): action returned status %d\n",
|
||||
WEXITSTATUS(result)));
|
||||
}
|
||||
DEBUG(0,("PANIC: %s\n", why));
|
||||
|
||||
call_backtrace();
|
||||
|
||||
#ifdef SIGABRT
|
||||
CatchSignal(SIGABRT, SIG_DFL);
|
||||
#endif
|
||||
abort();
|
||||
}
|
||||
|
||||
/**
|
||||
report a fault
|
||||
**/
|
||||
_NORETURN_ static void fault_report(int sig)
|
||||
{
|
||||
static int counter;
|
||||
|
||||
if (counter) _exit(1);
|
||||
|
||||
DEBUG(0,("=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=\n"));
|
||||
DEBUG(0,("INTERNAL ERROR: Signal %d in %s pid %d",sig, progname, (int)getpid()));
|
||||
DEBUG(0,("\nPlease read the file BUGS.txt in the distribution\n"));
|
||||
DEBUG(0,("=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=\n"));
|
||||
|
||||
smb_panic("internal error");
|
||||
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
catch serious errors
|
||||
**/
|
||||
_NORETURN_ static void sig_fault(int sig)
|
||||
{
|
||||
if (fault_handlers.fault_handler) {
|
||||
/* we have a fault handler, call it. It may not return. */
|
||||
fault_handlers.fault_handler(sig);
|
||||
}
|
||||
/* If it returns or doesn't exist, use regular reporter */
|
||||
fault_report(sig);
|
||||
}
|
||||
|
||||
/**
|
||||
setup our fault handlers
|
||||
**/
|
||||
_PUBLIC_ void fault_setup(void)
|
||||
{
|
||||
#ifdef SIGSEGV
|
||||
CatchSignal(SIGSEGV, sig_fault);
|
||||
#endif
|
||||
#ifdef SIGBUS
|
||||
CatchSignal(SIGBUS, sig_fault);
|
||||
#endif
|
||||
#ifdef SIGABRT
|
||||
CatchSignal(SIGABRT, sig_fault);
|
||||
#endif
|
||||
#ifdef SIGFPE
|
||||
CatchSignal(SIGFPE, sig_fault);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
register a fault handler.
|
||||
Should only be called once in the execution of smbd.
|
||||
*/
|
||||
_PUBLIC_ bool register_fault_handler(const char *name,
|
||||
void (*fault_handler)(int sig))
|
||||
{
|
||||
if (fault_handlers.name != NULL) {
|
||||
/* it's already registered! */
|
||||
DEBUG(2,("fault handler '%s' already registered - failed '%s'\n",
|
||||
fault_handlers.name, name));
|
||||
return false;
|
||||
}
|
||||
|
||||
fault_handlers.name = name;
|
||||
fault_handlers.fault_handler = fault_handler;
|
||||
|
||||
DEBUG(2,("fault handler '%s' registered\n", name));
|
||||
return true;
|
||||
}
|
@ -1,387 +0,0 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
|
||||
very efficient functions to manage mapping a id (such as a fnum) to
|
||||
a pointer. This is used for fnum and search id allocation.
|
||||
|
||||
Copyright (C) Andrew Tridgell 2004
|
||||
|
||||
This code is derived from lib/idr.c in the 2.6 Linux kernel, which was
|
||||
written by Jim Houston jim.houston@ccur.com, and is
|
||||
Copyright (C) 2002 by Concurrent Computer Corporation
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/*
|
||||
see the section marked "public interface" below for documentation
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
#define IDR_BITS 5
|
||||
#define IDR_FULL 0xfffffffful
|
||||
#if 0 /* unused */
|
||||
#define TOP_LEVEL_FULL (IDR_FULL >> 30)
|
||||
#endif
|
||||
#define IDR_SIZE (1 << IDR_BITS)
|
||||
#define IDR_MASK ((1 << IDR_BITS)-1)
|
||||
#define MAX_ID_SHIFT (sizeof(int)*8 - 1)
|
||||
#define MAX_ID_BIT (1U << MAX_ID_SHIFT)
|
||||
#define MAX_ID_MASK (MAX_ID_BIT - 1)
|
||||
#define MAX_LEVEL (MAX_ID_SHIFT + IDR_BITS - 1) / IDR_BITS
|
||||
#define IDR_FREE_MAX MAX_LEVEL + MAX_LEVEL
|
||||
|
||||
#define set_bit(bit, v) (v) |= (1<<(bit))
|
||||
#define clear_bit(bit, v) (v) &= ~(1<<(bit))
|
||||
#define test_bit(bit, v) ((v) & (1<<(bit)))
|
||||
|
||||
struct idr_layer {
|
||||
uint32_t bitmap;
|
||||
struct idr_layer *ary[IDR_SIZE];
|
||||
int count;
|
||||
};
|
||||
|
||||
struct idr_context {
|
||||
struct idr_layer *top;
|
||||
struct idr_layer *id_free;
|
||||
int layers;
|
||||
int id_free_cnt;
|
||||
};
|
||||
|
||||
static struct idr_layer *alloc_layer(struct idr_context *idp)
|
||||
{
|
||||
struct idr_layer *p;
|
||||
|
||||
if (!(p = idp->id_free))
|
||||
return NULL;
|
||||
idp->id_free = p->ary[0];
|
||||
idp->id_free_cnt--;
|
||||
p->ary[0] = NULL;
|
||||
return p;
|
||||
}
|
||||
|
||||
static int find_next_bit(uint32_t bm, int maxid, int n)
|
||||
{
|
||||
while (n<maxid && !test_bit(n, bm)) n++;
|
||||
return n;
|
||||
}
|
||||
|
||||
static void free_layer(struct idr_context *idp, struct idr_layer *p)
|
||||
{
|
||||
p->ary[0] = idp->id_free;
|
||||
idp->id_free = p;
|
||||
idp->id_free_cnt++;
|
||||
}
|
||||
|
||||
static int idr_pre_get(struct idr_context *idp)
|
||||
{
|
||||
while (idp->id_free_cnt < IDR_FREE_MAX) {
|
||||
struct idr_layer *new = talloc_zero(idp, struct idr_layer);
|
||||
if(new == NULL)
|
||||
return (0);
|
||||
free_layer(idp, new);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int sub_alloc(struct idr_context *idp, void *ptr, int *starting_id)
|
||||
{
|
||||
int n, m, sh;
|
||||
struct idr_layer *p, *new;
|
||||
struct idr_layer *pa[MAX_LEVEL+1];
|
||||
unsigned int l, id, oid;
|
||||
uint32_t bm;
|
||||
|
||||
memset(pa, 0, sizeof(pa));
|
||||
|
||||
id = *starting_id;
|
||||
restart:
|
||||
p = idp->top;
|
||||
l = idp->layers;
|
||||
pa[l--] = NULL;
|
||||
while (1) {
|
||||
/*
|
||||
* We run around this while until we reach the leaf node...
|
||||
*/
|
||||
n = (id >> (IDR_BITS*l)) & IDR_MASK;
|
||||
bm = ~p->bitmap;
|
||||
m = find_next_bit(bm, IDR_SIZE, n);
|
||||
if (m == IDR_SIZE) {
|
||||
/* no space available go back to previous layer. */
|
||||
l++;
|
||||
oid = id;
|
||||
id = (id | ((1 << (IDR_BITS*l))-1)) + 1;
|
||||
|
||||
/* if already at the top layer, we need to grow */
|
||||
if (!(p = pa[l])) {
|
||||
*starting_id = id;
|
||||
return -2;
|
||||
}
|
||||
|
||||
/* If we need to go up one layer, continue the
|
||||
* loop; otherwise, restart from the top.
|
||||
*/
|
||||
sh = IDR_BITS * (l + 1);
|
||||
if (oid >> sh == id >> sh)
|
||||
continue;
|
||||
else
|
||||
goto restart;
|
||||
}
|
||||
if (m != n) {
|
||||
sh = IDR_BITS*l;
|
||||
id = ((id >> sh) ^ n ^ m) << sh;
|
||||
}
|
||||
if ((id >= MAX_ID_BIT) || (id < 0))
|
||||
return -1;
|
||||
if (l == 0)
|
||||
break;
|
||||
/*
|
||||
* Create the layer below if it is missing.
|
||||
*/
|
||||
if (!p->ary[m]) {
|
||||
if (!(new = alloc_layer(idp)))
|
||||
return -1;
|
||||
p->ary[m] = new;
|
||||
p->count++;
|
||||
}
|
||||
pa[l--] = p;
|
||||
p = p->ary[m];
|
||||
}
|
||||
/*
|
||||
* We have reached the leaf node, plant the
|
||||
* users pointer and return the raw id.
|
||||
*/
|
||||
p->ary[m] = (struct idr_layer *)ptr;
|
||||
set_bit(m, p->bitmap);
|
||||
p->count++;
|
||||
/*
|
||||
* If this layer is full mark the bit in the layer above
|
||||
* to show that this part of the radix tree is full.
|
||||
* This may complete the layer above and require walking
|
||||
* up the radix tree.
|
||||
*/
|
||||
n = id;
|
||||
while (p->bitmap == IDR_FULL) {
|
||||
if (!(p = pa[++l]))
|
||||
break;
|
||||
n = n >> IDR_BITS;
|
||||
set_bit((n & IDR_MASK), p->bitmap);
|
||||
}
|
||||
return(id);
|
||||
}
|
||||
|
||||
static int idr_get_new_above_int(struct idr_context *idp, void *ptr, int starting_id)
|
||||
{
|
||||
struct idr_layer *p, *new;
|
||||
int layers, v, id;
|
||||
|
||||
idr_pre_get(idp);
|
||||
|
||||
id = starting_id;
|
||||
build_up:
|
||||
p = idp->top;
|
||||
layers = idp->layers;
|
||||
if (!p) {
|
||||
if (!(p = alloc_layer(idp)))
|
||||
return -1;
|
||||
layers = 1;
|
||||
}
|
||||
/*
|
||||
* Add a new layer to the top of the tree if the requested
|
||||
* id is larger than the currently allocated space.
|
||||
*/
|
||||
while ((layers < MAX_LEVEL) && (id >= (1 << (layers*IDR_BITS)))) {
|
||||
layers++;
|
||||
if (!p->count)
|
||||
continue;
|
||||
if (!(new = alloc_layer(idp))) {
|
||||
/*
|
||||
* The allocation failed. If we built part of
|
||||
* the structure tear it down.
|
||||
*/
|
||||
for (new = p; p && p != idp->top; new = p) {
|
||||
p = p->ary[0];
|
||||
new->ary[0] = NULL;
|
||||
new->bitmap = new->count = 0;
|
||||
free_layer(idp, new);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
new->ary[0] = p;
|
||||
new->count = 1;
|
||||
if (p->bitmap == IDR_FULL)
|
||||
set_bit(0, new->bitmap);
|
||||
p = new;
|
||||
}
|
||||
idp->top = p;
|
||||
idp->layers = layers;
|
||||
v = sub_alloc(idp, ptr, &id);
|
||||
if (v == -2)
|
||||
goto build_up;
|
||||
return(v);
|
||||
}
|
||||
|
||||
static int sub_remove(struct idr_context *idp, int shift, int id)
|
||||
{
|
||||
struct idr_layer *p = idp->top;
|
||||
struct idr_layer **pa[1+MAX_LEVEL];
|
||||
struct idr_layer ***paa = &pa[0];
|
||||
int n;
|
||||
|
||||
*paa = NULL;
|
||||
*++paa = &idp->top;
|
||||
|
||||
while ((shift > 0) && p) {
|
||||
n = (id >> shift) & IDR_MASK;
|
||||
clear_bit(n, p->bitmap);
|
||||
*++paa = &p->ary[n];
|
||||
p = p->ary[n];
|
||||
shift -= IDR_BITS;
|
||||
}
|
||||
n = id & IDR_MASK;
|
||||
if (p != NULL && test_bit(n, p->bitmap)) {
|
||||
clear_bit(n, p->bitmap);
|
||||
p->ary[n] = NULL;
|
||||
while(*paa && ! --((**paa)->count)){
|
||||
free_layer(idp, **paa);
|
||||
**paa-- = NULL;
|
||||
}
|
||||
if ( ! *paa )
|
||||
idp->layers = 0;
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void *_idr_find(struct idr_context *idp, int id)
|
||||
{
|
||||
int n;
|
||||
struct idr_layer *p;
|
||||
|
||||
n = idp->layers * IDR_BITS;
|
||||
p = idp->top;
|
||||
/*
|
||||
* This tests to see if bits outside the current tree are
|
||||
* present. If so, tain't one of ours!
|
||||
*/
|
||||
if (n + IDR_BITS < 31 &&
|
||||
((id & ~(~0 << MAX_ID_SHIFT)) >> (n + IDR_BITS))) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Mask off upper bits we don't use for the search. */
|
||||
id &= MAX_ID_MASK;
|
||||
|
||||
while (n >= IDR_BITS && p) {
|
||||
n -= IDR_BITS;
|
||||
p = p->ary[(id >> n) & IDR_MASK];
|
||||
}
|
||||
return((void *)p);
|
||||
}
|
||||
|
||||
static int _idr_remove(struct idr_context *idp, int id)
|
||||
{
|
||||
struct idr_layer *p;
|
||||
|
||||
/* Mask off upper bits we don't use for the search. */
|
||||
id &= MAX_ID_MASK;
|
||||
|
||||
if (sub_remove(idp, (idp->layers - 1) * IDR_BITS, id) == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ( idp->top && idp->top->count == 1 &&
|
||||
(idp->layers > 1) &&
|
||||
idp->top->ary[0]) {
|
||||
/* We can drop a layer */
|
||||
p = idp->top->ary[0];
|
||||
idp->top->bitmap = idp->top->count = 0;
|
||||
free_layer(idp, idp->top);
|
||||
idp->top = p;
|
||||
--idp->layers;
|
||||
}
|
||||
while (idp->id_free_cnt >= IDR_FREE_MAX) {
|
||||
p = alloc_layer(idp);
|
||||
talloc_free(p);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
this is the public interface
|
||||
**************************************************************************/
|
||||
|
||||
/**
|
||||
initialise a idr tree. The context return value must be passed to
|
||||
all subsequent idr calls. To destroy the idr tree use talloc_free()
|
||||
on this context
|
||||
*/
|
||||
_PUBLIC_ struct idr_context *idr_init(TALLOC_CTX *mem_ctx)
|
||||
{
|
||||
return talloc_zero(mem_ctx, struct idr_context);
|
||||
}
|
||||
|
||||
/**
|
||||
allocate the next available id, and assign 'ptr' into its slot.
|
||||
you can retrieve later this pointer using idr_find()
|
||||
*/
|
||||
_PUBLIC_ int idr_get_new(struct idr_context *idp, void *ptr, int limit)
|
||||
{
|
||||
int ret = idr_get_new_above_int(idp, ptr, 0);
|
||||
if (ret > limit) {
|
||||
idr_remove(idp, ret);
|
||||
return -1;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
allocate a new id, giving the first available value greater than or
|
||||
equal to the given starting id
|
||||
*/
|
||||
_PUBLIC_ int idr_get_new_above(struct idr_context *idp, void *ptr, int starting_id, int limit)
|
||||
{
|
||||
int ret = idr_get_new_above_int(idp, ptr, starting_id);
|
||||
if (ret > limit) {
|
||||
idr_remove(idp, ret);
|
||||
return -1;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
find a pointer value previously set with idr_get_new given an id
|
||||
*/
|
||||
_PUBLIC_ void *idr_find(struct idr_context *idp, int id)
|
||||
{
|
||||
return _idr_find(idp, id);
|
||||
}
|
||||
|
||||
/**
|
||||
remove an id from the idr tree
|
||||
*/
|
||||
_PUBLIC_ int idr_remove(struct idr_context *idp, int id)
|
||||
{
|
||||
int ret;
|
||||
ret = _idr_remove((struct idr_context *)idp, id);
|
||||
if (ret != 0) {
|
||||
DEBUG(0,("WARNING: attempt to remove unset id %d in idtree\n", id));
|
||||
}
|
||||
return ret;
|
||||
}
|
@ -1,144 +0,0 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
signal handling functions
|
||||
|
||||
Copyright (C) Andrew Tridgell 1998
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include "system/wait.h"
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief Signal handling
|
||||
*/
|
||||
|
||||
/****************************************************************************
|
||||
Catch child exits and reap the child zombie status.
|
||||
****************************************************************************/
|
||||
|
||||
static void sig_cld(int signum)
|
||||
{
|
||||
while (waitpid((pid_t)-1,(int *)NULL, WNOHANG) > 0)
|
||||
;
|
||||
|
||||
/*
|
||||
* Turns out it's *really* important not to
|
||||
* restore the signal handler here if we have real POSIX
|
||||
* signal handling. If we do, then we get the signal re-delivered
|
||||
* immediately - hey presto - instant loop ! JRA.
|
||||
*/
|
||||
|
||||
#if !defined(HAVE_SIGACTION)
|
||||
CatchSignal(SIGCLD, sig_cld);
|
||||
#endif
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
catch child exits - leave status;
|
||||
****************************************************************************/
|
||||
|
||||
static void sig_cld_leave_status(int signum)
|
||||
{
|
||||
/*
|
||||
* Turns out it's *really* important not to
|
||||
* restore the signal handler here if we have real POSIX
|
||||
* signal handling. If we do, then we get the signal re-delivered
|
||||
* immediately - hey presto - instant loop ! JRA.
|
||||
*/
|
||||
|
||||
#if !defined(HAVE_SIGACTION)
|
||||
CatchSignal(SIGCLD, sig_cld_leave_status);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
Block sigs.
|
||||
**/
|
||||
|
||||
void BlockSignals(bool block, int signum)
|
||||
{
|
||||
#ifdef HAVE_SIGPROCMASK
|
||||
sigset_t set;
|
||||
sigemptyset(&set);
|
||||
sigaddset(&set,signum);
|
||||
sigprocmask(block?SIG_BLOCK:SIG_UNBLOCK,&set,NULL);
|
||||
#elif defined(HAVE_SIGBLOCK)
|
||||
if (block) {
|
||||
sigblock(sigmask(signum));
|
||||
} else {
|
||||
sigsetmask(siggetmask() & ~sigmask(signum));
|
||||
}
|
||||
#else
|
||||
/* yikes! This platform can't block signals? */
|
||||
static int done;
|
||||
if (!done) {
|
||||
DEBUG(0,("WARNING: No signal blocking available\n"));
|
||||
done=1;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
Catch a signal. This should implement the following semantics:
|
||||
|
||||
1) The handler remains installed after being called.
|
||||
2) The signal should be blocked during handler execution.
|
||||
**/
|
||||
|
||||
void (*CatchSignal(int signum,void (*handler)(int )))(int)
|
||||
{
|
||||
#ifdef HAVE_SIGACTION
|
||||
struct sigaction act;
|
||||
struct sigaction oldact;
|
||||
|
||||
ZERO_STRUCT(act);
|
||||
|
||||
act.sa_handler = handler;
|
||||
#ifdef SA_RESTART
|
||||
/*
|
||||
* We *want* SIGALRM to interrupt a system call.
|
||||
*/
|
||||
if(signum != SIGALRM)
|
||||
act.sa_flags = SA_RESTART;
|
||||
#endif
|
||||
sigemptyset(&act.sa_mask);
|
||||
sigaddset(&act.sa_mask,signum);
|
||||
sigaction(signum,&act,&oldact);
|
||||
return oldact.sa_handler;
|
||||
#else /* !HAVE_SIGACTION */
|
||||
/* FIXME: need to handle sigvec and systems with broken signal() */
|
||||
return signal(signum, handler);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
Ignore SIGCLD via whatever means is necessary for this OS.
|
||||
**/
|
||||
|
||||
void (*CatchChild(void))(int)
|
||||
{
|
||||
return CatchSignal(SIGCLD, sig_cld);
|
||||
}
|
||||
|
||||
/**
|
||||
Catch SIGCLD but leave the child around so it's status can be reaped.
|
||||
**/
|
||||
|
||||
void (*CatchChildLeaveStatus(void))(int)
|
||||
{
|
||||
return CatchSignal(SIGCLD, sig_cld_leave_status);
|
||||
}
|
@ -1,167 +0,0 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
Samba utility functions
|
||||
|
||||
Copyright (C) Andrew Tridgell 1992-2001
|
||||
Copyright (C) Simo Sorce 2001-2002
|
||||
Copyright (C) Martin Pool 2003
|
||||
Copyright (C) James Peach 2005
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief Substitute utilities.
|
||||
**/
|
||||
|
||||
/**
|
||||
Substitute a string for a pattern in another string. Make sure there is
|
||||
enough room!
|
||||
|
||||
This routine looks for pattern in s and replaces it with
|
||||
insert. It may do multiple replacements.
|
||||
|
||||
Any of " ; ' $ or ` in the insert string are replaced with _
|
||||
if len==0 then the string cannot be extended. This is different from the old
|
||||
use of len==0 which was for no length checks to be done.
|
||||
**/
|
||||
|
||||
_PUBLIC_ void string_sub(char *s, const char *pattern, const char *insert, size_t len)
|
||||
{
|
||||
char *p;
|
||||
ssize_t ls, lp, li, i;
|
||||
|
||||
if (!insert || !pattern || !*pattern || !s)
|
||||
return;
|
||||
|
||||
ls = (ssize_t)strlen(s);
|
||||
lp = (ssize_t)strlen(pattern);
|
||||
li = (ssize_t)strlen(insert);
|
||||
|
||||
if (len == 0)
|
||||
len = ls + 1; /* len is number of *bytes* */
|
||||
|
||||
while (lp <= ls && (p = strstr(s, pattern))) {
|
||||
if (ls + (li-lp) >= len) {
|
||||
DEBUG(0,("ERROR: string overflow by %d in string_sub(%.50s, %d)\n",
|
||||
(int)(ls + (li-lp) - len),
|
||||
pattern, (int)len));
|
||||
break;
|
||||
}
|
||||
if (li != lp) {
|
||||
memmove(p+li,p+lp,strlen(p+lp)+1);
|
||||
}
|
||||
for (i=0;i<li;i++) {
|
||||
switch (insert[i]) {
|
||||
case '`':
|
||||
case '"':
|
||||
case '\'':
|
||||
case ';':
|
||||
case '$':
|
||||
case '%':
|
||||
case '\r':
|
||||
case '\n':
|
||||
p[i] = '_';
|
||||
break;
|
||||
default:
|
||||
p[i] = insert[i];
|
||||
}
|
||||
}
|
||||
s = p + li;
|
||||
ls += (li-lp);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Talloc'ed version of string_sub
|
||||
*/
|
||||
_PUBLIC_ char *string_sub_talloc(TALLOC_CTX *mem_ctx, const char *s,
|
||||
const char *pattern, const char *insert)
|
||||
{
|
||||
const char *p;
|
||||
char *ret;
|
||||
size_t len, alloc_len;
|
||||
|
||||
if (insert == NULL || pattern == NULL || !*pattern || s == NULL)
|
||||
return NULL;
|
||||
|
||||
/* determine length needed */
|
||||
len = strlen(s);
|
||||
|
||||
for (p = strstr(s, pattern); p != NULL;
|
||||
p = strstr(p+strlen(pattern), pattern)) {
|
||||
len += strlen(insert) - strlen(pattern);
|
||||
}
|
||||
|
||||
alloc_len = MAX(len, strlen(s))+1;
|
||||
ret = talloc_array(mem_ctx, char, alloc_len);
|
||||
if (ret == NULL)
|
||||
return NULL;
|
||||
strncpy(ret, s, alloc_len);
|
||||
string_sub(ret, pattern, insert, alloc_len);
|
||||
|
||||
ret = talloc_realloc(mem_ctx, ret, char, len+1);
|
||||
if (ret == NULL)
|
||||
return NULL;
|
||||
|
||||
SMB_ASSERT(ret[len] == '\0');
|
||||
|
||||
talloc_set_name_const(ret, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
Similar to string_sub() but allows for any character to be substituted.
|
||||
Use with caution!
|
||||
if len==0 then the string cannot be extended. This is different from the old
|
||||
use of len==0 which was for no length checks to be done.
|
||||
**/
|
||||
|
||||
_PUBLIC_ void all_string_sub(char *s,const char *pattern,const char *insert, size_t len)
|
||||
{
|
||||
char *p;
|
||||
ssize_t ls,lp,li;
|
||||
|
||||
if (!insert || !pattern || !s)
|
||||
return;
|
||||
|
||||
ls = (ssize_t)strlen(s);
|
||||
lp = (ssize_t)strlen(pattern);
|
||||
li = (ssize_t)strlen(insert);
|
||||
|
||||
if (!*pattern)
|
||||
return;
|
||||
|
||||
if (len == 0)
|
||||
len = ls + 1; /* len is number of *bytes* */
|
||||
|
||||
while (lp <= ls && (p = strstr(s,pattern))) {
|
||||
if (ls + (li-lp) >= len) {
|
||||
DEBUG(0,("ERROR: string overflow by %d in all_string_sub(%.50s, %d)\n",
|
||||
(int)(ls + (li-lp) - len),
|
||||
pattern, (int)len));
|
||||
break;
|
||||
}
|
||||
if (li != lp) {
|
||||
memmove(p+li,p+lp,strlen(p+lp)+1);
|
||||
}
|
||||
memcpy(p, insert, li);
|
||||
s = p + li;
|
||||
ls += (li-lp);
|
||||
}
|
||||
}
|
@ -1,52 +0,0 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
|
||||
Copyright (C) Andrew Tridgell 2005
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include "system/filesys.h"
|
||||
|
||||
|
||||
/**
|
||||
Set a fd into blocking/nonblocking mode. Uses POSIX O_NONBLOCK if available,
|
||||
else
|
||||
if SYSV use O_NDELAY
|
||||
if BSD use FNDELAY
|
||||
**/
|
||||
|
||||
_PUBLIC_ int set_blocking(int fd, bool set)
|
||||
{
|
||||
int val;
|
||||
#ifdef O_NONBLOCK
|
||||
#define FLAG_TO_SET O_NONBLOCK
|
||||
#else
|
||||
#ifdef SYSV
|
||||
#define FLAG_TO_SET O_NDELAY
|
||||
#else /* BSD */
|
||||
#define FLAG_TO_SET FNDELAY
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if((val = fcntl(fd, F_GETFL, 0)) == -1)
|
||||
return -1;
|
||||
if(set) /* Turn blocking on - ie. clear nonblock flag */
|
||||
val &= ~FLAG_TO_SET;
|
||||
else
|
||||
val |= FLAG_TO_SET;
|
||||
return fcntl( fd, F_SETFL, val);
|
||||
#undef FLAG_TO_SET
|
||||
}
|
@ -1,565 +0,0 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
Utility functions for Samba
|
||||
Copyright (C) Andrew Tridgell 1992-1999
|
||||
Copyright (C) Jelmer Vernooij 2005
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _SAMBA_UTIL_H_
|
||||
#define _SAMBA_UTIL_H_
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief Helpful macros
|
||||
*/
|
||||
|
||||
struct smbsrv_tcon;
|
||||
|
||||
#ifdef _SAMBA_BUILD_
|
||||
extern const char *logfile;
|
||||
#endif
|
||||
extern const char *panic_action;
|
||||
extern void (*pre_panic_action_hook)(void);
|
||||
extern void (*post_panic_action_hook)(void);
|
||||
|
||||
/**
|
||||
* assert macros
|
||||
*/
|
||||
#ifdef DEVELOPER
|
||||
#define SMB_ASSERT(b) do { if (!(b)) { \
|
||||
DEBUG(0,("PANIC: assert failed at %s(%d): %s\n", \
|
||||
__FILE__, __LINE__, #b)); smb_panic("assert failed: " #b); }} while(0)
|
||||
#else
|
||||
/* redefine the assert macro for non-developer builds */
|
||||
#define SMB_ASSERT(b) do { if (!(b)) { \
|
||||
DEBUG(0,("PANIC: assert failed at %s(%d): %s\n", \
|
||||
__FILE__, __LINE__, #b)); }} while (0)
|
||||
#endif
|
||||
|
||||
#if _SAMBA_BUILD_ == 4
|
||||
#ifdef VALGRIND
|
||||
#define strlen(x) valgrind_strlen(x)
|
||||
size_t valgrind_strlen(const char *s);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef ABS
|
||||
#define ABS(a) ((a)>0?(a):(-(a)))
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Write backtrace to debug log
|
||||
*/
|
||||
_PUBLIC_ void call_backtrace(void);
|
||||
|
||||
/**
|
||||
Something really nasty happened - panic !
|
||||
**/
|
||||
_PUBLIC_ _NORETURN_ void smb_panic(const char *why);
|
||||
|
||||
/**
|
||||
setup our fault handlers
|
||||
**/
|
||||
_PUBLIC_ void fault_setup(void);
|
||||
|
||||
/**
|
||||
register a fault handler.
|
||||
Should only be called once in the execution of smbd.
|
||||
*/
|
||||
_PUBLIC_ bool register_fault_handler(const char *name, void (*fault_handler)(int sig));
|
||||
|
||||
/* The following definitions come from lib/util/signal.c */
|
||||
|
||||
|
||||
/**
|
||||
Block sigs.
|
||||
**/
|
||||
void BlockSignals(bool block, int signum);
|
||||
|
||||
/**
|
||||
Catch a signal. This should implement the following semantics:
|
||||
|
||||
1) The handler remains installed after being called.
|
||||
2) The signal should be blocked during handler execution.
|
||||
**/
|
||||
void (*CatchSignal(int signum,void (*handler)(int )))(int);
|
||||
|
||||
/**
|
||||
Ignore SIGCLD via whatever means is necessary for this OS.
|
||||
**/
|
||||
void (*CatchChild(void))(int);
|
||||
|
||||
/**
|
||||
Catch SIGCLD but leave the child around so it's status can be reaped.
|
||||
**/
|
||||
void (*CatchChildLeaveStatus(void))(int);
|
||||
|
||||
|
||||
/* The following definitions come from lib/util/util_str.c */
|
||||
|
||||
|
||||
/**
|
||||
Trim the specified elements off the front and back of a string.
|
||||
**/
|
||||
_PUBLIC_ bool trim_string(char *s, const char *front, const char *back);
|
||||
|
||||
/**
|
||||
Find the number of 'c' chars in a string
|
||||
**/
|
||||
_PUBLIC_ _PURE_ size_t count_chars(const char *s, char c);
|
||||
|
||||
/**
|
||||
Safe string copy into a known length string. maxlength does not
|
||||
include the terminating zero.
|
||||
**/
|
||||
_PUBLIC_ char *safe_strcpy(char *dest,const char *src, size_t maxlength);
|
||||
|
||||
/**
|
||||
Safe string cat into a string. maxlength does not
|
||||
include the terminating zero.
|
||||
**/
|
||||
_PUBLIC_ char *safe_strcat(char *dest, const char *src, size_t maxlength);
|
||||
|
||||
/**
|
||||
Routine to get hex characters and turn them into a 16 byte array.
|
||||
the array can be variable length, and any non-hex-numeric
|
||||
characters are skipped. "0xnn" or "0Xnn" is specially catered
|
||||
for.
|
||||
|
||||
valid examples: "0A5D15"; "0x15, 0x49, 0xa2"; "59\ta9\te3\n"
|
||||
|
||||
|
||||
**/
|
||||
_PUBLIC_ size_t strhex_to_str(char *p, size_t p_len, const char *strhex, size_t strhex_len);
|
||||
|
||||
#ifdef _SAMBA_BUILD_
|
||||
/**
|
||||
* Parse a hex string and return a data blob.
|
||||
*/
|
||||
_PUBLIC_ _PURE_ DATA_BLOB strhex_to_data_blob(TALLOC_CTX *mem_ctx, const char *strhex) ;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Routine to print a buffer as HEX digits, into an allocated string.
|
||||
*/
|
||||
_PUBLIC_ void hex_encode(const unsigned char *buff_in, size_t len, char **out_hex_buffer);
|
||||
|
||||
/**
|
||||
* talloc version of hex_encode()
|
||||
*/
|
||||
_PUBLIC_ char *hex_encode_talloc(TALLOC_CTX *mem_ctx, const unsigned char *buff_in, size_t len);
|
||||
|
||||
/**
|
||||
Substitute a string for a pattern in another string. Make sure there is
|
||||
enough room!
|
||||
|
||||
This routine looks for pattern in s and replaces it with
|
||||
insert. It may do multiple replacements.
|
||||
|
||||
Any of " ; ' $ or ` in the insert string are replaced with _
|
||||
if len==0 then the string cannot be extended. This is different from the old
|
||||
use of len==0 which was for no length checks to be done.
|
||||
**/
|
||||
_PUBLIC_ void string_sub(char *s,const char *pattern, const char *insert, size_t len);
|
||||
|
||||
|
||||
_PUBLIC_ char *string_sub_talloc(TALLOC_CTX *mem_ctx, const char *s,
|
||||
const char *pattern, const char *insert);
|
||||
|
||||
/**
|
||||
Similar to string_sub() but allows for any character to be substituted.
|
||||
Use with caution!
|
||||
if len==0 then the string cannot be extended. This is different from the old
|
||||
use of len==0 which was for no length checks to be done.
|
||||
**/
|
||||
_PUBLIC_ void all_string_sub(char *s,const char *pattern,const char *insert, size_t len);
|
||||
|
||||
/**
|
||||
Unescape a URL encoded string, in place.
|
||||
**/
|
||||
_PUBLIC_ void rfc1738_unescape(char *buf);
|
||||
|
||||
/**
|
||||
format a string into length-prefixed dotted domain format, as used in NBT
|
||||
and in some ADS structures
|
||||
**/
|
||||
_PUBLIC_ const char *str_format_nbt_domain(TALLOC_CTX *mem_ctx, const char *s);
|
||||
|
||||
/**
|
||||
* Add a string to an array of strings.
|
||||
*
|
||||
* num should be a pointer to an integer that holds the current
|
||||
* number of elements in strings. It will be updated by this function.
|
||||
*/
|
||||
_PUBLIC_ bool add_string_to_array(TALLOC_CTX *mem_ctx,
|
||||
const char *str, const char ***strings, int *num);
|
||||
|
||||
/**
|
||||
varient of strcmp() that handles NULL ptrs
|
||||
**/
|
||||
_PUBLIC_ int strcmp_safe(const char *s1, const char *s2);
|
||||
|
||||
/**
|
||||
return the number of bytes occupied by a buffer in ASCII format
|
||||
the result includes the null termination
|
||||
limited by 'n' bytes
|
||||
**/
|
||||
_PUBLIC_ size_t ascii_len_n(const char *src, size_t n);
|
||||
|
||||
/**
|
||||
Set a boolean variable from the text value stored in the passed string.
|
||||
Returns true in success, false if the passed string does not correctly
|
||||
represent a boolean.
|
||||
**/
|
||||
_PUBLIC_ bool set_boolean(const char *boolean_string, bool *boolean);
|
||||
|
||||
/**
|
||||
* Parse a string containing a boolean value.
|
||||
*
|
||||
* val will be set to the read value.
|
||||
*
|
||||
* @retval true if a boolean value was parsed, false otherwise.
|
||||
*/
|
||||
_PUBLIC_ bool conv_str_bool(const char * str, bool * val);
|
||||
|
||||
#if _SAMBA_BUILD_ == 4
|
||||
/**
|
||||
* Convert a size specification like 16K into an integral number of bytes.
|
||||
**/
|
||||
_PUBLIC_ bool conv_str_size(const char * str, uint64_t * val);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Parse a uint64_t value from a string
|
||||
*
|
||||
* val will be set to the value read.
|
||||
*
|
||||
* @retval true if parsing was successful, false otherwise
|
||||
*/
|
||||
_PUBLIC_ bool conv_str_u64(const char * str, uint64_t * val);
|
||||
|
||||
/**
|
||||
return the number of bytes occupied by a buffer in CH_UTF16 format
|
||||
the result includes the null termination
|
||||
**/
|
||||
_PUBLIC_ size_t utf16_len(const void *buf);
|
||||
|
||||
/**
|
||||
return the number of bytes occupied by a buffer in CH_UTF16 format
|
||||
the result includes the null termination
|
||||
limited by 'n' bytes
|
||||
**/
|
||||
_PUBLIC_ size_t utf16_len_n(const void *src, size_t n);
|
||||
_PUBLIC_ size_t ucs2_align(const void *base_ptr, const void *p, int flags);
|
||||
|
||||
/**
|
||||
Do a case-insensitive, whitespace-ignoring string compare.
|
||||
**/
|
||||
_PUBLIC_ int strwicmp(const char *psz1, const char *psz2);
|
||||
|
||||
/**
|
||||
String replace.
|
||||
**/
|
||||
_PUBLIC_ void string_replace(char *s, char oldc, char newc);
|
||||
|
||||
/**
|
||||
* Compare 2 strings.
|
||||
*
|
||||
* @note The comparison is case-insensitive.
|
||||
**/
|
||||
_PUBLIC_ bool strequal(const char *s1, const char *s2);
|
||||
|
||||
/* The following definitions come from lib/util/util_file.c */
|
||||
|
||||
|
||||
#ifdef _SAMBA_BUILD_
|
||||
/**
|
||||
read a line from a file with possible \ continuation chars.
|
||||
Blanks at the start or end of a line are stripped.
|
||||
The string will be allocated if s2 is NULL
|
||||
**/
|
||||
_PUBLIC_ char *fgets_slash(char *s2,int maxlen,XFILE *f);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Read one line (data until next newline or eof) and allocate it
|
||||
*/
|
||||
_PUBLIC_ char *afdgets(int fd, TALLOC_CTX *mem_ctx, size_t hint);
|
||||
|
||||
#ifdef _SAMBA_BUILD_
|
||||
/**
|
||||
load a file into memory from a fd.
|
||||
**/
|
||||
_PUBLIC_ char *fd_load(int fd, size_t *size, size_t maxsize, TALLOC_CTX *mem_ctx);
|
||||
|
||||
|
||||
char **file_lines_parse(char *p, size_t size, int *numlines, TALLOC_CTX *mem_ctx);
|
||||
|
||||
/**
|
||||
load a file into memory
|
||||
**/
|
||||
_PUBLIC_ char *file_load(const char *fname, size_t *size, size_t maxsize, TALLOC_CTX *mem_ctx);
|
||||
#endif
|
||||
|
||||
/**
|
||||
mmap (if possible) or read a file
|
||||
**/
|
||||
_PUBLIC_ void *map_file(const char *fname, size_t size);
|
||||
|
||||
/**
|
||||
load a file into memory and return an array of pointers to lines in the file
|
||||
must be freed with talloc_free().
|
||||
**/
|
||||
_PUBLIC_ char **file_lines_load(const char *fname, int *numlines, size_t maxsize, TALLOC_CTX *mem_ctx);
|
||||
|
||||
/**
|
||||
load a fd into memory and return an array of pointers to lines in the file
|
||||
must be freed with talloc_free(). If convert is true calls unix_to_dos on
|
||||
the list.
|
||||
**/
|
||||
_PUBLIC_ char **fd_lines_load(int fd, int *numlines, size_t maxsize, TALLOC_CTX *mem_ctx);
|
||||
|
||||
/**
|
||||
save a lump of data into a file. Mostly used for debugging
|
||||
*/
|
||||
_PUBLIC_ bool file_save(const char *fname, const void *packet, size_t length);
|
||||
_PUBLIC_ int vfdprintf(int fd, const char *format, va_list ap) PRINTF_ATTRIBUTE(2,0);
|
||||
_PUBLIC_ int fdprintf(int fd, const char *format, ...) PRINTF_ATTRIBUTE(2,3);
|
||||
|
||||
/* The following definitions come from lib/util/util.c */
|
||||
|
||||
|
||||
/**
|
||||
Find a suitable temporary directory. The result should be copied immediately
|
||||
as it may be overwritten by a subsequent call.
|
||||
**/
|
||||
_PUBLIC_ const char *tmpdir(void);
|
||||
|
||||
/**
|
||||
Check if a file exists - call vfs_file_exist for samba files.
|
||||
**/
|
||||
_PUBLIC_ bool file_exist(const char *fname);
|
||||
|
||||
/**
|
||||
Check a files mod time.
|
||||
**/
|
||||
_PUBLIC_ time_t file_modtime(const char *fname);
|
||||
|
||||
/**
|
||||
Check if a directory exists.
|
||||
**/
|
||||
_PUBLIC_ bool directory_exist(const char *dname);
|
||||
|
||||
/**
|
||||
* Try to create the specified directory if it didn't exist.
|
||||
*
|
||||
* @retval true if the directory already existed and has the right permissions
|
||||
* or was successfully created.
|
||||
*/
|
||||
_PUBLIC_ bool directory_create_or_exist(const char *dname, uid_t uid,
|
||||
mode_t dir_perms);
|
||||
|
||||
/**
|
||||
Set a fd into blocking/nonblocking mode. Uses POSIX O_NONBLOCK if available,
|
||||
else
|
||||
if SYSV use O_NDELAY
|
||||
if BSD use FNDELAY
|
||||
**/
|
||||
_PUBLIC_ int set_blocking(int fd, bool set);
|
||||
|
||||
/**
|
||||
Sleep for a specified number of milliseconds.
|
||||
**/
|
||||
_PUBLIC_ void msleep(unsigned int t);
|
||||
|
||||
/**
|
||||
Get my own name, return in malloc'ed storage.
|
||||
**/
|
||||
_PUBLIC_ char* get_myname(void);
|
||||
|
||||
/**
|
||||
Return true if a string could be a pure IP address.
|
||||
**/
|
||||
_PUBLIC_ bool is_ipaddress(const char *str);
|
||||
|
||||
/**
|
||||
Interpret an internet address or name into an IP address in 4 byte form.
|
||||
**/
|
||||
_PUBLIC_ uint32_t interpret_addr(const char *str);
|
||||
|
||||
/**
|
||||
A convenient addition to interpret_addr().
|
||||
**/
|
||||
_PUBLIC_ struct in_addr interpret_addr2(const char *str);
|
||||
|
||||
/**
|
||||
Check if an IP is the 0.0.0.0.
|
||||
**/
|
||||
_PUBLIC_ bool is_zero_ip_v4(struct in_addr ip);
|
||||
|
||||
/**
|
||||
Are two IPs on the same subnet?
|
||||
**/
|
||||
_PUBLIC_ bool same_net_v4(struct in_addr ip1,struct in_addr ip2,struct in_addr mask);
|
||||
|
||||
_PUBLIC_ bool is_ipaddress_v4(const char *str);
|
||||
|
||||
/**
|
||||
Check if a process exists. Does this work on all unixes?
|
||||
**/
|
||||
_PUBLIC_ bool process_exists_by_pid(pid_t pid);
|
||||
|
||||
/**
|
||||
Simple routine to do POSIX file locking. Cruft in NFS and 64->32 bit mapping
|
||||
is dealt with in posix.c
|
||||
**/
|
||||
_PUBLIC_ bool fcntl_lock(int fd, int op, off_t offset, off_t count, int type);
|
||||
|
||||
/**
|
||||
malloc that aborts with smb_panic on fail or zero size.
|
||||
**/
|
||||
_PUBLIC_ void *smb_xmalloc(size_t size);
|
||||
|
||||
/**
|
||||
Memdup with smb_panic on fail.
|
||||
**/
|
||||
_PUBLIC_ void *smb_xmemdup(const void *p, size_t size);
|
||||
|
||||
/**
|
||||
strdup that aborts on malloc fail.
|
||||
**/
|
||||
_PUBLIC_ char *smb_xstrdup(const char *s);
|
||||
|
||||
char *smb_xstrndup(const char *s, size_t n);
|
||||
|
||||
/**
|
||||
Like strdup but for memory.
|
||||
**/
|
||||
_PUBLIC_ void *smb_memdup(const void *p, size_t size);
|
||||
|
||||
/**
|
||||
* see if a range of memory is all zero. A NULL pointer is considered
|
||||
* to be all zero
|
||||
*/
|
||||
_PUBLIC_ bool all_zero(const uint8_t *ptr, size_t size);
|
||||
|
||||
/**
|
||||
realloc an array, checking for integer overflow in the array size
|
||||
*/
|
||||
_PUBLIC_ void *realloc_array(void *ptr, size_t el_size, unsigned count, bool free_on_fail);
|
||||
|
||||
void *malloc_array(size_t el_size, unsigned int count);
|
||||
|
||||
/* The following definitions come from lib/util/fsusage.c */
|
||||
|
||||
|
||||
/**
|
||||
* Retrieve amount of free disk space.
|
||||
* this does all of the system specific guff to get the free disk space.
|
||||
* It is derived from code in the GNU fileutils package, but has been
|
||||
* considerably mangled for use here
|
||||
*
|
||||
* results are returned in *dfree and *dsize, in 512 byte units
|
||||
*/
|
||||
_PUBLIC_ int sys_fsusage(const char *path, uint64_t *dfree, uint64_t *dsize);
|
||||
|
||||
/* The following definitions come from lib/util/ms_fnmatch.c */
|
||||
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief MS-style Filename matching
|
||||
*/
|
||||
|
||||
#if _SAMBA_BUILD_ == 4
|
||||
#include "libcli/smb/smb_constants.h"
|
||||
|
||||
int ms_fnmatch(const char *pattern, const char *string, enum protocol_types protocol);
|
||||
|
||||
/** a generic fnmatch function - uses for non-CIFS pattern matching */
|
||||
int gen_fnmatch(const char *pattern, const char *string);
|
||||
#endif
|
||||
|
||||
/* The following definitions come from lib/util/mutex.c */
|
||||
|
||||
|
||||
#ifdef _SAMBA_BUILD_
|
||||
/**
|
||||
register a set of mutex/rwlock handlers.
|
||||
Should only be called once in the execution of smbd.
|
||||
*/
|
||||
_PUBLIC_ bool register_mutex_handlers(const char *name, struct mutex_ops *ops);
|
||||
#endif
|
||||
|
||||
/* The following definitions come from lib/util/idtree.c */
|
||||
|
||||
|
||||
/**
|
||||
initialise a idr tree. The context return value must be passed to
|
||||
all subsequent idr calls. To destroy the idr tree use talloc_free()
|
||||
on this context
|
||||
*/
|
||||
_PUBLIC_ struct idr_context *idr_init(TALLOC_CTX *mem_ctx);
|
||||
|
||||
/**
|
||||
allocate the next available id, and assign 'ptr' into its slot.
|
||||
you can retrieve later this pointer using idr_find()
|
||||
*/
|
||||
_PUBLIC_ int idr_get_new(struct idr_context *idp, void *ptr, int limit);
|
||||
|
||||
/**
|
||||
allocate a new id, giving the first available value greater than or
|
||||
equal to the given starting id
|
||||
*/
|
||||
_PUBLIC_ int idr_get_new_above(struct idr_context *idp, void *ptr, int starting_id, int limit);
|
||||
|
||||
/**
|
||||
allocate a new id randomly in the given range
|
||||
*/
|
||||
_PUBLIC_ int idr_get_new_random(struct idr_context *idp, void *ptr, int limit);
|
||||
|
||||
/**
|
||||
find a pointer value previously set with idr_get_new given an id
|
||||
*/
|
||||
_PUBLIC_ void *idr_find(struct idr_context *idp, int id);
|
||||
|
||||
/**
|
||||
remove an id from the idr tree
|
||||
*/
|
||||
_PUBLIC_ int idr_remove(struct idr_context *idp, int id);
|
||||
|
||||
/* The following definitions come from lib/util/become_daemon.c */
|
||||
|
||||
#if _SAMBA_BUILD_ == 4
|
||||
/**
|
||||
Become a daemon, discarding the controlling terminal.
|
||||
**/
|
||||
_PUBLIC_ void become_daemon(bool fork);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Load a ini-style file.
|
||||
*/
|
||||
bool pm_process( const char *fileName,
|
||||
bool (*sfunc)(const char *, void *),
|
||||
bool (*pfunc)(const char *, const char *, void *),
|
||||
void *userdata);
|
||||
|
||||
bool unmap_file(void *start, size_t size);
|
||||
|
||||
#define CONST_DISCARD(type, ptr) ((type) ((void *) (ptr)))
|
||||
|
||||
#endif /* _SAMBA_UTIL_H_ */
|
@ -1,120 +0,0 @@
|
||||
/*
|
||||
functions taken from samba4 for quick prototyping of ctdb. These are
|
||||
not intended to remain part of ctdb
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include "includes.h"
|
||||
#include "system/filesys.h"
|
||||
|
||||
|
||||
static char *fd_load(int fd, size_t *size, TALLOC_CTX *mem_ctx)
|
||||
{
|
||||
struct stat sbuf;
|
||||
char *p;
|
||||
|
||||
if (fstat(fd, &sbuf) != 0) return NULL;
|
||||
|
||||
p = (char *)talloc_size(mem_ctx, sbuf.st_size+1);
|
||||
if (!p) return NULL;
|
||||
|
||||
if (read(fd, p, sbuf.st_size) != sbuf.st_size) {
|
||||
talloc_free(p);
|
||||
return NULL;
|
||||
}
|
||||
p[sbuf.st_size] = 0;
|
||||
|
||||
if (size) *size = sbuf.st_size;
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
static char *file_load(const char *fname, size_t *size, TALLOC_CTX *mem_ctx)
|
||||
{
|
||||
int fd;
|
||||
char *p;
|
||||
|
||||
if (!fname || !*fname) return NULL;
|
||||
|
||||
fd = open(fname,O_RDONLY);
|
||||
if (fd == -1) return NULL;
|
||||
|
||||
p = fd_load(fd, size, mem_ctx);
|
||||
|
||||
close(fd);
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
parse a buffer into lines
|
||||
'p' will be freed on error, and otherwise will be made a child of the returned array
|
||||
**/
|
||||
static char **file_lines_parse(char *p, size_t size, int *numlines, TALLOC_CTX *mem_ctx)
|
||||
{
|
||||
int i;
|
||||
char *s, **ret;
|
||||
|
||||
if (!p) return NULL;
|
||||
|
||||
for (s = p, i=0; s < p+size; s++) {
|
||||
if (s[0] == '\n') i++;
|
||||
}
|
||||
|
||||
ret = talloc_array(mem_ctx, char *, i+2);
|
||||
if (!ret) {
|
||||
talloc_free(p);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
talloc_steal(ret, p);
|
||||
|
||||
memset(ret, 0, sizeof(ret[0])*(i+2));
|
||||
if (numlines) *numlines = i;
|
||||
|
||||
ret[0] = p;
|
||||
for (s = p, i=0; s < p+size; s++) {
|
||||
if (s[0] == '\n') {
|
||||
s[0] = 0;
|
||||
i++;
|
||||
ret[i] = s+1;
|
||||
}
|
||||
if (s[0] == '\r') s[0] = 0;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
load a file into memory and return an array of pointers to lines in the file
|
||||
must be freed with talloc_free().
|
||||
**/
|
||||
_PUBLIC_ char **file_lines_load(const char *fname, int *numlines, size_t maxsize, TALLOC_CTX *mem_ctx)
|
||||
{
|
||||
char *p;
|
||||
size_t size;
|
||||
|
||||
assert(maxsize == 0);
|
||||
|
||||
p = file_load(fname, &size, mem_ctx);
|
||||
if (!p) return NULL;
|
||||
|
||||
return file_lines_parse(p, size, numlines, mem_ctx);
|
||||
}
|
||||
|
||||
char *hex_encode_talloc(TALLOC_CTX *mem_ctx, const unsigned char *buff_in, size_t len)
|
||||
{
|
||||
int i;
|
||||
char *hex_buffer;
|
||||
|
||||
hex_buffer = talloc_array(mem_ctx, char, (len*2)+1);
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
slprintf(&hex_buffer[i*2], 3, "%02X", buff_in[i]);
|
||||
|
||||
return hex_buffer;
|
||||
}
|
@ -1,102 +0,0 @@
|
||||
/*
|
||||
functions taken from samba4 for quick prototyping of ctdb. These are
|
||||
not intended to remain part of ctdb
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include "system/time.h"
|
||||
#include "system/filesys.h"
|
||||
|
||||
|
||||
/**
|
||||
return a zero timeval
|
||||
*/
|
||||
struct timeval timeval_zero(void)
|
||||
{
|
||||
struct timeval tv;
|
||||
tv.tv_sec = 0;
|
||||
tv.tv_usec = 0;
|
||||
return tv;
|
||||
}
|
||||
|
||||
/**
|
||||
return True if a timeval is zero
|
||||
*/
|
||||
bool timeval_is_zero(const struct timeval *tv)
|
||||
{
|
||||
return tv->tv_sec == 0 && tv->tv_usec == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
return a timeval for the current time
|
||||
*/
|
||||
struct timeval timeval_current(void)
|
||||
{
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, NULL);
|
||||
return tv;
|
||||
}
|
||||
|
||||
double timeval_elapsed(struct timeval *tv)
|
||||
{
|
||||
struct timeval tv2 = timeval_current();
|
||||
return (tv2.tv_sec - tv->tv_sec) +
|
||||
(tv2.tv_usec - tv->tv_usec)*1.0e-6;
|
||||
}
|
||||
|
||||
/**
|
||||
return a timeval struct with the given elements
|
||||
*/
|
||||
_PUBLIC_ struct timeval timeval_set(uint32_t secs, uint32_t usecs)
|
||||
{
|
||||
struct timeval tv;
|
||||
tv.tv_sec = secs;
|
||||
tv.tv_usec = usecs;
|
||||
return tv;
|
||||
}
|
||||
|
||||
_PUBLIC_ int timeval_compare(const struct timeval *tv1, const struct timeval *tv2)
|
||||
{
|
||||
if (tv1->tv_sec > tv2->tv_sec) return 1;
|
||||
if (tv1->tv_sec < tv2->tv_sec) return -1;
|
||||
if (tv1->tv_usec > tv2->tv_usec) return 1;
|
||||
if (tv1->tv_usec < tv2->tv_usec) return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
_PUBLIC_ struct timeval timeval_until(const struct timeval *tv1,
|
||||
const struct timeval *tv2)
|
||||
{
|
||||
struct timeval t;
|
||||
if (timeval_compare(tv1, tv2) >= 0) {
|
||||
return timeval_zero();
|
||||
}
|
||||
t.tv_sec = tv2->tv_sec - tv1->tv_sec;
|
||||
if (tv1->tv_usec > tv2->tv_usec) {
|
||||
t.tv_sec--;
|
||||
t.tv_usec = 1000000 - (tv1->tv_usec - tv2->tv_usec);
|
||||
} else {
|
||||
t.tv_usec = tv2->tv_usec - tv1->tv_usec;
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
static struct timeval timeval_add(const struct timeval *tv,
|
||||
uint32_t secs, uint32_t usecs)
|
||||
{
|
||||
struct timeval tv2 = *tv;
|
||||
const unsigned int million = 1000000;
|
||||
tv2.tv_sec += secs;
|
||||
tv2.tv_usec += usecs;
|
||||
tv2.tv_sec += tv2.tv_usec / million;
|
||||
tv2.tv_usec = tv2.tv_usec % million;
|
||||
return tv2;
|
||||
}
|
||||
|
||||
|
||||
_PUBLIC_ struct timeval timeval_current_ofs(uint32_t secs, uint32_t usecs)
|
||||
{
|
||||
struct timeval tv = timeval_current();
|
||||
return timeval_add(&tv, secs, usecs);
|
||||
}
|
||||
|
@ -1,9 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
bld.SAMBA_SUBSYSTEM('ctdb-util',
|
||||
source='''util.c util_file.c util_time.c
|
||||
debug.c fault.c idtree.c signal.c
|
||||
substitute.c''',
|
||||
deps='tdb talloc tevent execinfo',
|
||||
local_include=False,
|
||||
)
|
@ -88,7 +88,7 @@ fi
|
||||
export CC
|
||||
|
||||
CFLAGS="$RPM_OPT_FLAGS $EXTRA -D_GNU_SOURCE" ./buildtools/bin/waf configure \
|
||||
--builtin-libraries=replace,popt \
|
||||
--builtin-libraries=replace,popt,samba-debug,socket-blocking,tdb-wrap \
|
||||
--bundled-libraries=!talloc,!tevent,!tdb \
|
||||
--minimum-library-version=talloc:%libtalloc_version,tdb:%libtdb_version,tevent:%libtevent_version \
|
||||
%if %with_pcp_pmda
|
||||
|
45
ctdb/wscript
45
ctdb/wscript
@ -32,12 +32,18 @@ samba_dist.DIST_DIRS('''ctdb:. lib/replace:lib/replace lib/talloc:lib/talloc
|
||||
lib/tevent:lib/tevent lib/tdb:lib/tdb
|
||||
lib/socket_wrapper:lib/socket_wrapper
|
||||
third_party/popt:third_party/popt
|
||||
lib/util:lib/util lib/tdb_wrap:lib/tdb_wrap
|
||||
lib/ccan:lib/ccan libcli/util:libcli/util
|
||||
buildtools:buildtools''')
|
||||
|
||||
|
||||
def set_options(opt):
|
||||
opt.PRIVATE_EXTENSION_DEFAULT('ctdb')
|
||||
|
||||
opt.RECURSE('lib/replace')
|
||||
|
||||
opt.RECURSE('lib/util')
|
||||
|
||||
opt.RECURSE('lib/talloc')
|
||||
opt.RECURSE('lib/tevent')
|
||||
opt.RECURSE('lib/tdb')
|
||||
@ -67,6 +73,12 @@ def configure(conf):
|
||||
Options.options.disable_python = True
|
||||
|
||||
conf.RECURSE('lib/replace')
|
||||
|
||||
conf.SAMBA_CHECK_PERL(mandatory=True)
|
||||
|
||||
conf.SAMBA_CHECK_PYTHON(mandatory=True, version=(2,5,0))
|
||||
conf.SAMBA_CHECK_PYTHON_HEADERS(mandatory=True)
|
||||
|
||||
if conf.CHECK_FOR_THIRD_PARTY():
|
||||
conf.RECURSE('third_party/popt')
|
||||
else:
|
||||
@ -75,6 +87,8 @@ def configure(conf):
|
||||
else:
|
||||
conf.define('USING_SYSTEM_POPT', 1)
|
||||
|
||||
conf.RECURSE('lib/util')
|
||||
|
||||
conf.RECURSE('lib/talloc')
|
||||
conf.RECURSE('lib/tevent')
|
||||
conf.RECURSE('lib/tdb')
|
||||
@ -180,7 +194,8 @@ def configure(conf):
|
||||
'share/ctdb-tests')
|
||||
conf.env.CTDB_TEST_LIBDIR = os.path.join(conf.env.LIBDIR, 'ctdb-tests')
|
||||
|
||||
# Allow separate compilation of utilities to find includes
|
||||
# Allow unified compilation and separate compilation of utilities
|
||||
# to find includes
|
||||
if srcdir == '.':
|
||||
# Building from tarball
|
||||
conf.ADD_EXTRA_INCLUDES('#include')
|
||||
@ -190,8 +205,15 @@ def configure(conf):
|
||||
conf.ADD_EXTRA_INCLUDES('#ctdb/include')
|
||||
conf.ADD_EXTRA_INCLUDES('#ctdb/include/internal')
|
||||
conf.ADD_EXTRA_INCLUDES('#ctdb')
|
||||
conf.ADD_EXTRA_INCLUDES('#lib #lib/replace')
|
||||
|
||||
conf.SET_TARGET_TYPE('systemd-daemon', 'EMPTY')
|
||||
|
||||
del(conf.env.defines['PYTHONDIR'])
|
||||
del(conf.env.defines['PYTHONARCHDIR'])
|
||||
|
||||
conf.DEFINE('HAVE_CONFIG_H', 1, add_to_cflags=True)
|
||||
conf.DEFINE('SAMBA_UTIL_CORE_ONLY', 1, add_to_cflags=True)
|
||||
conf.SAMBA_CONFIG_H()
|
||||
|
||||
|
||||
@ -223,6 +245,15 @@ def build(bld):
|
||||
bld.RECURSE('lib/tdb')
|
||||
bld.RECURSE('lib/socket_wrapper')
|
||||
|
||||
# When a combined build is implemented, CTDB will wanted to build
|
||||
# against samba-util rather than samba-util-core. Similarly,
|
||||
# other Samba subsystems expect samba-util. So, for a standalone
|
||||
# build, just define a fake samba-util subsystem that pulls in
|
||||
# samba-util-core.
|
||||
bld.SAMBA_SUBSYSTEM('samba-util',
|
||||
source='',
|
||||
deps='samba-util-core')
|
||||
|
||||
bld.SAMBA_SUBSYSTEM('ctdb-tcp',
|
||||
source=bld.SUBDIR('tcp',
|
||||
'tcp_connect.c tcp_init.c tcp_io.c'),
|
||||
@ -276,7 +307,7 @@ def build(bld):
|
||||
includes='include include/internal',
|
||||
public_headers='include/ctdb_client.h',
|
||||
deps='''replace popt talloc tevent tdb
|
||||
ctdb-util tdb-wrap''')
|
||||
samba-util tdb-wrap''')
|
||||
|
||||
bld.SAMBA_SUBSYSTEM('ctdb-server',
|
||||
source='server/ctdbd.c ' +
|
||||
@ -326,14 +357,14 @@ def build(bld):
|
||||
|
||||
bld.SAMBA_BINARY('ctdb_lock_helper',
|
||||
source='server/ctdb_lock_helper.c',
|
||||
deps='ctdb-util ctdb-common-util talloc tdb',
|
||||
deps='samba-util ctdb-common-util talloc tdb',
|
||||
includes='include include/internal',
|
||||
install_path='${BINDIR}')
|
||||
|
||||
bld.SAMBA_BINARY('ctdb_event_helper',
|
||||
source='server/ctdb_event_helper.c',
|
||||
includes='include include/internal',
|
||||
deps='ctdb-util ctdb-common-util replace tdb',
|
||||
deps='samba-util ctdb-common-util replace tdb',
|
||||
install_path='${BINDIR}')
|
||||
|
||||
bld.SAMBA_GENERATOR('ctdb-smnotify-h',
|
||||
@ -491,7 +522,7 @@ def build(bld):
|
||||
bld.SAMBA_BINARY('ctdb_takeover_tests',
|
||||
source='tests/src/ctdb_takeover_tests.c',
|
||||
deps='''replace popt tdb tevent talloc ctdb-system
|
||||
ctdb-util tdb-wrap''' +
|
||||
samba-util tdb-wrap''' +
|
||||
ib_deps,
|
||||
includes='include include/internal',
|
||||
install_path='${CTDB_TEST_LIBDIR}')
|
||||
@ -499,14 +530,14 @@ def build(bld):
|
||||
bld.SAMBA_BINARY('ctdb_functest',
|
||||
source='tests/src/ctdb_functest.c',
|
||||
deps='''replace tdb tevent talloc popt ctdb-system
|
||||
ctdb-util tdb-wrap''',
|
||||
samba-util tdb-wrap''',
|
||||
includes='include include/internal',
|
||||
install_path='${CTDB_TEST_LIBDIR}')
|
||||
|
||||
bld.SAMBA_BINARY('ctdb_stubtest',
|
||||
source='tests/src/ctdb_test.c',
|
||||
deps='''replace tdb tevent talloc popt ctdb-system
|
||||
ctdb-util tdb-wrap''',
|
||||
samba-util tdb-wrap''',
|
||||
includes='include include/internal',
|
||||
install_path='${CTDB_TEST_LIBDIR}')
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user