00001
00002
00003
00004
00005
00006
00007
00008
00009 #include "copyright.h"
00010 #include "config.h"
00011
00012 #include <sys/types.h>
00013 #include <sys/stat.h>
00014 #include <unistd.h>
00015 #include <sys/file.h>
00016 #include <sys/ioctl.h>
00017 #include <sys/wait.h>
00018 #include <signal.h>
00019 #include <errno.h>
00020
00021 #include "mudconf.h"
00022 #include "externs.h"
00023 #include "interface.h"
00024 #include "flags.h"
00025 #include "command.h"
00026 #include "attrs.h"
00027 #include "rbtree.h"
00028 #include <errno.h>
00029
00030 #ifdef DEBUG_LOGCACHE
00031 #define DEBUG
00032 #endif
00033 #include "debug.h"
00034
00035
00036
00037
00038 #define LOGFILE_TIMEOUT 300 // Five Minutes
00039
00040 struct logfile_t {
00041 char *filename;
00042 int fd;
00043 struct event ev;
00044 };
00045
00046 rbtree logfiles = NULL;
00047
00048 static int logcache_compare(void *vleft, void *vright, void *arg)
00049 {
00050 return strcmp((char *) vleft, (char *) vright);
00051 }
00052
00053 static int logcache_close(struct logfile_t *log)
00054 {
00055 dprintk("closing logfile '%s'.", log->filename);
00056 if(evtimer_pending(&log->ev, NULL)) {
00057 evtimer_del(&log->ev);
00058 }
00059 close(log->fd);
00060 rb_delete(logfiles, log->filename);
00061 if(log->filename)
00062 free(log->filename);
00063 log->filename = NULL;
00064 log->fd = -1;
00065 free(log);
00066 return 1;
00067 }
00068
00069 static void logcache_expire(int fd, short event, void *arg)
00070 {
00071 dprintk("Expiring '%s'.", ((struct logfile_t *) arg)->filename);
00072 logcache_close((struct logfile_t *) arg);
00073 }
00074
00075 static int _logcache_list(void *key, void *data, int depth, void *arg)
00076 {
00077 struct timeval tv;
00078 struct logfile_t *log = (struct logfile_t *) data;
00079 dbref player = *(dbref *) arg;
00080 evtimer_pending(&log->ev, &tv);
00081 notify_printf(player, "%-40s%d", log->filename, tv.tv_sec - mudstate.now);
00082 return 1;
00083 }
00084
00085 void logcache_list(dbref player)
00086 {
00087 notify(player, "/--------------------------- Open Logfiles");
00088 if(rb_size(logfiles) == 0) {
00089 notify(player, "- There are no open logfile handles.");
00090 return;
00091 }
00092 notify(player, "Filename Timeout");
00093 rb_walk(logfiles, WALK_INORDER, _logcache_list, &player);
00094 }
00095
00096 static int logcache_open(char *filename)
00097 {
00098 int fd;
00099 struct logfile_t *newlog;
00100 struct timeval tv = { LOGFILE_TIMEOUT, 0 };
00101
00102 if(rb_exists(logfiles, filename)) {
00103 fprintf(stderr,
00104 "Serious braindamage, logcache_open() called for already open logfile.\n");
00105 return 0;
00106 }
00107
00108 fd = open(filename, O_RDWR | O_APPEND | O_CREAT, 0644);
00109 if(fd < 0) {
00110 fprintf(stderr,
00111 "Failed to open logfile %s because open() failed with code: %d - %s\n",
00112 filename, errno, strerror(errno));
00113 return 0;
00114 }
00115 if(fcntl(fd, F_SETFD, FD_CLOEXEC) < 0) {
00116 log_perror("LOGCACHE", "FAIL", NULL,
00117 "fcntl(fd, F_SETFD, FD_CLOEXEC)");
00118 }
00119
00120 newlog = malloc(sizeof(struct logfile_t));
00121 newlog->fd = fd;
00122 newlog->filename = strdup(filename);
00123 evtimer_set(&newlog->ev, logcache_expire, newlog);
00124 evtimer_add(&newlog->ev, &tv);
00125 rb_insert(logfiles, newlog->filename, newlog);
00126 dprintk("opened logfile '%s' fd = %d.", filename, fd);
00127 return 1;
00128 }
00129
00130 void logcache_init()
00131 {
00132 if(!logfiles) {
00133 dprintk("logcache initialized.");
00134 logfiles = rb_init(logcache_compare, NULL);
00135 } else {
00136 dprintk("REDUNDANT CALL TO logcache_init()!");
00137 }
00138 }
00139
00140 static int _logcache_destruct(void *key, void *data, int depth, void *arg)
00141 {
00142 struct logfile_t *log = (struct logfile_t *) data;
00143 logcache_close(log);
00144 return 1;
00145 }
00146
00147 void logcache_destruct()
00148 {
00149 dprintk("logcache destructing.");
00150 if(!logfiles) {
00151 dprintk("logcache_destruct() CALLED WHILE UNITIALIZED!");
00152 return;
00153 }
00154 rb_walk(logfiles, WALK_INORDER, _logcache_destruct, NULL);
00155 rb_destroy(logfiles);
00156 logfiles = NULL;
00157 }
00158
00159 int logcache_writelog(char *fname, char *fdata)
00160 {
00161 struct logfile_t *log;
00162 struct timeval tv = { LOGFILE_TIMEOUT, 0 };
00163 int len;
00164
00165 if(!logfiles)
00166 logcache_init();
00167
00168 len = strlen(fdata);
00169
00170 log = rb_find(logfiles, fname);
00171
00172 if(!log) {
00173 if(logcache_open(fname) < 0) {
00174 return 0;
00175 }
00176 log = rb_find(logfiles, fname);
00177 if(!log) {
00178 return 0;
00179 }
00180 }
00181
00182 if(evtimer_pending(&log->ev, NULL)) {
00183 event_del(&log->ev);
00184 event_add(&log->ev, &tv);
00185 }
00186
00187 if(write(log->fd, fdata, len) < 0) {
00188 fprintf(stderr,
00189 "System failed to write data to file with error '%s' on logfile '%s'. Closing.\n",
00190 strerror(errno), log->filename);
00191 logcache_close(log);
00192 }
00193 return 1;
00194 }