<commit_before>/*
 * logging.c: internal logging and debugging
 *
 * Copyright (C) 2008 Red Hat, Inc.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
 *
 */

#include <config.h>

#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <time.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#if HAVE_SYSLOG_H
#include <syslog.h>
#endif

#include "logging.h"
#include "memory.h"
#include "util.h"
#include "threads.h"

/*
 * Macro used to format the message as a string in virLogMessage
 * and borrowed from libxml2 (also used in virRaiseError)
 */
#define VIR_GET_VAR_STR(msg, str) {				\
    int       size, prev_size = -1;				\
    int       chars;						\
    char      *larger;						\
    va_list   ap;						\
                                                                \
    str = (char *) malloc(150);					\
    if (str != NULL) {						\
                                                                \
    size = 150;							\
                                                                \
    while (1) {							\
        va_start(ap, msg);					\
        chars = vsnprintf(str, size, msg, ap);			\
        va_end(ap);						\
        if ((chars > -1) && (chars < size)) {			\
            if (prev_size == chars) {				\
                break;						\
            } else {						\
                prev_size = chars;				\
            }							\
        }							\
        if (chars > -1)						\
            size += chars + 1;					\
        else							\
            size += 100;					\
        if ((larger = (char *) realloc(str, size)) == NULL) {	\
            break;						\
        }							\
        str = larger;						\
    }}								\
}

/*
 * A logging buffer to keep some history over logs
 */
#define LOG_BUFFER_SIZE 64000

static char virLogBuffer[LOG_BUFFER_SIZE + 1];
static int virLogLen = 0;
static int virLogStart = 0;
static int virLogEnd = 0;

/*
 * Filters are used to refine the rules on what to keep or drop
 * based on a matching pattern (currently a substring)
 */
struct _virLogFilter {
    const char *match;
    int priority;
};
typedef struct _virLogFilter virLogFilter;
typedef virLogFilter *virLogFilterPtr;

static virLogFilterPtr virLogFilters = NULL;
static int virLogNbFilters = 0;

/*
 * Outputs are used to emit the messages retained
 * after filtering, multiple output can be used simultaneously
 */
struct _virLogOutput {
    void *data;
    virLogOutputFunc f;
    virLogCloseFunc c;
    int priority;
};
typedef struct _virLogOutput virLogOutput;
typedef virLogOutput *virLogOutputPtr;

static virLogOutputPtr virLogOutputs = NULL;
static int virLogNbOutputs = 0;

/*
 * Default priorities
 */
static virLogPriority virLogDefaultPriority = VIR_LOG_DEFAULT;

static int virLogResetFilters(void);
static int virLogResetOutputs(void);

/*
 * Logs accesses must be serialized though a mutex
 */
virMutex virLogMutex;

static void virLogLock(void)
{
    virMutexLock(&virLogMutex);
}
static void virLogUnlock(void)
{
    virMutexUnlock(&virLogMutex);
}


static const char *virLogPriorityString(virLogPriority lvl) {
    switch (lvl) {
        case VIR_LOG_DEBUG:
            return("debug");
        case VIR_LOG_INFO:
            return("info");
        case VIR_LOG_WARN:
            return("warning");
        case VIR_LOG_ERROR:
            return("error");
    }
    return("unknown");
}

static int virLogInitialized = 0;

/**
 * virLogStartup:
 *
 * Initialize the logging module
 *
 * Returns 0 if successful, and -1 in case or error
 */
int virLogStartup(void) {
    if (virLogInitialized)
        return(-1);

    if (virMutexInit(&virLogMutex) < 0)
        return -1;

    virLogInitialized = 1;
    virLogLock();
    virLogLen = 0;
    virLogStart = 0;
    virLogEnd = 0;
    virLogDefaultPriority = VIR_LOG_DEFAULT;
    virLogUnlock();
    return(0);
}

/**
 * virLogReset:
 *
 * Reset the logging module to its default initial state
 *
 * Returns 0 if successful, and -1 in case or error
 */
int virLogReset(void) {
    if (!virLogInitialized)
        return(virLogStartup());

    virLogLock();
    virLogResetFilters();
    virLogResetOutputs();
    virLogLen = 0;
    virLogStart = 0;
    virLogEnd = 0;
    virLogDefaultPriority = VIR_LOG_DEFAULT;
    virLogUnlock();
    return(0);
}
/**
 * virLogShutdown:
 *
 * Shutdown the logging module
 */
