stasis: No need to keep a stasis type ref in a stasis msg or cache object.
[asterisk/asterisk.git] / main / logger.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 1999 - 2006, Digium, Inc.
5  *
6  * Mark Spencer <markster@digium.com>
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18
19 /*! \file
20  *
21  * \brief Asterisk Logger
22  *
23  * Logging routines
24  *
25  * \author Mark Spencer <markster@digium.com>
26  */
27
28 /*! \li \ref logger.c uses the configuration file \ref logger.conf
29  * \addtogroup configuration_file Configuration Files
30  */
31
32 /*!
33  * \page logger.conf logger.conf
34  * \verbinclude logger.conf.sample
35  */
36
37 /*** MODULEINFO
38         <support_level>core</support_level>
39  ***/
40
41 #include "asterisk.h"
42
43 /* When we include logger.h again it will trample on some stuff in syslog.h, but
44  * nothing we care about in here. */
45 #include <syslog.h>
46 #include <signal.h>
47 #include <time.h>
48 #include <sys/stat.h>
49 #include <fcntl.h>
50
51 #include "asterisk/_private.h"
52 #include "asterisk/module.h"
53 #include "asterisk/paths.h"     /* use ast_config_AST_LOG_DIR */
54 #include "asterisk/logger.h"
55 #include "asterisk/lock.h"
56 #include "asterisk/channel.h"
57 #include "asterisk/config.h"
58 #include "asterisk/term.h"
59 #include "asterisk/cli.h"
60 #include "asterisk/utils.h"
61 #include "asterisk/manager.h"
62 #include "asterisk/astobj2.h"
63 #include "asterisk/threadstorage.h"
64 #include "asterisk/strings.h"
65 #include "asterisk/pbx.h"
66 #include "asterisk/app.h"
67 #include "asterisk/syslog.h"
68 #include "asterisk/buildinfo.h"
69 #include "asterisk/ast_version.h"
70 #include "asterisk/backtrace.h"
71 #include "asterisk/json.h"
72
73 /*** DOCUMENTATION
74  ***/
75
76 static char dateformat[256] = "%b %e %T";               /* Original Asterisk Format */
77
78 static char queue_log_name[256] = QUEUELOG;
79 static char exec_after_rotate[256] = "";
80
81 static int filesize_reload_needed;
82 static unsigned int global_logmask = 0xFFFF;
83 static int queuelog_init;
84 static int logger_initialized;
85 static volatile int next_unique_callid = 1; /* Used to assign unique call_ids to calls */
86 static int display_callids;
87
88 AST_THREADSTORAGE(unique_callid);
89
90 static int logger_queue_size;
91 static int logger_queue_limit = 1000;
92 static int logger_messages_discarded;
93 static unsigned int high_water_alert;
94
95 static enum rotatestrategy {
96         NONE = 0,                /* Do not rotate log files at all, instead rely on external mechanisms */
97         SEQUENTIAL = 1 << 0,     /* Original method - create a new file, in order */
98         ROTATE = 1 << 1,         /* Rotate all files, such that the oldest file has the highest suffix */
99         TIMESTAMP = 1 << 2,      /* Append the epoch timestamp onto the end of the archived file */
100 } rotatestrategy = SEQUENTIAL;
101
102 static struct {
103         unsigned int queue_log:1;
104         unsigned int queue_log_to_file:1;
105         unsigned int queue_adaptive_realtime:1;
106         unsigned int queue_log_realtime_use_gmt:1;
107 } logfiles = { 1 };
108
109 static char hostname[MAXHOSTNAMELEN];
110 AST_THREADSTORAGE_RAW(in_safe_log);
111
112 struct logchannel;
113 struct logmsg;
114
115 struct logformatter {
116         /* The name of the log formatter */
117         const char *name;
118         /* Pointer to the function that will format the log */
119         int (* const format_log)(struct logchannel *channel, struct logmsg *msg, char *buf, size_t size);
120 };
121
122 enum logtypes {
123         LOGTYPE_SYSLOG,
124         LOGTYPE_FILE,
125         LOGTYPE_CONSOLE,
126 };
127
128 struct logchannel {
129         /*! How the logs sent to this channel will be formatted */
130         struct logformatter formatter;
131         /*! What to log to this channel */
132         unsigned int logmask;
133         /*! If this channel is disabled or not */
134         int disabled;
135         /*! syslog facility */
136         int facility;
137         /*! Verbosity level. (-1 if use option_verbose for the level.) */
138         int verbosity;
139         /*! Type of log channel */
140         enum logtypes type;
141         /*! logfile logging file pointer */
142         FILE *fileptr;
143         /*! Filename */
144         char filename[PATH_MAX];
145         /*! field for linking to list */
146         AST_LIST_ENTRY(logchannel) list;
147         /*! Line number from configuration file */
148         int lineno;
149         /*! Whether this log channel was created dynamically */
150         int dynamic;
151         /*! Components (levels) from last config load */
152         char components[0];
153 };
154
155 static AST_RWLIST_HEAD_STATIC(logchannels, logchannel);
156
157 enum logmsgtypes {
158         LOGMSG_NORMAL = 0,
159         LOGMSG_VERBOSE,
160 };
161
162 struct logmsg {
163         enum logmsgtypes type;
164         int level;
165         int sublevel;
166         int line;
167         int lwp;
168         ast_callid callid;
169         AST_DECLARE_STRING_FIELDS(
170                 AST_STRING_FIELD(date);
171                 AST_STRING_FIELD(file);
172                 AST_STRING_FIELD(function);
173                 AST_STRING_FIELD(message);
174                 AST_STRING_FIELD(level_name);
175         );
176         AST_LIST_ENTRY(logmsg) list;
177 };
178
179 static void logmsg_free(struct logmsg *msg)
180 {
181         ast_string_field_free_memory(msg);
182         ast_free(msg);
183 }
184
185 static AST_LIST_HEAD_STATIC(logmsgs, logmsg);
186 static pthread_t logthread = AST_PTHREADT_NULL;
187 static ast_cond_t logcond;
188 static int close_logger_thread = 0;
189
190 static FILE *qlog;
191
192 /*! \brief Logging channels used in the Asterisk logging system
193  *
194  * The first 16 levels are reserved for system usage, and the remaining
195  * levels are reserved for usage by dynamic levels registered via
196  * ast_logger_register_level.
197  */
198
199 /* Modifications to this array are protected by the rwlock in the
200  * logchannels list.
201  */
202
203 static char *levels[NUMLOGLEVELS] = {
204         "DEBUG",
205         "---EVENT---",          /* no longer used */
206         "NOTICE",
207         "WARNING",
208         "ERROR",
209         "VERBOSE",
210         "DTMF",
211 };
212
213 /*! \brief Colors used in the console for logging */
214 static const int colors[NUMLOGLEVELS] = {
215         COLOR_BRGREEN,
216         COLOR_BRBLUE,           /* no longer used */
217         COLOR_YELLOW,
218         COLOR_BRRED,
219         COLOR_RED,
220         COLOR_GREEN,
221         COLOR_BRGREEN,
222         0,
223         0,
224         0,
225         0,
226         0,
227         0,
228         0,
229         0,
230         0,
231         COLOR_BRBLUE,
232         COLOR_BRBLUE,
233         COLOR_BRBLUE,
234         COLOR_BRBLUE,
235         COLOR_BRBLUE,
236         COLOR_BRBLUE,
237         COLOR_BRBLUE,
238         COLOR_BRBLUE,
239         COLOR_BRBLUE,
240         COLOR_BRBLUE,
241         COLOR_BRBLUE,
242         COLOR_BRBLUE,
243         COLOR_BRBLUE,
244         COLOR_BRBLUE,
245         COLOR_BRBLUE,
246         COLOR_BRBLUE,
247 };
248
249 AST_THREADSTORAGE(verbose_buf);
250 AST_THREADSTORAGE(verbose_build_buf);
251 #define VERBOSE_BUF_INIT_SIZE   256
252
253 AST_THREADSTORAGE(log_buf);
254 #define LOG_BUF_INIT_SIZE       256
255
256 static int format_log_json(struct logchannel *channel, struct logmsg *msg, char *buf, size_t size)
257 {
258         struct ast_json *json;
259         char *str;
260         char call_identifier_str[13];
261         size_t json_str_len;
262
263         if (msg->callid) {
264                 snprintf(call_identifier_str, sizeof(call_identifier_str), "[C-%08x]", msg->callid);
265         } else {
266                 call_identifier_str[0] = '\0';
267         }
268
269         json = ast_json_pack("{s: s, s: s, "
270                 "s: {s: i, s: s} "
271                 "s: {s: {s: s, s: s, s: i}, "
272                 "s: s, s: s} }",
273                 "hostname", ast_config_AST_SYSTEM_NAME,
274                 "timestamp", msg->date,
275                 "identifiers",
276                 "lwp", msg->lwp,
277                 "callid", S_OR(call_identifier_str, ""),
278                 "logmsg",
279                 "location",
280                 "filename", msg->file,
281                 "function", msg->function,
282                 "line", msg->line,
283                 "level", msg->level_name,
284                 "message", msg->message);
285         if (!json) {
286                 return -1;
287         }
288
289         str = ast_json_dump_string(json);
290         if (!str) {
291                 ast_json_unref(json);
292                 return -1;
293         }
294
295         ast_copy_string(buf, str, size);
296         json_str_len = strlen(str);
297         if (json_str_len > size - 1) {
298                 json_str_len = size - 1;
299         }
300         buf[json_str_len] = '\n';
301         buf[json_str_len + 1] = '\0';
302
303         term_strip(buf, buf, size);
304
305         ast_json_free(str);
306         ast_json_unref(json);
307
308         return 0;
309 }
310
311 static struct logformatter logformatter_json = {
312         .name = "json",
313         .format_log = format_log_json
314 };
315
316 static int logger_add_verbose_magic(struct logmsg *logmsg, char *buf, size_t size)
317 {
318         const char *p;
319         const char *fmt;
320         struct ast_str *prefixed;
321         signed char magic = logmsg->sublevel > 9 ? -10 : -logmsg->sublevel - 1; /* 0 => -1, 1 => -2, etc.  Can't pass NUL, as it is EOS-delimiter */
322
323         /* For compatibility with modules still calling ast_verbose() directly instead of using ast_verb() */
324         if (logmsg->sublevel < 0) {
325                 if (!strncmp(logmsg->message, VERBOSE_PREFIX_4, strlen(VERBOSE_PREFIX_4))) {
326                         magic = -5;
327                 } else if (!strncmp(logmsg->message, VERBOSE_PREFIX_3, strlen(VERBOSE_PREFIX_3))) {
328                         magic = -4;
329                 } else if (!strncmp(logmsg->message, VERBOSE_PREFIX_2, strlen(VERBOSE_PREFIX_2))) {
330                         magic = -3;
331                 } else if (!strncmp(logmsg->message, VERBOSE_PREFIX_1, strlen(VERBOSE_PREFIX_1))) {
332                         magic = -2;
333                 } else {
334                         magic = -1;
335                 }
336         }
337
338         if (!(prefixed = ast_str_thread_get(&verbose_buf, VERBOSE_BUF_INIT_SIZE))) {
339                 return -1;
340         }
341
342         ast_str_reset(prefixed);
343
344         /* for every newline found in the buffer add verbose prefix data */
345         fmt = logmsg->message;
346         do {
347                 if (!(p = strchr(fmt, '\n'))) {
348                         p = strchr(fmt, '\0') - 1;
349                 }
350                 ++p;
351
352                 ast_str_append(&prefixed, 0, "%c", (char)magic);
353                 ast_str_append_substr(&prefixed, 0, fmt, p - fmt);
354                 fmt = p;
355         } while (p && *p);
356
357         snprintf(buf, size, "%s", ast_str_buffer(prefixed));
358
359         return 0;
360 }
361
362 static int format_log_default(struct logchannel *chan, struct logmsg *msg, char *buf, size_t size)
363 {
364         char call_identifier_str[13];
365
366         if (msg->callid) {
367                 snprintf(call_identifier_str, sizeof(call_identifier_str), "[C-%08x]", msg->callid);
368         } else {
369                 call_identifier_str[0] = '\0';
370         }
371
372         switch (chan->type) {
373         case LOGTYPE_SYSLOG:
374                 snprintf(buf, size, "%s[%d]%s: %s:%d in %s: %s",
375                      levels[msg->level], msg->lwp, call_identifier_str, msg->file,
376                      msg->line, msg->function, msg->message);
377                 term_strip(buf, buf, size);
378                 break;
379         case LOGTYPE_FILE:
380                 snprintf(buf, size, "[%s] %s[%d]%s %s: %s",
381                       msg->date, msg->level_name, msg->lwp, call_identifier_str,
382                       msg->file, msg->message);
383                 term_strip(buf, buf, size);
384                 break;
385         case LOGTYPE_CONSOLE:
386                 {
387                         char linestr[32];
388
389                         /*
390                          * Verbose messages are interpreted by console channels in their own
391                          * special way
392                          */
393                         if (msg->level == __LOG_VERBOSE) {
394                                 return logger_add_verbose_magic(msg, buf, size);
395                         }
396
397                         /* Turn the numeric line number into a string for colorization */
398                         snprintf(linestr, sizeof(linestr), "%d", msg->line);
399
400                         snprintf(buf, size, "[%s] " COLORIZE_FMT "[%d]%s: " COLORIZE_FMT ":" COLORIZE_FMT " " COLORIZE_FMT ": %s",
401                                  msg->date,
402                                  COLORIZE(colors[msg->level], 0, msg->level_name),
403                                  msg->lwp,
404                                  call_identifier_str,
405                                  COLORIZE(COLOR_BRWHITE, 0, msg->file),
406                                  COLORIZE(COLOR_BRWHITE, 0, linestr),
407                                  COLORIZE(COLOR_BRWHITE, 0, msg->function),
408                                  msg->message);
409                 }
410                 break;
411         }
412
413         return 0;
414 }
415
416 static struct logformatter logformatter_default = {
417         .name = "default",
418         .format_log = format_log_default,
419 };
420
421 static void make_components(struct logchannel *chan)
422 {
423         char *w;
424         unsigned int logmask = 0;
425         char *stringp = ast_strdupa(chan->components);
426         unsigned int x;
427         unsigned int verb_level;
428
429         /* Default to using option_verbose as the verbosity level of the logging channel.  */
430         verb_level = -1;
431
432         w = strchr(stringp, '[');
433         if (w) {
434                 char *end = strchr(w + 1, ']');
435                 if (!end) {
436                         fprintf(stderr, "Logger Warning: bad formatter definition for %s in logger.conf\n", chan->filename);
437                 } else {
438                         char *formatter_name = w + 1;
439
440                         *end = '\0';
441                         stringp = end + 1;
442
443                         if (!strcasecmp(formatter_name, "json")) {
444                                 memcpy(&chan->formatter, &logformatter_json, sizeof(chan->formatter));
445                         } else if (!strcasecmp(formatter_name, "default")) {
446                                 memcpy(&chan->formatter, &logformatter_default, sizeof(chan->formatter));
447                         } else {
448                                 fprintf(stderr, "Logger Warning: Unknown formatter definition %s for %s in logger.conf; using 'default'\n",
449                                         formatter_name, chan->filename);
450                                 memcpy(&chan->formatter, &logformatter_default, sizeof(chan->formatter));
451                         }
452                 }
453         }
454
455         if (!chan->formatter.name) {
456                 memcpy(&chan->formatter, &logformatter_default, sizeof(chan->formatter));
457         }
458
459         while ((w = strsep(&stringp, ","))) {
460                 w = ast_strip(w);
461                 if (ast_strlen_zero(w)) {
462                         continue;
463                 }
464                 if (!strcmp(w, "*")) {
465                         logmask = 0xFFFFFFFF;
466                 } else if (!strncasecmp(w, "verbose(", 8)) {
467                         if (levels[__LOG_VERBOSE] && sscanf(w + 8, "%30u)", &verb_level) == 1) {
468                                 logmask |= (1 << __LOG_VERBOSE);
469                         }
470                 } else {
471                         for (x = 0; x < ARRAY_LEN(levels); ++x) {
472                                 if (levels[x] && !strcasecmp(w, levels[x])) {
473                                         logmask |= (1 << x);
474                                         break;
475                                 }
476                         }
477                 }
478         }
479         if (chan->type == LOGTYPE_CONSOLE) {
480                 /*
481                  * Force to use the root console verbose level so if the
482                  * user specified any verbose level then it does not interfere
483                  * with calculating the ast_verb_sys_level value.
484                  */
485                 chan->verbosity = -1;
486                 logmask |= (1 << __LOG_VERBOSE);
487         } else {
488                 chan->verbosity = verb_level;
489         }
490         chan->logmask = logmask;
491 }
492
493 /*!
494  * \brief create the filename that will be used for a logger channel.
495  *
496  * \param channel The name of the logger channel
497  * \param[out] filename The filename for the logger channel
498  * \param size The size of the filename buffer
499  */
500 static void make_filename(const char *channel, char *filename, size_t size)
501 {
502         const char *log_dir_prefix = "";
503         const char *log_dir_separator = "";
504
505         *filename = '\0';
506
507         if (!strcasecmp(channel, "console")) {
508                 return;
509         }
510
511         if (!strncasecmp(channel, "syslog", 6)) {
512                 ast_copy_string(filename, channel, size);
513                 return;
514         }
515
516         /* It's a filename */
517
518         if (channel[0] != '/') {
519                 log_dir_prefix = ast_config_AST_LOG_DIR;
520                 log_dir_separator = "/";
521         }
522
523         if (!ast_strlen_zero(hostname)) {
524                 snprintf(filename, size, "%s%s%s.%s",
525                         log_dir_prefix, log_dir_separator, channel, hostname);
526         } else {
527                 snprintf(filename, size, "%s%s%s",
528                         log_dir_prefix, log_dir_separator, channel);
529         }
530 }
531
532 /*!
533  * \brief Find a particular logger channel by name
534  *
535  * \pre logchannels list is locked
536  *
537  * \param channel The name of the logger channel to find
538  * \retval non-NULL The corresponding logger channel
539  * \retval NULL Unable to find a logger channel with that particular name
540  */
541 static struct logchannel *find_logchannel(const char *channel)
542 {
543         char filename[PATH_MAX];
544         struct logchannel *chan;
545
546         make_filename(channel, filename, sizeof(filename));
547
548         AST_RWLIST_TRAVERSE(&logchannels, chan, list) {
549                 if (!strcmp(chan->filename, filename)) {
550                         return chan;
551                 }
552         }
553
554         return NULL;
555 }
556
557 static struct logchannel *make_logchannel(const char *channel, const char *components, int lineno, int dynamic)
558 {
559         struct logchannel *chan;
560         char *facility;
561         struct ast_tm tm;
562         struct timeval now = ast_tvnow();
563         char datestring[256];
564
565         if (ast_strlen_zero(channel) || !(chan = ast_calloc(1, sizeof(*chan) + strlen(components) + 1)))
566                 return NULL;
567
568         strcpy(chan->components, components);
569         chan->lineno = lineno;
570         chan->dynamic = dynamic;
571
572         make_filename(channel, chan->filename, sizeof(chan->filename));
573
574         if (!strcasecmp(channel, "console")) {
575                 chan->type = LOGTYPE_CONSOLE;
576         } else if (!strncasecmp(channel, "syslog", 6)) {
577                 /*
578                 * syntax is:
579                 *  syslog.facility => level,level,level
580                 */
581                 facility = strchr(channel, '.');
582                 if (!facility++ || !facility) {
583                         facility = "local0";
584                 }
585
586                 chan->facility = ast_syslog_facility(facility);
587
588                 if (chan->facility < 0) {
589                         fprintf(stderr, "Logger Warning: bad syslog facility in logger.conf\n");
590                         ast_free(chan);
591                         return NULL;
592                 }
593
594                 chan->type = LOGTYPE_SYSLOG;
595                 openlog("asterisk", LOG_PID, chan->facility);
596         } else {
597                 if (!(chan->fileptr = fopen(chan->filename, "a"))) {
598                         /* Can't do real logging here since we're called with a lock
599                          * so log to any attached consoles */
600                         ast_console_puts_mutable("ERROR: Unable to open log file '", __LOG_ERROR);
601                         ast_console_puts_mutable(chan->filename, __LOG_ERROR);
602                         ast_console_puts_mutable("': ", __LOG_ERROR);
603                         ast_console_puts_mutable(strerror(errno), __LOG_ERROR);
604                         ast_console_puts_mutable("'\n", __LOG_ERROR);
605                         ast_free(chan);
606                         return NULL;
607                 } else {
608                         /* Create our date/time */
609                         ast_localtime(&now, &tm, NULL);
610                         ast_strftime(datestring, sizeof(datestring), dateformat, &tm);
611
612                         fprintf(chan->fileptr, "[%s] Asterisk %s built by %s @ %s on a %s running %s on %s\n",
613                                 datestring, ast_get_version(), ast_build_user, ast_build_hostname,
614                                 ast_build_machine, ast_build_os, ast_build_date);
615                         fflush(chan->fileptr);
616                 }
617                 chan->type = LOGTYPE_FILE;
618         }
619         make_components(chan);
620
621         return chan;
622 }
623
624 /* \brief Read config, setup channels.
625  * \param altconf Alternate configuration file to read.
626  *
627  * \pre logchannels list is write locked
628  *
629  * \retval 0 Success
630  * \retval -1 No config found or Failed
631  */
632 static int init_logger_chain(const char *altconf)
633 {
634         struct logchannel *chan;
635         struct ast_config *cfg;
636         struct ast_variable *var;
637         const char *s;
638         struct ast_flags config_flags = { 0 };
639
640         if (!(cfg = ast_config_load2(S_OR(altconf, "logger.conf"), "logger", config_flags)) || cfg == CONFIG_STATUS_FILEINVALID) {
641                 cfg = NULL;
642         }
643
644         /* Set defaults */
645         hostname[0] = '\0';
646         display_callids = 1;
647         memset(&logfiles, 0, sizeof(logfiles));
648         logfiles.queue_log = 1;
649         ast_copy_string(dateformat, "%b %e %T", sizeof(dateformat));
650         ast_copy_string(queue_log_name, QUEUELOG, sizeof(queue_log_name));
651         exec_after_rotate[0] = '\0';
652         rotatestrategy = SEQUENTIAL;
653
654         /* delete our list of log channels */
655         while ((chan = AST_RWLIST_REMOVE_HEAD(&logchannels, list))) {
656                 ast_free(chan);
657         }
658         global_logmask = 0;
659
660         errno = 0;
661         /* close syslog */
662         closelog();
663
664         /* If no config file, we're fine, set default options. */
665         if (!cfg) {
666                 if (!(chan = ast_calloc(1, sizeof(*chan) + 1))) {
667                         fprintf(stderr, "Failed to initialize default logging\n");
668                         return -1;
669                 }
670                 chan->type = LOGTYPE_CONSOLE;
671                 chan->logmask = (1 << __LOG_WARNING) | (1 << __LOG_NOTICE) | (1 << __LOG_ERROR)
672                         | (1 << __LOG_VERBOSE);
673                 memcpy(&chan->formatter, &logformatter_default, sizeof(chan->formatter));
674
675                 AST_RWLIST_INSERT_HEAD(&logchannels, chan, list);
676                 global_logmask |= chan->logmask;
677
678                 return -1;
679         }
680
681         if ((s = ast_variable_retrieve(cfg, "general", "appendhostname"))) {
682                 if (ast_true(s)) {
683                         if (gethostname(hostname, sizeof(hostname) - 1)) {
684                                 ast_copy_string(hostname, "unknown", sizeof(hostname));
685                                 fprintf(stderr, "What box has no hostname???\n");
686                         }
687                 }
688         }
689         if ((s = ast_variable_retrieve(cfg, "general", "display_callids"))) {
690                 display_callids = ast_true(s);
691         }
692         if ((s = ast_variable_retrieve(cfg, "general", "dateformat"))) {
693                 ast_copy_string(dateformat, s, sizeof(dateformat));
694         }
695         if ((s = ast_variable_retrieve(cfg, "general", "queue_log"))) {
696                 logfiles.queue_log = ast_true(s);
697         }
698         if ((s = ast_variable_retrieve(cfg, "general", "queue_log_to_file"))) {
699                 logfiles.queue_log_to_file = ast_true(s);
700         }
701         if ((s = ast_variable_retrieve(cfg, "general", "queue_log_name"))) {
702                 ast_copy_string(queue_log_name, s, sizeof(queue_log_name));
703         }
704         if ((s = ast_variable_retrieve(cfg, "general", "queue_log_realtime_use_gmt"))) {
705                 logfiles.queue_log_realtime_use_gmt = ast_true(s);
706         }
707         if ((s = ast_variable_retrieve(cfg, "general", "exec_after_rotate"))) {
708                 ast_copy_string(exec_after_rotate, s, sizeof(exec_after_rotate));
709         }
710         if ((s = ast_variable_retrieve(cfg, "general", "rotatestrategy"))) {
711                 if (strcasecmp(s, "timestamp") == 0) {
712                         rotatestrategy = TIMESTAMP;
713                 } else if (strcasecmp(s, "rotate") == 0) {
714                         rotatestrategy = ROTATE;
715                 } else if (strcasecmp(s, "sequential") == 0) {
716                         rotatestrategy = SEQUENTIAL;
717                 } else if (strcasecmp(s, "none") == 0) {
718                         rotatestrategy = NONE;
719                 } else {
720                         fprintf(stderr, "Unknown rotatestrategy: %s\n", s);
721                 }
722         } else {
723                 if ((s = ast_variable_retrieve(cfg, "general", "rotatetimestamp"))) {
724                         rotatestrategy = ast_true(s) ? TIMESTAMP : SEQUENTIAL;
725                         fprintf(stderr, "rotatetimestamp option has been deprecated.  Please use rotatestrategy instead.\n");
726                 }
727         }
728         if ((s = ast_variable_retrieve(cfg, "general", "logger_queue_limit"))) {
729                 if (sscanf(s, "%30d", &logger_queue_limit) != 1) {
730                         fprintf(stderr, "logger_queue_limit has an invalid value.  Leaving at default of %d.\n",
731                                 logger_queue_limit);
732                 }
733                 if (logger_queue_limit < 10) {
734                         fprintf(stderr, "logger_queue_limit must be >= 10. Setting to 10.\n");
735                         logger_queue_limit = 10;
736                 }
737         }
738
739         var = ast_variable_browse(cfg, "logfiles");
740         for (; var; var = var->next) {
741                 if (!(chan = make_logchannel(var->name, var->value, var->lineno, 0))) {
742                         /* Print error message directly to the consoles since the lock is held
743                          * and we don't want to unlock with the list partially built */
744                         ast_console_puts_mutable("ERROR: Unable to create log channel '", __LOG_ERROR);
745                         ast_console_puts_mutable(var->name, __LOG_ERROR);
746                         ast_console_puts_mutable("'\n", __LOG_ERROR);
747                         continue;
748                 }
749                 AST_RWLIST_INSERT_HEAD(&logchannels, chan, list);
750                 global_logmask |= chan->logmask;
751         }
752
753         if (qlog) {
754                 fclose(qlog);
755                 qlog = NULL;
756         }
757
758         ast_config_destroy(cfg);
759
760         return 0;
761 }
762
763 void ast_child_verbose(int level, const char *fmt, ...)
764 {
765         char *msg = NULL, *emsg = NULL, *sptr, *eptr;
766         va_list ap, aq;
767         int size;
768
769         va_start(ap, fmt);
770         va_copy(aq, ap);
771         if ((size = vsnprintf(msg, 0, fmt, ap)) < 0) {
772                 va_end(ap);
773                 va_end(aq);
774                 return;
775         }
776         va_end(ap);
777
778         if (!(msg = ast_malloc(size + 1))) {
779                 va_end(aq);
780                 return;
781         }
782
783         vsnprintf(msg, size + 1, fmt, aq);
784         va_end(aq);
785
786         if (!(emsg = ast_malloc(size * 2 + 1))) {
787                 ast_free(msg);
788                 return;
789         }
790
791         for (sptr = msg, eptr = emsg; ; sptr++) {
792                 if (*sptr == '"') {
793                         *eptr++ = '\\';
794                 }
795                 *eptr++ = *sptr;
796                 if (*sptr == '\0') {
797                         break;
798                 }
799         }
800         ast_free(msg);
801
802         fprintf(stdout, "verbose \"%s\" %d\n", emsg, level);
803         fflush(stdout);
804         ast_free(emsg);
805 }
806
807 void ast_queue_log(const char *queuename, const char *callid, const char *agent, const char *event, const char *fmt, ...)
808 {
809         va_list ap;
810         struct timeval tv;
811         struct ast_tm tm;
812         char qlog_msg[8192];
813         int qlog_len;
814         char time_str[30];
815
816         if (!logger_initialized) {
817                 /* You are too early.  We are not open yet! */
818                 return;
819         }
820         if (!queuelog_init) {
821                 /* We must initialize now since someone is trying to log something. */
822                 logger_queue_start();
823         }
824
825         if (ast_check_realtime("queue_log")) {
826                 tv = ast_tvnow();
827                 ast_localtime(&tv, &tm, logfiles.queue_log_realtime_use_gmt ? "GMT" : NULL);
828                 ast_strftime(time_str, sizeof(time_str), "%F %T.%6q", &tm);
829                 va_start(ap, fmt);
830                 vsnprintf(qlog_msg, sizeof(qlog_msg), fmt, ap);
831                 va_end(ap);
832                 if (logfiles.queue_adaptive_realtime) {
833                         AST_DECLARE_APP_ARGS(args,
834                                 AST_APP_ARG(data)[5];
835                         );
836                         AST_NONSTANDARD_APP_ARGS(args, qlog_msg, '|');
837                         /* Ensure fields are large enough to receive data */
838                         ast_realtime_require_field("queue_log",
839                                 "data1", RQ_CHAR, strlen(S_OR(args.data[0], "")),
840                                 "data2", RQ_CHAR, strlen(S_OR(args.data[1], "")),
841                                 "data3", RQ_CHAR, strlen(S_OR(args.data[2], "")),
842                                 "data4", RQ_CHAR, strlen(S_OR(args.data[3], "")),
843                                 "data5", RQ_CHAR, strlen(S_OR(args.data[4], "")),
844                                 SENTINEL);
845
846                         /* Store the log */
847                         ast_store_realtime("queue_log", "time", time_str,
848                                 "callid", callid,
849                                 "queuename", queuename,
850                                 "agent", agent,
851                                 "event", event,
852                                 "data1", S_OR(args.data[0], ""),
853                                 "data2", S_OR(args.data[1], ""),
854                                 "data3", S_OR(args.data[2], ""),
855                                 "data4", S_OR(args.data[3], ""),
856                                 "data5", S_OR(args.data[4], ""),
857                                 SENTINEL);
858                 } else {
859                         ast_store_realtime("queue_log", "time", time_str,
860                                 "callid", callid,
861                                 "queuename", queuename,
862                                 "agent", agent,
863                                 "event", event,
864                                 "data", qlog_msg,
865                                 SENTINEL);
866                 }
867
868                 if (!logfiles.queue_log_to_file) {
869                         return;
870                 }
871         }
872
873         if (qlog) {
874                 va_start(ap, fmt);
875                 qlog_len = snprintf(qlog_msg, sizeof(qlog_msg), "%ld|%s|%s|%s|%s|", (long)time(NULL), callid, queuename, agent, event);
876                 vsnprintf(qlog_msg + qlog_len, sizeof(qlog_msg) - qlog_len, fmt, ap);
877                 va_end(ap);
878                 AST_RWLIST_RDLOCK(&logchannels);
879                 if (qlog) {
880                         fprintf(qlog, "%s\n", qlog_msg);
881                         fflush(qlog);
882                 }
883                 AST_RWLIST_UNLOCK(&logchannels);
884         }
885 }
886
887 static int rotate_file(const char *filename)
888 {
889         char old[PATH_MAX];
890         char new[PATH_MAX];
891         int x, y, which, found, res = 0, fd;
892         char *suffixes[4] = { "", ".gz", ".bz2", ".Z" };
893
894         switch (rotatestrategy) {
895         case NONE:
896                 /* No rotation */
897                 break;
898         case SEQUENTIAL:
899                 for (x = 0; ; x++) {
900                         snprintf(new, sizeof(new), "%s.%d", filename, x);
901                         fd = open(new, O_RDONLY);
902                         if (fd > -1)
903                                 close(fd);
904                         else
905                                 break;
906                 }
907                 if (rename(filename, new)) {
908                         fprintf(stderr, "Unable to rename file '%s' to '%s'\n", filename, new);
909                         res = -1;
910                 } else {
911                         filename = new;
912                 }
913                 break;
914         case TIMESTAMP:
915                 snprintf(new, sizeof(new), "%s.%ld", filename, (long)time(NULL));
916                 if (rename(filename, new)) {
917                         fprintf(stderr, "Unable to rename file '%s' to '%s'\n", filename, new);
918                         res = -1;
919                 } else {
920                         filename = new;
921                 }
922                 break;
923         case ROTATE:
924                 /* Find the next empty slot, including a possible suffix */
925                 for (x = 0; ; x++) {
926                         found = 0;
927                         for (which = 0; which < ARRAY_LEN(suffixes); which++) {
928                                 snprintf(new, sizeof(new), "%s.%d%s", filename, x, suffixes[which]);
929                                 fd = open(new, O_RDONLY);
930                                 if (fd > -1) {
931                                         close(fd);
932                                         found = 1;
933                                         break;
934                                 }
935                         }
936                         if (!found) {
937                                 break;
938                         }
939                 }
940
941                 /* Found an empty slot */
942                 for (y = x; y > 0; y--) {
943                         for (which = 0; which < ARRAY_LEN(suffixes); which++) {
944                                 snprintf(old, sizeof(old), "%s.%d%s", filename, y - 1, suffixes[which]);
945                                 fd = open(old, O_RDONLY);
946                                 if (fd > -1) {
947                                         /* Found the right suffix */
948                                         close(fd);
949                                         snprintf(new, sizeof(new), "%s.%d%s", filename, y, suffixes[which]);
950                                         if (rename(old, new)) {
951                                                 fprintf(stderr, "Unable to rename file '%s' to '%s'\n", old, new);
952                                                 res = -1;
953                                         }
954                                         break;
955                                 }
956                         }
957                 }
958
959                 /* Finally, rename the current file */
960                 snprintf(new, sizeof(new), "%s.0", filename);
961                 if (rename(filename, new)) {
962                         fprintf(stderr, "Unable to rename file '%s' to '%s'\n", filename, new);
963                         res = -1;
964                 } else {
965                         filename = new;
966                 }
967         }
968
969         if (!ast_strlen_zero(exec_after_rotate)) {
970                 struct ast_channel *c = ast_dummy_channel_alloc();
971                 char buf[512];
972
973                 pbx_builtin_setvar_helper(c, "filename", filename);
974                 pbx_substitute_variables_helper(c, exec_after_rotate, buf, sizeof(buf));
975                 if (c) {
976                         c = ast_channel_unref(c);
977                 }
978                 if (ast_safe_system(buf) == -1) {
979                         ast_log(LOG_WARNING, "error executing '%s'\n", buf);
980                 }
981         }
982         return res;
983 }
984
985 /*!
986  * \internal
987  * \brief Start the realtime queue logging if configured.
988  *
989  * \retval TRUE if not to open queue log file.
990  */
991 static int logger_queue_rt_start(void)
992 {
993         if (ast_check_realtime("queue_log")) {
994                 if (!ast_realtime_require_field("queue_log",
995                         "time", RQ_DATETIME, 26,
996                         "data1", RQ_CHAR, 20,
997                         "data2", RQ_CHAR, 20,
998                         "data3", RQ_CHAR, 20,
999                         "data4", RQ_CHAR, 20,
1000                         "data5", RQ_CHAR, 20,
1001                         SENTINEL)) {
1002                         logfiles.queue_adaptive_realtime = 1;
1003                 } else {
1004                         logfiles.queue_adaptive_realtime = 0;
1005                 }
1006
1007                 if (!logfiles.queue_log_to_file) {
1008                         /* Don't open the log file. */
1009                         return 1;
1010                 }
1011         }
1012         return 0;
1013 }
1014
1015 /*!
1016  * \internal
1017  * \brief Rotate the queue log file and restart.
1018  *
1019  * \param queue_rotate Log queue rotation mode.
1020  *
1021  * \note Assumes logchannels is write locked on entry.
1022  *
1023  * \retval 0 on success.
1024  * \retval -1 on error.
1025  */
1026 static int logger_queue_restart(int queue_rotate)
1027 {
1028         int res = 0;
1029         char qfname[PATH_MAX];
1030
1031         if (logger_queue_rt_start()) {
1032                 return res;
1033         }
1034
1035         snprintf(qfname, sizeof(qfname), "%s/%s", ast_config_AST_LOG_DIR, queue_log_name);
1036         if (qlog) {
1037                 /* Just in case it was still open. */
1038                 fclose(qlog);
1039                 qlog = NULL;
1040         }
1041         if (queue_rotate) {
1042                 rotate_file(qfname);
1043         }
1044
1045         /* Open the log file. */
1046         qlog = fopen(qfname, "a");
1047         if (!qlog) {
1048                 ast_log(LOG_ERROR, "Unable to create queue log: %s\n", strerror(errno));
1049                 res = -1;
1050         }
1051         return res;
1052 }
1053
1054 static int reload_logger(int rotate, const char *altconf)
1055 {
1056         int queue_rotate = rotate;
1057         struct logchannel *f;
1058         int res = 0;
1059
1060         AST_RWLIST_WRLOCK(&logchannels);
1061
1062         if (qlog) {
1063                 if (rotate < 0) {
1064                         /* Check filesize - this one typically doesn't need an auto-rotate */
1065                         if (ftello(qlog) > 0x40000000) { /* Arbitrarily, 1 GB */
1066                                 fclose(qlog);
1067                                 qlog = NULL;
1068                         } else {
1069                                 queue_rotate = 0;
1070                         }
1071                 } else {
1072                         fclose(qlog);
1073                         qlog = NULL;
1074                 }
1075         } else {
1076                 queue_rotate = 0;
1077         }
1078
1079         ast_mkdir(ast_config_AST_LOG_DIR, 0777);
1080
1081         AST_RWLIST_TRAVERSE(&logchannels, f, list) {
1082                 if (f->disabled) {
1083                         f->disabled = 0;        /* Re-enable logging at reload */
1084                         /*** DOCUMENTATION
1085                                 <managerEventInstance>
1086                                         <synopsis>Raised when a logging channel is re-enabled after a reload operation.</synopsis>
1087                                         <syntax>
1088                                                 <parameter name="Channel">
1089                                                         <para>The name of the logging channel.</para>
1090                                                 </parameter>
1091                                         </syntax>
1092                                 </managerEventInstance>
1093                         ***/
1094                         manager_event(EVENT_FLAG_SYSTEM, "LogChannel", "Channel: %s\r\nEnabled: Yes\r\n", f->filename);
1095                 }
1096                 if (f->fileptr && (f->fileptr != stdout) && (f->fileptr != stderr)) {
1097                         int rotate_this = 0;
1098                         if (rotatestrategy != NONE && ftello(f->fileptr) > 0x40000000) { /* Arbitrarily, 1 GB */
1099                                 /* Be more proactive about rotating massive log files */
1100                                 rotate_this = 1;
1101                         }
1102                         fclose(f->fileptr);     /* Close file */
1103                         f->fileptr = NULL;
1104                         if (rotate || rotate_this) {
1105                                 rotate_file(f->filename);
1106                         }
1107                 }
1108         }
1109
1110         filesize_reload_needed = 0;
1111
1112         init_logger_chain(altconf);
1113
1114         ast_unload_realtime("queue_log");
1115         if (logfiles.queue_log) {
1116                 res = logger_queue_restart(queue_rotate);
1117                 AST_RWLIST_UNLOCK(&logchannels);
1118                 ast_verb_update();
1119                 ast_queue_log("NONE", "NONE", "NONE", "CONFIGRELOAD", "%s", "");
1120                 ast_verb(1, "Asterisk Queue Logger restarted\n");
1121         } else {
1122                 AST_RWLIST_UNLOCK(&logchannels);
1123                 ast_verb_update();
1124         }
1125
1126         return res;
1127 }
1128
1129 static char *handle_logger_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1130 {
1131         switch (cmd) {
1132         case CLI_INIT:
1133                 e->command = "logger reload";
1134                 e->usage =
1135                         "Usage: logger reload [<alt-conf>]\n"
1136                         "       Reloads the logger subsystem state.  Use after restarting syslogd(8) if you are using syslog logging.\n";
1137                 return NULL;
1138         case CLI_GENERATE:
1139                 return NULL;
1140         }
1141         if (reload_logger(0, a->argc == 3 ? a->argv[2] : NULL)) {
1142                 ast_cli(a->fd, "Failed to reload the logger\n");
1143                 return CLI_FAILURE;
1144         }
1145         return CLI_SUCCESS;
1146 }
1147
1148 static char *handle_logger_rotate(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1149 {
1150         switch (cmd) {
1151         case CLI_INIT:
1152                 e->command = "logger rotate";
1153                 e->usage =
1154                         "Usage: logger rotate\n"
1155                         "       Rotates and Reopens the log files.\n";
1156                 return NULL;
1157         case CLI_GENERATE:
1158                 return NULL;
1159         }
1160         if (reload_logger(1, NULL)) {
1161                 ast_cli(a->fd, "Failed to reload the logger and rotate log files\n");
1162                 return CLI_FAILURE;
1163         }
1164         return CLI_SUCCESS;
1165 }
1166
1167 int ast_logger_rotate()
1168 {
1169         return reload_logger(1, NULL);
1170 }
1171
1172 int ast_logger_rotate_channel(const char *log_channel)
1173 {
1174         struct logchannel *f;
1175         int success = AST_LOGGER_FAILURE;
1176         char filename[PATH_MAX];
1177
1178         make_filename(log_channel, filename, sizeof(filename));
1179
1180         AST_RWLIST_WRLOCK(&logchannels);
1181
1182         ast_mkdir(ast_config_AST_LOG_DIR, 0644);
1183
1184         AST_RWLIST_TRAVERSE(&logchannels, f, list) {
1185                 if (f->disabled) {
1186                         f->disabled = 0;        /* Re-enable logging at reload */
1187                         manager_event(EVENT_FLAG_SYSTEM, "LogChannel", "Channel: %s\r\nEnabled: Yes\r\n",
1188                                 f->filename);
1189                 }
1190                 if (f->fileptr && (f->fileptr != stdout) && (f->fileptr != stderr)) {
1191                         fclose(f->fileptr);     /* Close file */
1192                         f->fileptr = NULL;
1193                         if (strcmp(filename, f->filename) == 0) {
1194                                 rotate_file(f->filename);
1195                                 success = AST_LOGGER_SUCCESS;
1196                         }
1197                 }
1198         }
1199
1200         init_logger_chain(NULL);
1201
1202         AST_RWLIST_UNLOCK(&logchannels);
1203
1204         return success;
1205 }
1206
1207 static char *handle_logger_set_level(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1208 {
1209         int x;
1210         int state;
1211         int level = -1;
1212
1213         switch (cmd) {
1214         case CLI_INIT:
1215                 e->command = "logger set level {DEBUG|NOTICE|WARNING|ERROR|VERBOSE|DTMF} {on|off}";
1216                 e->usage =
1217                         "Usage: logger set level {DEBUG|NOTICE|WARNING|ERROR|VERBOSE|DTMF} {on|off}\n"
1218                         "       Set a specific log level to enabled/disabled for this console.\n";
1219                 return NULL;
1220         case CLI_GENERATE:
1221                 return NULL;
1222         }
1223
1224         if (a->argc < 5)
1225                 return CLI_SHOWUSAGE;
1226
1227         AST_RWLIST_WRLOCK(&logchannels);
1228
1229         for (x = 0; x < ARRAY_LEN(levels); x++) {
1230                 if (levels[x] && !strcasecmp(a->argv[3], levels[x])) {
1231                         level = x;
1232                         break;
1233                 }
1234         }
1235
1236         AST_RWLIST_UNLOCK(&logchannels);
1237
1238         state = ast_true(a->argv[4]) ? 1 : 0;
1239
1240         if (level != -1) {
1241                 ast_console_toggle_loglevel(a->fd, level, state);
1242                 ast_cli(a->fd, "Logger status for '%s' has been set to '%s'.\n", levels[level], state ? "on" : "off");
1243         } else
1244                 return CLI_SHOWUSAGE;
1245
1246         return CLI_SUCCESS;
1247 }
1248
1249 int ast_logger_get_channels(int (*logentry)(const char *channel, const char *type,
1250         const char *status, const char *configuration, void *data), void *data)
1251 {
1252         struct logchannel *chan;
1253         struct ast_str *configs = ast_str_create(64);
1254         int res = AST_LOGGER_SUCCESS;
1255
1256         if (!configs) {
1257                 return AST_LOGGER_ALLOC_ERROR;
1258         }
1259
1260         AST_RWLIST_RDLOCK(&logchannels);
1261         AST_RWLIST_TRAVERSE(&logchannels, chan, list) {
1262                 unsigned int level;
1263
1264                 ast_str_reset(configs);
1265
1266                 for (level = 0; level < ARRAY_LEN(levels); level++) {
1267                         if ((chan->logmask & (1 << level)) && levels[level]) {
1268                                 ast_str_append(&configs, 0, "%s ", levels[level]);
1269                         }
1270                 }
1271
1272                 res = logentry(chan->filename, chan->type == LOGTYPE_CONSOLE ? "Console" :
1273                         (chan->type == LOGTYPE_SYSLOG ? "Syslog" : "File"), chan->disabled ?
1274                         "Disabled" : "Enabled", ast_str_buffer(configs), data);
1275
1276                 if (res) {
1277                         AST_RWLIST_UNLOCK(&logchannels);
1278                         ast_free(configs);
1279                         configs = NULL;
1280                         return AST_LOGGER_FAILURE;
1281                 }
1282         }
1283         AST_RWLIST_UNLOCK(&logchannels);
1284
1285         ast_free(configs);
1286         configs = NULL;
1287
1288         return AST_LOGGER_SUCCESS;
1289 }
1290
1291 /*! \brief CLI command to show logging system configuration */
1292 static char *handle_logger_show_channels(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1293 {
1294 #define FORMATL "%-35.35s %-8.8s %-10.10s %-9.9s "
1295         struct logchannel *chan;
1296         switch (cmd) {
1297         case CLI_INIT:
1298                 e->command = "logger show channels";
1299                 e->usage =
1300                         "Usage: logger show channels\n"
1301                         "       List configured logger channels.\n";
1302                 return NULL;
1303         case CLI_GENERATE:
1304                 return NULL;
1305         }
1306         ast_cli(a->fd, "Logger queue limit: %d\n\n", logger_queue_limit);
1307         ast_cli(a->fd, FORMATL, "Channel", "Type", "Formatter", "Status");
1308         ast_cli(a->fd, "Configuration\n");
1309         ast_cli(a->fd, FORMATL, "-------", "----", "---------", "------");
1310         ast_cli(a->fd, "-------------\n");
1311         AST_RWLIST_RDLOCK(&logchannels);
1312         AST_RWLIST_TRAVERSE(&logchannels, chan, list) {
1313                 unsigned int level;
1314
1315                 ast_cli(a->fd, FORMATL, chan->filename, chan->type == LOGTYPE_CONSOLE ? "Console" : (chan->type == LOGTYPE_SYSLOG ? "Syslog" : "File"),
1316                         chan->formatter.name,
1317                         chan->disabled ? "Disabled" : "Enabled");
1318                 ast_cli(a->fd, " - ");
1319                 for (level = 0; level < ARRAY_LEN(levels); level++) {
1320                         if ((chan->logmask & (1 << level)) && levels[level]) {
1321                                 ast_cli(a->fd, "%s ", levels[level]);
1322                         }
1323                 }
1324                 ast_cli(a->fd, "\n");
1325         }
1326         AST_RWLIST_UNLOCK(&logchannels);
1327         ast_cli(a->fd, "\n");
1328
1329         return CLI_SUCCESS;
1330 }
1331
1332 int ast_logger_create_channel(const char *log_channel, const char *components)
1333 {
1334         struct logchannel *chan;
1335
1336         if (ast_strlen_zero(components)) {
1337                 return AST_LOGGER_DECLINE;
1338         }
1339
1340         AST_RWLIST_WRLOCK(&logchannels);
1341
1342         chan = find_logchannel(log_channel);
1343         if (chan) {
1344                 AST_RWLIST_UNLOCK(&logchannels);
1345                 return AST_LOGGER_FAILURE;
1346         }
1347
1348         chan = make_logchannel(log_channel, components, 0, 1);
1349         if (!chan) {
1350                 AST_RWLIST_UNLOCK(&logchannels);
1351                 return AST_LOGGER_ALLOC_ERROR;
1352         }
1353
1354         AST_RWLIST_INSERT_HEAD(&logchannels, chan, list);
1355         global_logmask |= chan->logmask;
1356
1357         AST_RWLIST_UNLOCK(&logchannels);
1358
1359         return AST_LOGGER_SUCCESS;
1360 }
1361
1362 static char *handle_logger_add_channel(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1363 {
1364         switch (cmd) {
1365         case CLI_INIT:
1366                 e->command = "logger add channel";
1367                 e->usage =
1368                         "Usage: logger add channel <name> <levels>\n"
1369                         "       Adds a temporary logger channel. This logger channel\n"
1370                         "       will exist until removed or until Asterisk is restarted.\n"
1371                         "       <levels> is a comma-separated list of desired logger\n"
1372                         "       levels such as: verbose,warning,error\n"
1373                         "       An optional formatter may be specified with the levels;\n"
1374                         "       valid values are '[json]' and '[default]'.\n";
1375                 return NULL;
1376         case CLI_GENERATE:
1377                 return NULL;
1378         }
1379
1380         if (a->argc < 5) {
1381                 return CLI_SHOWUSAGE;
1382         }
1383
1384         switch (ast_logger_create_channel(a->argv[3], a->argv[4])) {
1385         case AST_LOGGER_SUCCESS:
1386                 return CLI_SUCCESS;
1387         case AST_LOGGER_FAILURE:
1388                 ast_cli(a->fd, "Logger channel '%s' already exists\n", a->argv[3]);
1389                 return CLI_SUCCESS;
1390         case AST_LOGGER_DECLINE:
1391         case AST_LOGGER_ALLOC_ERROR:
1392         default:
1393                 ast_cli(a->fd, "ERROR: Unable to create log channel '%s'\n", a->argv[3]);
1394                 return CLI_FAILURE;
1395         }
1396 }
1397
1398 int ast_logger_remove_channel(const char *log_channel)
1399 {
1400         struct logchannel *chan;
1401
1402         AST_RWLIST_WRLOCK(&logchannels);
1403
1404         chan = find_logchannel(log_channel);
1405         if (chan && chan->dynamic) {
1406                 AST_RWLIST_REMOVE(&logchannels, chan, list);
1407         } else {
1408                 AST_RWLIST_UNLOCK(&logchannels);
1409                 return AST_LOGGER_FAILURE;
1410         }
1411         AST_RWLIST_UNLOCK(&logchannels);
1412
1413         if (chan->fileptr) {
1414                 fclose(chan->fileptr);
1415                 chan->fileptr = NULL;
1416         }
1417         ast_free(chan);
1418         chan = NULL;
1419
1420         return AST_LOGGER_SUCCESS;
1421 }
1422
1423 static char *handle_logger_remove_channel(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1424 {
1425         struct logchannel *chan;
1426         int gen_count = 0;
1427         char *gen_ret = NULL;
1428
1429         switch (cmd) {
1430         case CLI_INIT:
1431                 e->command = "logger remove channel";
1432                 e->usage =
1433                         "Usage: logger remove channel <name>\n"
1434                         "       Removes a temporary logger channel.\n";
1435                 return NULL;
1436         case CLI_GENERATE:
1437                 if (a->argc > 4 || (a->argc == 4 && a->pos > 3)) {
1438                         return NULL;
1439                 }
1440                 AST_RWLIST_RDLOCK(&logchannels);
1441                 AST_RWLIST_TRAVERSE(&logchannels, chan, list) {
1442                         if (chan->dynamic && (ast_strlen_zero(a->argv[3])
1443                                 || !strncmp(a->argv[3], chan->filename, strlen(a->argv[3])))) {
1444                                 if (gen_count == a->n) {
1445                                         gen_ret = ast_strdup(chan->filename);
1446                                         break;
1447                                 }
1448                                 gen_count++;
1449                         }
1450                 }
1451                 AST_RWLIST_UNLOCK(&logchannels);
1452                 return gen_ret;
1453         }
1454
1455         if (a->argc < 4) {
1456                 return CLI_SHOWUSAGE;
1457         }
1458
1459         switch (ast_logger_remove_channel(a->argv[3])) {
1460         case AST_LOGGER_SUCCESS:
1461                 ast_cli(a->fd, "Removed dynamic logger channel '%s'\n", a->argv[3]);
1462                 return CLI_SUCCESS;
1463         case AST_LOGGER_FAILURE:
1464                 ast_cli(a->fd, "Unable to find dynamic logger channel '%s'\n", a->argv[3]);
1465                 return CLI_SUCCESS;
1466         default:
1467                 ast_cli(a->fd, "Internal failure attempting to delete dynamic logger channel '%s'\n", a->argv[3]);
1468                 return CLI_FAILURE;
1469         }
1470 }
1471
1472 static struct ast_cli_entry cli_logger[] = {
1473         AST_CLI_DEFINE(handle_logger_show_channels, "List configured log channels"),
1474         AST_CLI_DEFINE(handle_logger_reload, "Reopens the log files"),
1475         AST_CLI_DEFINE(handle_logger_rotate, "Rotates and reopens the log files"),
1476         AST_CLI_DEFINE(handle_logger_set_level, "Enables/Disables a specific logging level for this console"),
1477         AST_CLI_DEFINE(handle_logger_add_channel, "Adds a new logging channel"),
1478         AST_CLI_DEFINE(handle_logger_remove_channel, "Removes a logging channel"),
1479 };
1480
1481 static void _handle_SIGXFSZ(int sig)
1482 {
1483         /* Indicate need to reload */
1484         filesize_reload_needed = 1;
1485 }
1486
1487 static struct sigaction handle_SIGXFSZ = {
1488         .sa_handler = _handle_SIGXFSZ,
1489         .sa_flags = SA_RESTART,
1490 };
1491
1492 /*! \brief Print a normal log message to the channels */
1493 static void logger_print_normal(struct logmsg *logmsg)
1494 {
1495         struct logchannel *chan = NULL;
1496         char buf[BUFSIZ];
1497         int level = 0;
1498
1499         AST_RWLIST_RDLOCK(&logchannels);
1500         if (!AST_RWLIST_EMPTY(&logchannels)) {
1501                 AST_RWLIST_TRAVERSE(&logchannels, chan, list) {
1502
1503                         /* If the channel is disabled, then move on to the next one */
1504                         if (chan->disabled) {
1505                                 continue;
1506                         }
1507                         if (logmsg->level == __LOG_VERBOSE
1508                                 && (((chan->verbosity < 0) ? option_verbose : chan->verbosity)) < level) {
1509                                 continue;
1510                         }
1511
1512                         if (!(chan->logmask & (1 << logmsg->level))) {
1513                                 continue;
1514                         }
1515
1516                         switch (chan->type) {
1517                         case LOGTYPE_SYSLOG:
1518                                 {
1519                                         int syslog_level = ast_syslog_priority_from_loglevel(logmsg->level);
1520
1521                                         if (syslog_level < 0) {
1522                                                 /* we are locked here, so cannot ast_log() */
1523                                                 fprintf(stderr, "ast_log_vsyslog called with bogus level: %d\n", logmsg->level);
1524                                                 continue;
1525                                         }
1526
1527                                         /* Don't use LOG_MAKEPRI because it's broken in glibc<2.17 */
1528                                         syslog_level = chan->facility | syslog_level; /* LOG_MAKEPRI(chan->facility, syslog_level); */
1529                                         if (!chan->formatter.format_log(chan, logmsg, buf, BUFSIZ)) {
1530                                                 syslog(syslog_level, "%s", buf);
1531                                         }
1532                                 }
1533                                 break;
1534                         case LOGTYPE_CONSOLE:
1535                                 if (!chan->formatter.format_log(chan, logmsg, buf, BUFSIZ)) {
1536                                         ast_console_puts_mutable_full(buf, logmsg->level, logmsg->sublevel);
1537                                 }
1538                                 break;
1539                         case LOGTYPE_FILE:
1540                                 {
1541                                         int res = 0;
1542
1543                                         if (!chan->fileptr) {
1544                                                 continue;
1545                                         }
1546
1547                                         if (chan->formatter.format_log(chan, logmsg, buf, BUFSIZ)) {
1548                                                 continue;
1549                                         }
1550
1551                                         /* Print out to the file */
1552                                         res = fprintf(chan->fileptr, "%s", buf);
1553                                         if (res > 0) {
1554                                                 fflush(chan->fileptr);
1555                                         } else if (res <= 0 && !ast_strlen_zero(logmsg->message)) {
1556                                                 fprintf(stderr, "**** Asterisk Logging Error: ***********\n");
1557                                                 if (errno == ENOMEM || errno == ENOSPC) {
1558                                                         fprintf(stderr, "Asterisk logging error: Out of disk space, can't log to log file %s\n", chan->filename);
1559                                                 } else {
1560                                                         fprintf(stderr, "Logger Warning: Unable to write to log file '%s': %s (disabled)\n", chan->filename, strerror(errno));
1561                                                 }
1562
1563                                                 /*** DOCUMENTATION
1564                                                         <managerEventInstance>
1565                                                                 <synopsis>Raised when a logging channel is disabled.</synopsis>
1566                                                                 <syntax>
1567                                                                         <parameter name="Channel">
1568                                                                                 <para>The name of the logging channel.</para>
1569                                                                         </parameter>
1570                                                                 </syntax>
1571                                                         </managerEventInstance>
1572                                                 ***/
1573                                                 manager_event(EVENT_FLAG_SYSTEM, "LogChannel", "Channel: %s\r\nEnabled: No\r\nReason: %d - %s\r\n", chan->filename, errno, strerror(errno));
1574                                                 chan->disabled = 1;
1575                                         }
1576                                 }
1577                                 break;
1578                         }
1579                 }
1580         } else if (logmsg->level != __LOG_VERBOSE || option_verbose >= logmsg->sublevel) {
1581                 fputs(logmsg->message, stdout);
1582         }
1583
1584         AST_RWLIST_UNLOCK(&logchannels);
1585
1586         /* If we need to reload because of the file size, then do so */
1587         if (filesize_reload_needed) {
1588                 reload_logger(-1, NULL);
1589                 ast_verb(1, "Rotated Logs Per SIGXFSZ (Exceeded file size limit)\n");
1590         }
1591
1592         return;
1593 }
1594
1595 static struct logmsg * __attribute__((format(printf, 7, 0))) format_log_message_ap(int level,
1596         int sublevel, const char *file, int line, const char *function, ast_callid callid,
1597         const char *fmt, va_list ap)
1598 {
1599         struct logmsg *logmsg = NULL;
1600         struct ast_str *buf = NULL;
1601         struct ast_tm tm;
1602         struct timeval now = ast_tvnow();
1603         int res = 0;
1604         char datestring[256];
1605
1606         if (!(buf = ast_str_thread_get(&log_buf, LOG_BUF_INIT_SIZE))) {
1607                 return NULL;
1608         }
1609
1610         /* Build string */
1611         res = ast_str_set_va(&buf, BUFSIZ, fmt, ap);
1612
1613         /* If the build failed, then abort and free this structure */
1614         if (res == AST_DYNSTR_BUILD_FAILED) {
1615                 return NULL;
1616         }
1617
1618         /* Create a new logging message */
1619         if (!(logmsg = ast_calloc_with_stringfields(1, struct logmsg, res + 128))) {
1620                 return NULL;
1621         }
1622
1623         /* Copy string over */
1624         ast_string_field_set(logmsg, message, ast_str_buffer(buf));
1625
1626         /* Set type */
1627         if (level == __LOG_VERBOSE) {
1628                 logmsg->type = LOGMSG_VERBOSE;
1629         } else {
1630                 logmsg->type = LOGMSG_NORMAL;
1631         }
1632
1633         if (display_callids && callid) {
1634                 logmsg->callid = callid;
1635         }
1636
1637         /* Create our date/time */
1638         ast_localtime(&now, &tm, NULL);
1639         ast_strftime(datestring, sizeof(datestring), dateformat, &tm);
1640         ast_string_field_set(logmsg, date, datestring);
1641
1642         /* Copy over data */
1643         logmsg->level = level;
1644         logmsg->sublevel = sublevel;
1645         logmsg->line = line;
1646         ast_string_field_set(logmsg, level_name, levels[level]);
1647         ast_string_field_set(logmsg, file, file);
1648         ast_string_field_set(logmsg, function, function);
1649         logmsg->lwp = ast_get_tid();
1650
1651         return logmsg;
1652 }
1653
1654 static struct logmsg * __attribute__((format(printf, 7, 0))) format_log_message(int level,
1655         int sublevel, const char *file, int line, const char *function, ast_callid callid,
1656         const char *fmt, ...)
1657 {
1658         struct logmsg *logmsg;
1659         va_list ap;
1660
1661         va_start(ap, fmt);
1662         logmsg = format_log_message_ap(level, sublevel, file, line, function, callid, fmt, ap);
1663         va_end(ap);
1664
1665         return logmsg;
1666 }
1667
1668 /*! \brief Actual logging thread */
1669 static void *logger_thread(void *data)
1670 {
1671         struct logmsg *next = NULL, *msg = NULL;
1672
1673         for (;;) {
1674                 /* We lock the message list, and see if any message exists... if not we wait on the condition to be signalled */
1675                 AST_LIST_LOCK(&logmsgs);
1676                 if (AST_LIST_EMPTY(&logmsgs)) {
1677                         if (close_logger_thread) {
1678                                 AST_LIST_UNLOCK(&logmsgs);
1679                                 break;
1680                         } else {
1681                                 ast_cond_wait(&logcond, &logmsgs.lock);
1682                         }
1683                 }
1684
1685                 if (high_water_alert) {
1686                         msg = format_log_message(__LOG_WARNING, 0, "logger", 0, "***", 0,
1687                                 "Logging resumed.  %d message%s discarded.\n",
1688                                 logger_messages_discarded, logger_messages_discarded == 1 ? "" : "s");
1689                         if (msg) {
1690                                 AST_LIST_INSERT_TAIL(&logmsgs, msg, list);
1691                         }
1692                         high_water_alert = 0;
1693                         logger_messages_discarded = 0;
1694                 }
1695
1696                 next = AST_LIST_FIRST(&logmsgs);
1697                 AST_LIST_HEAD_INIT_NOLOCK(&logmsgs);
1698                 logger_queue_size = 0;
1699                 AST_LIST_UNLOCK(&logmsgs);
1700
1701                 /* Otherwise go through and process each message in the order added */
1702                 while ((msg = next)) {
1703                         /* Get the next entry now so that we can free our current structure later */
1704                         next = AST_LIST_NEXT(msg, list);
1705
1706                         /* Depending on the type, send it to the proper function */
1707                         logger_print_normal(msg);
1708
1709                         /* Free the data since we are done */
1710                         logmsg_free(msg);
1711                 }
1712         }
1713
1714         return NULL;
1715 }
1716
1717 /*!
1718  * \internal
1719  * \brief Initialize the logger queue.
1720  *
1721  * \note Assumes logchannels is write locked on entry.
1722  *
1723  * \return Nothing
1724  */
1725 static void logger_queue_init(void)
1726 {
1727         ast_unload_realtime("queue_log");
1728         if (logfiles.queue_log) {
1729                 char qfname[PATH_MAX];
1730
1731                 if (logger_queue_rt_start()) {
1732                         return;
1733                 }
1734
1735                 /* Open the log file. */
1736                 snprintf(qfname, sizeof(qfname), "%s/%s", ast_config_AST_LOG_DIR,
1737                         queue_log_name);
1738                 if (qlog) {
1739                         /* Just in case it was already open. */
1740                         fclose(qlog);
1741                 }
1742                 qlog = fopen(qfname, "a");
1743                 if (!qlog) {
1744                         ast_log(LOG_ERROR, "Unable to create queue log: %s\n", strerror(errno));
1745                 }
1746         }
1747 }
1748
1749 int ast_is_logger_initialized(void)
1750 {
1751         return logger_initialized;
1752 }
1753
1754 /*!
1755  * \brief Start the ast_queue_log() logger.
1756  *
1757  * \note Called when the system is fully booted after startup
1758  * so preloaded realtime modules can get up.
1759  *
1760  * \return Nothing
1761  */
1762 void logger_queue_start(void)
1763 {
1764         /* Must not be called before the logger is initialized. */
1765         ast_assert(logger_initialized);
1766
1767         AST_RWLIST_WRLOCK(&logchannels);
1768         if (!queuelog_init) {
1769                 logger_queue_init();
1770                 queuelog_init = 1;
1771                 AST_RWLIST_UNLOCK(&logchannels);
1772                 ast_queue_log("NONE", "NONE", "NONE", "QUEUESTART", "%s", "");
1773         } else {
1774                 AST_RWLIST_UNLOCK(&logchannels);
1775         }
1776 }
1777
1778 int init_logger(void)
1779 {
1780         int res;
1781         /* auto rotate if sig SIGXFSZ comes a-knockin */
1782         sigaction(SIGXFSZ, &handle_SIGXFSZ, NULL);
1783
1784         /* Re-initialize the logmsgs mutex.  The recursive mutex can be accessed prior
1785          * to Asterisk being forked into the background, which can cause the thread
1786          * ID tracked by the underlying pthread mutex to be different than the ID of
1787          * the thread that unlocks the mutex.  Since init_logger is called after the
1788          * fork, it is safe to initialize the mutex here for future accesses.
1789          */
1790         ast_mutex_destroy(&logmsgs.lock);
1791         ast_mutex_init(&logmsgs.lock);
1792         ast_cond_init(&logcond, NULL);
1793
1794         /* start logger thread */
1795         if (ast_pthread_create(&logthread, NULL, logger_thread, NULL) < 0) {
1796                 ast_cond_destroy(&logcond);
1797                 return -1;
1798         }
1799
1800         /* register the logger cli commands */
1801         ast_cli_register_multiple(cli_logger, ARRAY_LEN(cli_logger));
1802
1803         ast_mkdir(ast_config_AST_LOG_DIR, 0777);
1804
1805         /* create log channels */
1806         AST_RWLIST_WRLOCK(&logchannels);
1807         res = init_logger_chain(NULL);
1808         AST_RWLIST_UNLOCK(&logchannels);
1809         ast_verb_update();
1810         logger_initialized = 1;
1811         if (res) {
1812                 ast_log(LOG_ERROR, "Errors detected in logger.conf.  Default console logging is being used.\n");
1813         }
1814
1815         return 0;
1816 }
1817
1818 void close_logger(void)
1819 {
1820         struct logchannel *f = NULL;
1821
1822         ast_cli_unregister_multiple(cli_logger, ARRAY_LEN(cli_logger));
1823
1824         logger_initialized = 0;
1825
1826         /* Stop logger thread */
1827         AST_LIST_LOCK(&logmsgs);
1828         close_logger_thread = 1;
1829         ast_cond_signal(&logcond);
1830         AST_LIST_UNLOCK(&logmsgs);
1831
1832         if (logthread != AST_PTHREADT_NULL) {
1833                 pthread_join(logthread, NULL);
1834         }
1835
1836         AST_RWLIST_WRLOCK(&logchannels);
1837
1838         if (qlog) {
1839                 fclose(qlog);
1840                 qlog = NULL;
1841         }
1842
1843         while ((f = AST_LIST_REMOVE_HEAD(&logchannels, list))) {
1844                 if (f->fileptr && (f->fileptr != stdout) && (f->fileptr != stderr)) {
1845                         fclose(f->fileptr);
1846                         f->fileptr = NULL;
1847                 }
1848                 ast_free(f);
1849         }
1850
1851         closelog(); /* syslog */
1852
1853         AST_RWLIST_UNLOCK(&logchannels);
1854 }
1855
1856 void ast_callid_strnprint(char *buffer, size_t buffer_size, ast_callid callid)
1857 {
1858         snprintf(buffer, buffer_size, "[C-%08x]", callid);
1859 }
1860
1861 ast_callid ast_create_callid(void)
1862 {
1863         return ast_atomic_fetchadd_int(&next_unique_callid, +1);
1864 }
1865
1866 ast_callid ast_read_threadstorage_callid(void)
1867 {
1868         ast_callid *callid;
1869
1870         callid = ast_threadstorage_get(&unique_callid, sizeof(*callid));
1871
1872         return callid ? *callid : 0;
1873 }
1874
1875 int ast_callid_threadassoc_change(ast_callid callid)
1876 {
1877         ast_callid *id = ast_threadstorage_get(&unique_callid, sizeof(*id));
1878
1879         if (!id) {
1880                 return -1;
1881         }
1882
1883         *id = callid;
1884
1885         return 0;
1886 }
1887
1888 int ast_callid_threadassoc_add(ast_callid callid)
1889 {
1890         ast_callid *pointing;
1891
1892         pointing = ast_threadstorage_get(&unique_callid, sizeof(*pointing));
1893         if (!pointing) {
1894                 return -1;
1895         }
1896
1897         if (*pointing) {
1898                 ast_log(LOG_ERROR, "ast_callid_threadassoc_add(C-%08x) on thread "
1899                         "already associated with callid [C-%08x].\n", callid, *pointing);
1900                 return 1;
1901         }
1902
1903         *pointing = callid;
1904         return 0;
1905 }
1906
1907 int ast_callid_threadassoc_remove(void)
1908 {
1909         ast_callid *pointing;
1910
1911         pointing = ast_threadstorage_get(&unique_callid, sizeof(*pointing));
1912         if (!pointing) {
1913                 return -1;
1914         }
1915
1916         if (*pointing) {
1917                 *pointing = 0;
1918                 return 0;
1919         }
1920
1921         return -1;
1922 }
1923
1924 int ast_callid_threadstorage_auto(ast_callid *callid)
1925 {
1926         ast_callid tmp;
1927
1928         /* Start by trying to see if a callid is available from thread storage */
1929         tmp = ast_read_threadstorage_callid();
1930         if (tmp) {
1931                 *callid = tmp;
1932                 return 0;
1933         }
1934
1935         /* If that failed, try to create a new one and bind it. */
1936         *callid = ast_create_callid();
1937         if (*callid) {
1938                 ast_callid_threadassoc_add(*callid);
1939                 return 1;
1940         }
1941
1942         /* If neither worked, then something must have gone wrong. */
1943         return -1;
1944 }
1945
1946 void ast_callid_threadstorage_auto_clean(ast_callid callid, int callid_created)
1947 {
1948         if (callid && callid_created) {
1949                 /* If the callid was created rather than simply grabbed from the thread storage, we need to unbind here. */
1950                 ast_callid_threadassoc_remove();
1951         }
1952 }
1953
1954 /*!
1955  * \brief send log messages to syslog and/or the console
1956  */
1957 static void __attribute__((format(printf, 7, 0))) ast_log_full(int level, int sublevel,
1958         const char *file, int line, const char *function, ast_callid callid,
1959         const char *fmt, va_list ap)
1960 {
1961         struct logmsg *logmsg = NULL;
1962
1963         if (level == __LOG_VERBOSE && ast_opt_remote && ast_opt_exec) {
1964                 return;
1965         }
1966
1967         AST_LIST_LOCK(&logmsgs);
1968         if (logger_queue_size >= logger_queue_limit && !close_logger_thread) {
1969                 logger_messages_discarded++;
1970                 if (!high_water_alert && !close_logger_thread) {
1971                         logmsg = format_log_message(__LOG_WARNING, 0, "logger", 0, "***", 0,
1972                                 "Log queue threshold (%d) exceeded.  Discarding new messages.\n", logger_queue_limit);
1973                         AST_LIST_INSERT_TAIL(&logmsgs, logmsg, list);
1974                         high_water_alert = 1;
1975                         ast_cond_signal(&logcond);
1976                 }
1977                 AST_LIST_UNLOCK(&logmsgs);
1978                 return;
1979         }
1980         AST_LIST_UNLOCK(&logmsgs);
1981
1982         logmsg = format_log_message_ap(level, sublevel, file, line, function, callid, fmt, ap);
1983         if (!logmsg) {
1984                 return;
1985         }
1986
1987         /* If the logger thread is active, append it to the tail end of the list - otherwise skip that step */
1988         if (logthread != AST_PTHREADT_NULL) {
1989                 AST_LIST_LOCK(&logmsgs);
1990                 if (close_logger_thread) {
1991                         /* Logger is either closing or closed.  We cannot log this message. */
1992                         logmsg_free(logmsg);
1993                 } else {
1994                         AST_LIST_INSERT_TAIL(&logmsgs, logmsg, list);
1995                         logger_queue_size++;
1996                         ast_cond_signal(&logcond);
1997                 }
1998                 AST_LIST_UNLOCK(&logmsgs);
1999         } else {
2000                 logger_print_normal(logmsg);
2001                 logmsg_free(logmsg);
2002         }
2003 }
2004
2005 void ast_log(int level, const char *file, int line, const char *function, const char *fmt, ...)
2006 {
2007         ast_callid callid;
2008         va_list ap;
2009
2010         callid = ast_read_threadstorage_callid();
2011
2012         va_start(ap, fmt);
2013         if (level == __LOG_VERBOSE) {
2014                 __ast_verbose_ap(file, line, function, 0, callid, fmt, ap);
2015         } else {
2016                 ast_log_full(level, -1, file, line, function, callid, fmt, ap);
2017         }
2018         va_end(ap);
2019 }
2020
2021 void ast_log_safe(int level, const char *file, int line, const char *function, const char *fmt, ...)
2022 {
2023         va_list ap;
2024         void *recursed = ast_threadstorage_get_ptr(&in_safe_log);
2025         ast_callid callid;
2026
2027         if (recursed) {
2028                 return;
2029         }
2030
2031         if (ast_threadstorage_set_ptr(&in_safe_log, (void*)1)) {
2032                 /* We've failed to set the flag that protects against
2033                  * recursion, so bail. */
2034                 return;
2035         }
2036
2037         callid = ast_read_threadstorage_callid();
2038
2039         va_start(ap, fmt);
2040         ast_log_full(level, -1, file, line, function, callid, fmt, ap);
2041         va_end(ap);
2042
2043         /* Clear flag so the next allocation failure can be logged. */
2044         ast_threadstorage_set_ptr(&in_safe_log, NULL);
2045 }
2046
2047 void ast_log_callid(int level, const char *file, int line, const char *function, ast_callid callid, const char *fmt, ...)
2048 {
2049         va_list ap;
2050         va_start(ap, fmt);
2051         ast_log_full(level, -1, file, line, function, callid, fmt, ap);
2052         va_end(ap);
2053 }
2054
2055
2056 void ast_log_backtrace(void)
2057 {
2058 #ifdef HAVE_BKTR
2059         struct ast_bt *bt;
2060         int i = 0;
2061         char **strings;
2062
2063         if (!(bt = ast_bt_create())) {
2064                 ast_log(LOG_WARNING, "Unable to allocate space for backtrace structure\n");
2065                 return;
2066         }
2067
2068         if ((strings = ast_bt_get_symbols(bt->addresses, bt->num_frames))) {
2069                 ast_verbose("Got %d backtrace record%c\n", bt->num_frames, bt->num_frames != 1 ? 's' : ' ');
2070                 for (i = 3; i < bt->num_frames - 2; i++) {
2071                         ast_verbose("#%d: [%p] %s\n", i - 3, bt->addresses[i], strings[i]);
2072                 }
2073
2074                 ast_std_free(strings);
2075         } else {
2076                 ast_verbose("Could not allocate memory for backtrace\n");
2077         }
2078         ast_bt_destroy(bt);
2079 #else
2080         ast_log(LOG_WARNING, "Must run configure with '--with-execinfo' for stack backtraces.\n");
2081 #endif /* defined(HAVE_BKTR) */
2082 }
2083
2084 void __ast_verbose_ap(const char *file, int line, const char *func, int level, ast_callid callid, const char *fmt, va_list ap)
2085 {
2086         ast_log_full(__LOG_VERBOSE, level, file, line, func, callid, fmt, ap);
2087 }
2088
2089 void __ast_verbose(const char *file, int line, const char *func, int level, const char *fmt, ...)
2090 {
2091         ast_callid callid;
2092         va_list ap;
2093
2094         callid = ast_read_threadstorage_callid();
2095
2096         va_start(ap, fmt);
2097         __ast_verbose_ap(file, line, func, level, callid, fmt, ap);
2098         va_end(ap);
2099 }
2100
2101 void __ast_verbose_callid(const char *file, int line, const char *func, int level, ast_callid callid, const char *fmt, ...)
2102 {
2103         va_list ap;
2104         va_start(ap, fmt);
2105         __ast_verbose_ap(file, line, func, level, callid, fmt, ap);
2106         va_end(ap);
2107 }
2108
2109 /*! Console verbosity level node. */
2110 struct verb_console {
2111         /*! List node link */
2112         AST_LIST_ENTRY(verb_console) node;
2113         /*! Console verbosity level. */
2114         int *level;
2115 };
2116
2117 /*! Registered console verbosity levels */
2118 static AST_RWLIST_HEAD_STATIC(verb_consoles, verb_console);
2119
2120 /*! ast_verb_update() reentrancy protection lock. */
2121 AST_MUTEX_DEFINE_STATIC(verb_update_lock);
2122
2123 void ast_verb_update(void)
2124 {
2125         struct logchannel *log;
2126         struct verb_console *console;
2127         int verb_level;
2128
2129         ast_mutex_lock(&verb_update_lock);
2130
2131         AST_RWLIST_RDLOCK(&verb_consoles);
2132
2133         /* Default to the root console verbosity. */
2134         verb_level = option_verbose;
2135
2136         /* Determine max remote console level. */
2137         AST_LIST_TRAVERSE(&verb_consoles, console, node) {
2138                 if (verb_level < *console->level) {
2139                         verb_level = *console->level;
2140                 }
2141         }
2142         AST_RWLIST_UNLOCK(&verb_consoles);
2143
2144         /* Determine max logger channel level. */
2145         AST_RWLIST_RDLOCK(&logchannels);
2146         AST_RWLIST_TRAVERSE(&logchannels, log, list) {
2147                 if (verb_level < log->verbosity) {
2148                         verb_level = log->verbosity;
2149                 }
2150         }
2151         AST_RWLIST_UNLOCK(&logchannels);
2152
2153         ast_verb_sys_level = verb_level;
2154
2155         ast_mutex_unlock(&verb_update_lock);
2156 }
2157
2158 /*!
2159  * \internal
2160  * \brief Unregister a console verbose level.
2161  *
2162  * \param console Which console to unregister.
2163  *
2164  * \return Nothing
2165  */
2166 static void verb_console_unregister(struct verb_console *console)
2167 {
2168         AST_RWLIST_WRLOCK(&verb_consoles);
2169         console = AST_RWLIST_REMOVE(&verb_consoles, console, node);
2170         AST_RWLIST_UNLOCK(&verb_consoles);
2171         if (console) {
2172                 ast_verb_update();
2173         }
2174 }
2175
2176 static void verb_console_free(void *v_console)
2177 {
2178         struct verb_console *console = v_console;
2179
2180         verb_console_unregister(console);
2181         ast_free(console);
2182 }
2183
2184 /*! Thread specific console verbosity level node. */
2185 AST_THREADSTORAGE_CUSTOM(my_verb_console, NULL, verb_console_free);
2186
2187 void ast_verb_console_register(int *level)
2188 {
2189         struct verb_console *console;
2190
2191         console = ast_threadstorage_get(&my_verb_console, sizeof(*console));
2192         if (!console || !level) {
2193                 return;
2194         }
2195         console->level = level;
2196
2197         AST_RWLIST_WRLOCK(&verb_consoles);
2198         AST_RWLIST_INSERT_HEAD(&verb_consoles, console, node);
2199         AST_RWLIST_UNLOCK(&verb_consoles);
2200         ast_verb_update();
2201 }
2202
2203 void ast_verb_console_unregister(void)
2204 {
2205         struct verb_console *console;
2206
2207         console = ast_threadstorage_get(&my_verb_console, sizeof(*console));
2208         if (!console) {
2209                 return;
2210         }
2211         verb_console_unregister(console);
2212 }
2213
2214 int ast_verb_console_get(void)
2215 {
2216         struct verb_console *console;
2217         int verb_level;
2218
2219         console = ast_threadstorage_get(&my_verb_console, sizeof(*console));
2220         AST_RWLIST_RDLOCK(&verb_consoles);
2221         if (!console) {
2222                 verb_level = 0;
2223         } else if (console->level) {
2224                 verb_level = *console->level;
2225         } else {
2226                 verb_level = option_verbose;
2227         }
2228         AST_RWLIST_UNLOCK(&verb_consoles);
2229         return verb_level;
2230 }
2231
2232 void ast_verb_console_set(int verb_level)
2233 {
2234         struct verb_console *console;
2235
2236         console = ast_threadstorage_get(&my_verb_console, sizeof(*console));
2237         if (!console) {
2238                 return;
2239         }
2240
2241         AST_RWLIST_WRLOCK(&verb_consoles);
2242         if (console->level) {
2243                 *console->level = verb_level;
2244         } else {
2245                 option_verbose = verb_level;
2246         }
2247         AST_RWLIST_UNLOCK(&verb_consoles);
2248         ast_verb_update();
2249 }
2250
2251 static void update_logchannels(void)
2252 {
2253         struct logchannel *cur;
2254
2255         AST_RWLIST_WRLOCK(&logchannels);
2256
2257         global_logmask = 0;
2258
2259         AST_RWLIST_TRAVERSE(&logchannels, cur, list) {
2260                 make_components(cur);
2261                 global_logmask |= cur->logmask;
2262         }
2263
2264         AST_RWLIST_UNLOCK(&logchannels);
2265 }
2266
2267 int ast_logger_register_level(const char *name)
2268 {
2269         unsigned int level;
2270         unsigned int available = 0;
2271
2272         AST_RWLIST_WRLOCK(&logchannels);
2273
2274         for (level = 0; level < ARRAY_LEN(levels); level++) {
2275                 if ((level >= 16) && !available && !levels[level]) {
2276                         available = level;
2277                         continue;
2278                 }
2279
2280                 if (levels[level] && !strcasecmp(levels[level], name)) {
2281                         ast_log(LOG_WARNING,
2282                                 "Unable to register dynamic logger level '%s': a standard logger level uses that name.\n",
2283                                 name);
2284                         AST_RWLIST_UNLOCK(&logchannels);
2285
2286                         return -1;
2287                 }
2288         }
2289
2290         if (!available) {
2291                 ast_log(LOG_WARNING,
2292                         "Unable to register dynamic logger level '%s'; maximum number of levels registered.\n",
2293                         name);
2294                 AST_RWLIST_UNLOCK(&logchannels);
2295
2296                 return -1;
2297         }
2298
2299         levels[available] = ast_strdup(name);
2300
2301         AST_RWLIST_UNLOCK(&logchannels);
2302
2303         ast_debug(1, "Registered dynamic logger level '%s' with index %u.\n", name, available);
2304
2305         update_logchannels();
2306
2307         return available;
2308 }
2309
2310 void ast_logger_unregister_level(const char *name)
2311 {
2312         unsigned int found = 0;
2313         unsigned int x;
2314
2315         AST_RWLIST_WRLOCK(&logchannels);
2316
2317         for (x = 16; x < ARRAY_LEN(levels); x++) {
2318                 if (!levels[x]) {
2319                         continue;
2320                 }
2321
2322                 if (strcasecmp(levels[x], name)) {
2323                         continue;
2324                 }
2325
2326                 found = 1;
2327                 break;
2328         }
2329
2330         if (found) {
2331                 /* take this level out of the global_logmask, to ensure that no new log messages
2332                  * will be queued for it
2333                  */
2334
2335                 global_logmask &= ~(1 << x);
2336
2337                 ast_free(levels[x]);
2338                 levels[x] = NULL;
2339                 AST_RWLIST_UNLOCK(&logchannels);
2340
2341                 ast_debug(1, "Unregistered dynamic logger level '%s' with index %u.\n", name, x);
2342
2343                 update_logchannels();
2344         } else {
2345                 AST_RWLIST_UNLOCK(&logchannels);
2346         }
2347 }
2348
2349 const char *ast_logger_get_dateformat(void)
2350 {
2351         return dateformat;
2352 }
2353
2354 void ast_logger_set_queue_limit(int queue_limit)
2355 {
2356         logger_queue_limit = queue_limit;
2357 }
2358
2359 int ast_logger_get_queue_limit(void)
2360 {
2361         return logger_queue_limit;
2362 }
2363
2364 static int reload_module(void)
2365 {
2366         return reload_logger(0, NULL);
2367 }
2368
2369 static int unload_module(void)
2370 {
2371         return 0;
2372 }
2373
2374 static int load_module(void)
2375 {
2376         return AST_MODULE_LOAD_SUCCESS;
2377 }
2378
2379 /* Logger is initialized separate from the module loader, only reload_module does anything. */
2380 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER, "Logger",
2381         .support_level = AST_MODULE_SUPPORT_CORE,
2382         .load = load_module,
2383         .unload = unload_module,
2384         /* This reload does not support realtime so it does not require "extconfig". */
2385         .reload = reload_module,
2386         .load_pri = 0,
2387 );