[asterisk-commits] murf: branch murf/bug_7638 r58919 - in /team/murf/bug_7638: ./ main/ utils/

asterisk-commits at lists.digium.com asterisk-commits at lists.digium.com
Wed Mar 14 22:34:48 MST 2007


Author: murf
Date: Thu Mar 15 00:34:47 2007
New Revision: 58919

URL: http://svn.digium.com/view/asterisk?view=rev&rev=58919
Log:
A couple steps back, and one forward... short of a few entry funcs, I've grouped all machinery needed to read in a config file into a single file, with every func declared static. This may seem insane, messy, stupid, but I need it to do what I need to do. The next step and decision is to step out of the category/variable world into the context/exten/priority world, but I think it'd be better if that was in a separate file, so others could use just external config file reader. I'll take the same approach with the pbx_load_config func in a different file.

Modified:
    team/murf/bug_7638/Makefile.rules
    team/murf/bug_7638/main/pval.c
    team/murf/bug_7638/utils/Makefile
    team/murf/bug_7638/utils/ael_main.c
    team/murf/bug_7638/utils/extconf.c

Modified: team/murf/bug_7638/Makefile.rules
URL: http://svn.digium.com/view/asterisk/team/murf/bug_7638/Makefile.rules?view=diff&rev=58919&r1=58918&r2=58919
==============================================================================
--- team/murf/bug_7638/Makefile.rules (original)
+++ team/murf/bug_7638/Makefile.rules Thu Mar 15 00:34:47 2007
@@ -39,7 +39,7 @@
 %.o: %.c
 	$(ECHO_PREFIX) echo "   [CC] $< -> $@"
 ifeq ($(AST_DEVMODE),yes)
-	$(CMD_PREFIX) $(CC) -o $@ -c $< $(PTHREAD_CFLAGS) $(ASTCFLAGS) -MMD -MT $@ -MF .$(subst /,_,$@).d -MP
+	$(CC) -o $@ -c $< $(PTHREAD_CFLAGS) $(ASTCFLAGS) -MMD -MT $@ -MF .$(subst /,_,$@).d -MP
 else
 	$(CMD_PREFIX) $(CC) -o $@ -c $< $(PTHREAD_CFLAGS) $(ASTCFLAGS)
 endif

Modified: team/murf/bug_7638/main/pval.c
URL: http://svn.digium.com/view/asterisk/team/murf/bug_7638/main/pval.c?view=diff&rev=58919&r1=58918&r2=58919
==============================================================================
--- team/murf/bug_7638/main/pval.c (original)
+++ team/murf/bug_7638/main/pval.c Thu Mar 15 00:34:47 2007
@@ -51,7 +51,6 @@
 #endif
 
 static char expr_output[2096];
-static char *config = "extensions.ael";
 
 /* these functions are in ../ast_expr2.fl */
 
@@ -1330,9 +1329,13 @@
 						}
 					}
 				} else {
-					ast_log(LOG_ERROR,"Error: file %s, line %d-%d: goto:  no context %s could be found that matches the goto target!\n",
-							item->filename, item->startline, item->endline, item->u1.list->u1.str);
-					errs++;
+					/* here is where code would go to check for target existence in extensions.conf files */
+					extern int this_target_in_extensions_dot_conf(char *context, char *exten, char *label);
+					
+					if (!this_target_in_extensions_dot_conf(first->u1.str, second->u1.str, third->u1.str))
+						ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: goto:  no context %s could be found that matches the goto target!\n",
+								item->filename, item->startline, item->endline, item->u1.list->u1.str);
+					warns++;
 				}
 			} else {
 				struct pval *mac = in_macro(item); /* is this goto inside a macro? */
@@ -5149,7 +5152,8 @@
 	return head;
 }
 
-
+#ifdef HERE_BY_MISTAKE_I_THINK
+static char *config = "extensions.ael";
 int do_pbx_load_module(void)
 {
 	int errs, sem_err, sem_warn, sem_note;
@@ -5193,4 +5197,5 @@
 	
 	return AST_MODULE_LOAD_SUCCESS;
 }
-
+#endif
+

Modified: team/murf/bug_7638/utils/Makefile
URL: http://svn.digium.com/view/asterisk/team/murf/bug_7638/utils/Makefile?view=diff&rev=58919&r1=58918&r2=58919
==============================================================================
--- team/murf/bug_7638/utils/Makefile (original)
+++ team/murf/bug_7638/utils/Makefile Thu Mar 15 00:34:47 2007
@@ -108,7 +108,7 @@
 aelparse.o: aelparse.c ../include/asterisk/ael_structs.h ../pbx/ael/ael.tab.h
 aelparse.o: ASTCFLAGS+=-I../pbx -DSTANDALONE_AEL
 
-aelparse: aelparse.o aelbison.o pbx_ael.o ael_main.o ast_expr2f.o ast_expr2.o strcompat.o pval.o
+aelparse: aelparse.o aelbison.o pbx_ael.o ael_main.o ast_expr2f.o ast_expr2.o strcompat.o pval.o extconf.o
 
 config_external.o : config_external.c
 

Modified: team/murf/bug_7638/utils/ael_main.c
URL: http://svn.digium.com/view/asterisk/team/murf/bug_7638/utils/ael_main.c?view=diff&rev=58919&r1=58918&r2=58919
==============================================================================
--- team/murf/bug_7638/utils/ael_main.c (original)
+++ team/murf/bug_7638/utils/ael_main.c Thu Mar 15 00:34:47 2007
@@ -350,73 +350,10 @@
 		printf("Executed ast_context_verify_includes();\n");
 }
 
