X-Git-Url: http://git.pk910.de/?a=blobdiff_plain;f=src%2Flog.c;h=87e4eb210b18769c0834b1b0f6c33332aa50878b;hb=a42b8b321339740efa6b12f98dba4585c504354f;hp=15d8e142e1590ed27bd4f63345a12038aaf60653;hpb=222e1b0003536cf7b47858961d4b56d45c6d6606;p=srvx.git diff --git a/src/log.c b/src/log.c index 15d8e14..87e4eb2 100644 --- a/src/log.c +++ b/src/log.c @@ -1,11 +1,12 @@ /* log.c - Diagnostic and error logging * Copyright 2000-2004 srvx Development Team * - * This program is free software; you can redistribute it and/or modify + * This file is part of srvx. + * + * srvx is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. Important limitations are - * listed in the COPYING file that accompanies this software. + * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -13,7 +14,8 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, email srvx-maintainers@srvx.net. + * along with srvx; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ #include "conf.h" @@ -49,6 +51,7 @@ struct log_type { unsigned int log_count; unsigned int max_age; unsigned int max_count; + unsigned int depth; unsigned int default_set : 1; }; @@ -71,7 +74,7 @@ static struct dict *log_types; static struct log_type *log_default; static int log_inited, log_debugged; -DEFINE_LIST(logList, struct logDestination*); +DEFINE_LIST(logList, struct logDestination*) static void log_format_audit(struct logEntry *entry); static const struct message_entry msgtab[] = { { "MSG_INVALID_FACILITY", "$b%s$b is an invalid log facility." }, @@ -86,6 +89,7 @@ log_open(const char *name) struct logDestination *ld; char *sep; char type_name[32]; + if ((ld = dict_find(log_dests, name, NULL))) { ld->refcnt++; return ld; @@ -100,9 +104,8 @@ log_open(const char *name) log_module(MAIN_LOG, LOG_ERROR, "Invalid log type for log '%s'.", name); return 0; } - if (!(ld = vtbl->open(sep ? sep+1 : 0))) { + if (!(ld = vtbl->open(sep ? sep+1 : 0))) return 0; - } ld->name = strdup(name); dict_insert(log_dests, ld->name, ld); ld->refcnt = 1; @@ -115,20 +118,17 @@ logList_open(struct logList *ll, struct record_data *rd) struct logDestination *ld; unsigned int ii; - if (!ll->size) { + if (!ll->size) logList_init(ll); - } switch (rd->type) { case RECDB_QSTRING: - if ((ld = log_open(rd->d.qstring))) { + if ((ld = log_open(rd->d.qstring))) logList_append(ll, ld); - } break; case RECDB_STRING_LIST: for (ii=0; iid.slist->used; ++ii) { - if ((ld = log_open(rd->d.slist->list[ii]))) { + if ((ld = log_open(rd->d.slist->list[ii]))) logList_append(ll, ld); - } } break; default: @@ -141,22 +141,21 @@ logList_join(struct logList *target, const struct logList *source) { unsigned int ii, jj, kk; - if (!source->used) { + if (!source->used) return; - } jj = target->used; target->used += source->used; target->size += source->used; target->list = realloc(target->list, target->size * sizeof(target->list[0])); for (ii = 0; ii < source->used; ++ii, ++jj) { - int dup; - for (dup = 0, kk = 0; kk < jj; kk++) { + int is_duplicate; + for (is_duplicate = 0, kk = 0; kk < jj; kk++) { if (target->list[kk] == source->list[ii]) { - dup = 1; + is_duplicate = 1; break; } } - if (dup) { + if (is_duplicate) { jj--; target->used--; continue; @@ -198,17 +197,27 @@ close_logs(void) } } +static void +log_type_free_oldest(struct log_type *lt) +{ + struct logEntry *next; + + if (!lt->log_oldest) + return; + next = lt->log_oldest->next; + free(lt->log_oldest->default_desc); + free(lt->log_oldest); + lt->log_oldest = next; + lt->log_count--; +} + static void log_type_free(void *ptr) { struct log_type *lt = ptr; - struct logEntry *le, *next; - - for (le = lt->log_oldest; le; le = next) { - next = le->next; - free(le->default_desc); - free(le); - } + + while (lt->log_oldest) + log_type_free_oldest(lt); free(lt); } @@ -236,7 +245,7 @@ find_severity(const char *text) * KEY := LOGSET '.' SEVSET * LOGSET := LOGLIT | LOGLIT ',' LOGSET * LOGLIT := a registered log type - * SEVSET := '*' | SEVLIT | '<' SEVLIT | '<=' SEVLIT | '>' SEVLIT | '>=' SEVLIT | SEVLIG ',' SEVSET + * SEVSET := '*' | SEVLIT | '<' SEVLIT | '<=' SEVLIT | '>' SEVLIT | '>=' SEVLIT | SEVLIT ',' SEVSET * SEVLIT := one of log_severity_names * A KEY contains the Cartesian product of the logs in its LOGSET * and the severities in its SEVSET. @@ -248,7 +257,8 @@ log_parse_logset(char *buffer, struct string_list *slist) slist->used = 0; while (buffer) { char *cont = strchr(buffer, ','); - if (cont) *cont++ = 0; + if (cont) + *cont++ = 0; string_list_append(slist, strdup(buffer)); buffer = cont; } @@ -264,7 +274,8 @@ log_parse_sevset(char *buffer, char targets[LOG_NUM_SEVERITIES]) int first; cont = strchr(buffer, ','); - if (cont) *cont++ = 0; + if (cont) + *cont++ = 0; if (buffer[0] == '*' && buffer[1] == 0) { for (bound = 0; bound < LOG_NUM_SEVERITIES; bound++) { /* make people explicitly specify replay targets */ @@ -272,11 +283,10 @@ log_parse_sevset(char *buffer, char targets[LOG_NUM_SEVERITIES]) targets[bound] = 1; } } else if (buffer[0] == '<') { - if (buffer[1] == '=') { + if (buffer[1] == '=') bound = find_severity(buffer+2) + 1; - } else { + else bound = find_severity(buffer+1); - } for (first = 1; bound > 0; bound--) { /* make people explicitly specify replay targets */ if (bound != LOG_REPLAY || first) { @@ -285,11 +295,10 @@ log_parse_sevset(char *buffer, char targets[LOG_NUM_SEVERITIES]) } } } else if (buffer[0] == '>') { - if (buffer[1] == '=') { + if (buffer[1] == '=') bound = find_severity(buffer+2); - } else { + else bound = find_severity(buffer+1) + 1; - } for (first = 1; bound < LOG_NUM_SEVERITIES; bound++) { /* make people explicitly specify replay targets */ if (bound != LOG_REPLAY || first) { @@ -298,6 +307,8 @@ log_parse_sevset(char *buffer, char targets[LOG_NUM_SEVERITIES]) } } } else { + if (buffer[0] == '=') + buffer++; bound = find_severity(buffer); targets[bound] = 1; } @@ -308,14 +319,14 @@ log_parse_sevset(char *buffer, char targets[LOG_NUM_SEVERITIES]) static void log_parse_cross(const char *buffer, struct string_list *types, char sevset[LOG_NUM_SEVERITIES]) { - char *dup, *sep; + char *buffer_copy, *sep; - dup = strdup(buffer); - sep = strchr(dup, '.'); + buffer_copy = strdup(buffer); + sep = strchr(buffer_copy, '.'); *sep++ = 0; - log_parse_logset(dup, types); + log_parse_logset(buffer_copy, types); log_parse_sevset(sep, sevset); - free(dup); + free(buffer_copy); } static void @@ -323,9 +334,11 @@ log_parse_options(struct log_type *type, struct dict *conf) { const char *opt; opt = database_get_data(conf, "max_age", RECDB_QSTRING); - if (opt) type->max_age = ParseInterval(opt); + if (opt) + type->max_age = ParseInterval(opt); opt = database_get_data(conf, "max_count", RECDB_QSTRING); - if (opt) type->max_count = strtoul(opt, NULL, 10); + if (opt) + type->max_count = strtoul(opt, NULL, 10); } static void @@ -360,7 +373,8 @@ log_conf_read(void) for (ii = 0; ii < slist->used; ++ii) { type = log_register_type(slist->list[ii], NULL); for (sev = 0; sev < LOG_NUM_SEVERITIES; ++sev) { - if (!sevset[sev]) continue; + if (!sevset[sev]) + continue; logList_join(&type->logs[sev], &logList); } } @@ -375,9 +389,8 @@ log_conf_read(void) } } } - if (log_debugged) { + if (log_debugged) log_debug(); - } } void @@ -391,9 +404,8 @@ log_debug(void) logList_init(&target); logList_append(&target, log_stdout); - for (sev = 0; sev < LOG_NUM_SEVERITIES; ++sev) { + for (sev = 0; sev < LOG_NUM_SEVERITIES; ++sev) logList_join(&log_default->logs[sev], &target); - } logList_close(&target); log_debugged = 1; @@ -427,11 +439,13 @@ log_register_type(const char *name, const char *default_log) /* If any severity level was unspecified in the config, use the default. */ dest = NULL; for (sev = 0; sev < LOG_NUM_SEVERITIES; ++sev) { - if (sev == LOG_REPLAY) continue; /* never default LOG_REPLAY */ + if (sev == LOG_REPLAY) + continue; /* never default LOG_REPLAY */ if (!type->logs[sev].size) { logList_init(&type->logs[sev]); if (!dest) { - if (!(dest = log_open(default_log))) break; + if (!(dest = log_open(default_log))) + break; dest->refcnt--; } logList_append(&type->logs[sev], dest); @@ -459,15 +473,12 @@ log_audit(struct log_type *type, enum log_severity sev, struct userNode *user, s } /* Allocate and fill in the log entry */ size = sizeof(*entry) + strlen(user->nick) + strlen(command) + 2; - if (user->handle_info) { + if (user->handle_info) size += strlen(user->handle_info->handle) + 1; - } - if (channel_name) { + if (channel_name) size += strlen(channel_name) + 1; - } - if (flags & AUDIT_HOSTMASK) { + if (flags & AUDIT_HOSTMASK) size += strlen(user->ident) + strlen(user->hostname) + 2; - } entry = calloc(1, size); str_next = (char*)(entry + 1); entry->time = now; @@ -507,29 +518,18 @@ log_audit(struct log_type *type, enum log_severity sev, struct userNode *user, s /* insert into the linked list */ entry->next = 0; entry->prev = type->log_newest; - if (type->log_newest) { + if (type->log_newest) type->log_newest->next = entry; - } else { + else type->log_oldest = entry; - } type->log_newest = entry; type->log_count++; /* remove old elements from the linked list */ - while (type->log_count > type->max_count) { - struct logEntry *next = type->log_oldest->next; - free(type->log_oldest->default_desc); - free(type->log_oldest); - type->log_oldest = next; - type->log_count--; - } - while (type->log_oldest && (type->log_oldest->time + type->max_age < (unsigned long)now)) { - struct logEntry *next = type->log_oldest->next; - free(type->log_oldest->default_desc); - free(type->log_oldest); - type->log_oldest = next; - type->log_count--; - } + while (type->log_count > type->max_count) + log_type_free_oldest(type); + while (type->log_oldest && (type->log_oldest->time + type->max_age < now)) + log_type_free_oldest(type); if (type->log_oldest) type->log_oldest->prev = 0; else @@ -568,6 +568,11 @@ log_module(struct log_type *type, enum log_severity sev, const char *format, ... unsigned int ii; va_list args; + if (!type) + return; + if (type->depth) + return; + ++type->depth; if (sev > LOG_FATAL) { log_module(MAIN_LOG, LOG_ERROR, "Illegal log_module severity %d", sev); return; @@ -588,6 +593,11 @@ log_module(struct log_type *type, enum log_severity sev, const char *format, ... /* Special behavior before we start full operation */ fprintf(stderr, "%s: %s\n", log_severity_names[sev], msgbuf); } + --type->depth; + if (sev == LOG_FATAL) { + assert(0 && "fatal message logged"); + _exit(1); + } } /* audit log searching */ @@ -601,8 +611,8 @@ log_discrim_create(struct userNode *service, struct userNode *user, unsigned int /* Assume all criteria require arguments. */ if((argc - 1) % 2) { - send_message(user, service, "MSG_MISSING_PARAMS", argv[0]); - return NULL; + send_message(user, service, "MSG_MISSING_PARAMS", argv[0]); + return NULL; } discrim = malloc(sizeof(struct logSearch)); @@ -635,19 +645,17 @@ log_discrim_create(struct userNode *service, struct userNode *user, unsigned int } else if (!irccasecmp(argv[ii], "age")) { const char *cmp = argv[++ii]; if (cmp[0] == '<') { - if (cmp[1] == '=') { + if (cmp[1] == '=') discrim->min_time = now - ParseInterval(cmp+2); - } else { + else discrim->min_time = now - (ParseInterval(cmp+1) - 1); - } } else if (cmp[0] == '>') { - if (cmp[1] == '=') { + if (cmp[1] == '=') discrim->max_time = now - ParseInterval(cmp+2); - } else { + else discrim->max_time = now - (ParseInterval(cmp+1) - 1); - } } else { - discrim->min_time = now - ParseInterval(cmp+2); + discrim->min_time = now - ParseInterval(cmp); } } else if (!irccasecmp(argv[ii], "limit")) { discrim->limit = strtoul(argv[++ii], NULL, 10); @@ -671,10 +679,10 @@ log_discrim_create(struct userNode *service, struct userNode *user, unsigned int send_message(user, service, "MSG_INVALID_FACILITY", argv[ii]); goto fail; } - } else { - send_message(user, service, "MSG_INVALID_CRITERIA", argv[ii]); - goto fail; - } + } else { + send_message(user, service, "MSG_INVALID_CRITERIA", argv[ii]); + goto fail; + } } return discrim; @@ -704,7 +712,7 @@ entry_match(struct logSearch *discrim, struct logEntry *entry) && !match_ircglob(entry->user_hostmask, discrim->masks.user_hostmask)) || (discrim->masks.command && !match_ircglob(entry->command, discrim->masks.command))) { - return 0; + return 0; } return 1; } @@ -724,7 +732,10 @@ log_entry_search(struct logSearch *discrim, entry_search_func esf, void *data) if (discrim->type) { struct logEntry *entry; - for (entry = discrim->type->log_oldest; entry; entry = entry->next) { + for (entry = discrim->type->log_oldest; + entry; + entry = entry->next) { + verify(entry); if (entry_match(discrim, entry)) { esf(entry, data); if (++matched >= discrim->limit) @@ -746,10 +757,12 @@ log_entry_search(struct logSearch *discrim, entry_search_func esf, void *data) /* generic helper functions */ static void -log_format_timestamp(time_t when, struct string_buffer *sbuf) +log_format_timestamp(unsigned long when, struct string_buffer *sbuf) { struct tm local; - localtime_r(&when, &local); + time_t feh; + feh = when; + localtime_r(&feh, &local); if (sbuf->size < 24) { sbuf->size = 24; free(sbuf->list); @@ -818,51 +831,51 @@ ldFile_open(const char *args) { } static void -ldFile_reopen(struct logDestination *self_) { - struct logDest_file *self = (struct logDest_file*)self_; - fclose(self->output); - self->output = fopen(self->fname, "a"); +ldFile_reopen(struct logDestination *dest_) { + struct logDest_file *dest = (struct logDest_file*)dest_; + fclose(dest->output); + dest->output = fopen(dest->fname, "a"); } static void -ldFile_close(struct logDestination *self_) { - struct logDest_file *self = (struct logDest_file*)self_; - fclose(self->output); - free(self->fname); - free(self); +ldFile_close(struct logDestination *dest_) { + struct logDest_file *dest = (struct logDest_file*)dest_; + fclose(dest->output); + free(dest->fname); + free(dest); } static void -ldFile_audit(struct logDestination *self_, UNUSED_ARG(struct log_type *type), struct logEntry *entry) { - struct logDest_file *self = (struct logDest_file*)self_; - fputs(entry->default_desc, self->output); - fputc('\n', self->output); - fflush(self->output); +ldFile_audit(struct logDestination *dest_, UNUSED_ARG(struct log_type *type), struct logEntry *entry) { + struct logDest_file *dest = (struct logDest_file*)dest_; + fputs(entry->default_desc, dest->output); + fputc('\n', dest->output); + fflush(dest->output); } static void -ldFile_replay(struct logDestination *self_, UNUSED_ARG(struct log_type *type), int is_write, const char *line) { - struct logDest_file *self = (struct logDest_file*)self_; +ldFile_replay(struct logDestination *dest_, UNUSED_ARG(struct log_type *type), int is_write, const char *line) { + struct logDest_file *dest = (struct logDest_file*)dest_; struct string_buffer sbuf; memset(&sbuf, 0, sizeof(sbuf)); log_format_timestamp(now, &sbuf); string_buffer_append_string(&sbuf, is_write ? "W: " : " "); string_buffer_append_string(&sbuf, line); - fputs(sbuf.list, self->output); - fputc('\n', self->output); + fputs(sbuf.list, dest->output); + fputc('\n', dest->output); free(sbuf.list); - fflush(self->output); + fflush(dest->output); } static void -ldFile_module(struct logDestination *self_, struct log_type *type, enum log_severity sev, const char *message) { - struct logDest_file *self = (struct logDest_file*)self_; +ldFile_module(struct logDestination *dest_, struct log_type *type, enum log_severity sev, const char *message) { + struct logDest_file *dest = (struct logDest_file*)dest_; struct string_buffer sbuf; memset(&sbuf, 0, sizeof(sbuf)); log_format_timestamp(now, &sbuf); - fprintf(self->output, "%s (%s:%s) %s\n", sbuf.list, type->name, log_severity_names[sev], message); + fprintf(dest->output, "%s (%s:%s) %s\n", sbuf.list, type->name, log_severity_names[sev], message); free(sbuf.list); - fflush(self->output); + fflush(dest->output); } static struct logDest_vtable ldFile_vtbl = { @@ -887,34 +900,33 @@ ldStd_open(const char *args) { ld->fname = strdup(args); /* Print to stderr if given "err" and default to stdout otherwise. */ - if (atoi(args)) { + if (atoi(args)) ld->output = fdopen(atoi(args), "a"); - } else if (!strcasecmp(args, "err")) { + else if (!strcasecmp(args, "err")) ld->output = stdout; - } else { + else ld->output = stderr; - } return &ld->base; } static void -ldStd_close(struct logDestination *self_) { - struct logDest_file *self = (struct logDest_file*)self_; - free(self->fname); - free(self); +ldStd_close(struct logDestination *dest_) { + struct logDest_file *dest = (struct logDest_file*)dest_; + free(dest->fname); + free(dest); } static void -ldStd_replay(struct logDestination *self_, UNUSED_ARG(struct log_type *type), int is_write, const char *line) { - struct logDest_file *self = (struct logDest_file*)self_; - fprintf(self->output, "%s%s\n", is_write ? "W: " : " ", line); +ldStd_replay(struct logDestination *dest_, UNUSED_ARG(struct log_type *type), int is_write, const char *line) { + struct logDest_file *dest = (struct logDest_file*)dest_; + fprintf(dest->output, "%s%s\n", is_write ? "W: " : " ", line); } static void -ldStd_module(struct logDestination *self_, UNUSED_ARG(struct log_type *type), enum log_severity sev, const char *message) { - struct logDest_file *self = (struct logDest_file*)self_; - fprintf(self->output, "%s: %s\n", log_severity_names[sev], message); +ldStd_module(struct logDestination *dest_, UNUSED_ARG(struct log_type *type), enum log_severity sev, const char *message) { + struct logDest_file *dest = (struct logDest_file*)dest_; + fprintf(dest->output, "%s: %s\n", log_severity_names[sev], message); } static struct logDest_vtable ldStd_vtbl = { @@ -945,29 +957,29 @@ ldIrc_open(const char *args) { } static void -ldIrc_close(struct logDestination *self_) { - struct logDest_irc *self = (struct logDest_irc*)self_; - free(self->target); - free(self); +ldIrc_close(struct logDestination *dest_) { + struct logDest_irc *dest = (struct logDest_irc*)dest_; + free(dest->target); + free(dest); } static void -ldIrc_audit(struct logDestination *self_, UNUSED_ARG(struct log_type *type), struct logEntry *entry) { - struct logDest_irc *self = (struct logDest_irc*)self_; +ldIrc_audit(struct logDestination *dest_, UNUSED_ARG(struct log_type *type), struct logEntry *entry) { + struct logDest_irc *dest = (struct logDest_irc*)dest_; if (entry->channel_name) { - send_target_message(4, self->target, entry->bot, "(%s", strchr(strchr(entry->default_desc, ' '), ':')+1); + send_target_message(5, dest->target, entry->bot, "(%s", strchr(strchr(entry->default_desc, ' '), ':')+1); } else { - send_target_message(4, self->target, entry->bot, "%s", strchr(entry->default_desc, ')')+2); + send_target_message(5, dest->target, entry->bot, "%s", strchr(entry->default_desc, ')')+2); } } static void -ldIrc_module(struct logDestination *self_, struct log_type *type, enum log_severity sev, const char *message) { - struct logDest_irc *self = (struct logDest_irc*)self_; +ldIrc_module(struct logDestination *dest_, struct log_type *type, enum log_severity sev, const char *message) { + struct logDest_irc *dest = (struct logDest_irc*)dest_; extern struct userNode *opserv; - send_target_message(4, self->target, opserv, "%s %s: %s\n", type->name, log_severity_names[sev], message); + send_target_message(5, dest->target, opserv, "%s %s: %s\n", type->name, log_severity_names[sev], message); } static struct logDest_vtable ldIrc_vtbl = {