00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014 #include <signal.h>
00015 #include <stdarg.h>
00016 #include <stdio.h>
00017 #include <unistd.h>
00018 #include <time.h>
00019 #include <asterisk/lock.h>
00020 #include <asterisk/options.h>
00021 #include <asterisk/channel.h>
00022 #include <asterisk/config.h>
00023 #include <asterisk/term.h>
00024 #include <asterisk/cli.h>
00025 #include <asterisk/utils.h>
00026 #include <string.h>
00027 #include <stdlib.h>
00028 #include <errno.h>
00029 #include <sys/stat.h>
00030 #include "asterisk.h"
00031 #include "astconf.h"
00032
00033 #define SYSLOG_NAMES
00034
00035 #include <syslog.h>
00036 static int syslog_level_map[] = {
00037 LOG_DEBUG,
00038 LOG_INFO,
00039 LOG_NOTICE,
00040 LOG_WARNING,
00041 LOG_ERR,
00042 LOG_DEBUG
00043 };
00044
00045 #define SYSLOG_NLEVELS 6
00046
00047 #include <asterisk/logger.h>
00048
00049 #define MAX_MSG_QUEUE 200
00050
00051 #if defined(__linux__) && defined (__NR_gettid)
00052 #include <asm/unistd.h>
00053 #define GETTID() syscall(__NR_gettid)
00054 #else
00055 #define GETTID() getpid()
00056 #endif
00057
00058 static char dateformat[256] = "%b %e %T";
00059 AST_MUTEX_DEFINE_STATIC(msglist_lock);
00060 AST_MUTEX_DEFINE_STATIC(loglock);
00061 static int pending_logger_reload = 0;
00062
00063 static struct msglist {
00064 char *msg;
00065 struct msglist *next;
00066 } *list = NULL, *last = NULL;
00067
00068 static char hostname[MAXHOSTNAMELEN];
00069
00070 struct logchannel {
00071 int logmask;
00072 int facility;
00073 int syslog;
00074 int console;
00075 FILE *fileptr;
00076 char filename[256];
00077 struct logchannel *next;
00078 };
00079
00080 static struct logchannel *logchannels = NULL;
00081
00082 static int msgcnt = 0;
00083
00084 static FILE *eventlog = NULL;
00085
00086 static char *levels[] = {
00087 "DEBUG",
00088 "EVENT",
00089 "NOTICE",
00090 "WARNING",
00091 "ERROR",
00092 "VERBOSE"
00093 };
00094
00095 static int colors[] = {
00096 COLOR_BRGREEN,
00097 COLOR_BRBLUE,
00098 COLOR_YELLOW,
00099 COLOR_BRRED,
00100 COLOR_RED,
00101 COLOR_GREEN
00102 };
00103
00104 static int make_components(char *s, int lineno)
00105 {
00106 char *w;
00107 int res = 0;
00108 char *stringp=NULL;
00109 stringp=s;
00110 w = strsep(&stringp, ",");
00111 while(w) {
00112 while(*w && (*w < 33))
00113 w++;
00114 if (!strcasecmp(w, "error"))
00115 res |= (1 << __LOG_ERROR);
00116 else if (!strcasecmp(w, "warning"))
00117 res |= (1 << __LOG_WARNING);
00118 else if (!strcasecmp(w, "notice"))
00119 res |= (1 << __LOG_NOTICE);
00120 else if (!strcasecmp(w, "event"))
00121 res |= (1 << __LOG_EVENT);
00122 else if (!strcasecmp(w, "debug"))
00123 res |= (1 << __LOG_DEBUG);
00124 else if (!strcasecmp(w, "verbose"))
00125 res |= (1 << __LOG_VERBOSE);
00126 else {
00127 fprintf(stderr, "Logfile Warning: Unknown keyword '%s' at line %d of logger.conf\n", w, lineno);
00128 }
00129 w = strsep(&stringp, ",");
00130 }
00131 return res;
00132 }
00133
00134 static struct logchannel *make_logchannel(char *channel, char *components, int lineno)
00135 {
00136 struct logchannel *chan;
00137 char *facility;
00138 CODE *cptr;
00139
00140 if (ast_strlen_zero(channel))
00141 return NULL;
00142 chan = malloc(sizeof(struct logchannel));
00143
00144 if (chan) {
00145 memset(chan, 0, sizeof(struct logchannel));
00146 if (!strcasecmp(channel, "console")) {
00147 chan->console = 1;
00148 } else if (!strncasecmp(channel, "syslog", 6)) {
00149
00150
00151
00152
00153 facility = strchr(channel, '.');
00154 if(!facility++ || !facility) {
00155 facility = "local0";
00156 }
00157
00158
00159
00160
00161 chan->facility = -1;
00162 cptr = facilitynames;
00163 while (cptr->c_name) {
00164 if (!strcasecmp(facility, cptr->c_name)) {
00165 chan->facility = cptr->c_val;
00166 break;
00167 }
00168 cptr++;
00169 }
00170 if (0 > chan->facility) {
00171 fprintf(stderr, "Logger Warning: bad syslog facility in logger.conf\n");
00172 free(chan);
00173 return NULL;
00174 }
00175
00176 chan->syslog = 1;
00177 openlog("asterisk", LOG_PID, chan->facility);
00178 } else {
00179 if (channel[0] == '/') {
00180 if(!ast_strlen_zero(hostname)) {
00181 snprintf(chan->filename, sizeof(chan->filename) - 1,"%s.%s", channel, hostname);
00182 } else {
00183 strncpy(chan->filename, channel, sizeof(chan->filename) - 1);
00184 }
00185 }
00186
00187 if(!ast_strlen_zero(hostname)) {
00188 snprintf(chan->filename, sizeof(chan->filename), "%s/%s.%s",(char *)ast_config_AST_LOG_DIR, channel, hostname);
00189 } else {
00190 snprintf(chan->filename, sizeof(chan->filename), "%s/%s", (char *)ast_config_AST_LOG_DIR, channel);
00191 }
00192 chan->fileptr = fopen(chan->filename, "a");
00193 if (!chan->fileptr) {
00194
00195 fprintf(stderr, "Logger Warning: Unable to open log file '%s': %s\n", chan->filename, strerror(errno));
00196 }
00197 }
00198 chan->logmask = make_components(components, lineno);
00199 }
00200 return chan;
00201 }
00202
00203 static void init_logger_chain(void)
00204 {
00205 struct logchannel *chan, *cur;
00206 struct ast_config *cfg;
00207 struct ast_variable *var;
00208 char *s;
00209
00210
00211 ast_mutex_lock(&loglock);
00212 chan = logchannels;
00213 while (chan) {
00214 cur = chan->next;
00215 free(chan);
00216 chan = cur;
00217 }
00218 logchannels = NULL;
00219 ast_mutex_unlock(&loglock);
00220
00221
00222 closelog();
00223
00224 cfg = ast_load("logger.conf");
00225
00226
00227 if (!cfg)
00228 return;
00229
00230 ast_mutex_lock(&loglock);
00231 if ((s = ast_variable_retrieve(cfg, "general", "appendhostname"))) {
00232 if(ast_true(s)) {
00233 if(gethostname(hostname, sizeof(hostname)-1)) {
00234 strncpy(hostname, "unknown", sizeof(hostname)-1);
00235 ast_log(LOG_WARNING, "What box has no hostname???\n");
00236 }
00237 } else
00238 hostname[0] = '\0';
00239 } else
00240 hostname[0] = '\0';
00241 if ((s = ast_variable_retrieve(cfg, "general", "dateformat"))) {
00242 strncpy(dateformat, s, sizeof(dateformat) - 1);
00243 } else
00244 strncpy(dateformat, "%b %e %T", sizeof(dateformat) - 1);
00245 var = ast_variable_browse(cfg, "logfiles");
00246 while(var) {
00247 chan = make_logchannel(var->name, var->value, var->lineno);
00248 if (chan) {
00249 chan->next = logchannels;
00250 logchannels = chan;
00251 }
00252 var = var->next;
00253 }
00254
00255 ast_destroy(cfg);
00256 ast_mutex_unlock(&loglock);
00257 }
00258
00259 static FILE *qlog = NULL;
00260 AST_MUTEX_DEFINE_STATIC(qloglock);
00261
00262 void ast_queue_log(const char *queuename, const char *callid, const char *agent, const char *event, const char *fmt, ...)
00263 {
00264 va_list ap;
00265 ast_mutex_lock(&qloglock);
00266 if (qlog) {
00267 va_start(ap, fmt);
00268 fprintf(qlog, "%ld|%s|%s|%s|%s|", (long)time(NULL), callid, queuename, agent, event);
00269 vfprintf(qlog, fmt, ap);
00270 fprintf(qlog, "\n");
00271 va_end(ap);
00272 fflush(qlog);
00273 }
00274 ast_mutex_unlock(&qloglock);
00275 }
00276
00277 static void queue_log_init(void)
00278 {
00279 char filename[256];
00280 int reloaded = 0;
00281 ast_mutex_lock(&qloglock);
00282 if (qlog) {
00283 reloaded = 1;
00284 fclose(qlog);
00285 qlog = NULL;
00286 }
00287 snprintf(filename, sizeof(filename), "%s/%s", (char *)ast_config_AST_LOG_DIR, "queue_log");
00288 qlog = fopen(filename, "a");
00289 ast_mutex_unlock(&qloglock);
00290 if (reloaded)
00291 ast_queue_log("NONE", "NONE", "NONE", "CONFIGRELOAD", "%s", "");
00292 else
00293 ast_queue_log("NONE", "NONE", "NONE", "QUEUESTART", "%s", "");
00294 }
00295
00296 int reload_logger(int rotate)
00297 {
00298 char old[AST_CONFIG_MAX_PATH] = "";
00299 char new[AST_CONFIG_MAX_PATH];
00300 struct logchannel *f;
00301 FILE *myf;
00302
00303 int x;
00304 ast_mutex_lock(&loglock);
00305 if (eventlog)
00306 fclose(eventlog);
00307 else
00308 rotate = 0;
00309 eventlog = NULL;
00310
00311
00312
00313 mkdir((char *)ast_config_AST_LOG_DIR, 0755);
00314 snprintf(old, sizeof(old), "%s/%s", (char *)ast_config_AST_LOG_DIR, EVENTLOG);
00315
00316 if(rotate) {
00317 for(x=0;;x++) {
00318 snprintf(new, sizeof(new), "%s/%s.%d", (char *)ast_config_AST_LOG_DIR, EVENTLOG,x);
00319 myf = fopen((char *)new, "r");
00320 if(myf)
00321 fclose(myf);
00322 else
00323 break;
00324 }
00325
00326
00327 if (rename(old,new))
00328 fprintf(stderr, "Unable to rename file '%s' to '%s'\n", old, new);
00329 }
00330
00331 eventlog = fopen(old, "a");
00332
00333 f = logchannels;
00334 while(f) {
00335 if (f->fileptr && (f->fileptr != stdout) && (f->fileptr != stderr)) {
00336 fclose(f->fileptr);
00337 f->fileptr = NULL;
00338 if(rotate) {
00339 strncpy(old, f->filename, sizeof(old) - 1);
00340
00341 for(x=0;;x++) {
00342 snprintf(new, sizeof(new), "%s.%d", f->filename, x);
00343 myf = fopen((char *)new, "r");
00344 if (myf) {
00345 fclose(myf);
00346 } else {
00347 break;
00348 }
00349 }
00350
00351
00352 if (rename(old,new))
00353 fprintf(stderr, "Unable to rename file '%s' to '%s'\n", old, new);
00354 }
00355 }
00356 f = f->next;
00357 }
00358
00359 ast_mutex_unlock(&loglock);
00360
00361 queue_log_init();
00362
00363 if (eventlog) {
00364 init_logger_chain();
00365 ast_log(LOG_EVENT, "Restarted Asterisk Event Logger\n");
00366 if (option_verbose)
00367 ast_verbose("Asterisk Event Logger restarted\n");
00368 return 0;
00369 } else
00370 ast_log(LOG_ERROR, "Unable to create event log: %s\n", strerror(errno));
00371 init_logger_chain();
00372 pending_logger_reload = 0;
00373 return -1;
00374 }
00375
00376 static int handle_logger_reload(int fd, int argc, char *argv[])
00377 {
00378 if(reload_logger(0))
00379 {
00380 ast_cli(fd, "Failed to reloadthe logger\n");
00381 return RESULT_FAILURE;
00382 }
00383 else
00384 return RESULT_SUCCESS;
00385 }
00386
00387 static int handle_logger_rotate(int fd, int argc, char *argv[])
00388 {
00389 if(reload_logger(1))
00390 {
00391 ast_cli(fd, "Failed to reloadthe logger\n");
00392 return RESULT_FAILURE;
00393 }
00394 else
00395 return RESULT_SUCCESS;
00396 }
00397
00398 static struct verb {
00399 void (*verboser)(const char *string, int opos, int replacelast, int complete);
00400 struct verb *next;
00401 } *verboser = NULL;
00402
00403
00404 static char logger_reload_help[] =
00405 "Usage: logger reload\n"
00406 " Reloads the logger subsystem state. Use after restarting syslogd(8)\n";
00407
00408 static char logger_rotate_help[] =
00409 "Usage: logger rotate\n"
00410 " Rotates and Reopens the log files.\n";
00411
00412 static struct ast_cli_entry reload_logger_cli =
00413 { { "logger", "reload", NULL },
00414 handle_logger_reload, "Reopens the log files",
00415 logger_reload_help };
00416
00417 static struct ast_cli_entry rotate_logger_cli =
00418 { { "logger", "rotate", NULL },
00419 handle_logger_rotate, "Rotates and reopens the log files",
00420 logger_rotate_help };
00421
00422 static int handle_SIGXFSZ(int sig)
00423 {
00424
00425 pending_logger_reload = 1;
00426 return 0;
00427 }
00428
00429 int init_logger(void)
00430 {
00431 char tmp[256];
00432
00433
00434 (void) signal(SIGXFSZ,(void *) handle_SIGXFSZ);
00435
00436
00437 ast_cli_register(&reload_logger_cli);
00438 ast_cli_register(&rotate_logger_cli);
00439
00440
00441 queue_log_init();
00442
00443
00444 mkdir((char *)ast_config_AST_LOG_DIR, 0755);
00445 snprintf(tmp, sizeof(tmp), "%s/%s", (char *)ast_config_AST_LOG_DIR, EVENTLOG);
00446 eventlog = fopen((char *)tmp, "a");
00447 if (eventlog) {
00448 init_logger_chain();
00449 ast_log(LOG_EVENT, "Started Asterisk Event Logger\n");
00450 if (option_verbose)
00451 ast_verbose("Asterisk Event Logger Started %s\n",(char *)tmp);
00452 return 0;
00453 } else
00454 ast_log(LOG_ERROR, "Unable to create event log: %s\n", strerror(errno));
00455
00456
00457 init_logger_chain();
00458 return -1;
00459 }
00460
00461 void close_logger(void)
00462 {
00463 struct msglist *m, *tmp;
00464
00465 ast_mutex_lock(&msglist_lock);
00466 m = list;
00467 while(m) {
00468 if (m->msg) {
00469 free(m->msg);
00470 }
00471 tmp = m->next;
00472 free(m);
00473 m = tmp;
00474 }
00475 list = last = NULL;
00476 msgcnt = 0;
00477 ast_mutex_unlock(&msglist_lock);
00478 return;
00479 }
00480
00481 static void strip_coloring(char *str)
00482 {
00483 char *src, *dest, *end;
00484
00485 if (!str)
00486 return;
00487
00488
00489
00490 src = strchr(str, '\033');
00491 if (!src)
00492 return;
00493
00494 dest = src;
00495 while (*src) {
00496
00497 if ((src[1] == '[') && ((end = strchr(src + 2, 'm'))))
00498 src = end + 1;
00499 else
00500 *dest++ = *src++;
00501
00502
00503 while (*src && (*src != '\033'))
00504 *dest++ = *src++;
00505 }
00506
00507 *dest = '\0';
00508 }
00509
00510 static void ast_log_vsyslog(int level, const char *file, int line, const char *function, const char *fmt, va_list args)
00511 {
00512 char buf[BUFSIZ];
00513 char *s;
00514
00515 if (level >= SYSLOG_NLEVELS) {
00516
00517 fprintf(stderr, "ast_log_vsyslog called with bogus level: %d\n", level);
00518 return;
00519 }
00520 if (level == __LOG_VERBOSE) {
00521 snprintf(buf, sizeof(buf), "VERBOSE[%ld]: ", (long)GETTID());
00522 level = __LOG_DEBUG;
00523 } else {
00524 snprintf(buf, sizeof(buf), "%s[%ld]: %s:%d in %s: ",
00525 levels[level], (long)GETTID(), file, line, function);
00526 }
00527 s = buf + strlen(buf);
00528 vsnprintf(s, sizeof(buf) - strlen(buf), fmt, args);
00529 strip_coloring(s);
00530 syslog(syslog_level_map[level], "%s", buf);
00531 }
00532
00533
00534
00535
00536 void ast_log(int level, const char *file, int line, const char *function, const char *fmt, ...)
00537 {
00538 struct logchannel *chan;
00539 char buf[BUFSIZ];
00540 time_t t;
00541 struct tm tm;
00542 char date[256];
00543
00544 va_list ap;
00545
00546 if (!option_verbose && !option_debug && (level == __LOG_DEBUG)) {
00547 return;
00548 }
00549
00550
00551 ast_mutex_lock(&loglock);
00552
00553 time(&t);
00554 localtime_r(&t, &tm);
00555 strftime(date, sizeof(date), dateformat, &tm);
00556
00557 if (level == __LOG_EVENT) {
00558 va_start(ap, fmt);
00559
00560 fprintf(eventlog, "%s asterisk[%d]: ", date, getpid());
00561 vfprintf(eventlog, fmt, ap);
00562 fflush(eventlog);
00563
00564 va_end(ap);
00565 ast_mutex_unlock(&loglock);
00566 return;
00567 }
00568
00569 if (logchannels) {
00570 chan = logchannels;
00571 while(chan) {
00572 if (chan->syslog && (chan->logmask & (1 << level))) {
00573 va_start(ap, fmt);
00574 ast_log_vsyslog(level, file, line, function, fmt, ap);
00575 va_end(ap);
00576 } else if ((chan->logmask & (1 << level)) && (chan->console)) {
00577 char linestr[128];
00578 char tmp1[80], tmp2[80], tmp3[80], tmp4[80];
00579
00580 if (level != __LOG_VERBOSE) {
00581 sprintf(linestr, "%d", line);
00582 snprintf(buf, sizeof(buf), "%s %s[%ld]: %s:%s %s: ",
00583 date,
00584 term_color(tmp1, levels[level], colors[level], 0, sizeof(tmp1)),
00585 (long)GETTID(),
00586 term_color(tmp2, file, COLOR_BRWHITE, 0, sizeof(tmp2)),
00587 term_color(tmp3, linestr, COLOR_BRWHITE, 0, sizeof(tmp3)),
00588 term_color(tmp4, function, COLOR_BRWHITE, 0, sizeof(tmp4)));
00589
00590 ast_console_puts(buf);
00591 va_start(ap, fmt);
00592 vsnprintf(buf, sizeof(buf), fmt, ap);
00593 va_end(ap);
00594 ast_console_puts(buf);
00595 }
00596 } else if ((chan->logmask & (1 << level)) && (chan->fileptr)) {
00597 snprintf(buf, sizeof(buf), "%s %s[%ld]: ", date,
00598 levels[level], (long)GETTID());
00599 fprintf(chan->fileptr, buf);
00600 va_start(ap, fmt);
00601 vsnprintf(buf, sizeof(buf), fmt, ap);
00602 strip_coloring(buf);
00603 va_end(ap);
00604 fputs(buf, chan->fileptr);
00605 fflush(chan->fileptr);
00606 }
00607 chan = chan->next;
00608 }
00609 } else {
00610
00611
00612
00613
00614 if (level != __LOG_VERBOSE) {
00615 va_start(ap, fmt);
00616 vsnprintf(buf, sizeof(buf), fmt, ap);
00617 va_end(ap);
00618 fputs(buf, stdout);
00619 }
00620 }
00621
00622 ast_mutex_unlock(&loglock);
00623
00624 if (pending_logger_reload) {
00625 reload_logger(1);
00626 ast_log(LOG_EVENT,"Rotated Logs Per SIGXFSZ\n");
00627 if (option_verbose)
00628 ast_verbose("Rotated Logs Per SIGXFSZ\n");
00629 }
00630 }
00631
00632 extern void ast_verbose(const char *fmt, ...)
00633 {
00634 static char stuff[4096];
00635 static int pos = 0, opos;
00636 static int replacelast = 0, complete;
00637 struct msglist *m;
00638 struct verb *v;
00639 va_list ap;
00640 va_start(ap, fmt);
00641 ast_mutex_lock(&msglist_lock);
00642 vsnprintf(stuff + pos, sizeof(stuff) - pos, fmt, ap);
00643 opos = pos;
00644 pos = strlen(stuff);
00645 if (fmt[strlen(fmt)-1] == '\n')
00646 complete = 1;
00647 else
00648 complete=0;
00649 if (complete) {
00650 if (msgcnt < MAX_MSG_QUEUE) {
00651
00652 m = malloc(sizeof(struct msglist));
00653 msgcnt++;
00654 } else {
00655
00656 m = list;
00657 list = list->next;
00658 free(m->msg);
00659 }
00660 if (m) {
00661 m->msg = strdup(stuff);
00662 if (m->msg) {
00663 if (last)
00664 last->next = m;
00665 else
00666 list = m;
00667 m->next = NULL;
00668 last = m;
00669 } else {
00670 msgcnt--;
00671 ast_log(LOG_ERROR, "Out of memory\n");
00672 free(m);
00673 }
00674 }
00675 }
00676 if (verboser) {
00677 v = verboser;
00678 while(v) {
00679 v->verboser(stuff, opos, replacelast, complete);
00680 v = v->next;
00681 }
00682 }
00683
00684
00685 ast_log(LOG_VERBOSE, "%s", stuff);
00686
00687 if (fmt[strlen(fmt)-1] != '\n')
00688 replacelast = 1;
00689 else
00690 replacelast = pos = 0;
00691 va_end(ap);
00692
00693 ast_mutex_unlock(&msglist_lock);
00694 }
00695
00696 int ast_verbose_dmesg(void (*v)(const char *string, int opos, int replacelast, int complete))
00697 {
00698 struct msglist *m;
00699 ast_mutex_lock(&msglist_lock);
00700 m = list;
00701 while(m) {
00702
00703 v(m->msg, 0, 0, 1);
00704 m = m->next;
00705 }
00706 ast_mutex_unlock(&msglist_lock);
00707 return 0;
00708 }
00709
00710 int ast_register_verbose(void (*v)(const char *string, int opos, int replacelast, int complete))
00711 {
00712 struct msglist *m;
00713 struct verb *tmp;
00714
00715 if ((tmp = malloc(sizeof (struct verb)))) {
00716 tmp->verboser = v;
00717 ast_mutex_lock(&msglist_lock);
00718 tmp->next = verboser;
00719 verboser = tmp;
00720 m = list;
00721 while(m) {
00722
00723 v(m->msg, 0, 0, 1);
00724 m = m->next;
00725 }
00726 ast_mutex_unlock(&msglist_lock);
00727 return 0;
00728 }
00729 return -1;
00730 }
00731
00732 int ast_unregister_verbose(void (*v)(const char *string, int opos, int replacelast, int complete))
00733 {
00734 int res = -1;
00735 struct verb *tmp, *tmpl=NULL;
00736 ast_mutex_lock(&msglist_lock);
00737 tmp = verboser;
00738 while(tmp) {
00739 if (tmp->verboser == v) {
00740 if (tmpl)
00741 tmpl->next = tmp->next;
00742 else
00743 verboser = tmp->next;
00744 free(tmp);
00745 break;
00746 }
00747 tmpl = tmp;
00748 tmp = tmp->next;
00749 }
00750 if (tmp)
00751 res = 0;
00752 ast_mutex_unlock(&msglist_lock);
00753 return res;
00754 }