+ return &silclogs[SILC_LOG_FATAL];
+ default:
+ return NULL;
+ }
+ return NULL;
+}
+
+/* Given an open log file, checks the size and rotates it if there is a
+ * max size set less then the current size */
+static void silc_log_checksize(SilcLog log)
+{
+ char newname[127];
+ long size;
+
+ 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",
+ log->filename, oldfp));
+ 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);
+ fflush(log->fp);
+ fclose(log->fp);
+ snprintf(newname, sizeof(newname), "%s.old", log->filename);
+ unlink(newname);
+
+ /* I heard the following syscall may cause portability issues, but I don't
+ * have any other solution since SILC library doesn't provide any other
+ * function like this. -Johnny */
+ rename(log->filename, newname);
+ 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)));
+}
+
+/* Reset a logging channel (close and reopen) */
+
+static bool silc_log_reset(SilcLog log)
+{
+ if (!log) return FALSE;
+ if (log->fp) {
+ fflush(log->fp);
+ fclose(log->fp);
+ }
+ if (!log->filename) 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)));
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/* Internal timeout callback to flush log channels and check file sizes */
+
+SILC_TASK_CALLBACK(silc_log_fflush_callback)
+{
+ unsigned int u;
+ if (!silc_log_quick) {
+ silc_log_flush_all();
+ SILC_FOREACH_LOG(u)
+ silc_log_checksize(&silclogs[u]);
+ }
+ silc_log_starting = FALSE;
+ if (silc_log_flushdelay < SILC_LOG_FLUSH_MIN_DELAY)
+ silc_log_flushdelay = SILC_LOG_FLUSH_MIN_DELAY;
+ silc_schedule_task_add((SilcSchedule) context, 0, silc_log_fflush_callback,
+ context, silc_log_flushdelay, 0, SILC_TASK_TIMEOUT,
+ SILC_TASK_PRI_NORMAL);
+}
+
+/* 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
+ * vice-versa. */
+
+void silc_log_output(SilcLogType type, char *string)
+{
+ char *typename;
+ FILE *fp;
+ SilcLog log;
+
+ if ((type > SILC_LOG_MAX) || !(log = silc_log_find_by_type(type)))
+ goto end;
+
+ /* 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,
+ "Warning, trying to output without log files initialization, "
+ "log output is going to stderr\n");
+ silc_log_no_init = TRUE;