-struct ast_context * ast_walk_contexts(void)
-{
-	if(!no_comp)
-		printf("Executed ast_walk_contexts();\n");
-	return 0;
-}
-
 void ast_cli_unregister_multiple(void)
 {
 	if(!no_comp)
 		printf("Executed ast_cli_unregister_multiple();\n");
-}
-
-void ast_context_destroy(void)
-{
-	if( !no_comp)
-		printf("Executed ast_context_destroy();\n");
-}
-
-void ast_log(int level, const char *file, int line, const char *function, const char *fmt, ...)
-{
-        va_list vars;
-        va_start(vars,fmt);
-	if( !quiet || level > 2 ) {
-    	    printf("LOG: lev:%d file:%s  line:%d func: %s  ",
-                   level, file, line, function);
-            vprintf(fmt, vars);
-            fflush(stdout);
-            va_end(vars);
-	}
-}
-
-void ast_verbose(const char *fmt, ...)
-{
-        va_list vars;
-        va_start(vars,fmt);
-
-        printf("VERBOSE: ");
-        vprintf(fmt, vars);
-        fflush(stdout);
-        va_end(vars);
-}
-
-char *ast_process_quotes_and_slashes(char *start, char find, char replace_with)
-{
-        char *dataPut = start;
-        int inEscape = 0;
-        int inQuotes = 0;
-
-        for (; *start; start++) {
-                if (inEscape) {
-                        *dataPut++ = *start;       /* Always goes verbatim */
-                        inEscape = 0;
-                } else {
-                        if (*start == '\\') {
-                                inEscape = 1;      /* Do not copy \ into the data */
-                        } else if (*start == '\'') {
-                                inQuotes = 1-inQuotes;   /* Do not copy ' into the data */
-                        } else {
-                                /* Replace , with |, unless in quotes */
-                                *dataPut++ = inQuotes ? *start : ((*start==find) ? replace_with : *start);
-                        }
-                }
-        }
-        if (start != dataPut)
-                *dataPut = 0;
-        return dataPut;
 }
 
 void filter_leading_space_from_exprs(char *str)

Modified: team/murf/bug_7638/utils/extconf.c
URL: http://svn.digium.com/view/asterisk/team/murf/bug_7638/utils/extconf.c?view=diff&rev=58919&r1=58918&r2=58919
==============================================================================
--- team/murf/bug_7638/utils/extconf.c (original)
+++ team/murf/bug_7638/utils/extconf.c Thu Mar 15 00:34:47 2007
@@ -27,8 +27,16 @@
 #include "asterisk/autoconfig.h"
 
 #include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <time.h>
+#include <sys/stat.h>
 #include <sys/types.h>
-#include <stdlib.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/wait.h>
 #include <stdarg.h>
 #include <string.h>
 #include <locale.h>
@@ -36,37 +44,2430 @@
 #if !defined(SOLARIS) && !defined(__CYGWIN__)
 #include <err.h>
 #endif
-#include <errno.h>
 #include <regex.h>
 #include <limits.h>
-
-#include "asterisk/pbx.h"
+#include <pthread.h>
+#include <netdb.h>
+#include <sys/param.h>
+#define AST_INCLUDE_GLOB 1
+#ifdef AST_INCLUDE_GLOB
+#if defined(__Darwin__) || defined(__CYGWIN__)
+#define GLOB_ABORTED GLOB_ABEND
+#endif
+# include <glob.h>
+#endif
+
+static char ast_config_AST_CONFIG_DIR[PATH_MAX];
+
+#include "asterisk/inline_api.h"
+#include "asterisk/compat.h"
+#include "asterisk/compiler.h"
+#include "asterisk/endian.h"
 #include "asterisk/ast_expr.h"
-#include "asterisk/channel.h"
-#include "asterisk/chanvars.h"
-#include "asterisk/module.h"
-#include "asterisk/app.h"
-#include "asterisk/config.h"
-#include "asterisk/options.h"
-#include "asterisk/callerid.h"
 #include "asterisk/ael_structs.h"
-#include "asterisk/devicestate.h"
-#include "asterisk/stringfields.h"
 #include "asterisk/ael_structs.h"
 #include "asterisk/pval.h"
 
