change opserv channel notice to channel privmsg
[srvx.git] / src / log.c
index 15d8e142e1590ed27bd4f63345a12038aaf60653..87e4eb210b18769c0834b1b0f6c33332aa50878b 100644 (file)
--- 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; 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:
@@ -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 = {