Skip to content
Snippets Groups Projects
extconf.c 170 KiB
Newer Older
  • Learn to ignore specific revisions
  • Steve Murphy's avatar
    Steve Murphy committed
    		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)
    			*(work--) = '\0';
    
    Steve Murphy's avatar
    Steve Murphy committed
    	return str;
    
    Steve Murphy's avatar
    Steve Murphy committed
    )
    
    Steve Murphy's avatar
    Steve Murphy committed
    /*!
      \brief Strip leading/trailing whitespace from a string.
      \param s The string to be stripped (will be modified).
      \return The stripped string.
    
    Steve Murphy's avatar
    Steve Murphy committed
      This functions strips all leading and trailing whitespace
      characters from the input string, and returns a pointer to
      the resulting string. The string is modified in place.
    */
    AST_INLINE_API(
    char *ast_strip(char *s),
    {
    	s = ast_skip_blanks(s);
    	if (s)
    		ast_trim_blanks(s);
    	return s;
    
    Steve Murphy's avatar
    Steve Murphy committed
    )
    
    Steve Murphy's avatar
    Steve Murphy committed
    /* from config.h */
    
    Steve Murphy's avatar
    Steve Murphy committed
    struct ast_variable {
    	char *name;
    	char *value;
    	char *file;
    	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];
    };
    
    Steve Murphy's avatar
    Steve Murphy committed
    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, const char *suggested_include_file);
    
    Steve Murphy's avatar
    Steve Murphy committed
    struct ast_config *localized_config_load_with_comments(const char *filename);
    static char *ast_category_browse(struct ast_config *config, const char *prev);
    static 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);
    static struct ast_config_include *ast_include_new(struct ast_config *conf, const char *from_file, const char *included_file, int is_exec, const char *exec_file, int from_lineno, char *real_included_file_name, int real_included_file_name_size);
    static struct ast_config_include *ast_include_find(struct ast_config *conf, const char *included_file);
    void localized_ast_include_rename(struct ast_config *conf, const char *from_file, const char *to_file);
    
    Steve Murphy's avatar
    Steve Murphy committed
    static struct ast_variable *ast_variable_new(const char *name, const char *value, const char *filename);
    
    static struct ast_variable *ast_variable_new(const char *name, const char *value, const char *filename)
    
    Steve Murphy's avatar
    Steve Murphy committed
    	struct ast_variable *variable;
    
    	int name_len = strlen(name) + 1;
    
    Steve Murphy's avatar
    Steve Murphy committed
    	if ((variable = ast_calloc(1, name_len + strlen(value) + 1 + strlen(filename) + 1 + sizeof(*variable)))) {
    		variable->name = variable->stuff;
    
    		variable->value = variable->stuff + name_len;
    		variable->file = variable->value + strlen(value) + 1;
    
    Steve Murphy's avatar
    Steve Murphy committed
    		strcpy(variable->name,name);
    		strcpy(variable->value,value);
    		strcpy(variable->file,filename);
    	}
    
    Steve Murphy's avatar
    Steve Murphy committed
    	return variable;
    
    Steve Murphy's avatar
    Steve Murphy committed
    static struct ast_config_include *ast_include_new(struct ast_config *conf, const char *from_file, const char *included_file, int is_exec, const char *exec_file, int from_lineno, char *real_included_file_name, int real_included_file_name_size)
    
    Steve Murphy's avatar
    Steve Murphy committed
    	/* a file should be included ONCE. Otherwise, if one of the instances is changed,
    
           then all be changed. -- how do we know to include it? -- Handling modified
    
    Steve Murphy's avatar
    Steve Murphy committed
           instances is possible, I'd have
           to create a new master for each instance. */
    	struct ast_config_include *inc;
    
    Steve Murphy's avatar
    Steve Murphy committed
    	inc = ast_include_find(conf, included_file);
    	if (inc)
    	{
    		inc->inclusion_count++;
    		snprintf(real_included_file_name, real_included_file_name_size, "%s~~%d", included_file, inc->inclusion_count);
    		ast_log(LOG_WARNING,"'%s', line %d:  Same File included more than once! This data will be saved in %s if saved back to disk.\n", from_file, from_lineno, real_included_file_name);
    	} else
    		*real_included_file_name = 0;
    
    Steve Murphy's avatar
    Steve Murphy committed
    	inc = ast_calloc(1,sizeof(struct ast_config_include));
    	inc->include_location_file = ast_strdup(from_file);
    	inc->include_location_lineno = from_lineno;
    	if (!ast_strlen_zero(real_included_file_name))
    		inc->included_file = ast_strdup(real_included_file_name);
    	else
    		inc->included_file = ast_strdup(included_file);
    
    Steve Murphy's avatar
    Steve Murphy committed
    	inc->exec = is_exec;
    	if (is_exec)
    		inc->exec_file = ast_strdup(exec_file);
    
    Steve Murphy's avatar
    Steve Murphy committed
    	/* attach this new struct to the conf struct */
    	inc->next = conf->includes;
    	conf->includes = inc;
    
    Steve Murphy's avatar
    Steve Murphy committed
    	return inc;
    
    Steve Murphy's avatar
    Steve Murphy committed
    void localized_ast_include_rename(struct ast_config *conf, const char *from_file, const char *to_file)
    
    Steve Murphy's avatar
    Steve Murphy committed
    	struct ast_config_include *incl;
    	struct ast_category *cat;
    	struct ast_variable *v;
    
    Steve Murphy's avatar
    Steve Murphy committed
    	int from_len = strlen(from_file);
    	int to_len = strlen(to_file);
    
    Steve Murphy's avatar
    Steve Murphy committed
    	if (strcmp(from_file, to_file) == 0) /* no use wasting time if the name is the same */
    		return;
    
    Steve Murphy's avatar
    Steve Murphy committed
    	/* the manager code allows you to read in one config file, then
           write it back out under a different name. But, the new arrangement
    	   ties output lines to the file name. So, before you try to write
           the config file to disk, better riffle thru the data and make sure
           the file names are changed.
    	*/
    	/* file names are on categories, includes (of course), and on variables. So,
    	   traverse all this and swap names */
    
    Steve Murphy's avatar
    Steve Murphy committed
    	for (incl = conf->includes; incl; incl=incl->next) {
    		if (strcmp(incl->include_location_file,from_file) == 0) {
    			if (from_len >= to_len)
    				strcpy(incl->include_location_file, to_file);
    			else {
    				free(incl->include_location_file);
    				incl->include_location_file = strdup(to_file);
    			}
    		}
    	}
    	for (cat = conf->root; cat; cat = cat->next) {
    		if (strcmp(cat->file,from_file) == 0) {
    			if (from_len >= to_len)
    				strcpy(cat->file, to_file);
    			else {
    				free(cat->file);
    				cat->file = strdup(to_file);
    			}
    		}
    		for (v = cat->root; v; v = v->next) {
    			if (strcmp(v->file,from_file) == 0) {
    				if (from_len >= to_len)
    					strcpy(v->file, to_file);
    				else {
    					free(v->file);
    					v->file = strdup(to_file);
    				}
    			}
    		}
    	}
    
    Steve Murphy's avatar
    Steve Murphy committed
    static struct ast_config_include *ast_include_find(struct ast_config *conf, const char *included_file)
    
    Steve Murphy's avatar
    Steve Murphy committed
    	struct ast_config_include *x;
    	for (x=conf->includes;x;x=x->next)
    	{
    		if (strcmp(x->included_file,included_file) == 0)
    			return x;
    	}
    	return 0;
    
    Steve Murphy's avatar
    Steve Murphy committed
    static void ast_variable_append(struct ast_category *category, struct ast_variable *variable);
    
    Steve Murphy's avatar
    Steve Murphy committed
    static void ast_variable_append(struct ast_category *category, struct ast_variable *variable)
    
    Steve Murphy's avatar
    Steve Murphy committed
    	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;
    
    Steve Murphy's avatar
    Steve Murphy committed
    static struct ast_category *category_get(const struct ast_config *config, const char *category_name, int ignored);
    
    Steve Murphy's avatar
    Steve Murphy committed
    static struct ast_category *category_get(const struct ast_config *config, const char *category_name, int ignored)
    
    Steve Murphy's avatar
    Steve Murphy committed
    	struct ast_category *cat;
    
    Steve Murphy's avatar
    Steve Murphy committed
    	/* try exact match first, then case-insensitive match */
    	for (cat = config->root; cat; cat = cat->next) {
    		if (cat->name == category_name && (ignored || !cat->ignored))
    			return cat;
    	}
    
    	for (cat = config->root; cat; cat = cat->next) {
    		if (!strcasecmp(cat->name, category_name) && (ignored || !cat->ignored))
    			return cat;
    	}
    
    	return NULL;
    
    Steve Murphy's avatar
    Steve Murphy committed
    static struct ast_category *ast_category_get(const struct ast_config *config, const char *category_name)
    
    Steve Murphy's avatar
    Steve Murphy committed
    	return category_get(config, category_name, 0);
    
    Steve Murphy's avatar
    Steve Murphy committed
    static struct ast_variable *ast_variable_browse(const struct ast_config *config, const char *category)
    
    Steve Murphy's avatar
    Steve Murphy committed
    	struct ast_category *cat = NULL;
    
    Steve Murphy's avatar
    Steve Murphy committed
    	if (category && config->last_browse && (config->last_browse->name == category))
    		cat = config->last_browse;
    	else
    		cat = ast_category_get(config, category);
    
    Steve Murphy's avatar
    Steve Murphy committed
    	return (cat) ? cat->root : NULL;
    
    Steve Murphy's avatar
    Steve Murphy committed
    static const char *ast_variable_retrieve(const struct ast_config *config, const char *category, const char *variable)
    
    Steve Murphy's avatar
    Steve Murphy committed
    	struct ast_variable *v;
    
    Steve Murphy's avatar
    Steve Murphy committed
    	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;
    
    Steve Murphy's avatar
    Steve Murphy committed
    		for (cat = config->root; cat; cat = cat->next)
    			for (v = cat->root; v; v = v->next)
    				if (!strcasecmp(variable, v->name))
    					return v->value;
    	}
    
    Steve Murphy's avatar
    Steve Murphy committed
    	return NULL;
    
    Steve Murphy's avatar
    Steve Murphy committed
    static struct ast_variable *variable_clone(const struct ast_variable *old)
    
    Steve Murphy's avatar
    Steve Murphy committed
    	struct ast_variable *new = ast_variable_new(old->name, old->value, old->file);
    
    	if (new) {
    		new->lineno = old->lineno;
    		new->object = old->object;
    		new->blanklines = old->blanklines;
    		/* TODO: clone comments? */
    	}
    
    Steve Murphy's avatar
    Steve Murphy committed
    	return new;
    
    Steve Murphy's avatar
    Steve Murphy committed
    static void ast_variables_destroy(struct ast_variable *v)
    
    Steve Murphy's avatar
    Steve Murphy committed
    	struct ast_variable *vn;
    
    Steve Murphy's avatar
    Steve Murphy committed
    	while (v) {
    		vn = v;
    		v = v->next;
    		free(vn);
    	}
    
    Steve Murphy's avatar
    Steve Murphy committed
    static void ast_includes_destroy(struct ast_config_include *incls)
    
    Steve Murphy's avatar
    Steve Murphy committed
    	struct ast_config_include *incl,*inclnext;
    
    Steve Murphy's avatar
    Steve Murphy committed
    	for (incl=incls; incl; incl = inclnext) {
    		inclnext = incl->next;
    		if (incl->include_location_file)
    			free(incl->include_location_file);
    		if (incl->exec_file)
    			free(incl->exec_file);
    		if (incl->included_file)
    			free(incl->included_file);
    		free(incl);
    	}
    
    Steve Murphy's avatar
    Steve Murphy committed
    static void ast_config_destroy(struct ast_config *cfg)
    
    Steve Murphy's avatar
    Steve Murphy committed
    	struct ast_category *cat, *catn;
    
    Steve Murphy's avatar
    Steve Murphy committed
    	if (!cfg)
    		return;
    
    Steve Murphy's avatar
    Steve Murphy committed
    	ast_includes_destroy(cfg->includes);
    
    Steve Murphy's avatar
    Steve Murphy committed
    	cat = cfg->root;
    	while (cat) {
    		ast_variables_destroy(cat->root);
    		catn = cat;
    		cat = cat->next;
    		free(catn);
    	}
    	free(cfg);
    
    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),
    	/*! 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() and DTMF Generation */
    	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),
    	/*! 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),
    	/*! There is a per-file debug setting */
    	AST_OPT_FLAG_DEBUG_FILE = (1 << 23),
    	/*! There is a per-file verbose setting */
    	AST_OPT_FLAG_VERBOSE_FILE = (1 << 24),
    	/*! Terminal colors should be adjusted for a light-colored background */
    	AST_OPT_FLAG_LIGHT_BACKGROUND = (1 << 25),
    	/*! Count Initiated seconds in CDR's */
    	AST_OPT_FLAG_INITIATED_SECONDS = (1 << 26),
    	/*! Force black background */
    	AST_OPT_FLAG_FORCE_BLACK_BACKGROUND = (1 << 27),
    };
    
    /* options.h declares ast_options extern; I need it static? */
    
    Steve Murphy's avatar
    Steve Murphy committed
    #define AST_CACHE_DIR_LEN 	512
    #define AST_FILENAME_MAX	80
    
    Steve Murphy's avatar
    Steve Murphy committed
    /*! These are the options that set by default when Asterisk starts */
    #define AST_DEFAULT_OPTIONS AST_OPT_FLAG_TRANSCODE_VIA_SLIN
    
    struct ast_flags ast_options = { AST_DEFAULT_OPTIONS };
    
    
    Steve Murphy's avatar
    Steve Murphy committed
    #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_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)
    
    extern int option_verbose;
    extern int option_debug;		/*!< Debugging */
    
    extern int ast_option_maxcalls;		/*!< Maximum number of simultaneous channels */
    extern double ast_option_maxload;
    extern char ast_defaultlanguage[];
    
    Steve Murphy's avatar
    Steve Murphy committed
    extern pid_t ast_mainpid;
    
    Steve Murphy's avatar
    Steve Murphy committed
    extern char record_cache_dir[AST_CACHE_DIR_LEN];
    extern char debug_filename[AST_FILENAME_MAX];
    
    extern int ast_language_is_prefix;
    
    
    
    
    /* linkedlists.h */
    
    /*!
      \brief Write locks a list.
      \param head This is a pointer to the list head structure
    
      This macro attempts to place an exclusive write lock in the
      list head structure pointed to by head.
      Returns non-zero on success, 0 on failure
    */
    #define AST_RWLIST_WRLOCK(head)                                         \
            ast_rwlock_wrlock(&(head)->lock)
    
    /*!
      \brief Read locks a list.
      \param head This is a pointer to the list head structure
    
      This macro attempts to place a read lock in the
      list head structure pointed to by head.
      Returns non-zero on success, 0 on failure
    */
    #define AST_RWLIST_RDLOCK(head)                                         \
            ast_rwlock_rdlock(&(head)->lock)
    
    /*!
      \brief Attempts to unlock a read/write based list.
      \param head This is a pointer to the list head structure
    
      This macro attempts to remove a read or write lock from the
      list head structure pointed to by head. If the list
      was not locked by this thread, this macro has no effect.
    */
    #define AST_RWLIST_UNLOCK(head)                                         \
            ast_rwlock_unlock(&(head)->lock)
    
    /*!
      \brief Defines a structure to be used to hold a list of specified type.
      \param name This will be the name of the defined structure.
      \param type This is the type of each list entry.
    
      This macro creates a structure definition that can be used
      to hold a list of the entries of type \a type. It does not actually
      declare (allocate) a structure; to do that, either follow this
      macro with the desired name of the instance you wish to declare,
      or use the specified \a name to declare instances elsewhere.
    
      Example usage:
      \code
      static AST_LIST_HEAD(entry_list, entry) entries;
      \endcode
    
      This would define \c struct \c entry_list, and declare an instance of it named
      \a entries, all intended to hold a list of type \c struct \c entry.
    */
    #define AST_LIST_HEAD(name, type)					\
    struct name {								\
    	struct type *first;						\
    	struct type *last;						\
    	ast_mutex_t lock;						\
    }
    
    /*!
      \brief Defines a structure to be used to hold a read/write list of specified type.
      \param name This will be the name of the defined structure.
      \param type This is the type of each list entry.
    
      This macro creates a structure definition that can be used
      to hold a list of the entries of type \a type. It does not actually
      declare (allocate) a structure; to do that, either follow this
      macro with the desired name of the instance you wish to declare,
      or use the specified \a name to declare instances elsewhere.
    
      Example usage:
      \code
      static AST_RWLIST_HEAD(entry_list, entry) entries;
      \endcode
    
      This would define \c struct \c entry_list, and declare an instance of it named
      \a entries, all intended to hold a list of type \c struct \c entry.
    */
    #define AST_RWLIST_HEAD(name, type)                                     \
    struct name {                                                           \
            struct type *first;                                             \
            struct type *last;                                              \
            ast_rwlock_t lock;                                              \
    }
    
    /*!
      \brief Defines a structure to be used to hold a list of specified type (with no lock).
      \param name This will be the name of the defined structure.
      \param type This is the type of each list entry.
    
      This macro creates a structure definition that can be used
      to hold a list of the entries of type \a type. It does not actually
      declare (allocate) a structure; to do that, either follow this
      macro with the desired name of the instance you wish to declare,
      or use the specified \a name to declare instances elsewhere.
    
      Example usage:
      \code
      static AST_LIST_HEAD_NOLOCK(entry_list, entry) entries;
      \endcode
    
      This would define \c struct \c entry_list, and declare an instance of it named
      \a entries, all intended to hold a list of type \c struct \c entry.
    */
    #define AST_LIST_HEAD_NOLOCK(name, type)				\
    struct name {								\
    	struct type *first;						\
    	struct type *last;						\
    }
    
    /*!
      \brief Defines initial values for a declaration of AST_LIST_HEAD
    */
    #define AST_LIST_HEAD_INIT_VALUE	{		\
    	.first = NULL,					\
    	.last = NULL,					\
    	.lock = AST_MUTEX_INIT_VALUE,			\
    	}
    
    /*!
      \brief Defines initial values for a declaration of AST_RWLIST_HEAD
    */
    #define AST_RWLIST_HEAD_INIT_VALUE      {               \
            .first = NULL,                                  \
            .last = NULL,                                   \
            .lock = AST_RWLOCK_INIT_VALUE,                  \
            }
    
    /*!
      \brief Defines initial values for a declaration of AST_LIST_HEAD_NOLOCK
    */
    #define AST_LIST_HEAD_NOLOCK_INIT_VALUE	{	\
    	.first = NULL,					\
    	.last = NULL,					\
    	}
    
    /*!
      \brief Defines a structure to be used to hold a list of specified type, statically initialized.
      \param name This will be the name of the defined structure.
      \param type This is the type of each list entry.
    
      This macro creates a structure definition that can be used
      to hold a list of the entries of type \a type, and allocates an instance
      of it, initialized to be empty.
    
      Example usage:
      \code
      static AST_LIST_HEAD_STATIC(entry_list, entry);
      \endcode
    
      This would define \c struct \c entry_list, intended to hold a list of
      type \c struct \c entry.
    */
    #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS)
    #define AST_LIST_HEAD_STATIC(name, type)				\
    struct name {								\
    	struct type *first;						\
    	struct type *last;						\
    	ast_mutex_t lock;						\
    } name;									\
    
    static void  __attribute__((constructor)) init_##name(void)		\
    
    static void  __attribute__((destructor)) fini_##name(void)		\
    
    {									\
            AST_LIST_HEAD_DESTROY(&name);					\
    }									\
    struct __dummy_##name
    #else
    #define AST_LIST_HEAD_STATIC(name, type)				\
    struct name {								\
    	struct type *first;						\
    	struct type *last;						\
    	ast_mutex_t lock;						\
    } name = AST_LIST_HEAD_INIT_VALUE
    #endif
    
    /*!
      \brief Defines a structure to be used to hold a read/write list of specified type, statically initialized.
      \param name This will be the name of the defined structure.
      \param type This is the type of each list entry.
    
      This macro creates a structure definition that can be used
      to hold a list of the entries of type \a type, and allocates an instance
      of it, initialized to be empty.
    
      Example usage:
      \code
      static AST_RWLIST_HEAD_STATIC(entry_list, entry);
      \endcode
    
      This would define \c struct \c entry_list, intended to hold a list of
      type \c struct \c entry.
    */
    #ifndef AST_RWLOCK_INIT_VALUE
    #define AST_RWLIST_HEAD_STATIC(name, type)                              \
    struct name {                                                           \
            struct type *first;                                             \
            struct type *last;                                              \
            ast_rwlock_t lock;                                              \
    } name;                                                                 \
    
    static void  __attribute__((constructor)) init_##name(void)            \
    
    static void  __attribute__((destructor)) fini_##name(void)             \
    
    {                                                                       \
            AST_RWLIST_HEAD_DESTROY(&name);                                 \
    }                                                                       \
    struct __dummy_##name
    #else
    #define AST_RWLIST_HEAD_STATIC(name, type)                              \
    struct name {                                                           \
            struct type *first;                                             \
            struct type *last;                                              \
            ast_rwlock_t lock;                                              \
    } name = AST_RWLIST_HEAD_INIT_VALUE
    #endif
    
    /*!
      \brief Defines a structure to be used to hold a list of specified type, statically initialized.
    
      This is the same as AST_LIST_HEAD_STATIC, except without the lock included.
    */
    #define AST_LIST_HEAD_NOLOCK_STATIC(name, type)				\
    struct name {								\
    	struct type *first;						\
    	struct type *last;						\
    } name = AST_LIST_HEAD_NOLOCK_INIT_VALUE
    
    /*!
      \brief Initializes a list head structure with a specified first entry.
      \param head This is a pointer to the list head structure
      \param entry pointer to the list entry that will become the head of the list
    
      This macro initializes a list head structure by setting the head
      entry to the supplied value and recreating the embedded lock.
    */
    #define AST_LIST_HEAD_SET(head, entry) do {				\
    	(head)->first = (entry);					\
    	(head)->last = (entry);						\
    	ast_mutex_init(&(head)->lock);					\
    } while (0)
    
    /*!
      \brief Initializes an rwlist head structure with a specified first entry.
      \param head This is a pointer to the list head structure
      \param entry pointer to the list entry that will become the head of the list
    
      This macro initializes a list head structure by setting the head
      entry to the supplied value and recreating the embedded lock.
    */
    #define AST_RWLIST_HEAD_SET(head, entry) do {                           \
            (head)->first = (entry);                                        \
            (head)->last = (entry);                                         \
            ast_rwlock_init(&(head)->lock);                                 \
    } while (0)
    
    /*!
      \brief Initializes a list head structure with a specified first entry.
      \param head This is a pointer to the list head structure
      \param entry pointer to the list entry that will become the head of the list
    
      This macro initializes a list head structure by setting the head
      entry to the supplied value.
    */
    #define AST_LIST_HEAD_SET_NOLOCK(head, entry) do {			\
    	(head)->first = (entry);					\
    	(head)->last = (entry);						\
    } while (0)
    
    /*!
      \brief Declare a forward link structure inside a list entry.
      \param type This is the type of each list entry.
    
      This macro declares a structure to be used to link list entries together.
      It must be used inside the definition of the structure named in
      \a type, as follows:
    
      \code
      struct list_entry {
      	...
      	AST_LIST_ENTRY(list_entry) list;
      }
      \endcode
    
      The field name \a list here is arbitrary, and can be anything you wish.
    */
    #define AST_LIST_ENTRY(type)						\
    struct {								\
    	struct type *next;						\
    }
    
    #define AST_RWLIST_ENTRY AST_LIST_ENTRY
    
    /*!
      \brief Returns the first entry contained in a list.
      \param head This is a pointer to the list head structure
     */
    #define	AST_LIST_FIRST(head)	((head)->first)
    
    #define AST_RWLIST_FIRST AST_LIST_FIRST
    
    /*!
      \brief Returns the last entry contained in a list.
      \param head This is a pointer to the list head structure
     */
    #define	AST_LIST_LAST(head)	((head)->last)
    
    #define AST_RWLIST_LAST AST_LIST_LAST
    
    /*!
      \brief Returns the next entry in the list after the given entry.
      \param elm This is a pointer to the current entry.
      \param field This is the name of the field (declared using AST_LIST_ENTRY())
      used to link entries of this list together.
    */
    #define AST_LIST_NEXT(elm, field)	((elm)->field.next)
    
    #define AST_RWLIST_NEXT AST_LIST_NEXT
    
    /*!
      \brief Checks whether the specified list contains any entries.
      \param head This is a pointer to the list head structure
    
      Returns non-zero if the list has entries, zero if not.
     */
    #define	AST_LIST_EMPTY(head)	(AST_LIST_FIRST(head) == NULL)
    
    #define AST_RWLIST_EMPTY AST_LIST_EMPTY
    
    /*!
      \brief Loops over (traverses) the entries in a list.
      \param head This is a pointer to the list head structure
      \param var This is the name of the variable that will hold a pointer to the
      current list entry on each iteration. It must be declared before calling
      this macro.
      \param field This is the name of the field (declared using AST_LIST_ENTRY())
      used to link entries of this list together.
    
      This macro is use to loop over (traverse) the entries in a list. It uses a
      \a for loop, and supplies the enclosed code with a pointer to each list
      entry as it loops. It is typically used as follows:
      \code
      static AST_LIST_HEAD(entry_list, list_entry) entries;
      ...
      struct list_entry {
      	...
      	AST_LIST_ENTRY(list_entry) list;
      }
      ...
      struct list_entry *current;
      ...
      AST_LIST_TRAVERSE(&entries, current, list) {
         (do something with current here)
      }
      \endcode
      \warning If you modify the forward-link pointer contained in the \a current entry while
      inside the loop, the behavior will be unpredictable. At a minimum, the following
      macros will modify the forward-link pointer, and should not be used inside