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