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