*
* 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
+ * the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
#include "conf.h"
#include "log.h"
#include "helpfile.h" /* send_message, message_register, etc */
+#include "modcmd.h"
#include "nickserv.h"
+#define Block 4096
+#define MAXLOGSEARCHLENGTH 10000
+
+struct userNode *chanserv;
+
struct logDestination;
struct logDest_vtable {
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." },
{ "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 }
};
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_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
/* 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;
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
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;
}
unsigned int matched = 0;
if (discrim->type) {
- struct logEntry *entry, *last;
+ static volatile struct logEntry *last;
+ struct logEntry *entry;
for (entry = discrim->type->log_oldest, last = NULL;
entry;
/* 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 = {
}
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(4, 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(4, 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(4, dest->target, opserv, "%s %s: %s\n", type->name, log_severity_names[sev], message);
}
static struct logDest_vtable ldIrc_vtbl = {
}
}
+
+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;
+}