src/logcache.c

Go to the documentation of this file.
00001 /*
00002  * logcache.c
00003  */
00004 
00005 /*
00006  * $Id $
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 /* The LOGFILE_TIMEOUT field describes how long a mux should keep an idle
00036  * open. LOGFILE_TIMEOUT seconds after the last write, it will close. The
00037  * timer is reset on each write. */
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 }

Generated on Mon May 28 04:25:24 2007 for BattletechMUX by  doxygen 1.4.7