Skip to content
Snippets Groups Projects
extconf.c 164 KiB
Newer Older
  • Learn to ignore specific revisions
  •  * Asterisk -- An open source telephony toolkit.
     *
     * Copyright (C) 2006, Digium, Inc.
     *
     * Steve Murphy <murf@digium.com>
     *
     * See http://www.asterisk.org for more information about
     * the Asterisk project. Please do not directly contact
     * any of the maintainers of this project for assistance;
     * the project provides a web site, mailing lists and IRC
     * channels for your use.
     *
     * This program is free software, distributed under the terms of
     * the GNU General Public License Version 2. See the LICENSE file
     * at the top of the source tree.
     */
    
    
    
    Andrew Latham's avatar
    Andrew Latham committed
    /*!
    
     * \file
    
     * A condensation of the pbx_config stuff, to read into exensions.conf, and provide an interface to the data there,
     * for operations outside of asterisk. A huge, awful hack.
     *
     */
    
    Andrew Latham's avatar
    Andrew Latham committed
    /*!
     * \li \ref extconf.c uses the configuration file \ref extconfig.conf and \ref extensions.conf and \ref asterisk.conf
     * \addtogroup configuration_file Configuration Files
     */
    
    /*!
     * \page extconfig.conf extconfig.conf
     * \verbinclude extconfig.conf.sample
     */
    
    /*!
     * \page extensions.conf extensions.conf
     * \verbinclude extensions.conf.sample
     */
    
    
    /*** MODULEINFO
    	<support_level>extended</support_level>
     ***/
    
    
    #define ASTMM_LIBC ASTMM_IGNORE
    
    Steve Murphy's avatar
    Steve Murphy committed
    #undef DEBUG_THREADS
    
    #include "asterisk/compat.h"
    
    #include "asterisk/paths.h"	/* we use AST_CONFIG_DIR */
    
    
    #include <errno.h>
    #include <time.h>
    #include <sys/stat.h>
    #include <sys/types.h>
    #include <sys/time.h>
    #include <sys/resource.h>
    #include <sys/wait.h>
    #include <stdarg.h>
    #include <string.h>
    #include <locale.h>
    #include <ctype.h>
    #if !defined(SOLARIS) && !defined(__CYGWIN__)
    #include <err.h>
    #endif
    #include <regex.h>
    #include <limits.h>
    #include <pthread.h>
    #include <netdb.h>
    #include <sys/param.h>
    
    #include <signal.h>
    
    static void ast_log(int level, const char *file, int line, const char *function, const char *fmt, ...) __attribute__((format(printf, 5, 6)));
    void ast_verbose(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
    
    
    #define AST_API_MODULE  1 /* gimme the inline defs! */
    
    struct ast_channel
    
    {
    	char x; /* basically empty! */
    };
    
    
    
    #include "asterisk/inline_api.h"
    #include "asterisk/endian.h"
    #include "asterisk/ast_expr.h"
    
    #include "asterisk/extconf.h"
    
    Steve Murphy's avatar
    Steve Murphy committed
    
    
    #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 "       > "
    
    
    
    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))); */
    
    
    void ast_console_puts(const char *string);
    
    #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_
    
    
    Steve Murphy's avatar
    Steve Murphy committed
    /* lock.h */
    
    #define _ASTERISK_LOCK_H /* A small indication that this is horribly wrong. */
    
    Steve Murphy's avatar
    Steve Murphy committed
    #ifndef	HAVE_MTX_PROFILE
    #define	__MTX_PROF(a)	return pthread_mutex_lock((a))
    #else
    
    Steve Murphy's avatar
    Steve Murphy committed
    #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 */
    
    Steve Murphy's avatar
    Steve Murphy committed
    #define AST_PTHREADT_NULL (pthread_t) -1
    #define AST_PTHREADT_STOP (pthread_t) -2
    
    Steve Murphy's avatar
    Steve Murphy committed
    #if defined(SOLARIS) || defined(BSD)
    #define AST_MUTEX_INIT_W_CONSTRUCTORS
    #endif /* SOLARIS || BSD */
    
    Steve Murphy's avatar
    Steve Murphy committed
    /* Asterisk REQUIRES recursive (not error checking) mutexes
       and will not run without them. */
    #if defined(PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP) && defined(PTHREAD_MUTEX_RECURSIVE_NP)
    #define PTHREAD_MUTEX_INIT_VALUE	PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
    #define AST_MUTEX_KIND			PTHREAD_MUTEX_RECURSIVE_NP
    
    Steve Murphy's avatar
    Steve Murphy committed
    #define PTHREAD_MUTEX_INIT_VALUE	PTHREAD_MUTEX_INITIALIZER
    #define AST_MUTEX_KIND			PTHREAD_MUTEX_RECURSIVE
    #endif /* PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP */
    
    Steve Murphy's avatar
    Steve Murphy committed
    #ifdef DEBUG_THREADS
    
    #define log_mutex_error(canlog, ...)  do { if (canlog) ast_log(LOG_ERROR, __VA_ARGS__); else fprintf(stderr, __VA_ARGS__); } while (0)
    
    Steve Murphy's avatar
    Steve Murphy committed
    #ifdef THREAD_CRASH
    #define DO_THREAD_CRASH do { *((int *)(0)) = 1; } while(0)
    #else
    #define DO_THREAD_CRASH do { } while (0)
    #endif
    
    Steve Murphy's avatar
    Steve Murphy committed
    #define AST_MUTEX_INIT_VALUE { PTHREAD_MUTEX_INIT_VALUE, { NULL }, { 0 }, 0, { NULL }, { 0 } }
    
    Steve Murphy's avatar
    Steve Murphy committed
    #define AST_MAX_REENTRANCY 10
    
    Steve Murphy's avatar
    Steve Murphy committed
    struct ast_mutex_info {
    	pthread_mutex_t mutex;
    	/*! Track which thread holds this lock */
    	unsigned int track:1;
    	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];
    };
    
    Steve Murphy's avatar
    Steve Murphy committed
    typedef struct ast_mutex_info ast_mutex_t;
    
    Steve Murphy's avatar
    Steve Murphy committed
    typedef pthread_cond_t ast_cond_t;
    
    Steve Murphy's avatar
    Steve Murphy committed
    static pthread_mutex_t empty_mutex;
    
    Steve Murphy's avatar
    Steve Murphy committed
    static void __attribute__((constructor)) init_empty_mutex(void)
    
    Steve Murphy's avatar
    Steve Murphy committed
    	memset(&empty_mutex, 0, sizeof(empty_mutex));
    
    Steve Murphy's avatar
    Steve Murphy committed
    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)
    
    Steve Murphy's avatar
    Steve Murphy committed
    #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
    	int canlog = strcmp(filename, "logger.c");
    
    Steve Murphy's avatar
    Steve Murphy committed
    	if ((t->mutex) != ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
    		if ((t->mutex) != (empty_mutex)) {
    
    			log_mutex_error(canlog, "%s line %d (%s): Error: mutex '%s' is already initialized.\n",
    
    Steve Murphy's avatar
    Steve Murphy committed
    					   filename, lineno, func, mutex_name);
    
    			log_mutex_error(canlog, "%s line %d (%s): Error: previously initialization of mutex '%s'.\n",
    
    Steve Murphy's avatar
    Steve Murphy committed
    					   t->file[0], t->lineno[0], t->func[0], mutex_name);
    			DO_THREAD_CRASH;
    			return 0;
    		}
    
    Steve Murphy's avatar
    Steve Murphy committed
    #endif
    
    Steve Murphy's avatar
    Steve Murphy committed
    	t->file[0] = filename;
    	t->lineno[0] = lineno;
    	t->func[0] = func;
    	t->thread[0]  = 0;
    	t->reentrancy = 0;
    
    Steve Murphy's avatar
    Steve Murphy committed
    	return pthread_mutex_init(&t->mutex, attr);
    }
    
    Steve Murphy's avatar
    Steve Murphy committed
    static inline int __ast_pthread_mutex_init(const char *filename, int lineno, const char *func,
    					   const char *mutex_name, ast_mutex_t *t)
    
    Steve Murphy's avatar
    Steve Murphy committed
    	static pthread_mutexattr_t  attr;
    
    Steve Murphy's avatar
    Steve Murphy committed
    	pthread_mutexattr_init(&attr);
    	pthread_mutexattr_settype(&attr, AST_MUTEX_KIND);
    
    Steve Murphy's avatar
    Steve Murphy committed
    	return __ast_pthread_mutex_init_attr(filename, lineno, func, mutex_name, t, &attr);
    
    Steve Murphy's avatar
    Steve Murphy committed
    #define ast_mutex_init(pmutex) __ast_pthread_mutex_init(__FILE__, __LINE__, __PRETTY_FUNCTION__, #pmutex, pmutex)
    
    Steve Murphy's avatar
    Steve Murphy committed
    static inline int __ast_pthread_mutex_destroy(const char *filename, int lineno, const char *func,
    						const char *mutex_name, ast_mutex_t *t)
    
    Steve Murphy's avatar
    Steve Murphy committed
    	int canlog = strcmp(filename, "logger.c");
    
    Steve Murphy's avatar
    Steve Murphy committed
    #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
    	if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
    
    		log_mutex_error(canlog, "%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
    
    Steve Murphy's avatar
    Steve Murphy committed
    				   filename, lineno, func, mutex_name);
    	}
    #endif
    
    	res = pthread_mutex_trylock(&t->mutex);
    	switch (res) {
    	case 0:
    		pthread_mutex_unlock(&t->mutex);
    		break;
    	case EINVAL:
    
    		log_mutex_error(canlog, "%s line %d (%s): Error: attempt to destroy invalid mutex '%s'.\n",
    
    Steve Murphy's avatar
    Steve Murphy committed
    				  filename, lineno, func, mutex_name);
    		break;
    	case EBUSY:
    
    		log_mutex_error(canlog, "%s line %d (%s): Error: attempt to destroy locked mutex '%s'.\n",
    
    Steve Murphy's avatar
    Steve Murphy committed
    				   filename, lineno, func, mutex_name);
    
    		log_mutex_error(canlog, "%s line %d (%s): Error: '%s' was locked here.\n",
    
    Steve Murphy's avatar
    Steve Murphy committed
    				   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)))
    
    		log_mutex_error(canlog, "%s line %d (%s): Error destroying mutex: %s\n",
    
    Steve Murphy's avatar
    Steve Murphy committed
    				   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;
    
    Steve Murphy's avatar
    Steve Murphy committed
    static inline int __ast_pthread_mutex_lock(const char *filename, int lineno, const char *func,
                                               const char* mutex_name, ast_mutex_t *t)
    
    Steve Murphy's avatar
    Steve Murphy committed
    	int canlog = strcmp(filename, "logger.c");
    
    Steve Murphy's avatar
    Steve Murphy committed
    #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS)
    	if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
    
    		log_mutex_error(canlog, "%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
    
    Steve Murphy's avatar
    Steve Murphy committed
    				 filename, lineno, func, mutex_name);
    		ast_mutex_init(t);
    	}
    #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
    
    Steve Murphy's avatar
    Steve Murphy committed
    #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))) {
    
    					log_mutex_error(canlog, "%s line %d (%s): Deadlock? waited %d sec for mutex '%s'?\n",
    
    Steve Murphy's avatar
    Steve Murphy committed
    							   filename, lineno, func, (int)(current - seconds), mutex_name);
    
    					log_mutex_error(canlog, "%s line %d (%s): '%s' was locked here.\n",
    
    Steve Murphy's avatar
    Steve Murphy committed
    							   t->file[t->reentrancy-1], t->lineno[t->reentrancy-1],
    							   t->func[t->reentrancy-1], mutex_name);
    				}
    				usleep(200);
    			}
    		} while (res == EBUSY);
    	}
    
    Steve Murphy's avatar
    Steve Murphy committed
    #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 */
    
    Steve Murphy's avatar
    Steve Murphy committed
    	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 {
    
    			log_mutex_error(canlog, "%s line %d (%s): '%s' really deep reentrancy!\n",
    
    Steve Murphy's avatar
    Steve Murphy committed
    							   filename, lineno, func, mutex_name);
    		}
    	} else {
    
    		log_mutex_error(canlog, "%s line %d (%s): Error obtaining mutex: %s\n",
    
    Steve Murphy's avatar
    Steve Murphy committed
    				   filename, lineno, func, strerror(errno));
    		DO_THREAD_CRASH;
    	}
    
    Steve Murphy's avatar
    Steve Murphy committed
    	return res;
    }
    
    Steve Murphy's avatar
    Steve Murphy committed
    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");
    
    Steve Murphy's avatar
    Steve Murphy committed
    #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS)
    	if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
    
    		log_mutex_error(canlog, "%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
    
    Steve Murphy's avatar
    Steve Murphy committed
    				   filename, lineno, func, mutex_name);
    		ast_mutex_init(t);
    	}
    #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
    
    Steve Murphy's avatar
    Steve Murphy committed
    	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 {
    
    			log_mutex_error(canlog, "%s line %d (%s): '%s' really deep reentrancy!\n",
    
    Steve Murphy's avatar
    Steve Murphy committed
    					   filename, lineno, func, mutex_name);
    		}
    	} else {
    
    		log_mutex_error(canlog, "%s line %d (%s): Warning: '%s' was locked here.\n",
    
    Steve Murphy's avatar
    Steve Murphy committed
                                       t->file[t->reentrancy-1], t->lineno[t->reentrancy-1], t->func[t->reentrancy-1], mutex_name);
    	}
    
    Steve Murphy's avatar
    Steve Murphy committed
    	return res;
    }
    
    Steve Murphy's avatar
    Steve Murphy committed
    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");
    
    Steve Murphy's avatar
    Steve Murphy committed
    #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
    	if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
    
    		log_mutex_error(canlog, "%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
    
    Steve Murphy's avatar
    Steve Murphy committed
    				   filename, lineno, func, mutex_name);
    	}
    #endif
    
    Steve Murphy's avatar
    Steve Murphy committed
    	if (t->reentrancy && (t->thread[t->reentrancy-1] != pthread_self())) {
    
    		log_mutex_error(canlog, "%s line %d (%s): attempted unlock mutex '%s' without owning it!\n",
    
    Steve Murphy's avatar
    Steve Murphy committed
    				   filename, lineno, func, mutex_name);
    
    		log_mutex_error(canlog, "%s line %d (%s): '%s' was locked here.\n",
    
    Steve Murphy's avatar
    Steve Murphy committed
    				   t->file[t->reentrancy-1], t->lineno[t->reentrancy-1], t->func[t->reentrancy-1], mutex_name);
    		DO_THREAD_CRASH;
    	}
    
    Steve Murphy's avatar
    Steve Murphy committed
    	if (--t->reentrancy < 0) {
    
    		log_mutex_error(canlog, "%s line %d (%s): mutex '%s' freed more times than we've locked!\n",
    
    Steve Murphy's avatar
    Steve Murphy committed
    				   filename, lineno, func, mutex_name);
    		t->reentrancy = 0;
    	}
    
    Steve Murphy's avatar
    Steve Murphy committed
    	if (t->reentrancy < AST_MAX_REENTRANCY) {
    		t->file[t->reentrancy] = NULL;
    		t->lineno[t->reentrancy] = 0;
    		t->func[t->reentrancy] = NULL;
    		t->thread[t->reentrancy] = 0;
    	}
    
    Steve Murphy's avatar
    Steve Murphy committed
    	if ((res = pthread_mutex_unlock(&t->mutex))) {
    
    		log_mutex_error(canlog, "%s line %d (%s): Error releasing mutex: %s\n",
    
    Steve Murphy's avatar
    Steve Murphy committed
    				   filename, lineno, func, strerror(res));
    		DO_THREAD_CRASH;
    	}
    
    Steve Murphy's avatar
    Steve Murphy committed
    	return res;
    }
    
    Steve Murphy's avatar
    Steve Murphy committed
    #else /* !DEBUG_THREADS */
    
    
    typedef pthread_mutex_t ast_mutex_t;
    
    #define AST_MUTEX_INIT_VALUE	((ast_mutex_t) PTHREAD_MUTEX_INIT_VALUE)
    
    static inline int ast_mutex_init(ast_mutex_t *pmutex)
    
    Steve Murphy's avatar
    Steve Murphy committed
    	pthread_mutexattr_t attr;
    
    Steve Murphy's avatar
    Steve Murphy committed
    	pthread_mutexattr_init(&attr);
    	pthread_mutexattr_settype(&attr, AST_MUTEX_KIND);
    
    Steve Murphy's avatar
    Steve Murphy committed
    	return pthread_mutex_init(pmutex, &attr);
    }
    
    Steve Murphy's avatar
    Steve Murphy committed
    #define ast_pthread_mutex_init(pmutex,a) pthread_mutex_init(pmutex,a)
    
    Steve Murphy's avatar
    Steve Murphy committed
    typedef pthread_cond_t ast_cond_t;
    
    Steve Murphy's avatar
    Steve Murphy committed
    #endif /* !DEBUG_THREADS */
    
    #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS)
    /* If AST_MUTEX_INIT_W_CONSTRUCTORS is defined, use file scope
     constructors/destructors to create/destroy mutexes.  */
    #define __AST_MUTEX_DEFINE(scope, mutex) \
    	scope ast_mutex_t mutex = AST_MUTEX_INIT_VALUE; \
    
    static void  __attribute__((constructor)) init_##mutex(void) \
    
    Steve Murphy's avatar
    Steve Murphy committed
    { \
    	ast_mutex_init(&mutex); \
    
    Steve Murphy's avatar
    Steve Murphy committed
    #else /* !AST_MUTEX_INIT_W_CONSTRUCTORS */
    
    /* By default, use static initialization of mutexes. */
    
    Steve Murphy's avatar
    Steve Murphy committed
    #define __AST_MUTEX_DEFINE(scope, mutex) \
    	scope ast_mutex_t mutex = AST_MUTEX_INIT_VALUE
    #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
    
    Steve Murphy's avatar
    Steve Murphy committed
    #define pthread_mutex_t use_ast_mutex_t_instead_of_pthread_mutex_t
    #define pthread_mutex_init use_ast_mutex_init_instead_of_pthread_mutex_init
    #define pthread_cond_t use_ast_cond_t_instead_of_pthread_cond_t
    
    Steve Murphy's avatar
    Steve Murphy committed
    #define AST_MUTEX_DEFINE_STATIC(mutex) __AST_MUTEX_DEFINE(static, mutex)
    
    Steve Murphy's avatar
    Steve Murphy committed
    #define AST_MUTEX_INITIALIZER __use_AST_MUTEX_DEFINE_STATIC_rather_than_AST_MUTEX_INITIALIZER__
    
    Steve Murphy's avatar
    Steve Murphy committed
    #define gethostbyname __gethostbyname__is__not__reentrant__use__ast_gethostbyname__instead__
    
    Steve Murphy's avatar
    Steve Murphy committed
    #ifndef __linux__
    #define pthread_create __use_ast_pthread_create_instead__
    #endif
    
    Steve Murphy's avatar
    Steve Murphy committed
    typedef pthread_rwlock_t ast_rwlock_t;
    
    Steve Murphy's avatar
    Steve Murphy committed
    static inline int ast_rwlock_init(ast_rwlock_t *prwlock)
    {
    	pthread_rwlockattr_t attr;
    
    Steve Murphy's avatar
    Steve Murphy committed
    	pthread_rwlockattr_init(&attr);
    
    Steve Murphy's avatar
    Steve Murphy committed
    #ifdef HAVE_PTHREAD_RWLOCK_PREFER_WRITER_NP
    	pthread_rwlockattr_setkind_np(&attr, PTHREAD_RWLOCK_PREFER_WRITER_NP);
    #endif
    
    	return pthread_rwlock_init(prwlock, &attr);
    }
    
    static inline int ast_rwlock_destroy(ast_rwlock_t *prwlock)
    
    Steve Murphy's avatar
    Steve Murphy committed
    	return pthread_rwlock_destroy(prwlock);
    }
    
    Steve Murphy's avatar
    Steve Murphy committed
    static inline int ast_rwlock_unlock(ast_rwlock_t *prwlock)
    {
    	return pthread_rwlock_unlock(prwlock);
    }
    
    Steve Murphy's avatar
    Steve Murphy committed
    static inline int ast_rwlock_rdlock(ast_rwlock_t *prwlock)
    {
    	return pthread_rwlock_rdlock(prwlock);
    
    Steve Murphy's avatar
    Steve Murphy committed
    static inline int ast_rwlock_wrlock(ast_rwlock_t *prwlock)
    
    Steve Murphy's avatar
    Steve Murphy committed
    	return pthread_rwlock_wrlock(prwlock);
    
    Steve Murphy's avatar
    Steve Murphy committed
    /* Statically declared read/write locks */
    
    Steve Murphy's avatar
    Steve Murphy committed
    #ifndef HAVE_PTHREAD_RWLOCK_INITIALIZER
    #define __AST_RWLOCK_DEFINE(scope, rwlock) \
            scope ast_rwlock_t rwlock; \
    
    static void  __attribute__((constructor)) init_##rwlock(void) \
    
    Steve Murphy's avatar
    Steve Murphy committed
    { \
            ast_rwlock_init(&rwlock); \
    } \
    
    static void  __attribute__((destructor)) fini_##rwlock(void) \
    
    Steve Murphy's avatar
    Steve Murphy committed
    { \
            ast_rwlock_destroy(&rwlock); \
    
    Steve Murphy's avatar
    Steve Murphy committed
    #else
    #define AST_RWLOCK_INIT_VALUE PTHREAD_RWLOCK_INITIALIZER
    #define __AST_RWLOCK_DEFINE(scope, rwlock) \
            scope ast_rwlock_t rwlock = AST_RWLOCK_INIT_VALUE
    #endif
    
    Steve Murphy's avatar
    Steve Murphy committed
    #define AST_RWLOCK_DEFINE_STATIC(rwlock) __AST_RWLOCK_DEFINE(static, rwlock)
    
    Steve Murphy's avatar
    Steve Murphy committed
    /*
     * Initial support for atomic instructions.
     * For platforms that have it, use the native cpu instruction to
     * implement them. For other platforms, resort to a 'slow' version
     * (defined in utils.c) that protects the atomic instruction with
     * a single lock.
     * The slow versions is always available, for testing purposes,
     * as ast_atomic_fetchadd_int_slow()
     */
    
    Steve Murphy's avatar
    Steve Murphy committed
    #if defined(HAVE_OSX_ATOMICS)
    #include "libkern/OSAtomic.h"
    #endif
    
    Steve Murphy's avatar
    Steve Murphy committed
    /*! \brief Atomically add v to *p and return * the previous value of *p.
     * This can be used to handle reference counts, and the return value
     * can be used to generate unique identifiers.
     */
    
    Steve Murphy's avatar
    Steve Murphy committed
    #if defined(HAVE_GCC_ATOMICS)
    AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
    
    Steve Murphy's avatar
    Steve Murphy committed
    	return __sync_fetch_and_add(p, v);
    })
    #elif defined(HAVE_OSX_ATOMICS) && (SIZEOF_INT == 4)
    AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
    {
    	return OSAtomicAdd32(v, (int32_t *) p);
    })
    #elif defined(HAVE_OSX_ATOMICS) && (SIZEOF_INT == 8)
    AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
    {
    	return OSAtomicAdd64(v, (int64_t *) p);
    #elif defined (__i386__) || defined(__x86_64__)
    AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
    {
    	__asm __volatile (
    	"       lock   xaddl   %0, %1 ;        "
    
    	: "+r" (v),                     /* 0 (result) */
    
    Steve Murphy's avatar
    Steve Murphy committed
    	  "=m" (*p)                     /* 1 */
    	: "m" (*p));                    /* 2 */
    	return (v);
    })
    #else
    static int ast_atomic_fetchadd_int_slow(volatile int *p, int v)
    {
    	int ret;
    	ret = *p;
    	*p += v;
    	return ret;
    
    Steve Murphy's avatar
    Steve Murphy committed
    AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
    {
    	return ast_atomic_fetchadd_int_slow(p, v);
    })
    #endif
    
    Steve Murphy's avatar
    Steve Murphy committed
    /*! \brief decrement *p by 1 and return true if the variable has reached 0.
     * Useful e.g. to check if a refcount has reached 0.
     */
    #if defined(HAVE_GCC_ATOMICS)
    AST_INLINE_API(int ast_atomic_dec_and_test(volatile int *p),
    
    Steve Murphy's avatar
    Steve Murphy committed
    	return __sync_sub_and_fetch(p, 1) == 0;
    })
    #elif defined(HAVE_OSX_ATOMICS) && (SIZEOF_INT == 4)
    AST_INLINE_API(int ast_atomic_dec_and_test(volatile int *p),
    {
    	return OSAtomicAdd32( -1, (int32_t *) p) == 0;
    })
    #elif defined(HAVE_OSX_ATOMICS) && (SIZEOF_INT == 8)
    AST_INLINE_API(int ast_atomic_dec_and_test(volatile int *p),
    {
    	return OSAtomicAdd64( -1, (int64_t *) p) == 0;
    #else
    AST_INLINE_API(int ast_atomic_dec_and_test(volatile int *p),
    {
    	int a = ast_atomic_fetchadd_int(p, -1);
    	return a == 1; /* true if the value is 0 now (so it was 1 previously) */
    })
    #endif
    
    Steve Murphy's avatar
    Steve Murphy committed
    /*! \brief Lock AST channel (and print debugging output)
    \note You need to enable DEBUG_CHANNEL_LOCKS for this function */
    int ast_channel_lock(struct ast_channel *chan);
    
    Steve Murphy's avatar
    Steve Murphy committed
    /*! \brief Unlock AST channel (and print debugging output)
    \note You need to enable DEBUG_CHANNEL_LOCKS for this function
    */
    int ast_channel_unlock(struct ast_channel *chan);
    
    Steve Murphy's avatar
    Steve Murphy committed
    /*! \brief Lock AST channel (and print debugging output)
    \note   You need to enable DEBUG_CHANNEL_LOCKS for this function */
    int ast_channel_trylock(struct ast_channel *chan);
    #endif
    
    Steve Murphy's avatar
    Steve Murphy committed
    #include "asterisk/hashtab.h"
    #include "asterisk/ael_structs.h"
    #include "asterisk/pval.h"
    
    Steve Murphy's avatar
    Steve Murphy committed
    /* from utils.h */
    
    Steve Murphy's avatar
    Steve Murphy committed
    struct ast_flags {  /* stolen from utils.h */
    	unsigned int flags;
    };
    #define ast_test_flag(p,flag) 		({ \
    					typeof ((p)->flags) __p = (p)->flags; \
    
    Steve Murphy's avatar
    Steve Murphy committed
    					(void) (&__p == &__x); \
    					((p)->flags & (flag)); \
    					})
    
    Steve Murphy's avatar
    Steve Murphy committed
    #define ast_set2_flag(p,value,flag)	do { \
    					typeof ((p)->flags) __p = (p)->flags; \
    
    Steve Murphy's avatar
    Steve Murphy committed
    					(void) (&__p == &__x); \
    					if (value) \
    						(p)->flags |= (flag); \
    					else \
    						(p)->flags &= ~(flag); \
    					} while (0)
    
    /* from config.c */
    
    Steve Murphy's avatar
    Steve Murphy committed
    #define MAX_NESTED_COMMENTS 128
    #define COMMENT_START ";--"
    #define COMMENT_END "--;"
    #define COMMENT_META ';'
    #define COMMENT_TAG '-'
    
    Steve Murphy's avatar
    Steve Murphy committed
    static char *extconfig_conf = "extconfig.conf";
    
    Steve Murphy's avatar
    Steve Murphy committed
    /*! 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 */
    
    Steve Murphy's avatar
    Steve Murphy committed
    static char *lline_buffer;    /*!< A buffer for stuff behind the ; */
    static int  lline_buffer_size;
    
    Steve Murphy's avatar
    Steve Murphy committed
    #define CB_INCR 250
    
    struct ast_comment {
    	struct ast_comment *next;
    	char cmt[0];
    };
    
    static void CB_INIT(void)
    
    Steve Murphy's avatar
    Steve Murphy committed
    	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;
    	}
    
    Steve Murphy's avatar
    Steve Murphy committed
    static void  CB_ADD(char *str)
    
    Steve Murphy's avatar
    Steve Murphy committed
    	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);
    }
    
    Steve Murphy's avatar
    Steve Murphy committed
    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;
    
    Steve Murphy's avatar
    Steve Murphy committed
    	strncat(comment_buffer,str,len); /* safe */
    	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);
    
    Steve Murphy's avatar
    Steve Murphy committed
    			return;
    		lline_buffer_size += CB_INCR + siz + 1;
    	}
    	strcat(lline_buffer,str);
    }
    
    static void CB_RESET(void )
    {
    	comment_buffer[0] = 0;
    
    Steve Murphy's avatar
    Steve Murphy committed
    	lline_buffer[0] = 0;
    }
    
    Steve Murphy's avatar
    Steve Murphy committed
    /*! \brief Keep track of how many threads are currently trying to wait*() on
     *  a child process */
    static unsigned int safe_system_level = 0;
    
    static struct sigaction safe_system_prev_handler;
    
    Steve Murphy's avatar
    Steve Murphy committed
    
    /*! \brief NULL handler so we can collect the child exit status */
    
    static void _null_sig_handler(int sig)
    
    Steve Murphy's avatar
    Steve Murphy committed
    {
    
    static struct sigaction null_sig_handler = {
    	.sa_handler = _null_sig_handler,
    
    	.sa_flags = SA_RESTART,
    
    Steve Murphy's avatar
    Steve Murphy committed
    void ast_replace_sigchld(void);
    
    void ast_replace_sigchld(void)
    
    Steve Murphy's avatar
    Steve Murphy committed
    	unsigned int level;
    
    Steve Murphy's avatar
    Steve Murphy committed
    	level = safe_system_level++;
    
    	/* only replace the handler if it has not already been done */
    
    	if (level == 0) {
    		sigaction(SIGCHLD, &null_sig_handler, &safe_system_prev_handler);
    	}
    
    Steve Murphy's avatar
    Steve Murphy committed
    void ast_unreplace_sigchld(void);
    
    Steve Murphy's avatar
    Steve Murphy committed
    void ast_unreplace_sigchld(void)
    {
    	unsigned int level;
    
    Steve Murphy's avatar
    Steve Murphy committed
    	level = --safe_system_level;
    
    Steve Murphy's avatar
    Steve Murphy committed
    	/* only restore the handler if we are the last one */
    
    	if (level == 0) {
    		sigaction(SIGCHLD, &safe_system_prev_handler, NULL);
    	}
    
    Steve Murphy's avatar
    Steve Murphy committed
    int ast_safe_system(const char *s);
    
    int ast_safe_system(const char *s)
    
    Steve Murphy's avatar
    Steve Murphy committed
    	pid_t pid;
    #ifdef HAVE_WORKING_FORK
    	int x;
    #endif
    
    Steve Murphy's avatar
    Steve Murphy committed
    	int status;
    
    Steve Murphy's avatar
    Steve Murphy committed
    #if defined(HAVE_WORKING_FORK) || defined(HAVE_WORKING_VFORK)
    	ast_replace_sigchld();
    
    Steve Murphy's avatar
    Steve Murphy committed
    #ifdef HAVE_WORKING_FORK
    	pid = fork();
    
    Steve Murphy's avatar
    Steve Murphy committed
    	pid = vfork();
    
    Steve Murphy's avatar
    Steve Murphy committed
    	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 = waitpid(pid, &status, 0);
    
    Steve Murphy's avatar
    Steve Murphy committed
    			if (res > -1) {
    				res = WIFEXITED(status) ? WEXITSTATUS(status) : -1;
    				break;
    
    			} else if (errno != EINTR)
    
    Steve Murphy's avatar
    Steve Murphy committed
    				break;
    
    Steve Murphy's avatar
    Steve Murphy committed
    		ast_log(LOG_WARNING, "Fork failed: %s\n", strerror(errno));
    		res = -1;
    
    Steve Murphy's avatar
    Steve Murphy committed
    	ast_unreplace_sigchld();
    #else
    	res = -1;
    #endif
    
    
    Steve Murphy's avatar
    Steve Murphy committed
    static struct ast_comment *ALLOC_COMMENT(const char *buffer)
    
    Steve Murphy's avatar
    Steve Murphy committed
    	struct ast_comment *x = ast_calloc(1,sizeof(struct ast_comment)+strlen(buffer)+1);
    	strcpy(x->cmt, buffer);
    	return x;
    }
    
    Steve Murphy's avatar
    Steve Murphy committed
    static struct ast_config_map {
    	struct ast_config_map *next;
    	char *name;
    	char *driver;
    	char *database;
    	char *table;
    	char stuff[0];
    } *config_maps = NULL;
    
    Steve Murphy's avatar
    Steve Murphy committed
    static struct ast_config_engine *config_engine_list;
    
    Steve Murphy's avatar
    Steve Murphy committed
    #define MAX_INCLUDE_LEVEL 10
    
    Steve Murphy's avatar
    Steve Murphy committed
    struct ast_category {
    	char name[80];
    	int ignored;			/*!< do not let user of the config see this category */
    
    Steve Murphy's avatar
    Steve Murphy committed
        char *file;                /*!< the file name from whence this declaration was read */
        int lineno;
    	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;
        struct ast_config_include *includes;  /*!< a list of inclusions, which should describe the entire tree */
    };
    
    Steve Murphy's avatar
    Steve Murphy committed
    struct ast_config_include {
    	char *include_location_file;     /*!< file name in which the include occurs */
    	int  include_location_lineno;    /*!< lineno where include occurred */
    	int  exec;                       /*!< set to non-zero if itsa #exec statement */
    	char *exec_file;                 /*!< if it's an exec, you'll have both the /var/tmp to read, and the original script */
    	char *included_file;             /*!< file name included */
    	int inclusion_count;             /*!< if the file is included more than once, a running count thereof -- but, worry not,
    									   we explode the instances and will include those-- so all entries will be unique */
    	int output;                      /*!< a flag to indicate if the inclusion has been output */
    	struct ast_config_include *next; /*!< ptr to next inclusion in the list */
    };
    
    Steve Murphy's avatar
    Steve Murphy committed
    typedef struct ast_config *config_load_func(const char *database, const char *table, const char *configfile, struct ast_config *config, int withcomments, const char *suggested_include_file);
    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);
    
    Steve Murphy's avatar
    Steve Murphy committed
    /*! \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;
    };
    
    Steve Murphy's avatar
    Steve Murphy committed
    static struct ast_config_engine *config_engine_list;
    
    Steve Murphy's avatar
    Steve Murphy committed
    /* taken from strings.h */
    
    Steve Murphy's avatar
    Steve Murphy committed
    static force_inline int ast_strlen_zero(const char *s)
    
    Steve Murphy's avatar
    Steve Murphy committed
    	return (!s || (*s == '\0'));
    
    Steve Murphy's avatar
    Steve Murphy committed
    #define S_OR(a, b)	(!ast_strlen_zero(a) ? (a) : (b))
    
    Steve Murphy's avatar
    Steve Murphy committed
    AST_INLINE_API(
    void ast_copy_string(char *dst, const char *src, size_t size),
    
    Steve Murphy's avatar
    Steve Murphy committed
    	while (*src && size) {
    		*dst++ = *src++;
    		size--;
    	}
    	if (__builtin_expect(!size, 0))
    		dst--;
    	*dst = '\0';
    
    Steve Murphy's avatar
    Steve Murphy committed
    )
    
    Steve Murphy's avatar
    Steve Murphy committed
    AST_INLINE_API(
    char *ast_skip_blanks(const char *str),
    
    Steve Murphy's avatar
    Steve Murphy committed
    	while (*str && *str < 33)
    		str++;
    	return (char *)str;
    
    Steve Murphy's avatar
    Steve Murphy committed
    )
    
    Steve Murphy's avatar
    Steve Murphy committed
    /*!
      \brief Trims trailing whitespace characters from a string.
      \param ast_trim_blanks function being used
      \param str the input string
      \return a pointer to the modified string
     */
    AST_INLINE_API(
    char *ast_trim_blanks(char *str),
    
    Steve Murphy's avatar
    Steve Murphy committed
    	char *work = str;
    
    Steve Murphy's avatar
    Steve Murphy committed
    	if (work) {
    		work += strlen(work) - 1;
    
    		/* It's tempting to only want to erase after we exit this loop,
    
    Steve Murphy's avatar
    Steve Murphy committed
    		   but since ast_trim_blanks *could* receive a constant string
    		   (which we presumably wouldn't have to touch), we shouldn't
    		   actually set anything unless we must, and it's easier just
    		   to set each position to \0 than to keep track of a variable
    		   for it */
    		while ((work >= str) && *work < 33)