silclog.c
- Author: Johnny Mnemonic <johnny@themnemonic.org>
+ Author: Giovanni Giacobbi <giovanni@giacobbi.net>
- Copyright (C) 1997 - 2002 Pekka Riikonen
+ Copyright (C) 1997 - 2005 Pekka Riikonen
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
/* Our working struct -- at the moment we keep it private, but this could
* change in the future */
struct SilcLogStruct {
- char *filename;
+ char filename[256];
FILE *fp;
- uint32 maxsize;
- char *typename;
+ SilcUInt32 maxsize;
+ const char *typename;
SilcLogType type;
SilcLogCb cb;
void *context;
};
typedef struct SilcLogStruct *SilcLog;
-/* These are the known logging channels */
+/* These are the known logging channels. We initialize this struct with most
+ * of the fields set to NULL, because we'll fill in those values at runtime. */
static struct SilcLogStruct silclogs[SILC_LOG_MAX] = {
- {NULL, NULL, 0, "Info", SILC_LOG_INFO, NULL, NULL},
- {NULL, NULL, 0, "Warning", SILC_LOG_WARNING, NULL, NULL},
- {NULL, NULL, 0, "Error", SILC_LOG_ERROR, NULL, NULL},
- {NULL, NULL, 0, "Fatal", SILC_LOG_FATAL, NULL, NULL},
+ {"", NULL, 0, "Info", SILC_LOG_INFO, NULL, NULL},
+ {"", NULL, 0, "Warning", SILC_LOG_WARNING, NULL, NULL},
+ {"", NULL, 0, "Error", SILC_LOG_ERROR, NULL, NULL},
+ {"", NULL, 0, "Fatal", SILC_LOG_FATAL, NULL, NULL},
};
+/* Causes logging output to contain timestamps */
+bool silc_log_timestamp = TRUE;
+
/* If TRUE, log files will be flushed for each log input */
bool silc_log_quick = FALSE;
bool silc_debug = FALSE;
bool silc_debug_hexdump = FALSE;
-/* Flush delay */
+/* Flush delay (in seconds) */
long silc_log_flushdelay = 300;
/* Regular pattern matching expression for the debug output */
-char *silc_log_debug_string = NULL;
+char silc_log_debug_string[128];
-/* Debug callbacks. If set these are used instead of default ones. */
+/* Debug callbacks. If set, these are triggered for each specific output. */
static SilcLogDebugCb silc_log_debug_cb = NULL;
static void *silc_log_debug_context = NULL;
static SilcLogHexdumpCb silc_log_hexdump_cb = NULL;
static bool silc_log_scheduled = FALSE;
static bool silc_log_no_init = FALSE;
-/* This is only needed during starting up -- don't lose any logging */
+/* This is only needed during starting up -- don't lose any logging message */
static bool silc_log_starting = TRUE;
/* The type wrapper utility. Translates a SilcLogType id to the corresponding
}
/* Given an open log file, checks the size and rotates it if there is a
- * max size set less then the current size */
+ * max size set lower then the current size */
static void silc_log_checksize(SilcLog log)
{
char newname[127];
if (!log || !log->fp || !log->maxsize)
return; /* we are not interested */
+
if ((size = ftell(log->fp)) < 0) {
/* OMG, EBADF is here.. we'll try our best.. */
FILE *oldfp = log->fp;
fclose(oldfp); /* we can discard the error */
log->fp = NULL; /* make sure we don't get here recursively */
- SILC_LOG_ERROR(("Error while checking size of the log file %s, fp=%d",
+ SILC_LOG_ERROR(("Error while checking size of the log file %s, fp=%p",
log->filename, oldfp));
return;
}
- if (size < log->maxsize) return;
+ if (size < log->maxsize)
+ return;
/* It's too big */
fprintf(log->fp, "[%s] [%s] Cycling log file, over max "
"logsize (%lu kilobytes)\n",
- silc_get_time(), log->typename, log->maxsize / 1024);
+ silc_get_time(0), log->typename, (unsigned long)log->maxsize / 1024);
fflush(log->fp);
fclose(log->fp);
- snprintf(newname, sizeof(newname), "%s.old", log->filename);
+ memset(newname, 0, sizeof(newname));
+ snprintf(newname, sizeof(newname) - 1, "%s.old", log->filename);
unlink(newname);
/* I heard the following syscall may cause portability issues, but I don't
if (!(log->fp = fopen(log->filename, "w")))
SILC_LOG_WARNING(("Couldn't reopen logfile %s for type \"%s\": %s",
log->filename, log->typename, strerror(errno)));
+#ifdef HAVE_CHMOD
+ chmod(log->filename, 0600);
+#endif /* HAVE_CHMOD */
}
/* Reset a logging channel (close and reopen) */
fflush(log->fp);
fclose(log->fp);
}
- if (!log->filename) return FALSE;
+ if (!log->filename[0]) return FALSE;
if (!(log->fp = fopen(log->filename, "a+"))) {
SILC_LOG_WARNING(("Couldn't reset logfile %s for type \"%s\": %s",
- log->filename, log->typename, strerror(errno)));
+ log->filename, log->typename, strerror(errno)));
return FALSE;
}
+
return TRUE;
}
/* Outputs the log message to the first available channel. Channels are
* ordered by importance (see SilcLogType documentation).
- * More importants channels can be printed on less important ones, but not
+ * More important channels can be printed on less important ones, but not
* vice-versa. */
void silc_log_output(SilcLogType type, char *string)
{
- char *typename;
+ const char *typename = NULL;
FILE *fp;
SilcLog log;
if ((type > SILC_LOG_MAX) || !(log = silc_log_find_by_type(type)))
goto end;
+ /* Save the original typename, because even if we redirect the message
+ * to another channel we'll keep however the original channel name */
+ typename = log->typename;
+
/* If there is a custom callback set, use it and return. */
if (log->cb) {
if ((*log->cb)(type, string, log->context))
goto end;
}
- /* save the original typename, because if we redirect the channel we
- * keep however the original destination channel name */
- typename = log->typename;
-
if (!silc_log_scheduled) {
if (silc_log_no_init == FALSE) {
fprintf(stderr,
goto end;
found:
- fprintf(fp, "[%s] [%s] %s\n", silc_get_time(), typename, string);
+ /* writes the logging string to the selected channel */
+ if (silc_log_timestamp)
+ fprintf(fp, "[%s] [%s] %s\n", silc_get_time(0), typename, string);
+ else
+ fprintf(fp, "[%s] %s\n", typename, string);
+
if (silc_log_quick || silc_log_starting) {
fflush(fp);
- if (log)
+ if (log) /* we may have been redirected to stderr */
silc_log_checksize(log);
}
end:
+ /* If debugging, also output the logging message to the console */
+ if (typename && silc_debug) {
+ fprintf(stderr, "[Logging] [%s] %s\n", typename, string);
+ fflush(stderr);
+ }
silc_free(string);
}
}
/* Set and initialize the specified logging channel. See the API reference */
-bool silc_log_set_file(SilcLogType type, char *filename, uint32 maxsize,
+bool silc_log_set_file(SilcLogType type, char *filename, SilcUInt32 maxsize,
SilcSchedule scheduler)
{
FILE *fp = NULL;
SilcLog log;
log = silc_log_find_by_type(type);
- if (!log || !scheduler)
+ if (!log)
return FALSE;
SILC_LOG_DEBUG(("Setting \"%s\" file to %s (max size=%d)",
filename, strerror(errno));
return FALSE;
}
+#ifdef HAVE_CHMOD
+ chmod(filename, 0600);
+#endif /* HAVE_CHMOD */
}
- /* remove old file */
- if (log->filename) {
- if (log->fp) {
- fflush(fp);
- fclose(fp);
- }
- silc_free(log->filename);
- log->filename = NULL;
+ /* clean the logging channel */
+ if (strlen(log->filename)) {
+ if (log->fp)
+ fclose(log->fp);
+ memset(log->filename, 0, sizeof(log->filename));
log->fp = NULL;
}
if (fp) {
- log->filename = strdup(filename);
+ memset(log->filename, 0, sizeof(log->filename));
+ strncpy(log->filename, filename,
+ strlen(filename) < sizeof(log->filename) ? strlen(filename) :
+ sizeof(log->filename) - 1);
log->fp = fp;
log->maxsize = maxsize;
}
- if (silc_log_scheduled)
- return TRUE;
-
- /* add schedule hook with a short delay to make sure we'll use right delay */
- silc_schedule_task_add(scheduler, 0, silc_log_fflush_callback,
- (void *) scheduler, 10, 0,
- SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
+ if (scheduler) {
+ if (silc_log_scheduled)
+ return TRUE;
- silc_log_scheduled = TRUE;
+ /* Add schedule hook with a short delay to make sure we'll use
+ right delay */
+ silc_schedule_task_add(scheduler, 0, silc_log_fflush_callback,
+ (void *) scheduler, 10, 0,
+ SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
+ silc_log_scheduled = TRUE;
+ }
return TRUE;
}
SILC_LOG_DEBUG(("Resetting all logs"));
SILC_FOREACH_LOG(u)
silc_log_reset(&silclogs[u]);
+ /* Immediately flush any possible warning message */
+ silc_log_flush_all();
}
/* Outputs the debug message to stderr. */
-void silc_log_output_debug(char *file, char *function,
+void silc_log_output_debug(char *file, const char *function,
int line, char *string)
{
if (!silc_debug)
goto end;
if (silc_log_debug_cb) {
- if ((*silc_log_debug_cb)(file, function, line, string,
+ if ((*silc_log_debug_cb)(file, (char *)function, line, string,
silc_log_debug_context))
goto end;
}
/* Hexdumps a message */
-void silc_log_output_hexdump(char *file, char *function,
+void silc_log_output_hexdump(char *file, const char *function,
int line, void *data_in,
- uint32 len, char *string)
+ SilcUInt32 len, char *string)
{
int i, k;
int off, pos, count;
goto end;
if (silc_log_hexdump_cb) {
- if ((*silc_log_hexdump_cb)(file, function, line, data_in, len, string,
+ if ((*silc_log_hexdump_cb)(file, (char *)function, line,
+ data_in, len, string,
silc_log_hexdump_context))
goto end;
}
void silc_log_set_debug_string(const char *debug_string)
{
- silc_free(silc_log_debug_string);
- if ((strchr(debug_string, '(') &&
- strchr(debug_string, ')')) ||
- strchr(debug_string, '$'))
- silc_log_debug_string = strdup(debug_string);
+ char *string;
+ int len;
+ if ((strchr(debug_string, '(') && strchr(debug_string, ')')) ||
+ strchr(debug_string, '$'))
+ string = strdup(debug_string);
else
- silc_log_debug_string = silc_string_regexify(debug_string);
+ string = silc_string_regexify(debug_string);
+ len = strlen(string);
+ if (len >= sizeof(silc_log_debug_string))
+ len = sizeof(silc_log_debug_string) - 1;
+ memset(silc_log_debug_string, 0, sizeof(silc_log_debug_string));
+ strncpy(silc_log_debug_string, string, len);
+ silc_free(string);
}