-
-char *config = "extensions.conf";
+/* logger.h */
+#define EVENTLOG "event_log"
+#define	QUEUELOG	"queue_log"
+
+#define DEBUG_M(a) { \
+	a; \
+}
+
+#define VERBOSE_PREFIX_1 " "
+#define VERBOSE_PREFIX_2 "  == "
+#define VERBOSE_PREFIX_3 "    -- "
+#define VERBOSE_PREFIX_4 "       > "
+
+/* IN CONFLICT: void ast_log(int level, const char *file, int line, const char *function, const char *fmt, ...)
+   __attribute__ ((format (printf, 5, 6))); */
+
+static void ast_log(int level, const char *file, int line, const char *function, const char *fmt, ...) __attribute__ ((format (printf,5,6)));
+
+
+void ast_backtrace(void);
+
+void ast_queue_log(const char *queuename, const char *callid, const char *agent, const char *event, const char *fmt, ...)
+	__attribute__ ((format (printf, 5, 6)));
+
+/* IN CONFLICT: void ast_verbose(const char *fmt, ...)
+   __attribute__ ((format (printf, 1, 2))); */
+
+int ast_register_verbose(void (*verboser)(const char *string));
+int ast_unregister_verbose(void (*verboser)(const char *string));
+
+void ast_console_puts(const char *string);
+
+void ast_console_puts_mutable(const char *string);
+void ast_console_toggle_mute(int fd);
+
+#define _A_ __FILE__, __LINE__, __PRETTY_FUNCTION__
+
+#ifdef LOG_DEBUG
+#undef LOG_DEBUG
+#endif
+#define __LOG_DEBUG    0
+#define LOG_DEBUG      __LOG_DEBUG, _A_
+
+#ifdef LOG_EVENT
+#undef LOG_EVENT
+#endif
+#define __LOG_EVENT    1
+#define LOG_EVENT      __LOG_EVENT, _A_
+
+#ifdef LOG_NOTICE
+#undef LOG_NOTICE
+#endif
+#define __LOG_NOTICE   2
+#define LOG_NOTICE     __LOG_NOTICE, _A_
+
+#ifdef LOG_WARNING
+#undef LOG_WARNING
+#endif
+#define __LOG_WARNING  3
+#define LOG_WARNING    __LOG_WARNING, _A_
+
+#ifdef LOG_ERROR
+#undef LOG_ERROR
+#endif
+#define __LOG_ERROR    4
+#define LOG_ERROR      __LOG_ERROR, _A_
+
+#ifdef LOG_VERBOSE
+#undef LOG_VERBOSE
+#endif
+#define __LOG_VERBOSE  5
+#define LOG_VERBOSE    __LOG_VERBOSE, _A_
+
+#ifdef LOG_DTMF
+#undef LOG_DTMF
+#endif
+#define __LOG_DTMF  6
+#define LOG_DTMF    __LOG_DTMF, _A_
+
+/* from utils.h */
+
+static unsigned int __unsigned_int_flags_dummy;
+
+struct ast_flags {  /* stolen from utils.h */
+	unsigned int flags;
+};
+#define ast_test_flag(p,flag) 		({ \
+					typeof ((p)->flags) __p = (p)->flags; \
+					typeof (__unsigned_int_flags_dummy) __x = 0; \
+					(void) (&__p == &__x); \
+					((p)->flags & (flag)); \
+					})
+
+#define ast_set2_flag(p,value,flag)	do { \
+					typeof ((p)->flags) __p = (p)->flags; \
+					typeof (__unsigned_int_flags_dummy) __x = 0; \
+					(void) (&__p == &__x); \
+					if (value) \
+						(p)->flags |= (flag); \
+					else \
+						(p)->flags &= ~(flag); \
+					} while (0)
+
+
+#ifdef __AST_DEBUG_MALLOC
+static void ast_free(void *ptr) attribute_unused;
+static void ast_free(void *ptr)
+{
+	free(ptr);
+}
+#else
+#define ast_free free
+#endif
+
+#ifndef __AST_DEBUG_MALLOC
+
+#define MALLOC_FAILURE_MSG \
+	ast_log(LOG_ERROR, "Memory Allocation Failure in function %s at line %d of %s\n", func, lineno, file);
+/*!
+ * \brief A wrapper for malloc()
+ *
+ * ast_malloc() is a wrapper for malloc() that will generate an Asterisk log
+ * message in the case that the allocation fails.
+ *
+ * The argument and return value are the same as malloc()
+ */
+#define ast_malloc(len) \
+	_ast_malloc((len), __FILE__, __LINE__, __PRETTY_FUNCTION__)
+
+AST_INLINE_API(
+void * attribute_malloc _ast_malloc(size_t len, const char *file, int lineno, const char *func),
+{
+	void *p;
+
+	if (!(p = malloc(len)))
+		MALLOC_FAILURE_MSG;
+
+	return p;
+}
+)
+
+/*!
+ * \brief A wrapper for calloc()
+ *
+ * ast_calloc() is a wrapper for calloc() that will generate an Asterisk log
+ * message in the case that the allocation fails.
+ *
+ * The arguments and return value are the same as calloc()
+ */
+#define ast_calloc(num, len) \
+	_ast_calloc((num), (len), __FILE__, __LINE__, __PRETTY_FUNCTION__)
+
+AST_INLINE_API(
+void * attribute_malloc _ast_calloc(size_t num, size_t len, const char *file, int lineno, const char *func),
+{
+	void *p;
+
+	if (!(p = calloc(num, len)))
+		MALLOC_FAILURE_MSG;
+
+	return p;
+}
+)
+
+/*!
+ * \brief A wrapper for calloc() for use in cache pools
+ *
+ * ast_calloc_cache() is a wrapper for calloc() that will generate an Asterisk log
+ * message in the case that the allocation fails. When memory debugging is in use,
+ * the memory allocated by this function will be marked as 'cache' so it can be
+ * distinguished from normal memory allocations.
+ *
+ * The arguments and return value are the same as calloc()
+ */
+#define ast_calloc_cache(num, len) \
+	_ast_calloc((num), (len), __FILE__, __LINE__, __PRETTY_FUNCTION__)
+
+/*!
+ * \brief A wrapper for realloc()
+ *
+ * ast_realloc() is a wrapper for realloc() that will generate an Asterisk log
+ * message in the case that the allocation fails.
+ *
+ * The arguments and return value are the same as realloc()
+ */
+#define ast_realloc(p, len) \
+	_ast_realloc((p), (len), __FILE__, __LINE__, __PRETTY_FUNCTION__)
+
+AST_INLINE_API(
+void * attribute_malloc _ast_realloc(void *p, size_t len, const char *file, int lineno, const char *func),
+{
+	void *newp;
+
+	if (!(newp = realloc(p, len)))
+		MALLOC_FAILURE_MSG;
+
+	return newp;
+}
+)
+
+/*!
+ * \brief A wrapper for strdup()
+ *
+ * ast_strdup() is a wrapper for strdup() that will generate an Asterisk log
+ * message in the case that the allocation fails.
+ *
+ * ast_strdup(), unlike strdup(), can safely accept a NULL argument. If a NULL
+ * argument is provided, ast_strdup will return NULL without generating any
+ * kind of error log message.
+ *
+ * The argument and return value are the same as strdup()
+ */
+#define ast_strdup(str) \
+	_ast_strdup((str), __FILE__, __LINE__, __PRETTY_FUNCTION__)
+
+AST_INLINE_API(
+char * attribute_malloc _ast_strdup(const char *str, const char *file, int lineno, const char *func),
+{
+	char *newstr = NULL;
+
+	if (str) {
+		if (!(newstr = strdup(str)))
+			MALLOC_FAILURE_MSG;
+	}
+
+	return newstr;
+}
+)
+
+/*!
+ * \brief A wrapper for strndup()
+ *
+ * ast_strndup() is a wrapper for strndup() that will generate an Asterisk log
+ * message in the case that the allocation fails.
+ *
+ * ast_strndup(), unlike strndup(), can safely accept a NULL argument for the
+ * string to duplicate. If a NULL argument is provided, ast_strdup will return  
+ * NULL without generating any kind of error log message.
+ *
+ * The arguments and return value are the same as strndup()
+ */
+#define ast_strndup(str, len) \
+	_ast_strndup((str), (len), __FILE__, __LINE__, __PRETTY_FUNCTION__)
+
+AST_INLINE_API(
+char * attribute_malloc _ast_strndup(const char *str, size_t len, const char *file, int lineno, const char *func),
+{
+	char *newstr = NULL;
+
+	if (str) {
+		if (!(newstr = strndup(str, len)))
+			MALLOC_FAILURE_MSG;
+	}
+
+	return newstr;
+}
+)
+
+/*!
+ * \brief A wrapper for asprintf()
+ *
+ * ast_asprintf() is a wrapper for asprintf() that will generate an Asterisk log
+ * message in the case that the allocation fails.
+ *
+ * The arguments and return value are the same as asprintf()
+ */
+#define ast_asprintf(ret, fmt, ...) \
+	_ast_asprintf((ret), __FILE__, __LINE__, __PRETTY_FUNCTION__, fmt, __VA_ARGS__)
+
+AST_INLINE_API(
+int _ast_asprintf(char **ret, const char *file, int lineno, const char *func, const char *fmt, ...),
+{
+	int res;
+	va_list ap;
+
+	va_start(ap, fmt);
+	if ((res = vasprintf(ret, fmt, ap)) == -1)
+		MALLOC_FAILURE_MSG;
+	va_end(ap);
+
+	return res;
+}
+)
+
+/*!
+ * \brief A wrapper for vasprintf()
+ *
+ * ast_vasprintf() is a wrapper for vasprintf() that will generate an Asterisk log
+ * message in the case that the allocation fails.
+ *
+ * The arguments and return value are the same as vasprintf()
+ */
+#define ast_vasprintf(ret, fmt, ap) \
+	_ast_vasprintf((ret), __FILE__, __LINE__, __PRETTY_FUNCTION__, (fmt), (ap))
+
+AST_INLINE_API(
+int _ast_vasprintf(char **ret, const char *file, int lineno, const char *func, const char *fmt, va_list ap),
+{
+	int res;
+
+	if ((res = vasprintf(ret, fmt, ap)) == -1)
+		MALLOC_FAILURE_MSG;
+
+	return res;
+}
+)
+
+#else
+
+/* If astmm is in use, let it handle these.  Otherwise, it will report that
+   all allocations are coming from this header file */
+
+#define ast_malloc(a)		malloc(a)
+#define ast_calloc(a,b)		calloc(a,b)
+#define ast_realloc(a,b)	realloc(a,b)
+#define ast_strdup(a)		strdup(a)
+#define ast_strndup(a,b)	strndup(a,b)
+#define ast_asprintf(a,b,c)	asprintf(a,b,c)
+#define ast_vasprintf(a,b,c)	vasprintf(a,b,c)
+
+#endif /* AST_DEBUG_MALLOC */
+
+#if !defined(ast_strdupa) && defined(__GNUC__)
+/*!
+  \brief duplicate a string in memory from the stack
+  \param s The string to duplicate
+
+  This macro will duplicate the given string.  It returns a pointer to the stack
+  allocatted memory for the new string.
+*/
+#define ast_strdupa(s)                                                    \
+	(__extension__                                                    \
+	({                                                                \
+		const char *__old = (s);                                  \
+		size_t __len = strlen(__old) + 1;                         \
+		char *__new = __builtin_alloca(__len);                    \
+		memcpy (__new, __old, __len);                             \
+		__new;                                                    \
+	}))
+#endif
+
+
+/* from config.c */
+
+#define MAX_NESTED_COMMENTS 128
+#define COMMENT_START ";--"
+#define COMMENT_END "--;"
+#define COMMENT_META ';'
+#define COMMENT_TAG '-'
+
+static char *extconfig_conf = "extconfig.conf";
+
+/*! Growable string buffer */
+static char *comment_buffer;   /*!< this will be a comment collector.*/
+static int   comment_buffer_size;  /*!< the amount of storage so far alloc'd for the comment_buffer */
+
+static char *lline_buffer;    /*!< A buffer for stuff behind the ; */
+static int  lline_buffer_size;
+
+#define CB_INCR 250
+
+struct ast_comment {
+	struct ast_comment *next;
+	char cmt[0];
+};
+
+static void CB_INIT(void)
+{
+	if (!comment_buffer) {
+		comment_buffer = ast_malloc(CB_INCR);
+		if (!comment_buffer)
+			return;
+		comment_buffer[0] = 0;
+		comment_buffer_size = CB_INCR;
+		lline_buffer = ast_malloc(CB_INCR);
+		if (!lline_buffer)
+			return;
+		lline_buffer[0] = 0;
+		lline_buffer_size = CB_INCR;
+	} else {
+		comment_buffer[0] = 0;
+		lline_buffer[0] = 0;
+	}
+}
+
+static void  CB_ADD(char *str)
+{
+	int rem = comment_buffer_size - strlen(comment_buffer) - 1;
+	int siz = strlen(str);
+	if (rem < siz+1) {
+		comment_buffer = ast_realloc(comment_buffer, comment_buffer_size + CB_INCR + siz + 1);
+		if (!comment_buffer)
+			return;
+		comment_buffer_size += CB_INCR+siz+1;
+	}
+	strcat(comment_buffer,str);
+}
+
+static void  CB_ADD_LEN(char *str, int len)
+{
+	int cbl = strlen(comment_buffer) + 1;
+	int rem = comment_buffer_size - cbl;
+	if (rem < len+1) {
+		comment_buffer = ast_realloc(comment_buffer, comment_buffer_size + CB_INCR + len + 1);
+		if (!comment_buffer)
+			return;
+		comment_buffer_size += CB_INCR+len+1;
+	}
+	strncat(comment_buffer,str,len);
+	comment_buffer[cbl+len-1] = 0;
+}
+
+static void  LLB_ADD(char *str)
+{
+	int rem = lline_buffer_size - strlen(lline_buffer) - 1;
+	int siz = strlen(str);
+	if (rem < siz+1) {
+		lline_buffer = ast_realloc(lline_buffer, lline_buffer_size + CB_INCR + siz + 1);
+		if (!lline_buffer) 
+			return;
+		lline_buffer_size += CB_INCR + siz + 1;
+	}
+	strcat(lline_buffer,str);
+}
+
+static void CB_RESET(void )  
+{ 
+	comment_buffer[0] = 0; 
+	lline_buffer[0] = 0;
+}
+		
+/*! \brief Keep track of how many threads are currently trying to wait*() on
+ *  a child process */
+static unsigned int safe_system_level = 0;
+static void *safe_system_prev_handler;
+
+/*! \brief NULL handler so we can collect the child exit status */
+static void null_sig_handler(int signal)
+{
+
+}
+
+void ast_replace_sigchld(void);
+
+void ast_replace_sigchld(void)
+{
+	unsigned int level;
+
+	level = safe_system_level++;
+
+	/* only replace the handler if it has not already been done */
+	if (level == 0)
+		safe_system_prev_handler = signal(SIGCHLD, null_sig_handler);
+
+}
+
+void ast_unreplace_sigchld(void);
+
+void ast_unreplace_sigchld(void)
+{
+	unsigned int level;
+
+	level = --safe_system_level;
+
+	/* only restore the handler if we are the last one */
+	if (level == 0)
+		signal(SIGCHLD, safe_system_prev_handler);
+
+}
+
+int ast_safe_system(const char *s);
+
+int ast_safe_system(const char *s)
+{
+	pid_t pid;
+#ifdef HAVE_WORKING_FORK
+	int x;
+#endif
+	int res;
+	struct rusage rusage;
+	int status;
+
+#if defined(HAVE_WORKING_FORK) || defined(HAVE_WORKING_VFORK)
+	ast_replace_sigchld();
+
+#ifdef HAVE_WORKING_FORK
+	pid = fork();
+#else
+	pid = vfork();
+#endif	
+
+	if (pid == 0) {
+#ifdef HAVE_WORKING_FORK
+		/* Close file descriptors and launch system command */
+		for (x = STDERR_FILENO + 1; x < 4096; x++)
+			close(x);
+#endif
+		execl("/bin/sh", "/bin/sh", "-c", s, (char *) NULL);
+		_exit(1);
+	} else if (pid > 0) {
+		for(;;) {
+			res = wait4(pid, &status, 0, &rusage);
+			if (res > -1) {
+				res = WIFEXITED(status) ? WEXITSTATUS(status) : -1;
+				break;
+			} else if (errno != EINTR) 
+				break;
+		}
+	} else {
+		ast_log(LOG_WARNING, "Fork failed: %s\n", strerror(errno));
+		res = -1;
+	}
+
+	ast_unreplace_sigchld();
+#else
+	res = -1;
+#endif
+
+	return res;
+}
+
+static struct ast_comment *ALLOC_COMMENT(const char *buffer)
+{ 
+	struct ast_comment *x = ast_calloc(1,sizeof(struct ast_comment)+strlen(buffer)+1);
+	strcpy(x->cmt, buffer);
+	return x;
+}
+
+static struct ast_config_map {
+	struct ast_config_map *next;
+	char *name;
+	char *driver;
+	char *database;
+	char *table;
+	char stuff[0];
+} *config_maps = NULL;
+
+static struct ast_config_engine *config_engine_list;
+
+#define MAX_INCLUDE_LEVEL 10
+
+
+struct ast_category {
+	char name[80];
+	int ignored;			/*!< do not let user of the config see this category */
+	int include_level;	
+	struct ast_comment *precomments;
+	struct ast_comment *sameline;
+	struct ast_variable *root;
+	struct ast_variable *last;
+	struct ast_category *next;
+};
+
+struct ast_config {
+	struct ast_category *root;
+	struct ast_category *last;
+	struct ast_category *current;
+	struct ast_category *last_browse;		/*!< used to cache the last category supplied via category_browse */
+	int include_level;
+	int max_include_level;
+};
+
+typedef struct ast_config *config_load_func(const char *database, const char *table, const char *configfile, struct ast_config *config, int withcomments);
+typedef struct ast_variable *realtime_var_get(const char *database, const char *table, va_list ap);
+typedef struct ast_config *realtime_multi_get(const char *database, const char *table, va_list ap);
+typedef int realtime_update(const char *database, const char *table, const char *keyfield, const char *entity, va_list ap);
+
+/*! \brief Configuration engine structure, used to define realtime drivers */
+struct ast_config_engine {
+	char *name;
+	config_load_func *load_func;
+	realtime_var_get *realtime_func;
+	realtime_multi_get *realtime_multi_func;
+	realtime_update *update_func;
+	struct ast_config_engine *next;
+};
+
+static struct ast_config_engine *config_engine_list;
+
+/* from config.h */
+
+struct ast_variable {
+	char *name;
+	char *value;
+	int lineno;
+	int object;		/*!< 0 for variable, 1 for object */
+	int blanklines; 	/*!< Number of blanklines following entry */
+	struct ast_comment *precomments;
+	struct ast_comment *sameline;
+	struct ast_variable *next;
+	char stuff[0];
+};
+
+static const char *ast_variable_retrieve(const struct ast_config *config, const char *category, const char *variable);
+static struct ast_config *config_text_file_load(const char *database, const char *table, const char *filename, struct ast_config *cfg, int withcomments);
+
+static struct ast_config *ast_config_load_with_comments(const char *filename);
+static char *ast_category_browse(struct ast_config *config, const char *prev);
+struct ast_variable *ast_variable_browse(const struct ast_config *config, const char *category);
+static void ast_variables_destroy(struct ast_variable *v);
+static void ast_config_destroy(struct ast_config *cfg);
+
+struct ast_variable *ast_variable_new(const char *name, const char *value);
+
+struct ast_variable *ast_variable_new(const char *name, const char *value) 
+{
+	struct ast_variable *variable;
+	int name_len = strlen(name) + 1;	
+
+	if ((variable = ast_calloc(1, name_len + strlen(value) + 1 + sizeof(*variable)))) {
+		variable->name = variable->stuff;
+		variable->value = variable->stuff + name_len;		
+		strcpy(variable->name,name);
+		strcpy(variable->value,value);
+	}
+
+	return variable;
+}
+
+void ast_variable_append(struct ast_category *category, struct ast_variable *variable);
+
+void ast_variable_append(struct ast_category *category, struct ast_variable *variable)
+{
+	if (!variable)
+		return;
+	if (category->last)
+		category->last->next = variable;
+	else
+		category->root = variable;
+	category->last = variable;
+	while (category->last->next)
+		category->last = category->last->next;
+}
+
+static const char *ast_variable_retrieve(const struct ast_config *config, const char *category, const char *variable)
+{
+	struct ast_variable *v;
+
+	if (category) {
+		for (v = ast_variable_browse(config, category); v; v = v->next) {
+			if (!strcasecmp(variable, v->name))
+				return v->value;
+		}
+	} else {
+		struct ast_category *cat;
+
+		for (cat = config->root; cat; cat = cat->next)
+			for (v = cat->root; v; v = v->next)
+				if (!strcasecmp(variable, v->name))
+					return v->value;
+	}
+
+	return NULL;
+}
+
+static struct ast_variable *variable_clone(const struct ast_variable *old)
+{
+	struct ast_variable *new = ast_variable_new(old->name, old->value);
+
+	if (new) {
+		new->lineno = old->lineno;
+		new->object = old->object;
+		new->blanklines = old->blanklines;
+		/* TODO: clone comments? */
+	}
+
+	return new;
+}
+ 
+static void ast_variables_destroy(struct ast_variable *v)
+{
+	struct ast_variable *vn;
+
+	while (v) {
+		vn = v;
+		v = v->next;
+		free(vn);
+	}
+}
+
+static void ast_config_destroy(struct ast_config *cfg)
+{
+	struct ast_category *cat, *catn;
+
+	if (!cfg)
+		return;
+
+	cat = cfg->root;
+	while (cat) {
+		ast_variables_destroy(cat->root);
+		catn = cat;
+		cat = cat->next;
+		free(catn);
+	}
+	free(cfg);
+}
+
+
+/* options.h declars ast_options extern; I need it static? */
+
+#define AST_CACHE_DIR_LEN 	512
+#define AST_FILENAME_MAX	80
+
+/*! \ingroup main_options */
+enum ast_option_flags {
+	/*! Allow \#exec in config files */
+	AST_OPT_FLAG_EXEC_INCLUDES = (1 << 0),
+	/*! Do not fork() */
+	AST_OPT_FLAG_NO_FORK = (1 << 1),
+	/*! Keep quiet */
+	AST_OPT_FLAG_QUIET = (1 << 2),
+	/*! Console mode */
+	AST_OPT_FLAG_CONSOLE = (1 << 3),
+	/*! Run in realtime Linux priority */
+	AST_OPT_FLAG_HIGH_PRIORITY = (1 << 4),
+	/*! Initialize keys for RSA authentication */
+	AST_OPT_FLAG_INIT_KEYS = (1 << 5),
+	/*! Remote console */
+	AST_OPT_FLAG_REMOTE = (1 << 6),
+	/*! Execute an asterisk CLI command upon startup */
+	AST_OPT_FLAG_EXEC = (1 << 7),
+	/*! Don't use termcap colors */
+	AST_OPT_FLAG_NO_COLOR = (1 << 8),
+	/*! Are we fully started yet? */
+	AST_OPT_FLAG_FULLY_BOOTED = (1 << 9),
+	/*! Trascode via signed linear */
+	AST_OPT_FLAG_TRANSCODE_VIA_SLIN = (1 << 10),
+	/*! Enable priority jumping in applications */
+	AST_OPT_FLAG_PRIORITY_JUMPING = (1 << 11),
+	/*! Dump core on a seg fault */
+	AST_OPT_FLAG_DUMP_CORE = (1 << 12),
+	/*! Cache sound files */
+	AST_OPT_FLAG_CACHE_RECORD_FILES = (1 << 13),
+	/*! Display timestamp in CLI verbose output */
+	AST_OPT_FLAG_TIMESTAMP = (1 << 14),
+	/*! Override config */
+	AST_OPT_FLAG_OVERRIDE_CONFIG = (1 << 15),
+	/*! Reconnect */
+	AST_OPT_FLAG_RECONNECT = (1 << 16),
+	/*! Transmit Silence during Record() */
+	AST_OPT_FLAG_TRANSMIT_SILENCE = (1 << 17),
+	/*! Suppress some warnings */
+	AST_OPT_FLAG_DONT_WARN = (1 << 18),
+	/*! End CDRs before the 'h' extension */
+	AST_OPT_FLAG_END_CDR_BEFORE_H_EXTEN = (1 << 19),
+	/*! Use Zaptel Timing for generators if available */
+	AST_OPT_FLAG_INTERNAL_TIMING = (1 << 20),
+	/*! Always fork, even if verbose or debug settings are non-zero */
+	AST_OPT_FLAG_ALWAYS_FORK = (1 << 21),
+	/*! Disable log/verbose output to remote consoles */
+	AST_OPT_FLAG_MUTE = (1 << 22)
+};
+
+/*! These are the options that set by default when Asterisk starts */
+#define AST_DEFAULT_OPTIONS AST_OPT_FLAG_TRANSCODE_VIA_SLIN
+
+#define ast_opt_exec_includes		ast_test_flag(&ast_options, AST_OPT_FLAG_EXEC_INCLUDES)
+#define ast_opt_no_fork			ast_test_flag(&ast_options, AST_OPT_FLAG_NO_FORK)
+#define ast_opt_quiet			ast_test_flag(&ast_options, AST_OPT_FLAG_QUIET)
+#define ast_opt_console			ast_test_flag(&ast_options, AST_OPT_FLAG_CONSOLE)
+#define ast_opt_high_priority		ast_test_flag(&ast_options, AST_OPT_FLAG_HIGH_PRIORITY)
+#define ast_opt_init_keys		ast_test_flag(&ast_options, AST_OPT_FLAG_INIT_KEYS)
+#define ast_opt_remote			ast_test_flag(&ast_options, AST_OPT_FLAG_REMOTE)
+#define ast_opt_exec			ast_test_flag(&ast_options, AST_OPT_FLAG_EXEC)
+#define ast_opt_no_color		ast_test_flag(&ast_options, AST_OPT_FLAG_NO_COLOR)
+#define ast_fully_booted		ast_test_flag(&ast_options, AST_OPT_FLAG_FULLY_BOOTED)
+#define ast_opt_transcode_via_slin	ast_test_flag(&ast_options, AST_OPT_FLAG_TRANSCODE_VIA_SLIN)
+#define ast_opt_priority_jumping	ast_test_flag(&ast_options, AST_OPT_FLAG_PRIORITY_JUMPING)
+#define ast_opt_dump_core		ast_test_flag(&ast_options, AST_OPT_FLAG_DUMP_CORE)
+#define ast_opt_cache_record_files	ast_test_flag(&ast_options, AST_OPT_FLAG_CACHE_RECORD_FILES)
+#define ast_opt_timestamp		ast_test_flag(&ast_options, AST_OPT_FLAG_TIMESTAMP)
+#define ast_opt_override_config		ast_test_flag(&ast_options, AST_OPT_FLAG_OVERRIDE_CONFIG)
+#define ast_opt_reconnect		ast_test_flag(&ast_options, AST_OPT_FLAG_RECONNECT)
+#define ast_opt_transmit_silence	ast_test_flag(&ast_options, AST_OPT_FLAG_TRANSMIT_SILENCE)
+#define ast_opt_dont_warn		ast_test_flag(&ast_options, AST_OPT_FLAG_DONT_WARN)
+#define ast_opt_end_cdr_before_h_exten	ast_test_flag(&ast_options, AST_OPT_FLAG_END_CDR_BEFORE_H_EXTEN)
+#define ast_opt_internal_timing		ast_test_flag(&ast_options, AST_OPT_FLAG_INTERNAL_TIMING)
+#define ast_opt_always_fork		ast_test_flag(&ast_options, AST_OPT_FLAG_ALWAYS_FORK)
+#define ast_opt_mute			ast_test_flag(&ast_options, AST_OPT_FLAG_MUTE)
+
+/*  IN CONFLICT: extern int option_verbose; */
+/*  IN CONFLICT: extern int option_debug;	*/	/*!< Debugging */
+extern int option_maxcalls;		/*!< Maximum number of simultaneous channels */
+extern double option_maxload;
+extern char defaultlanguage[];
+
+extern time_t ast_startuptime;
+extern time_t ast_lastreloadtime;
+extern pid_t ast_mainpid;
+
+extern char record_cache_dir[AST_CACHE_DIR_LEN];
+extern char debug_filename[AST_FILENAME_MAX];
+
+extern int ast_language_is_prefix;
+
+
+
+/* lock.h */
+
+#ifndef	HAVE_MTX_PROFILE
+#define	__MTX_PROF(a)	return pthread_mutex_lock((a))
+#else
+#define	__MTX_PROF(a)	do {			\
+	int i;					\
+	/* profile only non-blocking events */	\
+	ast_mark(mtx_prof, 1);			\
+	i = pthread_mutex_trylock((a));		\
+	ast_mark(mtx_prof, 0);			\
+	if (!i)					\
+		return i;			\
+	else					\
+		return pthread_mutex_lock((a)); \
+	} while (0)
+#endif	/* HAVE_MTX_PROFILE */
+
+#define AST_PTHREADT_NULL (pthread_t) -1
+#define AST_PTHREADT_STOP (pthread_t) -2
+
+#if defined(SOLARIS) || defined(BSD)
+#define AST_MUTEX_INIT_W_CONSTRUCTORS
+#endif /* SOLARIS || BSD */
+
+/* Asterisk REQUIRES recursive (not error checking) mutexes
+   and will not run without them. */
+#if defined(PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP)
+#define PTHREAD_MUTEX_INIT_VALUE	PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
+#define AST_MUTEX_KIND			PTHREAD_MUTEX_RECURSIVE_NP
+#else
+#define PTHREAD_MUTEX_INIT_VALUE	PTHREAD_MUTEX_INITIALIZER
+#define AST_MUTEX_KIND			PTHREAD_MUTEX_RECURSIVE
+#endif /* PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP */
+
+#ifdef DEBUG_THREADS
+
+#define __ast_mutex_logger(...)  do { if (canlog) ast_log(LOG_ERROR, __VA_ARGS__); else fprintf(stderr, __VA_ARGS__); } while (0)
+
+#ifdef THREAD_CRASH
+#define DO_THREAD_CRASH do { *((int *)(0)) = 1; } while(0)
+#else
+#define DO_THREAD_CRASH do { } while (0)
+#endif
+
+#define AST_MUTEX_INIT_VALUE { PTHREAD_MUTEX_INIT_VALUE, { NULL }, { 0 }, 0, { NULL }, { 0 } }
+
+#define AST_MAX_REENTRANCY 10
+
+struct ast_mutex_info {
+	pthread_mutex_t mutex;
+	const char *file[AST_MAX_REENTRANCY];
+	int lineno[AST_MAX_REENTRANCY];
+	int reentrancy;
+	const char *func[AST_MAX_REENTRANCY];
+	pthread_t thread[AST_MAX_REENTRANCY];
+};
+
+typedef struct ast_mutex_info ast_mutex_t;
+
+typedef pthread_cond_t ast_cond_t;
+
+static pthread_mutex_t empty_mutex;
+
+static void __attribute__((constructor)) init_empty_mutex(void)
+{
+	memset(&empty_mutex, 0, sizeof(empty_mutex));
+}
+
+static inline int __ast_pthread_mutex_init_attr(const char *filename, int lineno, const char *func,
+						const char *mutex_name, ast_mutex_t *t,
+						pthread_mutexattr_t *attr) 
+{
+#ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
+	int canlog = strcmp(filename, "logger.c");
+
+	if ((t->mutex) != ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
+		if ((t->mutex) != (empty_mutex)) {
+			__ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is already initialized.\n",
+					   filename, lineno, func, mutex_name);
+			__ast_mutex_logger("%s line %d (%s): Error: previously initialization of mutex '%s'.\n",
+					   t->file[0], t->lineno[0], t->func[0], mutex_name);
+			DO_THREAD_CRASH;
+			return 0;
+		}
+	}
+#endif
+
+	t->file[0] = filename;
+	t->lineno[0] = lineno;
+	t->func[0] = func;
+	t->thread[0]  = 0;
+	t->reentrancy = 0;
+
+	return pthread_mutex_init(&t->mutex, attr);
+}
+
+static inline int __ast_pthread_mutex_init(const char *filename, int lineno, const char *func,
+					   const char *mutex_name, ast_mutex_t *t)
+{
+	static pthread_mutexattr_t  attr;
+
+	pthread_mutexattr_init(&attr);
+	pthread_mutexattr_settype(&attr, AST_MUTEX_KIND);
+
+	return __ast_pthread_mutex_init_attr(filename, lineno, func, mutex_name, t, &attr);
+}
+#define ast_mutex_init(pmutex) __ast_pthread_mutex_init(__FILE__, __LINE__, __PRETTY_FUNCTION__, #pmutex, pmutex)
+
+static inline int __ast_pthread_mutex_destroy(const char *filename, int lineno, const char *func,
+						const char *mutex_name, ast_mutex_t *t)
+{
+	int res;
+	int canlog = strcmp(filename, "logger.c");
+
+#ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
+	if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
+		__ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
+				   filename, lineno, func, mutex_name);
+	}
+#endif
+
+	res = pthread_mutex_trylock(&t->mutex);
+	switch (res) {
+	case 0:
+		pthread_mutex_unlock(&t->mutex);
+		break;
+	case EINVAL:
+		__ast_mutex_logger("%s line %d (%s): Error: attempt to destroy invalid mutex '%s'.\n",
+				  filename, lineno, func, mutex_name);
+		break;
+	case EBUSY:
+		__ast_mutex_logger("%s line %d (%s): Error: attempt to destroy locked mutex '%s'.\n",
+				   filename, lineno, func, mutex_name);
+		__ast_mutex_logger("%s line %d (%s): Error: '%s' was locked here.\n",
+				   t->file[t->reentrancy-1], t->lineno[t->reentrancy-1], t->func[t->reentrancy-1], mutex_name);
+		break;
+	}
+
+	if ((res = pthread_mutex_destroy(&t->mutex)))
+		__ast_mutex_logger("%s line %d (%s): Error destroying mutex: %s\n",
+				   filename, lineno, func, strerror(res));
+#ifndef PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
+	else
+		t->mutex = PTHREAD_MUTEX_INIT_VALUE;
+#endif
+	t->file[0] = filename;
+	t->lineno[0] = lineno;
+	t->func[0] = func;
+
+	return res;
+}
+
+static inline int __ast_pthread_mutex_lock(const char *filename, int lineno, const char *func,
+                                           const char* mutex_name, ast_mutex_t *t)
+{
+	int res;
+	int canlog = strcmp(filename, "logger.c");
+
+#if defined(AST_MUTEX_INIT_W_CONSTRUCTORS)
+	if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
+		__ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
+				 filename, lineno, func, mutex_name);
+		ast_mutex_init(t);
+	}
+#endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
+
+#ifdef DETECT_DEADLOCKS
+	{
+		time_t seconds = time(NULL);
+		time_t current;
+		do {
+#ifdef	HAVE_MTX_PROFILE
+			ast_mark(mtx_prof, 1);
+#endif
+			res = pthread_mutex_trylock(&t->mutex);
+#ifdef	HAVE_MTX_PROFILE
+			ast_mark(mtx_prof, 0);
+#endif
+			if (res == EBUSY) {
+				current = time(NULL);
+				if ((current - seconds) && (!((current - seconds) % 5))) {
+					__ast_mutex_logger("%s line %d (%s): Deadlock? waited %d sec for mutex '%s'?\n",
+							   filename, lineno, func, (int)(current - seconds), mutex_name);
+					__ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
+							   t->file[t->reentrancy-1], t->lineno[t->reentrancy-1],
+							   t->func[t->reentrancy-1], mutex_name);
+				}
+				usleep(200);
+			}
+		} while (res == EBUSY);
+	}
+#else
+#ifdef	HAVE_MTX_PROFILE
+	ast_mark(mtx_prof, 1);
+	res = pthread_mutex_trylock(&t->mutex);
+	ast_mark(mtx_prof, 0);
+	if (res)
+#endif
+	res = pthread_mutex_lock(&t->mutex);
+#endif /* DETECT_DEADLOCKS */
+
+	if (!res) {
+		if (t->reentrancy < AST_MAX_REENTRANCY) {
+			t->file[t->reentrancy] = filename;
+			t->lineno[t->reentrancy] = lineno;
+			t->func[t->reentrancy] = func;
+			t->thread[t->reentrancy] = pthread_self();
+			t->reentrancy++;
+		} else {
+			__ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n",
+							   filename, lineno, func, mutex_name);
+		}
+	} else {
+		__ast_mutex_logger("%s line %d (%s): Error obtaining mutex: %s\n",
+				   filename, lineno, func, strerror(errno));
+		DO_THREAD_CRASH;
+	}
+
+	return res;
+}
+
+static inline int __ast_pthread_mutex_trylock(const char *filename, int lineno, const char *func,
+                                              const char* mutex_name, ast_mutex_t *t)
+{
+	int res;
+	int canlog = strcmp(filename, "logger.c");
+
+#if defined(AST_MUTEX_INIT_W_CONSTRUCTORS)
+	if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
+		__ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
+				   filename, lineno, func, mutex_name);
+		ast_mutex_init(t);
+	}
+#endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
+
+	if (!(res = pthread_mutex_trylock(&t->mutex))) {
+		if (t->reentrancy < AST_MAX_REENTRANCY) {
+			t->file[t->reentrancy] = filename;
+			t->lineno[t->reentrancy] = lineno;
+			t->func[t->reentrancy] = func;
+			t->thread[t->reentrancy] = pthread_self();
+			t->reentrancy++;
+		} else {
+			__ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n",
+					   filename, lineno, func, mutex_name);
+		}
+	} else {
+		__ast_mutex_logger("%s line %d (%s): Warning: '%s' was locked here.\n",
+                                   t->file[t->reentrancy-1], t->lineno[t->reentrancy-1], t->func[t->reentrancy-1], mutex_name);
+	}
+
+	return res;
+}
+
+static inline int __ast_pthread_mutex_unlock(const char *filename, int lineno, const char *func,
+					     const char *mutex_name, ast_mutex_t *t)
+{
+	int res;
+	int canlog = strcmp(filename, "logger.c");
+
+#ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
+	if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
+		__ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
+				   filename, lineno, func, mutex_name);
+	}
+#endif
+
+	if (t->reentrancy && (t->thread[t->reentrancy-1] != pthread_self())) {
+		__ast_mutex_logger("%s line %d (%s): attempted unlock mutex '%s' without owning it!\n",
+				   filename, lineno, func, mutex_name);
+		__ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",

[... 3243 lines stripped ...]


More information about the asterisk-commits mailing list