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 m = list;
00459
ast_mutex_lock(&msglist_lock);
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 m = list;
00660
ast_mutex_lock(&msglist_lock);
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 }