X-Git-Url: https://jfr.im/git/irc/evilnet/x3.git/blobdiff_plain/eb5d6b73587847fd4a98767248c56ae9b854c1d2..8dc0685213ead3f8896c83cadc130143ccc4d181:/src/log.c diff --git a/src/log.c b/src/log.c index c6761de..ef531ee 100644 --- a/src/log.c +++ b/src/log.c @@ -1,9 +1,9 @@ /* log.c - Diagnostic and error logging * Copyright 2000-2004 srvx Development Team * - * This file is part of srvx. + * This file is part of x3. * - * srvx is free software; you can redistribute it and/or modify + * x3 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. @@ -20,9 +20,14 @@ #include "conf.h" #include "log.h" +#include "modcmd.h" #include "helpfile.h" /* send_message, message_register, etc */ #include "nickserv.h" +#define Block 4096 +#define MAXLOGSEARCHLENGTH 10000 + +struct userNode *chanserv; struct logDestination; struct logDest_vtable { @@ -78,6 +83,15 @@ 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." }, { "MSG_INVALID_SEVERITY", "$b%s$b is an invalid severity level." }, + + { "LAST_RESULTS", "$b%s$b] %s %s $b%s$b %s" }, + { "LAST_ERROR", "%s:%s" }, + { "LAST_COMMAND_LOG", "Channel Events for %s" }, + { "LAST_LINE", "----------------------------------------" }, + { "LAST_STOPPING_AT", "--------- Stopping at %d lines ---------" }, + { "LAST_MAX_AGE", "-------- Data age limit reached --------" }, + { "LAST_END_OF_LOG", "---------- Found %d Matches ------------" }, + { NULL, NULL } }; @@ -527,7 +541,7 @@ log_audit(struct log_type *type, enum log_severity sev, struct userNode *user, s /* remove old elements from the linked list */ while (type->log_count > type->max_count) log_type_free_oldest(type); - while (type->log_oldest && (type->log_oldest->time + type->max_age < (unsigned long)now)) + while (type->log_oldest && (type->log_oldest->time + (time_t)type->max_age < now)) log_type_free_oldest(type); if (type->log_oldest) type->log_oldest->prev = 0; @@ -587,6 +601,10 @@ 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); } + if (sev == LOG_FATAL) { + //assert(0 && "fatal message logged"); + _exit(1); + } } /* audit log searching */ @@ -719,9 +737,13 @@ log_entry_search(struct logSearch *discrim, entry_search_func esf, void *data) unsigned int matched = 0; if (discrim->type) { + static volatile struct logEntry *last; struct logEntry *entry; - for (entry = discrim->type->log_oldest; entry; entry = entry->next) { + for (entry = discrim->type->log_oldest, last = NULL; + entry; + last = entry, entry = entry->next) { + verify(entry); if (entry_match(discrim, entry)) { esf(entry, data); if (++matched >= discrim->limit) @@ -947,14 +969,17 @@ ldIrc_close(struct logDestination *self_) { free(self); } +/* + * ldIrc_audit and ldIrc_module send log messages targetted to an IRC channel, to the channel + */ static void ldIrc_audit(struct logDestination *self_, UNUSED_ARG(struct log_type *type), struct logEntry *entry) { struct logDest_irc *self = (struct logDest_irc*)self_; if (entry->channel_name) { - send_target_message(4, self->target, entry->bot, "(%s", strchr(strchr(entry->default_desc, ' '), ':')+1); + send_target_message(5, self->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, self->target, entry->bot, "%s", strchr(entry->default_desc, ')')+2); } } @@ -963,7 +988,7 @@ ldIrc_module(struct logDestination *self_, struct log_type *type, enum log_sever struct logDest_irc *self = (struct logDest_irc*)self_; 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, self->target, opserv, "%s %s: %s\n", type->name, log_severity_names[sev], message); } static struct logDest_vtable ldIrc_vtbl = { @@ -1021,3 +1046,210 @@ void SyncLog(char *fmt,...) } } + +int parselog(char *LogLine, struct userNode *user, struct chanNode *cptr, char *chan, char *nuh, char *command, char *rest) +{ + struct svccmd *svccmd; + struct svccmd *cmd; + struct service *service; + const char *info; + char serv[NICKLEN+1]; + char buf[MAXLEN]; + char myservc[MAXLEN]; + char* mychan; + char* mynuh; + char* mycommand; + char* myrest; + char* datestr; + char* mywho; + char *myserv; + char* myserva; + char* mychana; + unsigned int pos; + int p = 0; + + datestr = (char *) mysep(&LogLine, "]"); + mywho = (char *) mysep(&LogLine, " "); + mynuh = (char *) mysep(&LogLine, " "); + mycommand = (char *) mysep(&LogLine, " "); + myrest = (char *) mysep(&LogLine, "\0"); + myserva = (char *) mysep(&mywho, ":"); + mychana = (char *) mysep(&mywho, ":"); + myserv = (char *) mysep(&myserva, "("); + mychan = (char *) mysep(&mychana, ")"); + + if(!mycommand) + return 0; + + if(cptr) + chan = cptr->name; + + if (!mychan) + mychan = ""; + + if(!chan) + chan = ""; + + if(!nuh) + nuh = ""; + if(!command) + command = ""; + if(!rest) + rest = ""; + if(*chan && strcasecmp(mychan, chan)) + return 0; + if(!myrest) + myrest = ""; + + info = conf_get_data("services/opserv/nick", RECDB_QSTRING); + + if (!myserv) + myserv = ""; + else + strcpy(myservc, myserv); + + + if (!strcmp(myserv, info)) { + if (!IsOper(user)) + return 0; + else { + if ((service = service_find(myserv))) { + if (!(cmd = dict_find(service->commands, mycommand, NULL))) + return 0; + + if (!(svccmd = svccmd_resolve_name(cmd, mycommand))) + return 0; + + pos = snprintf(buf, sizeof(buf), "%s.%s", svccmd->command->parent->name, svccmd->command->name); + + if (svccmd->alias.used) { + buf[pos++] = ' '; + unsplit_string((char**)svccmd->alias.list+1, svccmd->alias.used-1, buf+pos); + } + } + } + + if (!(strcmp(buf+0, "OpServ.OP"))) + p = 1; + if (!(strcmp(buf+0, "OpServ.DEOP"))) + p = 1; + if (!(strcmp(buf+0, "OpServ.VOICE"))) + p = 1; + if (!(strcmp(buf+0, "OpServ.DEVOICE"))) + p = 1; + if (!(strcmp(buf+0, "OpServ.KICK"))) + p = 1; + if (!(strcmp(buf+0, "OpServ.KICKBAN"))) + p = 1; + + if (!(strcmp(buf+0, "OpServ.OPALL"))) + p = 1; + if (!(strcmp(buf+0, "OpServ.DEOPALL"))) + p = 1; + if (!(strcmp(buf+0, "OpServ.VOICEALL"))) + p = 1; + if (!(strcmp(buf+0, "OpServ.DEVOICEALL"))) + p = 1; + if (!(strcmp(buf+0, "OpServ.KICKALL"))) + p = 1; + if (!(strcmp(buf+0, "OpServ.KICKBANALL"))) + p = 1; + + + if (!(strcmp(buf+0, "OpServ.INVITE"))) + p = 1; + if (!(strcmp(buf+0, "OpServ.INVITEME"))) + p = 1; + if (!(strcmp(buf+0, "OpServ.CLEARBANS"))) + p = 1; + if (!(strcmp(buf+0, "OpServ.CLEARMODES"))) + p = 1; + + if (p == 1) + send_message(user, chanserv, "LAST_RESULTS", datestr, myserv, mynuh, mycommand, myrest); + + p = 0; + } else { + sprintf(serv, "%s", ""); + send_message(user, chanserv, "LAST_RESULTS", datestr, serv, mynuh, mycommand, myrest); + } + + return 1; + +} + +int ShowLog(struct userNode *user, struct chanNode *cptr, char *chan, char *nuh, char *command, char *rest, int maxlines) +{ + FILE *TheFile; + int i, s, Last = 0, filelen, first; + int line = 0, searchline = 0; + int FilePosition; + + char Buff[Block+1] = "", PrevBuff[Block+1] = ""; + char LogLine[(Block+1)*2] = ""; /* To hold our exported results. */ + + if(!(TheFile = fopen(AccountingLog, "r"))) + { + send_message(user, chanserv, "LAST_ERROR", AccountingLog, strerror(errno)); + return 0; + } + s = fseek(TheFile, 0, SEEK_END); /* Start at the end. */ + filelen = ftell(TheFile); /* Find out the length. */ + FilePosition = 0; /* (from the bottom) */ + send_message(user, chanserv, "LAST_COMMAND_LOG", cptr->name); + send_message(user, chanserv, "LAST_LINE"); + while(Last == 0) + { + FilePosition += Block; + if(FilePosition > filelen) + { + FilePosition = filelen; + Last = 1; + } + if((s = fseek(TheFile, filelen-FilePosition, SEEK_SET)) < 0) + { + send_message(user, chanserv, "LAST_ERROR", AccountingLog, strerror(errno)); + fclose(TheFile); + return 0; + } + s = fread(Buff, 1, Block, TheFile); + Buff[Block] = '\0'; + if(ferror(TheFile)) + { + send_message(user, chanserv, "LAST_ERROR", AccountingLog, strerror(errno)); + fclose(TheFile); + return 0; + } + first = 1; + for(i = s-1; i >= 0; i--) + { + if(Buff[i] == '\n') + { + Buff[i] = '\0'; + strcpy(LogLine, &Buff[i+1]); + if(first) + strcat(LogLine, PrevBuff); + first = 0; + searchline++; + if(parselog(LogLine, user, cptr, chan, nuh, command, rest)) + line++; + if(line >= maxlines) + { + send_message(user, chanserv, "LAST_STOPPING_AT", maxlines); + return 1; + } + if( searchline >= MAXLOGSEARCHLENGTH ) + { + send_message(user, chanserv, "LAST_MAX_AGE"); + fclose(TheFile); + return 1; + } + + } + } + strcpy(PrevBuff, Buff); /* Save the remaining bit. */ + } + send_message(user, chanserv, "LAST_END_OF_LOG", line); + fclose(TheFile); + return 1; +}