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