From ee342cc3b80db292625e41019a3afd8bb4cdc568 Mon Sep 17 00:00:00 2001 From: Mark Spencer Date: Mon, 12 Jan 2004 05:05:35 +0000 Subject: Add ww's improved syslog support (bug #587) git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@1973 65c4cc65-6c06-0410-ace0-fbb531ad65f3 --- asterisk.c | 31 ++- configs/logger.conf.sample | 7 +- include/asterisk/logger.h | 36 +++- logger.c | 489 +++++++++++++++++++++++++-------------------- pbx/pbx_config.c | 20 ++ 5 files changed, 352 insertions(+), 231 deletions(-) diff --git a/asterisk.c b/asterisk.c index b4985e28c..6c45865ba 100755 --- a/asterisk.c +++ b/asterisk.c @@ -148,13 +148,34 @@ static int fdprint(int fd, const char *s) return write(fd, s, strlen(s) + 1); } +/* + * write the string to all attached console clients + */ +static void ast_network_puts(const char *string) +{ + int x; + for (x=0;x -1) + fdprint(consoles[x].p[1], string); + } +} + + +/* + * write the string to the console, and all attached + * console clients + */ +void ast_console_puts(const char *string) +{ + fputs(string, stdout); + fflush(stdout); + ast_network_puts(string); +} + static void network_verboser(const char *s, int pos, int replace, int complete) + /* ARGUSED */ { - int x; - for (x=0;x -1) - fdprint(consoles[x].p[1], s); - } + ast_network_puts(s); } static pthread_t lthread; diff --git a/configs/logger.conf.sample b/configs/logger.conf.sample index 7d7e73afa..f7e32abb3 100755 --- a/configs/logger.conf.sample +++ b/configs/logger.conf.sample @@ -17,9 +17,6 @@ console => notice,warning,error messages => notice,warning,error ;syslog keyword : This special keyword logs to syslog facility -;local0 edit /etc/syslog.conf and add -;local0.* /var/log/myastlog ; -;syslog => notice,warning,error - - +;syslog.local0 => notice,warning,error +; diff --git a/include/asterisk/logger.h b/include/asterisk/logger.h index 62eb34f65..9278e2b54 100755 --- a/include/asterisk/logger.h +++ b/include/asterisk/logger.h @@ -54,13 +54,39 @@ extern void ast_verbose(const char *fmt, ...) extern int ast_register_verbose(void (*verboser)(const char *string, int opos, int replacelast, int complete)); extern int ast_unregister_verbose(void (*verboser)(const char *string, int opos, int replacelast, int complete)); extern int ast_verbose_dmesg(void (*verboser)(const char *string, int opos, int replacelast, int complete)); +extern void ast_console_puts(const char *string); + #define _A_ __FILE__, __LINE__, __PRETTY_FUNCTION__ -#define LOG_DEBUG 0, _A_ -#define LOG_EVENT 1, _A_ -#define LOG_NOTICE 2, _A_ -#define LOG_WARNING 3, _A_ -#define LOG_ERROR 4, _A_ +#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_ #if defined(__cplusplus) || defined(c_plusplus) } diff --git a/logger.c b/logger.c index 91c2743d4..d6fa6ab97 100755 --- a/logger.c +++ b/logger.c @@ -17,7 +17,6 @@ #include #include #include -#include #include #include #include @@ -28,10 +27,23 @@ #include #include #include -#include #include "asterisk.h" #include "astconf.h" +#define SYSLOG_NAMES /* so we can map syslog facilities names to their numeric values, + from which is included by logger.h */ +#include +static int syslog_level_map[] = { + LOG_DEBUG, + LOG_INFO, /* arbitrary equivalent of LOG_EVENT */ + LOG_NOTICE, + LOG_WARNING, + LOG_ERR +}; +#define SYSLOG_NLEVELS 5 + +#include + #define MAX_MSG_QUEUE 200 static ast_mutex_t msglist_lock = AST_MUTEX_INITIALIZER; @@ -42,38 +54,38 @@ static struct msglist { struct msglist *next; } *list = NULL, *last = NULL; -struct logfile { - char fn[256]; - int logflags; - FILE *f; +struct logchannel { + int logmask; int facility; /* syslog */ - struct logfile *next; + int syslog; /* syslog flag */ + int console; /* console logging */ + FILE *fileptr; /* logfile logging */ + char filename[256]; + struct logchannel *next; }; -static struct logfile *logfiles = NULL; +static struct logchannel *logchannels = NULL; static int msgcnt = 0; static FILE *eventlog = NULL; static char *levels[] = { - "DEBUG", - "EVENT", - "NOTICE", - "WARNING", - "ERROR" + "DEBUG", + "EVENT", + "NOTICE", + "WARNING", + "ERROR" }; static int colors[] = { - COLOR_BRGREEN, - COLOR_BRBLUE, - COLOR_YELLOW, - COLOR_BRRED, - COLOR_RED + COLOR_BRGREEN, + COLOR_BRBLUE, + COLOR_YELLOW, + COLOR_BRRED, + COLOR_RED }; - - static int make_components(char *s, int lineno) { char *w; @@ -82,120 +94,141 @@ static int make_components(char *s, int lineno) stringp=s; w = strsep(&stringp, ","); while(w) { - while(*w && (*w < 33)) - w++; - if (!strcasecmp(w, "debug")) - res |= (1 << 0); - else if (!strcasecmp(w, "notice")) - res |= (1 << 2); - else if (!strcasecmp(w, "warning")) - res |= (1 << 3); - else if (!strcasecmp(w, "error")) - res |= (1 << 4); - else { - fprintf(stderr, "Logfile Warning: Unknown keyword '%s' at line %d of logger.conf\n", w, lineno); - } - w = strsep(&stringp, ","); + while(*w && (*w < 33)) + w++; + if (!strcasecmp(w, "error")) + res |= (1 << __LOG_ERROR); + else if (!strcasecmp(w, "warning")) + res |= (1 << __LOG_WARNING); + else if (!strcasecmp(w, "notice")) + res |= (1 << __LOG_NOTICE); + else if (!strcasecmp(w, "event")) + res |= (1 << __LOG_EVENT); + else if (!strcasecmp(w, "debug")) + res |= (1 << __LOG_DEBUG); + else { + fprintf(stderr, "Logfile Warning: Unknown keyword '%s' at line %d of logger.conf\n", w, lineno); + } + w = strsep(&stringp, ","); } return res; } -static struct logfile *make_logfile(char *fn, char *components, int lineno) +static struct logchannel *make_logchannel(char *channel, char *components, int lineno) { - struct logfile *f; - char tmp[256]; - if (!strlen(fn)) + struct logchannel *chan; + char *facility; + CODE *cptr; + + if (!strlen(channel)) return NULL; - f = malloc(sizeof(struct logfile)); - if (f) { - memset(f, 0, sizeof(struct logfile)); - strncpy(f->fn, fn, sizeof(f->fn) - 1); - if (!strcasecmp(fn, "ignore")) { - f->f = NULL; - } else if (!strcasecmp(fn, "console")) { - f->f = stdout; - } else if (!strcasecmp(fn, "syslog")) { - f->f = NULL; - f->facility = LOG_LOCAL0; + chan = malloc(sizeof(struct logchannel)); + + if (chan) { + memset(chan, 0, sizeof(chan)); + if (!strcasecmp(channel, "console")) { + chan->console = 1; + } else if (!strncasecmp(channel, "syslog", 6)) { + /* + * syntax is: + * syslog.facility => level,level,level + */ + facility = strchr(channel, '.'); + if(!facility++ || !facility) { + facility = "local0"; + } + /* + * Walk through the list of facilitynames (defined in sys/syslog.h) + * to see if we can find the one we have been given + */ + chan->facility = -1; + cptr = facilitynames; + while (cptr->c_name) { + if (!strncasecmp(facility, cptr->c_name, sizeof(cptr->c_name))) { + chan->facility = cptr->c_val; + break; + } + cptr++; + } + if (0 > chan->facility) { + fprintf(stderr, "Logger Warning: bad syslog facility in logger.conf\n"); + free(chan); + return NULL; + } + + chan->syslog = 1; + openlog("asterisk", LOG_PID, chan->facility); } else { - if (fn[0] == '/') - strncpy(tmp, fn, sizeof(tmp) - 1); + if (channel[0] == '/') + strncpy(chan->filename, channel, sizeof(chan->filename) - 1); else - snprintf(tmp, sizeof(tmp), "%s/%s", (char *)ast_config_AST_LOG_DIR, fn); - f->f = fopen(tmp, "a"); - if (!f->f) { + snprintf(chan->filename, sizeof(chan->filename), "%s/%s", (char *)ast_config_AST_LOG_DIR, channel); + chan->fileptr = fopen(chan->filename, "a"); + if (!chan->fileptr) { /* Can't log here, since we're called with a lock */ - fprintf(stderr, "Logger Warning: Unable to open log file '%s': %s\n", tmp, strerror(errno)); + fprintf(stderr, "Logger Warning: Unable to open log file '%s': %s\n", chan->filename, strerror(errno)); } } - f->logflags = make_components(components, lineno); - + chan->logmask = make_components(components, lineno); } - return f; + return chan; } static void init_logger_chain(void) { - struct logfile *f, *cur; + struct logchannel *chan, *cur; struct ast_config *cfg; struct ast_variable *var; + /* delete our list of log channels */ ast_mutex_lock(&loglock); - - /* Free anything that is here */ - f = logfiles; - while(f) { - cur = f->next; - if (f->f && (f->f != stdout) && (f->f != stderr)) - fclose(f->f); - free(f); - f = cur; + chan = logchannels; + while (chan) { + cur = chan->next; + free(chan); + chan = cur; } + logchannels = NULL; + ast_mutex_unlock(&loglock); - logfiles = NULL; + /* close syslog */ + closelog(); - ast_mutex_unlock(&loglock); cfg = ast_load("logger.conf"); - ast_mutex_lock(&loglock); /* If no config file, we're fine */ - if (!cfg) { - ast_mutex_unlock(&loglock); - return; - } + if (!cfg) + return; + + ast_mutex_lock(&loglock); var = ast_variable_browse(cfg, "logfiles"); while(var) { - f = make_logfile(var->name, var->value, var->lineno); - if (f) { - f->next = logfiles; - logfiles = f; + chan = make_logchannel(var->name, var->value, var->lineno); + if (chan) { + chan->next = logchannels; + logchannels = chan; } var = var->next; } - if (!logfiles) { - /* Gotta have at least one. We'll make a NULL one */ - logfiles = make_logfile("ignore", "", -1); - } + ast_destroy(cfg); ast_mutex_unlock(&loglock); - - } int reload_logger(int rotate) { char old[AST_CONFIG_MAX_PATH]; char new[AST_CONFIG_MAX_PATH]; - struct logfile *f; + struct logchannel *f; FILE *myf; int x; ast_mutex_lock(&loglock); if (eventlog) - fclose(eventlog); + fclose(eventlog); else - rotate = 0; + rotate = 0; eventlog = NULL; @@ -205,51 +238,47 @@ int reload_logger(int rotate) if(rotate) { for(x=0;;x++) { - snprintf(new, sizeof(new), "%s/%s.%d", (char *)ast_config_AST_LOG_DIR, EVENTLOG,x); - myf = fopen((char *)new, "r"); - if(myf) - fclose(myf); - else - break; + snprintf(new, sizeof(new), "%s/%s.%d", (char *)ast_config_AST_LOG_DIR, EVENTLOG,x); + myf = fopen((char *)new, "r"); + if(myf) + fclose(myf); + else + break; } - /* do it */ + /* do it */ if (rename(old,new)) fprintf(stderr, "Unable to rename file '%s' to '%s'\n", old, new); } eventlog = fopen(old, "a"); - f = logfiles; + f = logchannels; while(f) { - if (f->f && (f->f != stdout) && (f->f != stderr)) { - fclose(f->f); - f->f = NULL; - if(rotate) { - snprintf(old, sizeof(old), "%s/%s", (char *)ast_config_AST_LOG_DIR,f->fn); + if (f->fileptr && (f->fileptr != stdout) && (f->fileptr != stderr)) { + fclose(f->fileptr); + f->fileptr = NULL; + if(rotate) { + strncpy(old, f->filename, sizeof(old)); - for(x=0;;x++) { - snprintf(new, sizeof(new), "%s/%s.%d", (char *)ast_config_AST_LOG_DIR,f->fn,x); - myf = fopen((char *)new, "r"); - if(myf) - fclose(myf); - else - break; - } - - /* do it */ - if (rename(old,new)) - fprintf(stderr, "Unable to rename file '%s' to '%s'\n", old, new); - } + for(x=0;;x++) { + snprintf(new, sizeof(new), "%s.%d", f->filename, x); + myf = fopen((char *)new, "r"); + if (myf) { + fclose(myf); + } else { + break; + } + } - - } - - - f = f->next; + /* do it */ + if (rename(old,new)) + fprintf(stderr, "Unable to rename file '%s' to '%s'\n", old, new); + } + } + f = f->next; } - ast_mutex_unlock(&loglock); if (eventlog) { @@ -275,13 +304,6 @@ static int handle_logger_reload(int fd, int argc, char *argv[]) return RESULT_SUCCESS; } - - - - - - - static int handle_logger_rotate(int fd, int argc, char *argv[]) { if(reload_logger(1)) @@ -301,41 +323,33 @@ static struct verb { static char logger_reload_help[] = "Usage: logger reload\n" -" Reopens the log files. Use after a rotating the log files\n"; - +" Reloads the logger subsystem state. Use after restarting syslogd(8)\n"; static char logger_rotate_help[] = "Usage: logger reload\n" " Rotates and Reopens the log files.\n"; - static struct ast_cli_entry reload_logger_cli = { { "logger", "reload", NULL }, handle_logger_reload, "Reopens the log files", logger_reload_help }; - static struct ast_cli_entry rotate_logger_cli = { { "logger", "rotate", NULL }, handle_logger_rotate, "Reopens the log files", logger_rotate_help }; - - static int handle_SIGXFSZ(int sig) { - reload_logger(1); - ast_log(LOG_EVENT,"Rotated Logs Per SIGXFSZ\n"); - if (option_verbose) - ast_verbose("Rotated Logs Per SIGXFSZ\n"); - - return 0; + reload_logger(1); + ast_log(LOG_EVENT,"Rotated Logs Per SIGXFSZ\n"); + if (option_verbose) + ast_verbose("Rotated Logs Per SIGXFSZ\n"); + return 0; } int init_logger(void) { - char tmp[AST_CONFIG_MAX_PATH]; - - + char tmp[256]; /* auto rotate if sig SIGXFSZ comes a-knockin */ (void) signal(SIGXFSZ,(void *) handle_SIGXFSZ); @@ -343,7 +357,8 @@ int init_logger(void) /* register the relaod logger cli command */ ast_cli_register(&reload_logger_cli); ast_cli_register(&rotate_logger_cli); - + + /* create the eventlog */ mkdir((char *)ast_config_AST_LOG_DIR, 0755); snprintf(tmp, sizeof(tmp), "%s/%s", (char *)ast_config_AST_LOG_DIR, EVENTLOG); eventlog = fopen((char *)tmp, "a"); @@ -355,89 +370,124 @@ int init_logger(void) return 0; } else ast_log(LOG_ERROR, "Unable to create event log: %s\n", strerror(errno)); + + init_logger_chain(); + + /* create log channels */ init_logger_chain(); return -1; } +static void ast_log_vsyslog(int level, const char *file, int line, const char *function, const char *fmt, va_list args) { + char buf[BUFSIZ]; + + if(level >= SYSLOG_NLEVELS) { + /* we are locked here, so cannot ast_log() */ + fprintf(stderr, "ast_log_vsyslog called with bogus level: %d\n", level); + return; + } + if(file && line && function) { + snprintf(buf, sizeof(buf), "%s[%ld]: %s:%d in %s: ", + levels[level], (long)pthread_self(), file, line, function); + } else { + snprintf(buf, sizeof(buf), "VERBOSE[%ld]: ", (long)pthread_self()); + level = __LOG_DEBUG; + } + vsnprintf(buf+strlen(buf), sizeof(buf)-strlen(buf), fmt, args); + syslog(syslog_level_map[level], buf); +} -extern void ast_log(int level, const char *file, int line, const char *function, const char *fmt, ...) +/* + * send log messages to syslog and/or the console + */ +void ast_log(int level, const char *file, int line, const char *function, const char *fmt, ...) { - char date[256]; - char tmp[80]; - char tmp2[80]; - char tmp3[80]; - char tmp4[80]; - char linestr[80]; - time_t t; - struct tm tm; - struct logfile *f; + struct logchannel *chan; + char buf[BUFSIZ]; + time_t t; + struct tm tm; + char date[256]; + + va_list ap; + + if (!option_verbose && !option_debug && (level == __LOG_DEBUG)) { + return; + } + + /* begin critical section */ + ast_mutex_lock(&loglock); + + if (level == __LOG_EVENT) { + time(&t); + localtime_r(&t,&tm); + if (&tm) { + /* Log events into the event log file, with a different format */ + strftime(date, sizeof(date), "%b %e %T", &tm); + va_start(ap, fmt); + + fprintf(eventlog, "%s asterisk[%d]: ", date, getpid()); + vfprintf(eventlog, fmt, ap); + fflush(eventlog); + + va_end(ap); + } else + /** Cannot use ast_log() from locked section of ast_log()! + ast_log(LOG_WARNING, "Unable to retrieve local time?\n"); **/ + fprintf(stderr, "ast_log: Unable to retrieve local time for %ld?\n", (long)t); + ast_mutex_unlock(&loglock); + return; + } + + if (logchannels) { + chan = logchannels; + while(chan) { + if (chan->syslog && (chan->logmask & (1 << level))) { + va_start(ap, fmt); + ast_log_vsyslog(level, file, line, function, fmt, ap); + va_end(ap); + } else if ((chan->logmask & (1 << level)) && (chan->console || chan->fileptr)) { + char linestr[128]; + char tmp1[80], tmp2[80], tmp3[80], tmp4[80]; - va_list ap; - if (!option_verbose && !option_debug && (!level)) { - return; - } - ast_mutex_lock(&loglock); - if (level == 1 /* Event */) { time(&t); - localtime_r(&t,&tm); - if (&tm) { - /* Log events into the event log file, with a different format */ - strftime(date, sizeof(date), "%b %e %T", &tm); - fprintf(eventlog, "%s asterisk[%d]: ", date, getpid()); - va_start(ap, fmt); - vfprintf(eventlog, fmt, ap); - va_end(ap); - fflush(eventlog); - } else - /** Cannot use ast_log() from locked section of ast_log()! - ast_log(LOG_WARNING, "Unable to retrieve local time?\n"); **/ - fprintf(stderr, "ast_log: Unable to retrieve local time for %ld?\n", (long)t); - } else { - if (logfiles) { - f = logfiles; - while(f) { - if (f->logflags & (1 << level) && f->facility) { - time(&t); - localtime_r(&t,&tm); - strftime(date, sizeof(date), "%b %e %T", &tm); - - openlog("asterisk_pbx",LOG_PID,f->facility); - syslog(LOG_INFO|f->facility,"%s %s[%ld]: File %s, Line %d (%s): ",date, - levels[level], (long)pthread_self(), file, line, function); - closelog(); - - } - else if (f->logflags & (1 << level) && f->f) { - if ((f->f != stdout) && (f->f != stderr)) { - time(&t); - localtime_r(&t,&tm); - strftime(date, sizeof(date), "%b %e %T", &tm); - fprintf(f->f, "%s %s[%ld]: File %s, Line %d (%s): ", date, levels[level], (long)pthread_self(), file, line, function); - } else { - sprintf(linestr, "%d", line); - fprintf(f->f, "%s[%ld]: File %s, Line %s (%s): ", - term_color(tmp, levels[level], colors[level], 0, sizeof(tmp)), - (long)pthread_self(), - term_color(tmp2, file, COLOR_BRWHITE, 0, sizeof(tmp2)), - term_color(tmp3, linestr, COLOR_BRWHITE, 0, sizeof(tmp3)), - term_color(tmp4, function, COLOR_BRWHITE, 0, sizeof(tmp4))); - } - va_start(ap, fmt); - vfprintf(f->f, fmt, ap); - va_end(ap); - fflush(f->f); - } - f = f->next; - } - } else { - fprintf(stdout, "%s[%ld]: File %s, Line %d (%s): ", levels[level], (long)pthread_self(), file, line, function); - va_start(ap, fmt); - vfprintf(stdout, fmt, ap); - va_end(ap); - fflush(stdout); + localtime_r(&t, &tm); + if(!&tm) { + /** Cannot use ast_log() from locked section of ast_log()! + ast_log(AST_LOG_WARNING, "Unable to retrieve local time?\n"); **/ + fprintf(stderr, "ast_log: Unable to retrieve local time for %ld?\n", (long)t); + ast_mutex_unlock(&loglock); + return; } + strftime(date, sizeof(date), "%b %e %T", &tm); + + sprintf(linestr, "%d", line); + snprintf(buf, sizeof(buf), "%s %s[%ld]: %s:%s %s: ", + date, + term_color(tmp1, levels[level], colors[level], 0, sizeof(tmp1)), + (long)pthread_self(), + term_color(tmp2, file, COLOR_BRWHITE, 0, sizeof(tmp2)), + term_color(tmp3, linestr, COLOR_BRWHITE, 0, sizeof(tmp3)), + term_color(tmp4, function, COLOR_BRWHITE, 0, sizeof(tmp4))); + + if (chan->console) + ast_console_puts(buf); + else + fprintf(chan->fileptr, buf); + va_start(ap, fmt); + vsnprintf(buf, sizeof(buf), fmt, ap); + va_end(ap); + if (chan->console) + ast_console_puts(buf); + else + fprintf(chan->fileptr, buf); + + } + chan = chan->next; } - ast_mutex_unlock(&loglock); + } + + ast_mutex_unlock(&loglock); + /* end critical section */ } extern void ast_verbose(const char *fmt, ...) @@ -498,6 +548,13 @@ extern void ast_verbose(const char *fmt, ...) else replacelast = pos = 0; va_end(ap); + + va_start(ap, fmt); + if(stuff[strlen(stuff)-1] == '\n') + stuff[strlen(stuff)-1] = '\0'; + ast_log_vsyslog(0, NULL, 0, NULL, fmt, ap); + va_end(ap); + ast_mutex_unlock(&msglist_lock); } diff --git a/pbx/pbx_config.c b/pbx/pbx_config.c index d68c5adf4..b0a55978d 100755 --- a/pbx/pbx_config.c +++ b/pbx/pbx_config.c @@ -903,6 +903,8 @@ static int handle_save_dialplan(int fd, int argc, char *argv[]) { char filename[256]; struct ast_context *c; + struct ast_config *cfg; + struct ast_variable *var; int context_header_written; int incomplete = 0; /* incomplete config write? */ FILE *output; @@ -922,6 +924,9 @@ static int handle_save_dialplan(int fd, int argc, char *argv[]) return RESULT_FAILURE; } + /* Load old file first */ + cfg = ast_load(config); + /* have config path? */ if (argc == 3) { /* is there extension.conf too? */ @@ -946,6 +951,8 @@ static int handle_save_dialplan(int fd, int argc, char *argv[]) if (ast_lock_contexts()) { ast_cli(fd, "Failed to lock contexts list\n"); ast_mutex_unlock(&save_dialplan_lock); + if (cfg) + ast_destroy(cfg); return RESULT_FAILURE; } @@ -955,6 +962,8 @@ static int handle_save_dialplan(int fd, int argc, char *argv[]) filename); ast_unlock_contexts(); ast_mutex_unlock(&save_dialplan_lock); + if (cfg) + ast_destroy(cfg); return RESULT_FAILURE; } @@ -963,6 +972,15 @@ static int handle_save_dialplan(int fd, int argc, char *argv[]) static_config ? "yes" : "no", write_protect_config ? "yes" : "no"); + var = ast_variable_walk(cfg, "globals"); + if (var) { + fprintf(output, "[globals]\n"); + while(var) { + fprintf(output, "%s => %s", var->name, var->value); + var = var->next; + } + } + /* walk all contexts */ c = ast_walk_contexts(NULL); while (c) { @@ -1079,6 +1097,8 @@ static int handle_save_dialplan(int fd, int argc, char *argv[]) ast_unlock_contexts(); ast_mutex_unlock(&save_dialplan_lock); fclose(output); + if (cfg) + ast_destroy(cfg); if (incomplete) { ast_cli(fd, "Saved dialplan is incomplete\n"); -- cgit v1.2.3