void virLogShutdown(void) {
    if (!virLogInitialized)
        return;
    virLogLock();
    virLogResetFilters();
    virLogResetOutputs();
    virLogLen = 0;
    virLogStart = 0;
    virLogEnd = 0;
    virLogUnlock();
    virMutexDestroy(&virLogMutex);
    virLogInitialized = 0;
}

/*
 * Store a string in the ring buffer
 */
static void virLogStr(const char *str, int len) {
    int tmp;

    if (str == NULL)
        return;
    if (len <= 0)
        len = strlen(str);
    if (len > LOG_BUFFER_SIZE)
        return;
    virLogLock();

    /*
     * copy the data and reset the end, we cycle over the end of the buffer
     */
    if (virLogEnd + len >= LOG_BUFFER_SIZE) {
        tmp = LOG_BUFFER_SIZE - virLogEnd;
        memcpy(&virLogBuffer[virLogEnd], str, tmp);
        virLogBuffer[LOG_BUFFER_SIZE] = 0;
        memcpy(&virLogBuffer[0], &str[len], len - tmp);
        virLogEnd = len - tmp;
    } else {
        memcpy(&virLogBuffer[virLogEnd], str, len);
        virLogEnd += len;
    }
    /*
     * Update the log length, and if full move the start index
     */
    virLogLen += len;
    if (virLogLen > LOG_BUFFER_SIZE) {
        tmp = virLogLen - LOG_BUFFER_SIZE;
        virLogLen = LOG_BUFFER_SIZE;
        virLogStart += tmp;
    }
    virLogUnlock();
}

#if 0
/*
 * Output the ring buffer
 */
static int virLogDump(void *data, virLogOutputFunc f) {
    int ret = 0, tmp;

    if ((virLogLen == 0) || (f == NULL))<commit_msg>Fix logging buffer overrun read<commit_after>/*
 * logging.c: internal logging and debugging
 *
 * Copyright (C) 2008 Red Hat, Inc.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
 *
 */

#include <config.h>

#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <time.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#if HAVE_SYSLOG_H
#include <syslog.h>
#endif

#include "logging.h"
#include "memory.h"
#include "util.h"
#include "threads.h"

/*
 * Macro used to format the message as a string in virLogMessage
 * and borrowed from libxml2 (also used in virRaiseError)
 */
#define VIR_GET_VAR_STR(msg, str) {				\
    int       size, prev_size = -1;				\
    int       chars;						\
    char      *larger;						\
    va_list   ap;						\
                                                                \
    str = (char *) malloc(150);					\
    if (str != NULL) {						\
                                                                \
    size = 150;							\
                                                                \
    while (1) {							\
        va_start(ap, msg);					\
        chars = vsnprintf(str, size, msg, ap);			\
        va_end(ap);						\
        if ((chars > -1) && (chars < size)) {			\
            if (prev_size == chars) {				\
                break;						\
            } else {						\
                prev_size = chars;				\
            }							\
        }							\
        if (chars > -1)						\
            size += chars + 1;					\
        else							\
            size += 100;					\
        if ((larger = (char *) realloc(str, size)) == NULL) {	\
            break;						\
        }							\
        str = larger;						\
    }}								\
}

/*
 * A logging buffer to keep some history over logs
 */
#define LOG_BUFFER_SIZE 64000

static char virLogBuffer[LOG_BUFFER_SIZE + 1];
static int virLogLen = 0;
static int virLogStart = 0;
static int virLogEnd = 0;

/*
 * Filters are used to refine the rules on what to keep or drop
 * based on a matching pattern (currently a substring)
 */
struct _virLogFilter {
    const char *match;
    int priority;
};
typedef struct _virLogFilter virLogFilter;
typedef virLogFilter *virLogFilterPtr;

static virLogFilterPtr virLogFilters = NULL;
static int virLogNbFilters = 0;

/*
 * Outputs are used to emit the messages retained
 * after filtering, multiple output can be used simultaneously
 */
struct _virLogOutput {
    void *data;
    virLogOutputFunc f;
    virLogCloseFunc c;
    int priority;
};
typedef struct _virLogOutput virLogOutput;
typedef virLogOutput *virLogOutputPtr;

