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[256];
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 (!strncasecmp(facility, cptr->c_name, sizeof(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))) {
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 ast_log_vsyslog(int level, const char *file, int line, const char *function, const char *fmt, va_list args)
00482 {
00483 char buf[BUFSIZ];
00484
00485 if (level >= SYSLOG_NLEVELS) {
00486
00487 fprintf(stderr, "ast_log_vsyslog called with bogus level: %d\n", level);
00488 return;
00489 }
00490 if (level == __LOG_VERBOSE) {
00491 snprintf(buf, sizeof(buf), "VERBOSE[%ld]: ", (long)GETTID());
00492 level = __LOG_DEBUG;
00493 } else {
00494 snprintf(buf, sizeof(buf), "%s[%ld]: %s:%d in %s: ",
00495 levels[level], (long)GETTID(), file, line, function);
00496 }
00497 vsnprintf(buf+strlen(buf), sizeof(buf)-strlen(buf), fmt, args);
00498 syslog(syslog_level_map[level], "%s", buf);
00499 }
00500
00501
00502
00503
00504 void ast_log(int level, const char *file, int line, const char *function, const char *fmt, ...)
00505 {
00506 struct logchannel *chan;
00507 char buf[BUFSIZ];
00508 time_t t;
00509 struct tm tm;
00510 char date[256];
00511
00512 va_list ap;
00513
00514 if (!option_verbose && !option_debug && (level == __LOG_DEBUG)) {
00515 return;
00516 }
00517
00518
00519 ast_mutex_lock(&loglock);
00520
00521 time(&t);
00522 localtime_r(&t, &tm);
00523 strftime(date, sizeof(date), dateformat, &tm);
00524
00525 if (level == __LOG_EVENT) {
00526 va_start(ap, fmt);
00527
00528 fprintf(eventlog, "%s asterisk[%d]: ", date, getpid());
00529 vfprintf(eventlog, fmt, ap);
00530 fflush(eventlog);
00531
00532 va_end(ap);
00533 ast_mutex_unlock(&loglock);
00534 return;
00535 }
00536
00537 if (logchannels) {
00538 chan = logchannels;
00539 while(chan) {
00540 if (chan->syslog && (chan->logmask & (1 << level))) {
00541 va_start(ap, fmt);
00542 ast_log_vsyslog(level, file, line, function, fmt, ap);
00543 va_end(ap);
00544 } else if ((chan->logmask & (1 << level)) && (chan->console)) {
00545 char linestr[128];
00546 char tmp1[80], tmp2[80], tmp3[80], tmp4[80];
00547
00548 if (level != __LOG_VERBOSE) {
00549 sprintf(linestr, "%d", line);
00550 snprintf(buf, sizeof(buf), "%s %s[%ld]: %s:%s %s: ",
00551 date,
00552 term_color(tmp1, levels[level], colors[level], 0, sizeof(tmp1)),
00553 (long)GETTID(),
00554 term_color(tmp2, file, COLOR_BRWHITE, 0, sizeof(tmp2)),
00555 term_color(tmp3, linestr, COLOR_BRWHITE, 0, sizeof(tmp3)),
00556 term_color(tmp4, function, COLOR_BRWHITE, 0, sizeof(tmp4)));
00557
00558 ast_console_puts(buf);
00559 va_start(ap, fmt);
00560 vsnprintf(buf, sizeof(buf), fmt, ap);
00561 va_end(ap);
00562 ast_console_puts(buf);
00563 }
00564 } else if ((chan->logmask & (1 << level)) && (chan->fileptr)) {
00565 snprintf(buf, sizeof(buf), "%s %s[%ld]: ", date,
00566 levels[level], (long)GETTID());
00567 fprintf(chan->fileptr, buf);
00568 va_start(ap, fmt);
00569 vsnprintf(buf, sizeof(buf), fmt, ap);
00570 va_end(ap);
00571 fputs(buf, chan->fileptr);
00572 fflush(chan->fileptr);
00573 }
00574 chan = chan->next;
00575 }
00576 } else {
00577
00578
00579
00580
00581 if (level != __LOG_VERBOSE) {
00582 va_start(ap, fmt);
00583 vsnprintf(buf, sizeof(buf), fmt, ap);
00584 va_end(ap);
00585 fputs(buf, stdout);
00586 }
00587 }
00588
00589 ast_mutex_unlock(&loglock);
00590
00591 if (pending_logger_reload) {
00592 reload_logger(1);
00593 ast_log(LOG_EVENT,"Rotated Logs Per SIGXFSZ\n");
00594 if (option_verbose)
00595 ast_verbose("Rotated Logs Per SIGXFSZ\n");
00596 }
00597 }
00598
00599 extern void ast_verbose(const char *fmt, ...)
00600 {
00601 static char stuff[4096];
00602 static int pos = 0, opos;
00603 static int replacelast = 0, complete;
00604 struct msglist *m;
00605 struct verb *v;
00606 va_list ap;
00607 va_start(ap, fmt);
00608 ast_mutex_lock(&msglist_lock);
00609 vsnprintf(stuff + pos, sizeof(stuff) - pos, fmt, ap);
00610 opos = pos;
00611 pos = strlen(stuff);
00612 if (fmt[strlen(fmt)-1] == '\n')
00613 complete = 1;
00614 else
00615 complete=0;
00616 if (complete) {
00617 if (msgcnt < MAX_MSG_QUEUE) {
00618
00619 m = malloc(sizeof(struct msglist));
00620 msgcnt++;
00621 } else {
00622
00623 m = list;
00624 list = list->next;
00625 free(m->msg);
00626 }
00627 if (m) {
00628 m->msg = strdup(stuff);
00629 if (m->msg) {
00630 if (last)
00631 last->next = m;
00632 else
00633 list = m;
00634 m->next = NULL;
00635 last = m;
00636 } else {
00637 msgcnt--;
00638 ast_log(LOG_ERROR, "Out of memory\n");
00639 free(m);
00640 }
00641 }
00642 }
00643 if (verboser) {
00644 v = verboser;
00645 while(v) {
00646 v->verboser(stuff, opos, replacelast, complete);
00647 v = v->next;
00648 }
00649 }
00650
00651
00652 ast_log(LOG_VERBOSE, "%s", stuff);
00653
00654 if (fmt[strlen(fmt)-1] != '\n')
00655 replacelast = 1;
00656 else
00657 replacelast = pos = 0;
00658 va_end(ap);
00659
00660 ast_mutex_unlock(&msglist_lock);
00661 }
00662
00663 int ast_verbose_dmesg(void (*v)(const char *string, int opos, int replacelast, int complete))
00664 {
00665 struct msglist *m;
00666 ast_mutex_lock(&msglist_lock);
00667 m = list;
00668 while(m) {
00669
00670 v(m->msg, 0, 0, 1);
00671 m = m->next;
00672 }
00673 ast_mutex_unlock(&msglist_lock);
00674 return 0;
00675 }
00676
00677 int ast_register_verbose(void (*v)(const char *string, int opos, int replacelast, int complete))
00678 {
00679 struct msglist *m;
00680 struct verb *tmp;
00681
00682 if ((tmp = malloc(sizeof (struct verb)))) {
00683 tmp->verboser = v;
00684 ast_mutex_lock(&msglist_lock);
00685 tmp->next = verboser;
00686 verboser = tmp;
00687 m = list;
00688 while(m) {
00689
00690 v(m->msg, 0, 0, 1);
00691 m = m->next;
00692 }
00693 ast_mutex_unlock(&msglist_lock);
00694 return 0;
00695 }
00696 return -1;
00697 }
00698
00699 int ast_unregister_verbose(void (*v)(const char *string, int opos, int replacelast, int complete))
00700 {
00701 int res = -1;
00702 struct verb *tmp, *tmpl=NULL;
00703 ast_mutex_lock(&msglist_lock);
00704 tmp = verboser;
00705 while(tmp) {
00706 if (tmp->verboser == v) {
00707 if (tmpl)
00708 tmpl->next = tmp->next;
00709 else
00710 verboser = tmp->next;
00711 free(tmp);
00712 break;
00713 }
00714 tmpl = tmp;
00715 tmp = tmp->next;
00716 }
00717 if (tmp)
00718 res = 0;
00719 ast_mutex_unlock(&msglist_lock);
00720 return res;
00721 }