X-Git-Url: http://git.onelab.eu/?p=codemux.git;a=blobdiff_plain;f=codemuxlib.c;h=206c08fd2bb4265fe26283a5beaa92179b340259;hp=1f8863347593ae8d81d0d4248651773195307932;hb=7311509d11a0986a52967c1195f4cfb8bce2b332;hpb=2c6a4b237f366c423f5a208cd4c427cfaeecbbca diff --git a/codemuxlib.c b/codemuxlib.c index 1f88633..206c08f 100644 --- a/codemuxlib.c +++ b/codemuxlib.c @@ -10,8 +10,8 @@ #include #include #include -#include "debug.h" #include "codemuxlib.h" +#include "debug.h" /*-----------------------------------------------------------------*/ static char * @@ -271,3 +271,255 @@ NiceExitBack(int val, char *reason, char *file, int line) fprintf(stderr, "%s", buf); exit(val); } +/*-----------------------------------------------------------------*/ +/* Logging & Trace support */ + +/* buffer threshold : when the size hits this value, it flushes its content + to the file */ +#define LOG_BYTES_THRESHOLD (32*1024) + +/* this flag indicates that it preserves the base file name for the current + one, and changes its name when it actually closes it off */ +#define CHANGE_FILE_NAME_ON_SAVE 0x01 + +/* size of the actual log buffer */ +#define LOG_BYTES_MAX (2*LOG_BYTES_THRESHOLD) + +/* log/trace book keeping information */ +typedef struct ExtendedLog { + char buffer[LOG_BYTES_MAX]; /* 64 KB */ + int bytes; /* number of bytes written */ + int filesize; /* number of bytes written into this file so far */ + int fd; /* file descriptor */ + char* sig; /* base file name */ + int flags; /* flags */ + time_t nextday; +} ExtendedLog, *PExtendedLog; + +/* maximum single file size */ +int maxSingleLogSize = 100 * (1024*1024); + +static time_t +GetNextLogFileName(char* file, int size, const char* sig) +{ +#define COMPRESS_EXT1 ".bz2" +#define COMPRESS_EXT2 ".gz" + + struct tm cur_tm; + time_t cur_t; + int idx = 0; + + cur_t = time(NULL); + cur_tm = *gmtime(&cur_t); + + for (;;) { + /* check if .bz2 exists */ + snprintf(file, size, "%s.%04d%02d%02d_%03d%s", + sig, cur_tm.tm_year+1900, cur_tm.tm_mon+1, cur_tm.tm_mday, + idx, COMPRESS_EXT1); + + if (access(file, F_OK) == 0) { + idx++; + continue; + } + + /* check if .gz exists */ + snprintf(file, size, "%s.%04d%02d%02d_%03d%s", + sig, cur_tm.tm_year+1900, cur_tm.tm_mon+1, cur_tm.tm_mday, + idx++, COMPRESS_EXT2); + + if (access(file, F_OK) == 0) + continue; + + /* strip the extension and see if the (uncompressed) file exists */ + file[strlen(file) - sizeof(COMPRESS_EXT2) + 1] = 0; + if (access(file, F_OK) != 0) + break; + } + + /* calculate & return the next day */ + cur_t -= (3600*cur_tm.tm_hour + 60*cur_tm.tm_min + cur_tm.tm_sec); + return cur_t + 60*60*24; + +#undef COMPRESS_EXT1 +#undef COMPRESS_EXT2 +} +/*-----------------------------------------------------------------*/ +static void +FlushBuffer(HANDLE file) +{ + /* write data into the file */ + ExtendedLog* pel = (ExtendedLog *)file; + int written; + + if (pel == NULL || pel->fd < 0) + return; + + if ((written = write(pel->fd, pel->buffer, pel->bytes)) > 0) { + pel->bytes -= written; + + /* if it hasn't written all data, then we need to move memory */ + if (pel->bytes > 0) + memmove(pel->buffer, pel->buffer + written, pel->bytes); + pel->buffer[pel->bytes] = 0; + pel->filesize += written; + } + + /* if the filesize is bigger than maxSignleLogSize, then close it off */ + if (pel->filesize >= maxSingleLogSize) + OpenLogF(file); +} + +/*-----------------------------------------------------------------*/ +HANDLE +CreateLogFHandle(const char* signature, int change_file_name_on_save) +{ + ExtendedLog* pel; + char *temp; + + /* check if the file can be created */ + if ((temp = strrchr(signature, '/')) != NULL) { + int dirlen = temp - signature + 1; + char pardir[dirlen+1]; + + memcpy(pardir, signature, dirlen); + pardir[dirlen] = 0; + if (access(pardir, W_OK) != 0) + return NULL; + } else { + /* assume it's the current directory */ + if (access("./", W_OK) != 0) + return NULL; + } + + if ((pel = (ExtendedLog *)xcalloc(1, sizeof(ExtendedLog))) == NULL) + NiceExit(-1, "failed"); + + pel->fd = -1; + pel->sig = xstrdup(signature); + if (pel->sig == NULL) + NiceExit(-1, "signature copying failed"); + if (change_file_name_on_save) + pel->flags |= CHANGE_FILE_NAME_ON_SAVE; + + return pel; +} + + +/*-----------------------------------------------------------------*/ +int +OpenLogF(HANDLE file) +{ + char filename[1024]; + ExtendedLog* pel = (ExtendedLog *)file; + + if (pel == NULL) + return -1; + + if (pel->fd != -1) + close(pel->fd); + + pel->nextday = GetNextLogFileName(filename, sizeof(filename), pel->sig); + + /* change the file name only at saving time + use pel->sig as current file name */ + if (pel->flags & CHANGE_FILE_NAME_ON_SAVE) { + if (access(pel->sig, F_OK) == 0) + rename(pel->sig, filename); + strcpy(filename, pel->sig); + } + + /* file opening */ + if ((pel->fd = open(filename, O_RDWR | O_CREAT | O_APPEND, + S_IRUSR | S_IWUSR)) == -1) { + char errMessage[2048]; + sprintf(errMessage, "couldn't open the extended log file %s\n", filename); + NiceExit(-1, errMessage); + } + + /* reset the file size */ + pel->filesize = 0; + return 0; +} + +/*-----------------------------------------------------------------*/ +int +WriteLog(HANDLE file, const char* data, int size, int forceFlush) +{ + ExtendedLog* pel = (ExtendedLog *)file; + + /* if an error might occur, then stop here */ + if (pel == NULL || pel->fd < 0 || size > LOG_BYTES_MAX) + return -1; + + if (data != NULL) { + /* flush the previous data, if this data would overfill the buffer */ + if (pel->bytes + size >= LOG_BYTES_MAX) + FlushBuffer(file); + + /* write into the buffer */ + memcpy(pel->buffer + pel->bytes, data, size); + pel->bytes += size; + } + + /* need to flush ? */ + if ((forceFlush && (pel->bytes > 0)) || (pel->bytes >= LOG_BYTES_THRESHOLD)) + FlushBuffer(file); + + return 0; +} +/*-----------------------------------------------------------------*/ +void +DailyReopenLogF(HANDLE file) +{ + /* check if current file is a day long, + opens another for today's file */ + ExtendedLog* pel = (ExtendedLog *)file; + + if (pel && (time(NULL) >= pel->nextday)) { + FlushLogF(file); /* flush */ + OpenLogF(file); /* close previous one & reopen today's */ + } +} +/*-----------------------------------------------------------------*/ +int +HandleToFileNo(HANDLE file) +{ + ExtendedLog* pel = (ExtendedLog *)file; + + return (pel != NULL) ? pel->fd : -1; +} +/*-----------------------------------------------------------------*/ +unsigned int +HashString(const char *name, unsigned int hash, int endOnQuery, + int skipLastIfDot) +{ + /* if endOnQuery, we stop the hashing when we hit the question mark. + if skipLastIfDot, we check the last component of the path to see + if it includes a dot, and it so, we skip it. if both are specified, + we first try the query, and if that exists, we don't trim the path */ + + int i; + int len; + char *temp; + + if (name == NULL) + return 0; + + len = strlen(name); + if (endOnQuery && (temp = strchr(name, '?')) != NULL) + len = temp - name; + else if (skipLastIfDot) { + /* first, find last component by searching backward */ + if ((temp = strrchr(name, '/')) != NULL) { + /* now search forward for the dot */ + if (strchr(temp, '.') != NULL) + len = temp - name; + } + } + + for (i = 0; i < len; i ++) + hash += (_rotl(hash, 19) + name[i]); + + return hash; +}