static virLogOutputPtr virLogOutputs = NULL;
static int virLogNbOutputs = 0;

/*
 * Default priorities
 */
static virLogPriority virLogDefaultPriority = VIR_LOG_DEFAULT;

static int virLogResetFilters(void);
static int virLogResetOutputs(void);

/*
 * Logs accesses must be serialized though a mutex
 */
virMutex virLogMutex;

static void virLogLock(void)
{
    virMutexLock(&virLogMutex);
}
static void virLogUnlock(void)
{
    virMutexUnlock(&virLogMutex);
}


static const char *virLogPriorityString(virLogPriority lvl) {
    switch (lvl) {
        case VIR_LOG_DEBUG:
            return("debug");
        case VIR_LOG_INFO:
            return("info");
        case VIR_LOG_WARN:
            return("warning");
        case VIR_LOG_ERROR:
            return("error");
    }
    return("unknown");
}

static int virLogInitialized = 0;

/**
 * virLogStartup:
 *
 * Initialize the logging module
 *
 * Returns 0 if successful, and -1 in case or error
 */
int virLogStartup(void) {
    if (virLogInitialized)
        return(-1);

    if (virMutexInit(&virLogMutex) < 0)
        return -1;

    virLogInitialized = 1;
    virLogLock();
    virLogLen = 0;
    virLogStart = 0;
    virLogEnd = 0;
    virLogDefaultPriority = VIR_LOG_DEFAULT;
    virLogUnlock();
    return(0);
}

/**
 * virLogReset:
 *
 * Reset the logging module to its default initial state
 *
 * Returns 0 if successful, and -1 in case or error
 */
int virLogReset(void) {
    if (!virLogInitialized)
        return(virLogStartup());

    virLogLock();
    virLogResetFilters();
    virLogResetOutputs();
    virLogLen = 0;
    virLogStart = 0;
    virLogEnd = 0;
    virLogDefaultPriority = VIR_LOG_DEFAULT;
    virLogUnlock();
    return(0);
}
/**
 * virLogShutdown:
 *
 * Shutdown the logging module
 */
void virLogShutdown(void) {
    if (!virLogInitialized)
        return;
    virLogLock();
    virLogResetFilters();
    virLogResetOutputs();
    virLogLen = 0;
    virLogStart = 0;
    virLogEnd = 0;
    virLogUnlock();
    virMutexDestroy(&virLogMutex);
    virLogInitialized = 0;
}

/*
 * Store a string in the ring buffer
 */
static void virLogStr(const char *str, int len) {
    int tmp;

    if (str == NULL)
        return;
    if (len <= 0)
        len = strlen(str);
    if (len > LOG_BUFFER_SIZE)
        return;
    virLogLock();

    /*
     * copy the data and reset the end, we cycle over the end of the buffer
     */
    if (virLogEnd + len >= LOG_BUFFER_SIZE) {
        tmp = LOG_BUFFER_SIZE - virLogEnd;
        memcpy(&virLogBuffer[virLogEnd], str, tmp);
        virLogBuffer[LOG_BUFFER_SIZE] = 0;
        memcpy(&virLogBuffer[0], &str[tmp], len - tmp);
        virLogEnd = len - tmp;
    } else {
        memcpy(&virLogBuffer[virLogEnd], str, len);
        virLogEnd += len;
    }
    /*
     * Update the log length, and if full move the start index
     */
    virLogLen += len;
    if (virLogLen > LOG_BUFFER_SIZE) {
        tmp = virLogLen - LOG_BUFFER_SIZE;
        virLogLen = LOG_BUFFER_SIZE;
        virLogStart += tmp;
    }
    virLogUnlock();
}

#if 0
/*
 * Output the ring buffer
 */
static int virLogDump(void *data, virLogOutputFunc f) {
    int ret = 0, tmp;

    if ((virLogLen == 0) || (f == NULL))
{'fraction_non_alphanumeric': 0.10251688152240639, 'fraction_numerical': 0.011203192142418661, 'mean_word_length': 2.2093080522038906, 'pattern_counts': {'":': 0, '<': 31, '<?xml version=': 0, '>': 35, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 2}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 12, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7506000', 'n_tokens_mistral': 4388, 'n_tokens_neox': 4065, 'n_words': 1245}