/* 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
* 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"
unsigned int log_count;
unsigned int max_age;
unsigned int max_count;
+ unsigned int depth;
unsigned int default_set : 1;
};
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." },
struct logDestination *ld;
char *sep;
char type_name[32];
+
if ((ld = dict_find(log_dests, name, NULL))) {
ld->refcnt++;
return ld;
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;
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; ii<rd->d.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:
{
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;
}
}
+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);
}
* 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.
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;
}
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 */
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) {
}
}
} 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) {
}
}
} else {
+ if (buffer[0] == '=')
+ buffer++;
bound = find_severity(buffer);
targets[bound] = 1;
}
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
{
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
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);
}
}
}
}
}
- if (log_debugged) {
+ if (log_debugged)
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;
/* 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);
}
/* 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;
/* 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
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;
/* 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 */
/* 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));
} 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);
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;
&& !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;
}
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)
/* 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);
}
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 = {
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 = {
}
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 = {